本文旨在使用SpringBoot + MyBatisPlus + thymeleaf 模版引擎实现分页效果。目标功能实现如下:
在此案例中,表单数据从数据库拿到,可动态显示当前页,总页数以及记录数。并且实现分页按钮组,包括动态生成页码,前一页和后一页。
首先,需要引入MyBatisPlus以及thymleaf模版引擎相关starter
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.4.1version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
相关环境引入之后,本文以User表为案例进行测试
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
//指定该entity映射到数据库中user_table这张表
@TableName("user_table")
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
CREATE TABLE user_table
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, '[email protected]'),
(2, 'Jack', 20, '[email protected]'),
(3, 'Tom', 28, '[email protected]'),
(4, 'Sandy', 21, '[email protected]'),
(5, 'Billie', 24, '[email protected]');
@Configuration
public class MyBatisConfig {
@Bean
public MybatisPlusInterceptor paginationInterceptor(){
//新建MybatisPlus拦截器
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
//新建分页拦截器paginationInnerInterceptor
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
//设置分页拦截器的一些属性
paginationInnerInterceptor.setOverflow(true);
paginationInnerInterceptor.setMaxLimit(100L);
//把分页拦截器添加到MybatisPlus拦截器中
mybatisPlusInterceptor.addInnerInterceptor(paginationInnerInterceptor);
//添加组件,大功告成!
return mybatisPlusInterceptor;
}
}
@Mapper
@Repository
public interface UserMapper extends BaseMapper<User> {
}
BaseMapper
类,其中的范性为该目标实体User
。该写法为MyBatisPlus的标准写法,继承BaseMapper
后,可以给予
CRUD功能UserService
接口:
public interface UserService extends IService<User> {
}
IService
,其中的范型为目标实体UserServiceImpl
:UserService
的真正实现类
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
首先,肯定要实现其对应的接口:implements Userservice
其次需要继承ServiceImpl
,该类为mybatisPlus中的IService
实现类,需要指定两个范性
。显而易见,第一个范性为User对应的Mybatis需要指定的的Mapper类,第二个范性为目标实体类User
@Controller
public class TableController {
//自动注入userService
@Autowired
UserService userService;
@GetMapping("/table")
public String tableController(@RequestParam(value = "pn",defaultValue = "1") Integer pn, Model model){
//新建分页构造函数Page T为目标实体类
Page<User> userPage = new Page<User>(pn, 2);
//result为分页查询结果
Page<User> result = userService.page(userPage);
model.addAttribute("result",result);
return "table";
}
}
Controller层相对复杂,主要是以下几个方面:
控制器参数部分 @RequestParam(value = "pn",defaultValue = "1") Integer pn
:前端传入一个需要跳转到的页面值pn
,默认为第一页
Page
:new一个分页构造函数类Page
的实体userPage
这个Page对象是所有分页功能最重要的一个类,强烈建议看看源码!!分页查询的结果与分页信息会全部包装在这个类中返回!!!
其构造函数源代码如下:
/** * 分页构造函数 * * @param current 当前页 * @param size 每页显示条数 */ public Page(long current, long size) { this(current, size, 0); }
即:传入你想指定的当前页值,和每页显示条数(好像是废话。。。)
Page
:调用userService
里面的page()
方法,传入我们实例化好的userPage
。
问题在这里: userService
没有定义任何方法,为什么会出现page()
这个方法呢?
这其实是userServiceImpl
所继承的ServiceImpl
提供的方法
而这里的Page类型的result返回值,里面会包括所有我们查询到的结果以及分页信息!!
model.addAttribute("result",result);
没什么好说的,把这个result直接丢进Model,返回到前端处理
前端使用了thymeleaf模版引擎,具体引入请参照官方文档
https://www.thymeleaf.org/
样式截取关键代码
<tbody>
<tr class="gradeX" th:each="user,stat:${result.records}">
<td th:text="${stat.count}">td>
<td th:text="${user.id}">td>
<td th:text="${user.name}">td>
<td th:text="${user.age}">td>
<td th:text="${user.email}">td>
tr>
tbody>
th:each="user,stat:${result.records}"
:这里的result为之前controller放进model的Page result
对象,我们可以通过result.records
获得我们查询返回的结果,并且命名每一个结果为user
进行循环输出,其中stat
为每个user
的状态(提供自thymeleaf模版),可以得到许多额外信息<div class="row-fluid">
<div class="span6">
<div class="dataTables_info" id="dynamic-table_info">
当前第 [[${result.current}]]
总计 [[${result.pages}]] 页
共[[${result.total}]] 条记录div>
div>
div>
result
为Page
对象,里面包含了所有分页相关的信息,我们可以调用其属性动态显示当前页码,页码总数,记录总数等信息!![[${}]]
该写法为thyemleaf取值的行内写法,具体请见相关文档<ul>
<li th:class="${result.current == 1}? 'prev disabled':'prve'" class="prev disabled">
<a th:href="@{/table(pn=${result.current}-1)}">← Previousa>li>
<li th:class="${num == result.current} ?'active':''"
th:each="num:${#numbers.sequence(1,result.pages)}">
<a th:href="@{/table(pn=${num})}">[[${num}]]a>
li>
<li class="next" th:class="${result.current == result.pages?'disabled next':'next'}">
<a th:href="@{/table(pn=${result.current}+1)}">Next → a>li>
ul>
该区域看似比较复杂,实则结构十分简单,简化如下:
<ul>
<li><a href="#">← Previousa>li>
<li><a href="#">动态生成的页面数a>li>
<li><a href="#">Next →a>li>
ul>
其中,Previous按钮与Next按钮的实现大同小异,以Previous按钮举例:
<li th:class="${result.current == 1}? 'prev disabled':'prve'" class="prev disabled">
<a th:href="@{/table(pn=${result.current}-1)}">← Previousa>li>
首先是标签内:
th:class
是thymeleaf模版引擎语法,可以修改class属性。
${result.current == 1}? 'prev disabled':'prve'
是一个三元运算符,由显示分页信息区域 模块的解释可知,result
是一个Page
对象,可以得到分页信息,如果当当前页面为1时,给标签添加
disabled
样式禁用其选择。否则允许选择
标签内:
th:href
语法同理可以修改a href
里面的属性,@{/table(pn=${result.current}-1)}
表示该标签链接指向
/table
请求而(pn=${result.current}-1)
为thymeleaf语句,即传入一个参数pn
,其值为result.current -1
,即当前页数-1,传回给Controller。(见Controller章节写法)
动态生成页数区域:
<li th:class="${num == result.current} ?'active':''"
th:each="num:${#numbers.sequence(1,result.pages)}">
<a th:href="@{/table(pn=${num})}">[[${num}]]a>
li>
标签中${num == result.current} ?'active':''"
三元运算符给予当前页被选中的样式,如上同理,不多解释。th:each="num:${#numbers.sequence(1,result.pages)}"
表示遍历生成${#numbers.sequence(1,result.pages)}
这些数字,每个数字叫做num
。而#numbers.sequence(from,to)
为themeleaf内置函数,可以生成从from
到to
的序列。在此例中表示生成1到result.pages的序列
标签中的原理与上类似,不同点在于赋值给pn
对应的页面值至此大功告成!