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

下面先看代码:

@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<Object> WeChatLogin(@RequestParam("code") String code, @RequestParam("userName") String userName) {
        try {
        /*1.优化点:如果可以让第一次登录的openId存储在小程序本地内存中,只需在前端判断是否这个openId为空,
        如果不为空,直接传到后端查数据库,避免了每一次都要访问一次微信登录网址的时间消耗。*/
            QueryChainWrapper<Appinfo> query = appinfoService.query();
            Appinfo appinfo = query.list().get(0);
            String weChatOPenId = requestUtils.getWeChatOPenId(appinfo.getAppId(), appinfo.getAppSecrtet(), code);

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

            if (count == 1) {
                UpdateWrapper<User> 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.<ConnectionSocketFactory>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;
    }

}

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

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

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

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

我们看下query的源码:

  default QueryChainWrapper<T> query() {
        return ChainWrappers.queryChain(this.getBaseMapper());
    }

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

public class QueryChainWrapper<T> 
extends AbstractChainWrapper<T, String, QueryChainWrapper<T>, QueryWrapper<T>> 
implements ChainQuery<T>, Query<QueryChainWrapper<T>, T, String> 

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

public interface ChainQuery<T> extends ChainWrapper<T> {
    default List<T> list() {
        return this.getBaseMapper().selectList(this.getWrapper());
    }

    default T one() {
        return this.getBaseMapper().selectOne(this.getWrapper());
    }

    default Optional<T> 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 <E extends IPage<T>> E page(E page) {
        return this.getBaseMapper().selectPage(page, this.getWrapper());
    }
}

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

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

// 根据 ID 查询
T getById(Serializable id);
// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
T getOne(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
// 根据 Wrapper,查询一条记录
Map<String, Object> getMap(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);


// 查询所有
List<T> list();
// 查询列表
List<T> list(Wrapper<T> queryWrapper);
// 查询(根据ID 批量查询)
Collection<T> listByIds(Collection<? extends Serializable> idList);
// 查询(根据 columnMap 条件)
Collection<T> listByMap(Map<String, Object> columnMap);
// 查询所有列表
List<Map<String, Object>> listMaps();
// 查询列表
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
// 查询全部记录
List<Object> listObjs();
// 查询全部记录
<V> List<V> listObjs(Function<? super Object, V> mapper);
// 根据 Wrapper 条件,查询全部记录
List<Object> listObjs(Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录
<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

// 无条件分页查询
IPage<T> page(IPage<T> page);
// 条件分页查询
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
// 无条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page);
// 条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);


// 查询总记录数
int count();
// 根据 Wrapper 条件,查询总记录数
int count(Wrapper<T> queryWrapper);

2、查询数据库是否存在主键WeChatId等于该登录用户openId的记录。

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

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

public class QueryWrapper<T> 
extends AbstractWrapper<T, String, QueryWrapper<T>> 
implements Query<QueryWrapper<T>, T, String> 

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

    public <V> Children allEq(boolean condition, Map<R, V> 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 <V> Children allEq(boolean condition, BiPredicate<R, V> filter, Map<R, V> 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<Children> consumer) {
        return this.and(condition).addNestedCondition(condition, consumer);
    }
    public Children or(boolean condition, Consumer<Children> consumer) {
        return this.or(condition).addNestedCondition(condition, consumer);
    }
    public Children nested(boolean condition, Consumer<Children> consumer) {
        return this.addNestedCondition(condition, consumer);
    }
    public Children not(boolean condition, Consumer<Children> 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之类的两个字母代表逻辑关系。这些都是数据库常用的比较方法。

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

 UpdateWrapper<User> 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 中的关键字)。

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

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/vklXHhttp://t.csdn.cn/vklXHhttp://t.csdn.cn/SA2xQhttp://t.csdn.cn/SA2xQ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ForestSpringH

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值