• 关于MybatisPlus使用的部分经验


    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进行经验分享:

    下面先看代码:

    1. @Slf4j
    2. @RestController
    3. @RequestMapping("/User")
    4. public class UserController {
    5. @Autowired
    6. private UserService userService;
    7. @Autowired
    8. private RequestUtils requestUtils;
    9. @Autowired
    10. private AppinfoService appinfoService;
    11. /**
    12. * 用户采用微信登录
    13. *
    14. * @return 登录成功返回响应对象
    15. */
    16. @GetMapping("/wechatLogin")
    17. @ResponseBody
    18. public R WeChatLogin(@RequestParam("code") String code, @RequestParam("userName") String userName) {
    19. try {
    20. /*1.优化点:如果可以让第一次登录的openId存储在小程序本地内存中,只需在前端判断是否这个openId为空,
    21. 如果不为空,直接传到后端查数据库,避免了每一次都要访问一次微信登录网址的时间消耗。*/
    22. QueryChainWrapper query = appinfoService.query();
    23. Appinfo appinfo = query.list().get(0);
    24. String weChatOPenId = requestUtils.getWeChatOPenId(appinfo.getAppId(), appinfo.getAppSecrtet(), code);
    25. QueryWrapper wrapper = new QueryWrapper<>();
    26. wrapper.ge("WeChatId", weChatOPenId);
    27. int count = (int) userService.count(wrapper);
    28. if (count == 1) {
    29. UpdateWrapper updateWrapper = new UpdateWrapper<>();
    30. updateWrapper.eq("WeChatId", weChatOPenId);
    31. User user = new User();
    32. user.setUserName(userName);
    33. boolean update = userService.update(user, updateWrapper);
    34. if (update) return R.success("登陆成功!");
    35. else throw new Exception("更新用户名异常!");
    36. } else {
    37. User user = new User();
    38. user.setWeChatId(weChatOPenId);
    39. user.setUserName(userName);
    40. user.setUserAccount(weChatOPenId);
    41. boolean save = userService.save(user);
    42. if (save) return R.success("登录成功!");
    43. else throw new Exception("新用户openId插入数据库异常!");
    44. }
    45. } catch (Exception e) {
    46. e.printStackTrace();
    47. return R.error("微信登录异常!");
    48. }
    49. }
    50. }
    51. 涉及到微信小程序中后台获取openId的方法,我把代码先放这里:

      1. @Component
      2. public class RequestUtils {
      3. /**
      4. * 获取微信小程序openid
      5. *
      6. * @param AppId 小程序Id
      7. * @param AppSecret 小程序密钥
      8. * @param code 小程序wx.login接口返回的临时的临时状态码
      9. * @return openid
      10. */
      11. public String getWeChatOPenId(String AppId, String AppSecret, String code) {
      12. try {
      13. /*1.拼接微信登录获取openId所需要访问的URL*/
      14. StringBuilder URL = new StringBuilder(WeChatConfig.loginUrl).append("?appId=").append(AppId).
      15. append("&secret=").append(AppSecret).append("&js_code=").append(code).
      16. append("&grant_type=authorization_code");
      17. /*2.创建http连接的客户端对象*/
      18. BasicHttpClientConnectionManager connectionManager;
      19. connectionManager = new BasicHttpClientConnectionManager(
      20. RegistryBuilder.create().
      21. register("http", PlainConnectionSocketFactory.getSocketFactory())
      22. .register("https", SSLConnectionSocketFactory.getSocketFactory())
      23. .build(), null, null, null
      24. );
      25. CloseableHttpClient httpClient = HttpClientBuilder.create().
      26. setConnectionManager(connectionManager)
      27. .build();
      28. HttpGet httpGet = new HttpGet(URL.toString());
      29. /*3.执行访问一次请求获取响应体内容*/
      30. HttpResponse httpResponse = httpClient.execute(httpGet);
      31. HttpEntity entity = httpResponse.getEntity();
      32. String s = EntityUtils.toString(entity, "UTF-8");
      33. JSONObject jsonObject = new JSONObject(s);
      34. /*4.从响应体中拿到openId并返回*/
      35. return jsonObject.get("openid").toString();
      36. } catch (Exception e) {
      37. System.out.println("---------小程序获取微信登录openId异常--------");
      38. e.printStackTrace();
      39. }
      40. /*出现异常即返回null*/
      41. return null;
      42. }
      43. }

      下面我们来逐步看登录的代码:

      1、获取小程序关键信息调用getWeChatOpenId方法获取openId。

      1. QueryChainWrapper query = appinfoService.query();
      2. Appinfo appinfo = query.list().get(0);
      3. String weChatOPenId = requestUtils.getWeChatOPenId(appinfo.getAppId(),appinfo.getAppSecrtet(), code);

      这里使用到了service层从IService继承来的方法query();

      我们看下query的源码:

      1. default QueryChainWrapper query() {
      2. return ChainWrappers.queryChain(this.getBaseMapper());
      3. }

      它的返回值类型是QueryChainWrapper,我们去看看这个类型的源码:

      1. public class QueryChainWrapper
      2. extends AbstractChainWrapper, QueryWrapper>
      3. implements ChainQuery, Query, T, String>

      它继承了AbstractChainWrapper父类,实现了ChainQuery接口,我们来看看这个接口的方法:

      1. public interface ChainQuery extends ChainWrapper {
      2. default List list() {
      3. return this.getBaseMapper().selectList(this.getWrapper());
      4. }
      5. default T one() {
      6. return this.getBaseMapper().selectOne(this.getWrapper());
      7. }
      8. default Optional oneOpt() {
      9. return Optional.ofNullable(this.one());
      10. }
      11. default Long count() {
      12. return SqlHelper.retCount(this.getBaseMapper().selectCount(this.getWrapper()));
      13. }
      14. default boolean exists() {
      15. return this.count() > 0L;
      16. }
      17. default extends IPage> E page(E page) {
      18. return this.getBaseMapper().selectPage(page, this.getWrapper());
      19. }
      20. }

      这里不难发现,我们的query.list();方法就是从这里得来的,显然就是从BaseMapper这个通用的类里得来的方法,这么看其实这些CRUD接口方法不过是从底层的BaseMapper拓展出来的。

      这里是IService可调用关于查询的方法

      1. // 根据 ID 查询
      2. T getById(Serializable id);
      3. // 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
      4. T getOne(Wrapper queryWrapper);
      5. // 根据 Wrapper,查询一条记录
      6. T getOne(Wrapper queryWrapper, boolean throwEx);
      7. // 根据 Wrapper,查询一条记录
      8. Map getMap(Wrapper queryWrapper);
      9. // 根据 Wrapper,查询一条记录
      10. V getObj(Wrapper queryWrapper, Functionsuper Object, V> mapper);
      11. // 查询所有
      12. List list();
      13. // 查询列表
      14. List list(Wrapper queryWrapper);
      15. // 查询(根据ID 批量查询)
      16. Collection listByIds(Collection idList);
      17. // 查询(根据 columnMap 条件)
      18. Collection listByMap(Map columnMap);
      19. // 查询所有列表
      20. List> listMaps();
      21. // 查询列表
      22. List> listMaps(Wrapper queryWrapper);
      23. // 查询全部记录
      24. List listObjs();
      25. // 查询全部记录
      26. List listObjs(Functionsuper Object, V> mapper);
      27. // 根据 Wrapper 条件,查询全部记录
      28. List listObjs(Wrapper queryWrapper);
      29. // 根据 Wrapper 条件,查询全部记录
      30. List listObjs(Wrapper queryWrapper, Functionsuper Object, V> mapper);
      31. // 无条件分页查询
      32. IPage page(IPage page);
      33. // 条件分页查询
      34. IPage page(IPage page, Wrapper queryWrapper);
      35. // 无条件分页查询
      36. IPage> pageMaps(IPage page);
      37. // 条件分页查询
      38. IPage> pageMaps(IPage page, Wrapper queryWrapper);
      39. // 查询总记录数
      40. int count();
      41. // 根据 Wrapper 条件,查询总记录数
      42. int count(Wrapper queryWrapper);
      43. 2、查询数据库是否存在主键WeChatId等于该登录用户openId的记录。

        1. QueryWrapper wrapper = new QueryWrapper<>();
        2. wrapper.ge("WeChatId", weChatOPenId);
        3. int count = (int) userService.count(wrapper);

        这里涉及到我们自行创建的实例wrapper,也即是常说的条件构造器。看一下它的源码:

        1. public class QueryWrapper
        2. extends AbstractWrapper>
        3. implements Query, T, String>

        继承了统一类型,看一下AbstractWrapper的源码:

        1. public Children allEq(boolean condition, Map params, boolean null2IsNull) {
        2. if (condition && CollectionUtils.isNotEmpty(params)) {
        3. params.forEach((k, v) -> {
        4. if (StringUtils.checkValNotNull(v)) {
        5. this.eq(k, v);
        6. } else if (null2IsNull) {
        7. this.isNull(k);
        8. }
        9. });
        10. }
        11. return this.typedThis;
        12. }
        13. public Children allEq(boolean condition, BiPredicate filter, Map params, boolean null2IsNull) {
        14. if (condition && CollectionUtils.isNotEmpty(params)) {
        15. params.forEach((k, v) -> {
        16. if (filter.test(k, v)) {
        17. if (StringUtils.checkValNotNull(v)) {
        18. this.eq(k, v);
        19. } else if (null2IsNull) {
        20. this.isNull(k);
        21. }
        22. }
        23. });
        24. }
        25. return this.typedThis;
        26. }
        27. public Children eq(boolean condition, R column, Object val) {
        28. return this.addCondition(condition, column, SqlKeyword.EQ, val);
        29. }
        30. public Children ne(boolean condition, R column, Object val) {
        31. return this.addCondition(condition, column, SqlKeyword.NE, val);
        32. }
        33. public Children gt(boolean condition, R column, Object val) {
        34. return this.addCondition(condition, column, SqlKeyword.GT, val);
        35. }
        36. public Children ge(boolean condition, R column, Object val) {
        37. return this.addCondition(condition, column, SqlKeyword.GE, val);
        38. }
        39. public Children lt(boolean condition, R column, Object val) {
        40. return this.addCondition(condition, column, SqlKeyword.LT, val);
        41. }
        42. public Children le(boolean condition, R column, Object val) {
        43. return this.addCondition(condition, column, SqlKeyword.LE, val);
        44. }
        45. public Children like(boolean condition, R column, Object val) {
        46. return this.likeValue(condition, SqlKeyword.LIKE, column, val, SqlLike.DEFAULT);
        47. }
        48. public Children notLike(boolean condition, R column, Object val) {
        49. return this.likeValue(condition, SqlKeyword.NOT_LIKE, column, val, SqlLike.DEFAULT);
        50. }
        51. public Children likeLeft(boolean condition, R column, Object val) {
        52. return this.likeValue(condition, SqlKeyword.LIKE, column, val, SqlLike.LEFT);
        53. }
        54. public Children likeRight(boolean condition, R column, Object val) {
        55. return this.likeValue(condition, SqlKeyword.LIKE, column, val, SqlLike.RIGHT);
        56. }
        57. public Children between(boolean condition, R column, Object val1, Object val2) {
        58. return this.maybeDo(condition, () -> {
        59. this.appendSqlSegments(this.columnToSqlSegment(column), SqlKeyword.BETWEEN, () -> {
        60. return this.formatParam((String)null, val1);
        61. }, SqlKeyword.AND, () -> {
        62. return this.formatParam((String)null, val2);
        63. });
        64. });
        65. }
        66. public Children notBetween(boolean condition, R column, Object val1, Object val2) {
        67. return this.maybeDo(condition, () -> {
        68. this.appendSqlSegments(this.columnToSqlSegment(column), SqlKeyword.NOT_BETWEEN, () -> {
        69. return this.formatParam((String)null, val1);
        70. }, SqlKeyword.AND, () -> {
        71. return this.formatParam((String)null, val2);
        72. });
        73. });
        74. }
        75. public Children and(boolean condition, Consumer consumer) {
        76. return this.and(condition).addNestedCondition(condition, consumer);
        77. }
        78. public Children or(boolean condition, Consumer consumer) {
        79. return this.or(condition).addNestedCondition(condition, consumer);
        80. }
        81. public Children nested(boolean condition, Consumer consumer) {
        82. return this.addNestedCondition(condition, consumer);
        83. }
        84. public Children not(boolean condition, Consumer consumer) {
        85. return this.not(condition).addNestedCondition(condition, consumer);
        86. }
        87. public Children or(boolean condition) {
        88. return this.maybeDo(condition, () -> {
        89. this.appendSqlSegments(SqlKeyword.OR);
        90. });
        91. }
        92. public Children apply(boolean condition, String applySql, Object... values) {
        93. return this.maybeDo(condition, () -> {
        94. this.appendSqlSegments(WrapperKeyword.APPLY, () -> {
        95. return this.formatSqlMaybeWithParam(applySql, (String)null, values);
        96. });
        97. });
        98. }
        99. public Children last(boolean condition, String lastSql) {
        100. if (condition) {
        101. this.lastSql.setStringValue(" " + lastSql);
        102. }
        103. return this.typedThis;
        104. }
        105. public Children comment(boolean condition, String comment) {
        106. if (condition) {
        107. this.sqlComment.setStringValue(comment);
        108. }
        109. return this.typedThis;
        110. }
        111. public Children first(boolean condition, String firstSql) {
        112. if (condition) {
        113. this.sqlFirst.setStringValue(firstSql);
        114. }
        115. return this.typedThis;
        116. }
        117. public Children exists(boolean condition, String existsSql, Object... values) {
        118. return this.maybeDo(condition, () -> {
        119. this.appendSqlSegments(SqlKeyword.EXISTS, () -> {
        120. return String.format("(%s)", this.formatSqlMaybeWithParam(existsSql, (String)null, values));
        121. });
        122. });
        123. }
        124. public Children notExists(boolean condition, String existsSql, Object... values) {
        125. return this.not(condition).exists(condition, existsSql, values);
        126. }
        127. public Children isNull(boolean condition, R column) {
        128. return this.maybeDo(condition, () -> {
        129. this.appendSqlSegments(this.columnToSqlSegment(column), SqlKeyword.IS_NULL);
        130. });
        131. }
        132. public Children isNotNull(boolean condition, R column) {
        133. return this.maybeDo(condition, () -> {
        134. this.appendSqlSegments(this.columnToSqlSegment(column), SqlKeyword.IS_NOT_NULL);
        135. });
        136. }
        137. public Children in(boolean condition, R column, Collection coll) {
        138. return this.maybeDo(condition, () -> {
        139. this.appendSqlSegments(this.columnToSqlSegment(column), SqlKeyword.IN, this.inExpression(coll));
        140. });
        141. }
        142. public Children in(boolean condition, R column, Object... values) {
        143. return this.maybeDo(condition, () -> {
        144. this.appendSqlSegments(this.columnToSqlSegment(column), SqlKeyword.IN, this.inExpression(values));
        145. });
        146. }
        147. public Children notIn(boolean condition, R column, Collection coll) {
        148. return this.maybeDo(condition, () -> {
        149. this.appendSqlSegments(this.columnToSqlSegment(column), SqlKeyword.NOT_IN, this.inExpression(coll));
        150. });
        151. }
        152. public Children notIn(boolean condition, R column, Object... values) {
        153. return this.maybeDo(condition, () -> {
        154. this.appendSqlSegments(this.columnToSqlSegment(column), SqlKeyword.NOT_IN, this.inExpression(values));
        155. });
        156. }

        不难发现里面有很多与linux的脚本程序的逻辑代码eq之类的两个字母代表逻辑关系。这些都是数据库常用的比较方法。

        3、如果用户登录过,需要实时更新用户的微信昵称。

        1. UpdateWrapper updateWrapper = new UpdateWrapper<>();
        2. updateWrapper.eq("WeChatId", weChatOPenId);
        3. User user = new User();
        4. user.setUserName(userName);
        5. boolean update = userService.update(user, updateWrapper);
        6. if (update) return R.success("登陆成功!");
        7. else throw new Exception("更新用户名异常!");

        这里需要注意的是wrapper条件构造器给的是比较,也就是sql语句中where的作用,实际上的user.setUserName(userName);决定的是set的作用(这里说的是update 表名 set 属性 = value  where 属性 = value 中的关键字)。

        4、如果用户没有登录过,就可以将唯一标识与相关信息插入数据库

        1. User user = new User();
        2. user.setWeChatId(weChatOPenId);
        3. user.setUserName(userName);
        4. user.setUserAccount(weChatOPenId);
        5. boolean save = userService.save(user);
        6. if (save) return R.success("登录成功!");
        7. else throw new Exception("新用户openId插入数据库异常!");

        这个就很简单的逻辑了,大家自行查看mybatisplus的CRUD接口描述也可以弄清楚的。

        至于微信登录后台发请求获取openId的方法,大家可以看我写的这两篇文章:

        http://t.csdn.cn/vklXHhttp://t.csdn.cn/vklXHhttp://t.csdn.cn/SA2xQhttp://t.csdn.cn/SA2xQ

      44. 相关阅读:
        c++知识点之 --输入输出
        视频号视频提取小程序,快速下载视频号视频
        sqoop连接MYSQL报错处理
        python机器学习之梯度下降法
        【集合】如果初始化HashMap,传一个17的值,它会怎么处理?
        学者观察 | 数字经济中长期发展中的区块链影响力——清华大学柴跃廷
        mkv转mp4,大家都在用的方法
        Python教程:csv如何保存字典数据
        12 克莱姆法则的几何解释
        Chapter0.1:拉普拉斯变换
      45. 原文地址:https://blog.csdn.net/m0_59588838/article/details/126310548