mybatis plus是我国程序员对mybatis框架的一个近国人开发习惯的改版,使用起来风格特殊,大部分的CRUD接口都需要自己尝试测试之后才能熟悉它的作用,使用起来的好处也很明显,相比于mybatis框架而言,它的dao层与service层对CRUD代码量进行了进一步的减少,使得我们在开发过程中只需要对controller层与特殊的核心业务进行大精力开发,常规业务它都给我们内置了。
关于这个框架的常规CRUD接口,大家可以查看官方文档,讲解的比较详细:CRUD 接口 | MyBatis-PlusMyBatis-Plus 官方文档https://www.baomidou.com/pages/49cc81/#service-crud-%E6%8E%A5%E5%8F%A3
我通过一个登录的controller层代码对mybatis plus进行经验分享:
下面先看代码:
- @Slf4j
- @RestController
- @RequestMapping("/User")
- public class UserController {
- @Autowired
- private UserService userService;
- @Autowired
- private RequestUtils requestUtils;
- @Autowired
- private AppinfoService appinfoService;
-
- /**
- * 用户采用微信登录
- *
- * @return 登录成功返回响应对象
- */
- @GetMapping("/wechatLogin")
- @ResponseBody
- public R
- try {
- /*1.优化点:如果可以让第一次登录的openId存储在小程序本地内存中,只需在前端判断是否这个openId为空,
- 如果不为空,直接传到后端查数据库,避免了每一次都要访问一次微信登录网址的时间消耗。*/
- QueryChainWrapper
query = appinfoService.query(); - Appinfo appinfo = query.list().get(0);
- String weChatOPenId = requestUtils.getWeChatOPenId(appinfo.getAppId(), appinfo.getAppSecrtet(), code);
-
- QueryWrapper
wrapper = new QueryWrapper<>(); - wrapper.ge("WeChatId", weChatOPenId);
- int count = (int) userService.count(wrapper);
-
- if (count == 1) {
- UpdateWrapper
updateWrapper = new UpdateWrapper<>(); - updateWrapper.eq("WeChatId", weChatOPenId);
- User user = new User();
- user.setUserName(userName);
- boolean update = userService.update(user, updateWrapper);
- if (update) return R.success("登陆成功!");
- else throw new Exception("更新用户名异常!");
- } else {
- User user = new User();
- user.setWeChatId(weChatOPenId);
- user.setUserName(userName);
- user.setUserAccount(weChatOPenId);
- boolean save = userService.save(user);
- if (save) return R.success("登录成功!");
- else throw new Exception("新用户openId插入数据库异常!");
- }
- } catch (Exception e) {
- e.printStackTrace();
- return R.error("微信登录异常!");
- }
- }
-
- }
涉及到微信小程序中后台获取openId的方法,我把代码先放这里:
- @Component
- public class RequestUtils {
- /**
- * 获取微信小程序openid
- *
- * @param AppId 小程序Id
- * @param AppSecret 小程序密钥
- * @param code 小程序wx.login接口返回的临时的临时状态码
- * @return openid
- */
- public String getWeChatOPenId(String AppId, String AppSecret, String code) {
- try {
- /*1.拼接微信登录获取openId所需要访问的URL*/
- StringBuilder URL = new StringBuilder(WeChatConfig.loginUrl).append("?appId=").append(AppId).
- append("&secret=").append(AppSecret).append("&js_code=").append(code).
- append("&grant_type=authorization_code");
- /*2.创建http连接的客户端对象*/
- BasicHttpClientConnectionManager connectionManager;
- connectionManager = new BasicHttpClientConnectionManager(
- RegistryBuilder.
create(). - register("http", PlainConnectionSocketFactory.getSocketFactory())
- .register("https", SSLConnectionSocketFactory.getSocketFactory())
- .build(), null, null, null
- );
- CloseableHttpClient httpClient = HttpClientBuilder.create().
- setConnectionManager(connectionManager)
- .build();
- HttpGet httpGet = new HttpGet(URL.toString());
- /*3.执行访问一次请求获取响应体内容*/
- HttpResponse httpResponse = httpClient.execute(httpGet);
- HttpEntity entity = httpResponse.getEntity();
- String s = EntityUtils.toString(entity, "UTF-8");
- JSONObject jsonObject = new JSONObject(s);
- /*4.从响应体中拿到openId并返回*/
- return jsonObject.get("openid").toString();
- } catch (Exception e) {
- System.out.println("---------小程序获取微信登录openId异常--------");
- e.printStackTrace();
- }
- /*出现异常即返回null*/
- return null;
- }
-
- }
下面我们来逐步看登录的代码:
- QueryChainWrapper
query = appinfoService.query(); - Appinfo appinfo = query.list().get(0);
- String weChatOPenId = requestUtils.getWeChatOPenId(appinfo.getAppId(),appinfo.getAppSecrtet(), code);
这里使用到了service层从IService
我们看下query的源码:
- default QueryChainWrapper
query() { - return ChainWrappers.queryChain(this.getBaseMapper());
- }
它的返回值类型是QueryChainWrapper
- public class QueryChainWrapper
- extends AbstractChainWrapper
, QueryWrapper> - implements ChainQuery
, Query, T, String>
它继承了AbstractChainWrapper父类,实现了ChainQuery接口,我们来看看这个接口的方法:
- public interface ChainQuery
extends ChainWrapper { - default List
list() { - return this.getBaseMapper().selectList(this.getWrapper());
- }
-
- default T one() {
- return this.getBaseMapper().selectOne(this.getWrapper());
- }
-
- default Optional
oneOpt() { - return Optional.ofNullable(this.one());
- }
-
- default Long count() {
- return SqlHelper.retCount(this.getBaseMapper().selectCount(this.getWrapper()));
- }
-
- default boolean exists() {
- return this.count() > 0L;
- }
-
- default
extends IPage> E page(E page) { - return this.getBaseMapper().selectPage(page, this.getWrapper());
- }
- }
这里不难发现,我们的query.list();方法就是从这里得来的,显然就是从BaseMapper这个通用的类里得来的方法,这么看其实这些CRUD接口方法不过是从底层的BaseMapper拓展出来的。
这里是IService
- // 根据 ID 查询
- T getById(Serializable id);
- // 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
- T getOne(Wrapper
queryWrapper) ; - // 根据 Wrapper,查询一条记录
- T getOne(Wrapper
queryWrapper, boolean throwEx) ; - // 根据 Wrapper,查询一条记录
- Map
getMap(Wrapper queryWrapper) ; - // 根据 Wrapper,查询一条记录
V getObj(Wrapper queryWrapper, Function super Object, V> mapper) ; -
-
- // 查询所有
- List
list(); - // 查询列表
- List
list(Wrapper queryWrapper) ; - // 查询(根据ID 批量查询)
- Collection
listByIds(Collection extends Serializable> idList); - // 查询(根据 columnMap 条件)
- Collection
listByMap(Map columnMap) ; - // 查询所有列表
- List
- // 查询列表
- List
- // 查询全部记录
- List
- // 查询全部记录
List listObjs(Function super Object, V> mapper); - // 根据 Wrapper 条件,查询全部记录
- List
- // 根据 Wrapper 条件,查询全部记录
List listObjs(Wrapper queryWrapper, Function super Object, V> mapper) ; -
- // 无条件分页查询
- IPage
page(IPage page) ; - // 条件分页查询
- IPage
page(IPage page, Wrapper queryWrapper) ; - // 无条件分页查询
- IPage
- // 条件分页查询
- IPage
-
-
- // 查询总记录数
- int count();
- // 根据 Wrapper 条件,查询总记录数
- int count(Wrapper
queryWrapper) ; -
- QueryWrapper
wrapper = new QueryWrapper<>(); - wrapper.ge("WeChatId", weChatOPenId);
- int count = (int) userService.count(wrapper);
这里涉及到我们自行创建的实例wrapper,也即是常说的条件构造器。看一下它的源码:
- public class QueryWrapper
- extends AbstractWrapper
> - implements Query
, T, String>
继承了统一类型,看一下AbstractWrapper的源码:
- public
Children allEq(boolean condition, Map params, boolean null2IsNull) { - if (condition && CollectionUtils.isNotEmpty(params)) {
- params.forEach((k, v) -> {
- if (StringUtils.checkValNotNull(v)) {
- this.eq(k, v);
- } else if (null2IsNull) {
- this.isNull(k);
- }
-
- });
- }
-
- return this.typedThis;
- }
- public
Children allEq(boolean condition, BiPredicate filter, Map params, boolean null2IsNull) { - if (condition && CollectionUtils.isNotEmpty(params)) {
- params.forEach((k, v) -> {
- if (filter.test(k, v)) {
- if (StringUtils.checkValNotNull(v)) {
- this.eq(k, v);
- } else if (null2IsNull) {
- this.isNull(k);
- }
- }
-
- });
- }
-
- return this.typedThis;
- }
- public Children eq(boolean condition, R column, Object val) {
- return this.addCondition(condition, column, SqlKeyword.EQ, val);
- }
- public Children ne(boolean condition, R column, Object val) {
- return this.addCondition(condition, column, SqlKeyword.NE, val);
- }
- public Children gt(boolean condition, R column, Object val) {
- return this.addCondition(condition, column, SqlKeyword.GT, val);
- }
- public Children ge(boolean condition, R column, Object val) {
- return this.addCondition(condition, column, SqlKeyword.GE, val);
- }
- public Children lt(boolean condition, R column, Object val) {
- return this.addCondition(condition, column, SqlKeyword.LT, val);
- }
- public Children le(boolean condition, R column, Object val) {
- return this.addCondition(condition, column, SqlKeyword.LE, val);
- }
- public Children like(boolean condition, R column, Object val) {
- return this.likeValue(condition, SqlKeyword.LIKE, column, val, SqlLike.DEFAULT);
- }
- public Children notLike(boolean condition, R column, Object val) {
- return this.likeValue(condition, SqlKeyword.NOT_LIKE, column, val, SqlLike.DEFAULT);
- }
- public Children likeLeft(boolean condition, R column, Object val) {
- return this.likeValue(condition, SqlKeyword.LIKE, column, val, SqlLike.LEFT);
- }
- public Children likeRight(boolean condition, R column, Object val) {
- return this.likeValue(condition, SqlKeyword.LIKE, column, val, SqlLike.RIGHT);
- }
- public Children between(boolean condition, R column, Object val1, Object val2) {
- return this.maybeDo(condition, () -> {
- this.appendSqlSegments(this.columnToSqlSegment(column), SqlKeyword.BETWEEN, () -> {
- return this.formatParam((String)null, val1);
- }, SqlKeyword.AND, () -> {
- return this.formatParam((String)null, val2);
- });
- });
- }
- public Children notBetween(boolean condition, R column, Object val1, Object val2) {
- return this.maybeDo(condition, () -> {
- this.appendSqlSegments(this.columnToSqlSegment(column), SqlKeyword.NOT_BETWEEN, () -> {
- return this.formatParam((String)null, val1);
- }, SqlKeyword.AND, () -> {
- return this.formatParam((String)null, val2);
- });
- });
- }
- public Children and(boolean condition, Consumer
consumer) { - return this.and(condition).addNestedCondition(condition, consumer);
- }
- public Children or(boolean condition, Consumer
consumer) { - return this.or(condition).addNestedCondition(condition, consumer);
- }
- public Children nested(boolean condition, Consumer
consumer) { - return this.addNestedCondition(condition, consumer);
- }
- public Children not(boolean condition, Consumer
consumer) { - return this.not(condition).addNestedCondition(condition, consumer);
- }
- public Children or(boolean condition) {
- return this.maybeDo(condition, () -> {
- this.appendSqlSegments(SqlKeyword.OR);
- });
- }
- public Children apply(boolean condition, String applySql, Object... values) {
- return this.maybeDo(condition, () -> {
- this.appendSqlSegments(WrapperKeyword.APPLY, () -> {
- return this.formatSqlMaybeWithParam(applySql, (String)null, values);
- });
- });
- }
- public Children last(boolean condition, String lastSql) {
- if (condition) {
- this.lastSql.setStringValue(" " + lastSql);
- }
-
- return this.typedThis;
- }
- public Children comment(boolean condition, String comment) {
- if (condition) {
- this.sqlComment.setStringValue(comment);
- }
-
- return this.typedThis;
- }
- public Children first(boolean condition, String firstSql) {
- if (condition) {
- this.sqlFirst.setStringValue(firstSql);
- }
-
- return this.typedThis;
- }
- public Children exists(boolean condition, String existsSql, Object... values) {
- return this.maybeDo(condition, () -> {
- this.appendSqlSegments(SqlKeyword.EXISTS, () -> {
- return String.format("(%s)", this.formatSqlMaybeWithParam(existsSql, (String)null, values));
- });
- });
- }
- public Children notExists(boolean condition, String existsSql, Object... values) {
- return this.not(condition).exists(condition, existsSql, values);
- }
- public Children isNull(boolean condition, R column) {
- return this.maybeDo(condition, () -> {
- this.appendSqlSegments(this.columnToSqlSegment(column), SqlKeyword.IS_NULL);
- });
- }
- public Children isNotNull(boolean condition, R column) {
- return this.maybeDo(condition, () -> {
- this.appendSqlSegments(this.columnToSqlSegment(column), SqlKeyword.IS_NOT_NULL);
- });
- }
- public Children in(boolean condition, R column, Collection> coll) {
- return this.maybeDo(condition, () -> {
- this.appendSqlSegments(this.columnToSqlSegment(column), SqlKeyword.IN, this.inExpression(coll));
- });
- }
- public Children in(boolean condition, R column, Object... values) {
- return this.maybeDo(condition, () -> {
- this.appendSqlSegments(this.columnToSqlSegment(column), SqlKeyword.IN, this.inExpression(values));
- });
- }
- public Children notIn(boolean condition, R column, Collection> coll) {
- return this.maybeDo(condition, () -> {
- this.appendSqlSegments(this.columnToSqlSegment(column), SqlKeyword.NOT_IN, this.inExpression(coll));
- });
- }
- public Children notIn(boolean condition, R column, Object... values) {
- return this.maybeDo(condition, () -> {
- this.appendSqlSegments(this.columnToSqlSegment(column), SqlKeyword.NOT_IN, this.inExpression(values));
- });
- }
不难发现里面有很多与linux的脚本程序的逻辑代码eq之类的两个字母代表逻辑关系。这些都是数据库常用的比较方法。
- UpdateWrapper
updateWrapper = new UpdateWrapper<>(); - updateWrapper.eq("WeChatId", weChatOPenId);
- User user = new User();
- user.setUserName(userName);
- boolean update = userService.update(user, updateWrapper);
- if (update) return R.success("登陆成功!");
- else throw new Exception("更新用户名异常!");
这里需要注意的是wrapper条件构造器给的是比较,也就是sql语句中where的作用,实际上的user.setUserName(userName);决定的是set的作用(这里说的是update 表名 set 属性 = value where 属性 = value 中的关键字)。
- User user = new User();
- user.setWeChatId(weChatOPenId);
- user.setUserName(userName);
- user.setUserAccount(weChatOPenId);
- boolean save = userService.save(user);
- if (save) return R.success("登录成功!");
- else throw new Exception("新用户openId插入数据库异常!");
这个就很简单的逻辑了,大家自行查看mybatisplus的CRUD接口描述也可以弄清楚的。
至于微信登录后台发请求获取openId的方法,大家可以看我写的这两篇文章:
http://t.csdn.cn/vklXH
http://t.csdn.cn/vklXHhttp://t.csdn.cn/SA2xQ
http://t.csdn.cn/SA2xQ