mybatis-plus使用练习

本文详细介绍了如何在项目中导入Mybatis-Plus依赖,配置数据源和分页插件,以及如何使用BaseMapper和IService接口进行数据库操作,包括Wrapper和IPage的使用方法。
摘要由CSDN通过智能技术生成

1、导入依赖

导入mybatis-plus 依赖

<!--导入 mybatis-plus 依赖 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>
       

第二:配置,包括配置文件配置和代码中的配置

1、在本地配置文件或配置中心 配置mysql数据源和mybatis-plus;

      注意:classpath* 与 classpath 的区别?

                 classpath* 记载本工程及其导入的依赖jar中的指定目录下的xml文件

                 classpath 只能导入本工程下的指定目录下的xml文件

spring:
  #配置数据源datasource
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://IP:PORT/database?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: username
    password: password

#配置mybatis-plus
mybatis-plus:
  #mapper文件地址
  mapper-locations: classpath*:/mapper/**/*.xml
  #设置主键自增
  global-config:
    db-config:
      id-type: auto

2、在工程的启动类上加上注解 @MapperScan(dao层接口的包路径)  来扫描注入dao层接口,

      代码如下所示:

//@MapperScan("com.gulimall.product.dao")
           @SpringBootApplication
           public class GulimallProductApplication {
              public static void main(String[] args) {
                 SpringApplication.run(GulimallProductApplication.class, args);
              }
           }

3、向工程中注入mybatis-plus 的分页插件 PaginationInnerInterceptor,否则分页报错;

     代码如下所示:

@Configuration
@EnableTransactionManagement //开启事务,只有这里开启了事务save/update/delete方法上的事务才会生效(可以在启动类上或mybatis配置上开启事务)
@MapperScan("com.gulimall.product.dao") //开启mapper接口扫描(可以在启动类上或mybatis配置上开启dao扫描)
public class MyBatisConfig {

    /**
     * 注入 mybatis plus 分页插件
     * @return
     */
    @Bean
    PaginationInnerInterceptor paginationInnerInterceptor(){
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();

        //配置请求页数大于最大页时的操作,true=返回首页,false=继续请求;默认是false
        paginationInnerInterceptor.setOverflow(true);
        //设置最大单页数据量限制,默认500单页最大显示500条,-1 表示不限制单页数量(即-1表示不分页)
        //paginationInnerInterceptor.setMaxLimit(500l);

        return paginationInnerInterceptor;
    }
}

第三:使用

       在工程中使用mybatis-plus 时,有三点要注意:

         1、dao层接口需要继承接口BaseMapper<T>,T表示sql要操作的对象类,代码如下所示:

//若BaseMapper 中的方法不满足业务场景,我们还可以根据业务需要定义相关方法
//并完成相应的sql
@Mapper
public interface CategoryDao extends BaseMapper<CategoryEntity> {
}

           BaseMapper接口常用方法介绍介绍:

//插入操作
int insert(T entity);
//根据id删除
int deleteById(Serializable id);
//删除,根据参数删除,参数以map方式传入
int deleteByMap(@Param("cm") Map<String, Object> columnMap);
//删除,根据queryWrapper 包含的条件删除
int delete(@Param("ew") Wrapper<T> queryWrapper);
//根据id集合批量删除
int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);
//根据id更改
int updateById(@Param("et") T entity);
//更新操作,只更新 entity包含的字段(updateWrapper中包含的条件字段不更新 )
int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);
//根据id查询
T selectById(Serializable id);

//根据多个id批量查询
List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
//根据map参数查询
List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);
//查询一条数据
T selectOne(@Param("ew") Wrapper<T> queryWrapper);
//统计符合条件数据总条数
Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);
//查询,不分页
List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
//查询结果是map
List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
//对象查询
List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);
//分页查询
<E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);
//分页查询
<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param("ew") Wrapper<T> queryWrapper);

2、service接口需要集成IService<T>,T表示业务操作的实体类;

               如果 IService 中的方法无法满足我们的业务需要,则可以在我们自己定义的service

               接口中定义方法;代码如下图所示:

public interface CategoryService extends IService<CategoryEntity> {

    /**
     * 分页查询
     * @param params
     * @return
     */
    PageUtils queryPage(Map<String,Object> params);

    /**
     * 将所有的商品分类查询出来,并构建成tree树结构
     * @return
     */
    List<CategoryEntity> listWithTree();
}

        3、service 接口的实现类需要集成类 ServiceImpl<M,T>,其中M表示dao层的mapper接口,

              T 表示要操作的实体类;代码如下所示:

@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage page = this.page(new Query<CategoryEntity>().getPage(params),
                new QueryWrapper<CategoryEntity>());

        return new PageUtils(page);
    }

    /**
     * 查询所有的商品分类,并按商品分类的层级关系构建出商品分类的Tree 树结构
     * @return
     */
    @Override
    public List<CategoryEntity> listWithTree() {

        //1、查询所有的商品分类
        List<CategoryEntity> list = this.list();

        //2、过滤1级分类
        list.stream()
                .filter(categoryEntity -> categoryEntity.getParentCid()==0) //过滤1级分类
                .map((menu) -> { //map() 函数做一些业务处理
                    //设置当前分类的子分类
                    menu.setChildren(getChildrens(menu,list));
                    return menu;
                })
                .sorted((m1,m2) -> {  //排序
                    return (m1.getSort()==null?0:m1.getSort()) - (m2.getSort()==null?0:m2.getSort());
                })
                .collect(Collectors.toList());  //将最终结果转换成集合
        return list;
    }
}

第四步:mybatis-plus 中 Wrapper 、IPage介绍

1、Wrapper

      打开BaseMapper和 IService 接口,发现里面的方法很多参数类型都是Wrapper<T>;

      Wrapper是由mybatis-plus提供的一个接口,用于动态封装sql查询或修改 条件,他最

     常用的2个实现类是 QueryWrapper 和 UpdateWrapper

    QueryWrapper 主要用于构建查询条件

    UpdateWrapper 主要用于构建修改sql的条件

   示例代码:

 //1、QueryWrapper用法
//查询 attr_group_id = 100的数据,等价于sql 中的 where attr_group_id = 100
QueryWrapper<AttrAttrgroupRelationEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("attr_group_id",100);
        List<AttrAttrgroupRelationEntity> relationList = relationDao.selectList(queryWrapper);


//2、UpdateWrapper 用法
//修改对象 groupRelation(groupRelation 是类AttrAttrgroupRelationEntity 的对象) 中 attr_id=10的数据,
//注意:只修改 groupRelation 对象中存在的字段(即有值的字段)
UpdateWrapper<AttrAttrgroupRelationEntity> wrapper =  new UpdateWrapper()
wrapper.eq("attr_id",10)
//修改
relationDao.update(groupRelation,wrapper)

          QueryWrapper 和 UpdateWrapper 常用条件方法介绍:

//column-表示 表字段名称,val-输入的字段值
//等于,等价于 column=val
eq(column,val) 
//不等于,等价于 column <> val
ne(column,val)
//等价于 or,后边跟上判断函数
or()
//and嵌套,and(子查询)
and()
//大于
gt(column,val)
//大于等于
ge(column,val)
//小于,匹配 column 的值小于val的数据
lt(column,val)
//小于等于
le(column,val)
//匹配列column 的值在[val1,val2]之间的数据
between(column,val1,val2):
//模糊查询 like "%val%"
like(column,val)
//模糊查询 not like "%val%"
notLike(column,val)
//模糊查询 like "%val"
likeLeft(column,val)
//模糊查询 like "val%"
likeRight(column,val)

//匹配 column 的值为null的数据
isNull(column)
//匹配 column 的值不为null的数据
isNotNull(column)
等价于 in 关键字,匹配column 的值在集合 Collection中
in(column,Collection)
//not in
notIn(column,Collection)
//分组,单个或多个字段名称column
groupBy(column)
//根据列column 升序排序,排序列column可以有多个
orderByAsc(columns)
//根据列column 降序排序,排序列column可以有多个
orderByDesc(columns)
//having 关键字
//sqlHaving-sql语句,params-sql语句的参数值,如:having("sum(age)>${0}",12)-表示 having sum(age)>12, ${0} 中 0表示参数的下标
having(String sqlHaving, Object... params)
//匹配符合sql语句的数据
exists("sql语句")
//匹配步符合sql语句的数据
notExists("sql语句")
//val:这里的val是一个sql语句,等价于 column in "sql语句",即匹配 column 的值在 sql语句执行的结果中
inSql(column, val)
//匹配 column 的值不在 sql语句执行的结果中
notInSql(column, val)
//拼接sql,applySql-要拼接的sql,vale-sql参数值
apply(applySql, val)

2、IPage

      IPage是mybatis plus 提供的用于分页查询的一个接口,打开分页方法的源码可以发现,在

      接口IService中的分页方法page() 中第一个参数和返回值类型都是IPage,IPage接口只有

      一个实现类,即Page     

    page() 分页方法结构如下:

     

//page()方法源码如下:

<E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);

     Page类核心属性如下:

//page 类核心属性

public class Page<T> implements IPage<T> {
    private static final long serialVersionUID = 8545996863226528798L;
    //查询结果数据列表
    private List<T> records;
    //总条数
    private long total;
    //每页展示数据条数
    private long size;
    //当前页码
    private long current;
    //排序字段
    private List<OrderItem> orders;
    private boolean optimizeCountSql;
    private boolean isSearchCount;
    private boolean hitCount;

    public Page() {
        this.records = Collections.emptyList();
        this.total = 0L;
        this.size = 10L;
        this.current = 1L;
        this.orders = new ArrayList();
        this.optimizeCountSql = true;
        this.isSearchCount = true;
        this.hitCount = false;
    }

    public Page(long current, long size) {
        this(current, size, 0L);
    }

    public Page(long current, long size, long total) {
        this(current, size, total, true);
    }

    public Page(long current, long size, boolean isSearchCount) {
        this(current, size, 0L, isSearchCount);
    }

    public Page(long current, long size, long total, boolean isSearchCount) {
        this.records = Collections.emptyList();
        this.total = 0L;
        this.size = 10L;
        this.current = 1L;
        this.orders = new ArrayList();
        this.optimizeCountSql = true;
        this.isSearchCount = true;
        this.hitCount = false;
        if (current > 1L) {
            this.current = current;
        }

        this.size = size;
        this.total = total;
        this.isSearchCount = isSearchCount;
    }
}

     

由上边的代码可以发现2个问题,

      1)每次分页查询我们都需要创建 Page 对象,并把前台传送过来的分页属性

            一个个设置到Page对象中,这段代码是重复的,我们可以把这段代买抽成一个公用方法

           去获取Page,如:getPage()

           代码如下: 

/**
     *
     * @param params   前端传递的查询参数集合
     * @param defaultOrderField  排序字段
     * @param isAsc   是否是默认排序规则ASC
     * @return
     */
public class Query<T> {

    public IPage<T> getPage(Map<String,Object> params){

        return getPage(params,null,false);
    }

    /**
     *
     * @param params   查询参数集合
     * @param defaultOrderField  排序字段
     * @param isAsc   是否是默认排序规则ASC
     * @return
     */
    public IPage<T> getPage(Map<String,Object> params,String defaultOrderField,boolean isAsc){
        //初始化分页参数
        long curPage = 0;
        long limit = 10;

        //从参数params 中获取分页参数
        if(params.get(Constant.PAGE) != null){
            curPage = Long.parseLong(String.valueOf(params.get(Constant.PAGE)));
        }
        if(params.get(Constant.LIMIT) != null){
            limit = Long.parseLong(String.valueOf(params.get(Constant.LIMIT)));
        }

        Page<T> page = new Page<T>(curPage,limit);
        //
        params.put(Constant.PAGE,page);

        //过滤sql字符串
        //获取排序字段和排序规则
        String orderField = SQLFilter.sqlInject((String) params.get(Constant.ORDER_FIELD));
        String order = (String) params.get(Constant.ORDER);
        //前端字段排序
        if(StringUtils.isNotEmpty(orderField) && StringUtils.isNotEmpty(order)){
            if(Constant.ASC.equalsIgnoreCase(order)) {
                return  page.addOrder(OrderItem.asc(orderField));
            }else {
                return page.addOrder(OrderItem.desc(orderField));
            }
        }

        //没有排序字段
        if(StringUtils.isBlank(defaultOrderField)){
            return page;
        }

        if(isAsc){
            page.addOrder(OrderItem.asc(defaultOrderField));
        }else {
            page.addOrder(OrderItem.desc(defaultOrderField));
        }


        return page;
    }
}

     SQLFilter是一个sql防注入工具类,代码如下:

public class SQLFilter {

    public static String sqlInject(String sql){

        if(StringUtils.isBlank(sql)){
            return null;
        }

        //过滤掉 '、"、;、\
        sql = StringUtils.replace(sql,"'","");
        sql = StringUtils.replace(sql,";","");
        sql = StringUtils.replace(sql,"\"","");
        sql = StringUtils.replace(sql,"\\","");

        //sql字符串转小写
        sql = StringUtils.lowerCase(sql);

        //非法关键字
        String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alter", "drop"};

        for(int i=0;i<keywords.length;i++){
            if(sql.indexOf(keywords[i]) >= 0){
                throw new RRException("包含非法字符");
            }
        }

        return sql;
    }
}

2)若我们直接把Page对象返回给前端,一些前端不需要的属性也会一起返回;针对这种问题

           我们可以重新创建一个类只包含需要返回前端的属性,如 PageUtil

      PageUtil 代码如下:

@Data
public class PageUtils implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 总数据数
     */
    private int totalCount;
    /**
     * 总页数
     */
    private int totalPage;
    /**
     * 每页数据条数
     */
    private int pageSize;
    /**
     * 当前页码
     */
    private int currPage;
    /**
     * 数据列表
     * 在泛型中 我们常常看到 <T>、<K>、<E>、<K,V> 等,但这些都是有固定类型的,类型在初始化时指定。
     * 但 <?> 表示不确定的Java类型
     */
    private List<?> list;

    /**
     * 分页
     * @param list
     * @param totalCount
     * @param totalPage
     * @param pageSize
     * @param currPage
     */
    public PageUtils(List<?> list,int totalCount,int totalPage,int pageSize,int currPage){
        this.list = list;
        this.totalCount = totalCount;
        this.totalPage = totalPage;
        this.pageSize = pageSize;
        this.currPage = currPage;
    }

    /**
     * 分页
     * @param page
     */
    public PageUtils(IPage<?> page){
        this.list = page.getRecords();
        this.totalCount = (int)page.getTotal();
        this.totalPage = (int) page.getPages();
        this.pageSize = (int)page.getSize();
        this.currPage = (int)page.getCurrent();
    }
}

    

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值