百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 优雅编程 > 正文

mybatis分页设置方法(mybatis-plus分页方法)

sinye56 2024-09-19 02:21 4 浏览 0 评论

分页拦截器PageInterceptor

import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
 * 分页拦截器,用于拦截需要进行分页查询的操作,然后对其进行分页处理
 *
 */
@Intercepts({ @Signature(method = "prepare", type = StatementHandler.class, args = { Connection.class }) })
public class PageInterceptor implements Interceptor {
 private String databaseType;// 数据库类型,不同的数据库有不同的分页方法
 /**
 * 拦截后要执行的方法
 */
 public Object intercept(Invocation invocation) throws Throwable {
 RoutingStatementHandler handler = (RoutingStatementHandler) invocation
 .getTarget();
 StatementHandler delegate = (StatementHandler) ReflectUtil
 .getFieldValue(handler, "delegate");
 BoundSql boundSql = delegate.getBoundSql();
 Object paramObj = boundSql.getParameterObject();
 // 判断参数里是否有page对象
 Pagination page = null;
 if (paramObj instanceof Pagination) {
 page = (Pagination) paramObj;
 } else if (paramObj instanceof Map) {
 for (Object arg : ((Map) paramObj).values()) {
 if (arg instanceof Page<?>) {
 page = (Pagination) arg;
 break;
 }
 }
 }
 if (page != null) {
 MappedStatement mappedStatement = (MappedStatement) ReflectUtil
 .getFieldValue(delegate, "mappedStatement");
 Connection connection = (Connection) invocation.getArgs()[0];
 String sql = boundSql.getSql();
 if (page.getTotalCount() < 0) { // 如果总数为负数表需要设置
 this.setTotalRecord(paramObj, mappedStatement, connection, page);
 }
 // 获取分页Sql语句
 String pageSql = this.getPageSql(page, sql);
 // 利用反射设置当前BoundSql对应的sql属性为我们建立好的分页Sql语句
 ReflectUtil.setFieldValue(boundSql, "sql", pageSql);
 }
 return invocation.proceed();
 }
 /**
 * 拦截器对应的封装原始对象的方法
 */
 public Object plugin(Object target) {
 return Plugin.wrap(target, this);
 }
 /**
 * 设置注册拦截器时设定的属性
 */
 public void setProperties(Properties properties) {
 this.databaseType = properties.getProperty("databaseType");
 }
 /**
 * 根据page对象获取对应的分页查询Sql语句,这里只做了两种数据库类型,Mysql和Oracle 其它的数据库都 没有进行分页
 *
 * @param page
 * 分页对象
 * @param sql
 * 原sql语句
 * @return
 */
 private String getPageSql(Pagination page, String sql) {
 StringBuffer sqlBuffer = new StringBuffer(sql);
 if ("mysql".equalsIgnoreCase(databaseType)) {
 return getMysqlPageSql(page, sqlBuffer);
 } else if ("oracle".equalsIgnoreCase(databaseType)) {
 return getOraclePageSql(page, sqlBuffer);
 }
 return sqlBuffer.toString();
 }
 /**
 * 获取Mysql数据库的分页查询语句
 *
 * @param page
 * 分页对象
 * @param sqlBuffer
 * 包含原sql语句的StringBuffer对象
 * @return Mysql数据库分页语句
 */
 private String getMysqlPageSql(Pagination page, StringBuffer sqlBuffer) {
 // 计算第一条记录的位置,Mysql中记录的位置是从0开始的。
 int offset = (page.getPageNo() - 1) * page.getPageCount();
 sqlBuffer.append(" limit ").append(offset).append(",")
 .append(page.getPageCount());
 return sqlBuffer.toString();
 }
 /**
 * 获取Oracle数据库的分页查询语句
 *
 * @param page
 * 分页对象
 * @param sqlBuffer
 * 包含原sql语句的StringBuffer对象
 * @return Oracle数据库的分页查询语句
 */
 private String getOraclePageSql(Pagination page, StringBuffer sqlBuffer) {
 // 计算第一条记录的位置,Oracle分页是通过rownum进行的,而rownum是从1开始的
 int offset = (page.getPageNo() - 1) * page.getPageCount() + 1;
 sqlBuffer.insert(0, "select u.*, rownum _rownum from (")
 .append(") u where rownum < ")
 .append(offset + page.getPageCount());
 sqlBuffer.insert(0, "select * from (").append(") where _rownum >= ")
 .append(offset);
 // 上面的Sql语句拼接之后大概是这个样子:
 // select * from (select u.*, rownum r from (select * from t_user) u
 // where rownum < 31) where r >= 16
 return sqlBuffer.toString();
 }
 /**
 * 给当前的参数对象page设置总记录数
 *
 * @param obj
 * Mapper映射语句对应的参数对象
 * @param mappedStatement
 * Mapper映射语句
 * @param connection
 * 当前的数据库连接
 */
 private void setTotalRecord(Object obj, MappedStatement mappedStatement,
 Connection connection, Pagination page) {
 BoundSql boundSql = mappedStatement.getBoundSql(obj);
 String sql = boundSql.getSql();
 String countSql = this.getCountSql(sql);
 List<ParameterMapping> parameterMappings = boundSql
 .getParameterMappings();
 BoundSql countBoundSql = new BoundSql(
 mappedStatement.getConfiguration(), countSql,
 parameterMappings, obj);
 ReflectUtil.setFieldValue(countBoundSql, "additionalParameters",
 ReflectUtil.getFieldValue(boundSql, "additionalParameters"));
 ReflectUtil.setFieldValue(countBoundSql, "metaParameters",
 ReflectUtil.getFieldValue(boundSql, "metaParameters"));
 ParameterHandler parameterHandler = new DefaultParameterHandler(
 mappedStatement, obj, countBoundSql);
 PreparedStatement pstmt = null;
 ResultSet rs = null;
 try {
 pstmt = connection.prepareStatement(countSql);
 parameterHandler.setParameters(pstmt);
 rs = pstmt.executeQuery();
 if (rs.next()) {
 int totalRecord = rs.getInt(1);
 // 给当前的参数page对象设置总记录数
 page.setTotalCount(totalRecord);
 }
 } catch (SQLException e) {
 e.printStackTrace();
 } finally {
 try {
 if (rs != null)
 rs.close();
 if (pstmt != null)
 pstmt.close();
 } catch (SQLException e) {
 e.printStackTrace();
 }
 }
 }
 /**
 * 根据原Sql语句获取对应的查询总记录数的Sql语句
 *
 * @param sql
 * @return
 */
 private String getCountSql(String sql) {
 return "select count(1) from (" + sql + ") _tmp";
 }
 /**
 * 利用反射进行操作的一个工具类
 *
 */
 private static class ReflectUtil {
 /**
 * 利用反射获取指定对象的指定属性
 *
 * @param obj
 * 目标对象
 * @param fieldName
 * 目标属性
 * @return 目标属性的值
 */
 public static Object getFieldValue(Object obj, String fieldName) {
 Object result = null;
 Field field = ReflectUtil.getField(obj, fieldName);
 if (field != null) {
 field.setAccessible(true);
 try {
 result = field.get(obj);
 } catch (IllegalArgumentException e) {
 e.printStackTrace();
 } catch (IllegalAccessException e) {
 e.printStackTrace();
 }
 }
 return result;
 }
 /**
 * 利用反射获取指定对象里面的指定属性
 *
 * @param obj
 * 目标对象
 * @param fieldName
 * 目标属性
 * @return 目标字段
 */
 private static Field getField(Object obj, String fieldName) {
 Field field = null;
 for (Class<?> clazz = obj.getClass(); clazz != Object.class; clazz = clazz
 .getSuperclass()) {
 try {
 field = clazz.getDeclaredField(fieldName);
 break;
 } catch (NoSuchFieldException e) {
 // 这里不用做处理,子类没有该字段可能对应的父类有,都没有就返回null。
 }
 }
 return field;
 }
 /**
 * 利用反射设置指定对象的指定属性为指定的值
 *
 * @param obj
 * 目标对象
 * @param fieldName
 * 目标属性
 * @param fieldValue
 * 目标值
 */
 public static void setFieldValue(Object obj, String fieldName,
 String fieldValue) {
 Field field = ReflectUtil.getField(obj, fieldName);
 if (field != null) {
 try {
 field.setAccessible(true);
 field.set(obj, fieldValue);
 } catch (IllegalArgumentException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 } catch (IllegalAccessException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 }
 }
 }
 /**
 * 利用反射设置指定对象的指定属性为指定的值
 *
 * @param obj
 * 目标对象
 * @param fieldName
 * 目标属性
 * @param fieldValue
 * 目标值
 */
 public static void setFieldValue(Object obj, String fieldName,
 Object fieldValue) {
 Field field = ReflectUtil.getField(obj, fieldName);
 if (field != null) {
 try {
 field.setAccessible(true);
 field.set(obj, fieldValue);
 } catch (IllegalArgumentException e) {
 e.printStackTrace();
 } catch (IllegalAccessException e) {
 e.printStackTrace();
 }
 }
 }
 }
 public String getDatabaseType() {
 return databaseType;
 }
 public void setDatabaseType(String databaseType) {
 this.databaseType = databaseType;
 }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317

配置分页拦截器

import com.yuntu.commons.mybatispage.*;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
 */
@Configuration
@MapperScan("com.yuntu.core.repository")
@EnableTransactionManagement
public class MybatisConfig {
 private static final String MYBATIS_CONFIG_FILE = "mybatis-config.xml";
 /**
 * 注册datasource,通过@ConfigurationProperties(prefix="c3p0")将properties文件中c3p0开头的属性map到datasource相应的属性上
 * @return
 */
 @Bean
 @ConfigurationProperties(prefix="c3p0")
 public ComboPooledDataSource dataSource() {
 return new ComboPooledDataSource();
 }
 @Bean(name = "sqlSessionFactory")
 public SqlSessionFactory sqlSessionFactoryBean() throws Exception {
 SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
 sqlSessionFactoryBean.setDataSource(dataSource());
 sqlSessionFactoryBean.setTypeAliasesPackage("com.friday.core.model");
 sqlSessionFactoryBean.setConfigLocation(new ClassPathResource(MYBATIS_CONFIG_FILE));
 PageInterceptor pageInterceptor = new PageInterceptor();
 pageInterceptor.setDatabaseType("mysql");
 sqlSessionFactoryBean.setPlugins(new Interceptor[]{pageInterceptor});
 return sqlSessionFactoryBean.getObject();
 }
 @Bean
 public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
 return new SqlSessionTemplate(sqlSessionFactory);
 }
 @Bean
 public PlatformTransactionManager transactionManager() {
 return new DataSourceTransactionManager(dataSource());
 }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

其他支持类:

import java.util.List;
/**
 * 分页基本实现
 * @param <T>
 */
public class Page<T> implements Pagination {
 /** 页码 */
 protected int pageNo;
 /** 每页记录条数 */
 protected int pageCount;
 /** 总页数 */
 protected int totalPage;
 /** 总记录条数 */
 protected int totalCount = -1;
 /** 用于存放查询结果 */
 protected List<T> resultList;
 public Page() {}
 public Page(Integer pageNo, int pageCount) {
 if(pageNo==null){
 pageNo=1;
 }
 if (pageNo <= 0) {
 pageNo=1;
 //throw new IllegalArgumentException("pageNo must be greater than 0.");
 }
 if (pageCount<=0 && pageCount>50) {
 pageCount=50;
 //throw new IllegalArgumentException("pageCount must be greater than 0.");
 }
 this.pageNo = pageNo;
 this.pageCount = pageCount;
 }
 public void setPageNo(int pageNo) {
 this.pageNo = pageNo;
 }
 public void setPageCount(int pageCount) {
 this.pageCount = pageCount;
 }
 public void setTotalPage(int totalPage) {
 this.totalPage = totalPage;
 }
 public int getPageNo() {
 return pageNo;
 }
 public int getPageCount() {
 return pageCount;
 }
 public int getTotalCount() {
 return totalCount;
 }
 public void setTotalCount(int totalCount) {
 this.totalCount = totalCount;
 if (totalCount < 0) { // 如果总数为负数, 表未设置
 totalPage = 0;
 } else { // 计算总页数
 totalPage = (totalCount / pageCount) + (totalCount % pageCount == 0 ? 0 : 1);
 }
 }
 public List<T> getResultList() {
 return resultList;
 }
 public void setResultList(List<T> resultList) {
 this.resultList = resultList;
 }
 public int getTotalPage() {
 return totalPage;
 }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
/**
 * 分页,在分页挡截中使用
 *
 */
public interface Pagination {
 /**
 * @return 当前页码
 */
 int getPageNo();
 /**
 * @return 每页记录数
 */
 int getPageCount();
 /**
 * @return 总记录数: 负数表尚未设置, 挡截器会使用count语句统计总数; 0或正整数表总数已设置, 挡截器将不会统计总数.
 */
 int getTotalCount();
 /**
 * @param totalCount 设置记录总数
 */
 void setTotalCount(int totalCount);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

使用:

在mapper接口中:

List<LibraryBookResult> getLibraryStatics(@Param("libraryBooksDto") LibraryBooksCollectDto libraryBooksDto, Pagination pagination);
1
2

在mapper.xml中不用关心分页情况

相关推荐

Linux两种光驱自动挂载的方法

环境:CentOS6.4西昆云服务器方式一修改fstab文件/etc/fstab是系统保存文件系统信息?静态文件,每一行描述一个文件系统;系统每次启动会读取此文件信息以确定需要挂载哪些文件系统。参...

linux系统运维,挂载和分区概念太难?在虚机下操作一次全掌握

虚拟机的好处就是可以模拟和学习生产环境的一切操作,假如我们还不熟悉磁盘操作,那先在虚机环境下多操作几次。这次来练习下硬盘扩容操作。虚拟机环境:centos8vm11linux设备命名规则在linux中...

Linux 挂载 NFS 外部存储 (mount 和 /etc/fstab)

mount:手工挂载,下次重启需再重新挂载,操作命令:mount-tnfs-ooptionsserver:/remote/export/local/directory上面命令中,本地目录...

在Linux中如何设置自动挂载特定文件系统(示例)

Linux...

Linux环境中的绑定挂载(bind mount)

简介:Linux中的mount命令是一个特殊的指令,主要用于挂载文件目录。而绑定挂载(bindmount)命令更为特别。mount的bind选项将第一个目录克隆到第二个。一个目录中的改变将会在...

Linux挂载CIFS共享 临时挂载 1. 首先

如何解决服务器存储空间不足的问题?大家好,欢迎回来。在上一期视频中,我为大家介绍了如何利用Linux挂载来扩容服务器存储空间。这一期视频,我将以Linux为例,教大家如何进行扩容。群辉使用的是Linu...

Linux 硬盘挂载(服务器重启自动挂载)

1、先查看目前机器上有几块硬盘,及已挂载磁盘:fdisk-l能够查看到当前主机上已连接上的磁盘,以及已经分割的磁盘分区。(下面以/dev/vdb磁盘进行分区、挂载为例,挂载点设置为/data)df...

linux 挂载磁盘

在Linux中挂载硬盘的步骤如下:...

笨小猪教您Linux磁盘挂载

本教程针对Linux系统比较熟悉或者想学习Linux基础的用户朋友,本教程操作起来比较傻瓜式,跟着步骤就会操作,本文使用的工具是XShell同时多多注意空格(文中会有提示)。【问答】什么是磁盘挂载?答...

Linux 磁盘挂载和docker安装命令

本篇给大家介绍Linux磁盘挂载和docker安装的相关内容,Linux服务器的操作是一个手熟的过程,一些不常用的命令隔断时间就忘记了,熟话说好记性不如烂笔头,还需在平时的工作中多练习记录。...

Linux设置开机自动挂载分区

有时候,我们在安装完Linux系统之后,可能在使用过程中添加硬盘或者分区进行使用,这时候就需要手动把磁盘分区挂载到某个路径,但是开机之后就会消失,需要重新挂载,非常麻烦,那么我们应该如何设置开机自动挂...

在linux挂载一个新硬盘的完整步骤

以下是在Linux中挂载新原始磁盘的完整步骤,包括分区、创建文件系统以及使用UUID在/etc/fstab中启动时挂载磁盘:将新的原始磁盘连接到Linux系统并打开电源。运行以下命令,...

Linux系统如何挂载exFAT分区

简介:Linux系统中不能像Windows系统那样自动识别加载新设备,需要手动识别,手动加载。Linux中一切皆文件。文件通过一个很大的文件树来组织,文件树的根目录是:/,从根目开始录逐级展开。这些文...

Linux系统挂载硬盘

fdisk-l查看可挂载的磁盘都有哪些df-h查看已经挂载的磁盘...

WSL2发布,如何在Win10中挂载Linux文件系统

WSL2是最新版本的架构,它为Windows子系统提供支持,使其能够在Windows上运行ELF64Linux二进制文件。通过最近的更新,它允许使用Linux文件系统访问存储在硬盘中的文件。如果你...

取消回复欢迎 发表评论: