當前位置:
首頁 > 知識 > mybatis分頁設置方法

mybatis分頁設置方法

分頁攔截器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中不用關心分頁情況

mybatis分頁設置方法

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員小新人學習 的精彩文章:

教你編寫一個手勢解鎖控制項
HTTP協議又冷又實用的技能大全

TAG:程序員小新人學習 |