前面整合了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/… 分页的实现原理可以看一下这篇文章。