学习springBoot(7)Pagehelper、BaseMapper 整合

1,308 阅读7分钟

前面整合了redis ,现在继续,我们知道在web开发中分页是必不可少的,今天介绍一个分页插件,以及 baseMapper ,通过baseMapper 可以极大的减少我们开发中书写CRUD 的代码量

1、下面先加入我们的Jar包:

        <!-- 通用Mapper插件
        文档地址:https://gitee.com/free/Mapper/wikis/Home -->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>2.0.2</version>
        </dependency>

        <!-- 分页插件
         文档地址:https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.5</version>
        </dependency>

2、修改application.yml 文件,加入相关的配置

pagehelper:
  #分页插件会自动检测当前的数据库链接,自动选择合适的分页方式。 你可以配置helperDialect属性来指定分页插件使用哪种方言。配置时,可以使用下面的缩写值:
  #oracle,mysql,mariadb,sqlite,hsqldb,postgresql,db2,sqlserver,informix,h2,sqlserver2012,derby
  #特别注意:使用 SqlServer2012 数据库时,需要手动指定为 sqlserver2012,否则会使用 SqlServer2005 的方式进行分页
  helperDialect: mysql
  #分页合理化
  reasonable: false
  #是否支持接口参数来传递分页参数,默认false
  support-methods-arguments: true
  params: count=countSql
  helper-dialect: mysql
  #当设置为true的时候,如果pagesize设置为0(或RowBounds的limit=0),就不执行分页,返回全部结果
  pageSizeZero: false

mybatis:
  typeAliasesPackage: com.test.entity # 配置別名
  mapperLocations: classpath*:mapping/*.xml #注意点:在classpath后面的*必不可少,缺少星号的话后面的通配符不起作用。  **表示可以表示任意多级目录  *表示多个任意字符
  # 驼峰命名规范 如:数据库字段是  order_id 那么 实体字段就要写成 orderId
  configuration:
    map-underscore-to-camel-case: true
mapper:
  #枚举按简单类型处理,如果有枚举字段则需要加上该配置才会做映射
  enum-as-simple-type: true
  identity: MYSQL
  #设置以后,会去判断 insert 和 update 中符串类型!=’’
  not-empty: true
  mappers: tk.mybatis.mapper.common.BaseMapper

#设置将SQL语句打印到控制台 level后面是 mybatis接口目录
logging:
  level:
    com:
      test:
        mapper: DEBUG

3、修改实体类

package com.test.entity;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;

@Table(name="book") //数据库对应表名
public class Book implements Serializable {


    /**
     * PS:@GeneratedValue注解的strategy属性提供四种值:
     *
     * -AUTO主键由程序控制, 是默认选项 ,不设置就是这个
     *
     * -IDENTITY 主键由数据库生成, 采用数据库自增长, Oracle不支持这种方式
     *
     * -SEQUENCE 通过数据库的序列产生主键, MYSQL  不支持
     *
     * -Table 提供特定的数据库产生主键, 该方式更有利于数据库的移植
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String bookName;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName == null ? null : bookName.trim();
    }

    public Book(Integer id,String bookName) {
        this.id = id;
        this.bookName = bookName;
    }

}

4、修改mapper 接口文件,这里要注意的是,因为已经继承baseMapper, 我们自己的mapper 基本的CRUD就不用写了, 只写自己的业务代码即可,这里还有一个坑,因为之前通过代码生成工具已经生成了mapper的映射文件(****.xml),里面已经有了CRUD的方法,这里要都删除避免冲突

mapper:

@Component
public interface BookMapper extends BaseMapper<Book> {

}

mapper映射文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.test.mapper.BookMapper">

</mapper>

5、还有一个问题要处理,这时我们直接启动没有问题,通过测试类调用mapper时会报如下的错误

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: Error invoking SqlProvider method (tk.mybatis.mapper.provider.base.BaseSelectProvider.dynamicSQL).  Cause: java.lang.InstantiationException: tk.mybatis.mapper.provider.base.BaseSelectProvider

//后面的省略

在网上找了一下,结果发现又是一个坑。。。。

原因是SpringBoot主类中@MapperScan注解本来使用的是org.mybatis.spring.annotation.MapperScan;

重新引入tk.mybatis.spring.annotation.MapperScan;重启springboot服务器即可正常

@SpringBootApplication
@MapperScan("com.test.mapper")//将项目中对应的mapper类的路径加进来就可以了
public class Springboot1Application {

    private static Logger logger = LoggerFactory.getLogger(Springboot1Application.class);
    public static void main(String[] args) {
        SpringApplication.run(Springboot1Application.class, args);
        logger.info("项目启动成功!~~~~~~~~~~~~~~~~~");
    }
}

6、下面开始测试

这里还有一个问题,插入的时候出现乱码,修改一下application.yml 中的数据库连接配置,别的不用动

    url: jdbc:mysql://127.0.0.1:3306/springboot?useSSL=true&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true

测试类代码:

@RunWith(SpringRunner.class)
@SpringBootTest
public class Springboot1ApplicationTests {
    private static Logger logger = LoggerFactory.getLogger(Springboot1ApplicationTests.class);

    @Autowired
    private BookMapper bookMapper;

    @Test
    public void test() {

        for (int i = 0; i < 20; i++) {
            bookMapper.insertSelective(new Book(i,"西游记" + " - 卷("+i+")"));
        }

        logger.info("插入成功-----------------");

        PageInfo<Object> pageInfo = PageHelper.startPage(1, 10).setOrderBy("id desc").doSelectPageInfo(() -> this.bookMapper.selectAll());
        logger.info("[lambda写法] - [分页信息] - [{}]", pageInfo.toString());

        PageHelper.startPage(1, 10).setOrderBy("id desc");
        PageInfo<Book> userPageInfo = new PageInfo<Book>(this.bookMapper.selectAll());
        logger.info("[普通写法] - [{}]", userPageInfo);
        
        List<Book> bookList = userPageInfo.getList();
        bookList.forEach(book -> {
            logger.info("[查询数据集合] - [{}]", JSONObject.toJSON(book));
        });

    }

}

看一下数据的查询结果,没有问题,这样在结合一下前端的分页插件就可以轻松的实现分页查询

2018-09-03 17:07:36.002 INFO  com.example.demo.Springboot1ApplicationTests 46 lambda$test$1 - [查询数据集合] - [{id=19, bookName=西游记 - 卷(19)}]
2018-09-03 17:07:36.003 INFO  com.example.demo.Springboot1ApplicationTests 46 lambda$test$1 - [查询数据集合] - [{id=18, bookName=西游记 - 卷(18)}]
2018-09-03 17:07:36.003 INFO  com.example.demo.Springboot1ApplicationTests 46 lambda$test$1 - [查询数据集合] - [{id=17, bookName=西游记 - 卷(17)}]
2018-09-03 17:07:36.003 INFO  com.example.demo.Springboot1ApplicationTests 46 lambda$test$1 - [查询数据集合] - [{id=16, bookName=西游记 - 卷(16)}]
2018-09-03 17:07:36.003 INFO  com.example.demo.Springboot1ApplicationTests 46 lambda$test$1 - [查询数据集合] - [{id=15, bookName=西游记 - 卷(15)}]
2018-09-03 17:07:36.003 INFO  com.example.demo.Springboot1ApplicationTests 46 lambda$test$1 - [查询数据集合] - [{id=14, bookName=西游记 - 卷(14)}]
2018-09-03 17:07:36.003 INFO  com.example.demo.Springboot1ApplicationTests 46 lambda$test$1 - [查询数据集合] - [{id=13, bookName=西游记 - 卷(13)}]
2018-09-03 17:07:36.003 INFO  com.example.demo.Springboot1ApplicationTests 46 lambda$test$1 - [查询数据集合] - [{id=12, bookName=西游记 - 卷(12)}]
2018-09-03 17:07:36.004 INFO  com.example.demo.Springboot1ApplicationTests 46 lambda$test$1 - [查询数据集合] - [{id=11, bookName=西游记 - 卷(11)}]
2018-09-03 17:07:36.004 INFO  com.example.demo.Springboot1ApplicationTests 46 lambda$test$1 - [查询数据集合] - [{id=10, bookName=西游记 - 卷(10)}]

8、之前因为业务需要,做了mySql 的批量插入,在这里也做下总结吧,直接改一下之前的代码,在mapper中加入批量插入的方法

测试类:

        List<Book> books = new LinkedList<>();

        for (int i = 20; i < 40; i++) {
            books.add(new Book(i,"西游记" + " - 卷("+i+")"));
        }
        
        bookMapper.insertList(books);

bookMapper:

public interface BookMapper extends BaseMapper<Book> {

    int insertList(List<Book> books);
}

xml映射文件:

    <!--批量插入-->
    <insert id="insertList">
        INSERT INTO book(
        id,
        book_name
        ) VALUES
        <foreach collection="list" item="books" index="index" separator=",">
        (
            #{books.id},
            #{books.bookName}
        )
        </foreach>
    </insert>

在看一下查询结果:

2018-09-03 17:31:11.740 INFO  com.example.demo.Springboot1ApplicationTests 55 lambda$test$1 - [查询数据集合] - [{id=39, bookName=西游记 - 卷(39)}]
2018-09-03 17:31:11.741 INFO  com.example.demo.Springboot1ApplicationTests 55 lambda$test$1 - [查询数据集合] - [{id=38, bookName=西游记 - 卷(38)}]
2018-09-03 17:31:11.741 INFO  com.example.demo.Springboot1ApplicationTests 55 lambda$test$1 - [查询数据集合] - [{id=37, bookName=西游记 - 卷(37)}]
2018-09-03 17:31:11.741 INFO  com.example.demo.Springboot1ApplicationTests 55 lambda$test$1 - [查询数据集合] - [{id=36, bookName=西游记 - 卷(36)}]
2018-09-03 17:31:11.742 INFO  com.example.demo.Springboot1ApplicationTests 55 lambda$test$1 - [查询数据集合] - [{id=35, bookName=西游记 - 卷(35)}]
2018-09-03 17:31:11.742 INFO  com.example.demo.Springboot1ApplicationTests 55 lambda$test$1 - [查询数据集合] - [{id=34, bookName=西游记 - 卷(34)}]
2018-09-03 17:31:11.743 INFO  com.example.demo.Springboot1ApplicationTests 55 lambda$test$1 - [查询数据集合] - [{id=33, bookName=西游记 - 卷(33)}]
2018-09-03 17:31:11.743 INFO  com.example.demo.Springboot1ApplicationTests 55 lambda$test$1 - [查询数据集合] - [{id=32, bookName=西游记 - 卷(32)}]
2018-09-03 17:31:11.743 INFO  com.example.demo.Springboot1ApplicationTests 55 lambda$test$1 - [查询数据集合] - [{id=31, bookName=西游记 - 卷(31)}]
2018-09-03 17:31:11.743 INFO  com.example.demo.Springboot1ApplicationTests 55 lambda$test$1 - [查询数据集合] - [{id=30, bookName=西游记 - 卷(30)}]

foreach 中属性的含义:

collection="list" 其中list是固定的,如果是数组就是array

item="item" 循环中每一项的别名

open="" 开始标识,比如删除in (id1,id2), open="(" close=")"

close="" 结束标识

separator="," 分隔符号

index="index" 下标值

PageHelper分页插件源码及原理剖析: blog.csdn.net/u014082617/… 分页的实现原理可以看一下这篇文章。