分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow
也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!
1. Page
package com.sm.model;import java.util.List;public class Page<T> { public static final int DEFAULT_PAGE_SIZE = 20; protected int pageNo = 1; // 当前页, 默认为第1页 protected int pageSize = DEFAULT_PAGE_SIZE; // 每页记录数 protected long totalRecord = -1; // 总记录数, 默认为-1, 表示需要查询 protected int totalPage = -1; // 总页数, 默认为-1, 表示需要计算 protected List<T> results; // 当前页记录List形式 public int getPageNo() { return pageNo; } public void setPageNo(int pageNo) { this.pageNo = pageNo; } public int getPageSize() { return pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; computeTotalPage(); } public long getTotalRecord() { return totalRecord; } public int getTotalPage() { return totalPage; } public void setTotalRecord(long totalRecord) { this.totalRecord = totalRecord; computeTotalPage(); } protected void computeTotalPage() { if (getPageSize() > 0 && getTotalRecord() > -1) { this.totalPage = (int) (getTotalRecord() % getPageSize() == 0 ? getTotalRecord() / getPageSize() : getTotalRecord() / getPageSize() + 1); } } public List<T> getResults() { return results; } public void setResults(List<T> results) { this.results = results; } @Override public String toString() { StringBuilder builder = new StringBuilder().append("Page [pageNo=").append(pageNo).append(", pageSize=").append(pageSize) .append(", totalRecord=").append(totalRecord < 0 ? "null" : totalRecord).append(", totalPage=") .append(totalPage < 0 ? "null" : totalPage).append(", results=").append(results == null ? "null" : results).append("]"); return builder.toString(); }}
- 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
2. 实现拦截器
package com.sm.model;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;import org.apache.ibatis.executor.Executor;import org.apache.ibatis.executor.parameter.DefaultParameterHandler;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.Interceptor;import org.apache.ibatis.plugin.Intercepts;import org.apache.ibatis.plugin.Invocation;import org.apache.ibatis.plugin.Plugin;import org.apache.ibatis.plugin.Signature;import org.apache.ibatis.session.ResultHandler;import org.apache.ibatis.session.RowBounds;import org.slf4j.Logger;import org.slf4j.LoggerFactory;@Intercepts({ @Signature(method = "prepare", type = StatementHandler.class, args = { Connection.class }), @Signature(method = "query", type = Executor.class, args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class }) })public class PageInterceptor implements Interceptor { private static final Logger log = LoggerFactory.getLogger(PageInterceptor.class); public static final String MYSQL = "mysql"; public static final String ORACLE = "oracle"; protected String databaseType;// 数据库类型,不同的数据库有不同的分页方法 protected ThreadLocal<Page> pageThreadLocal = new ThreadLocal<Page>(); public String getDatabaseType() { return databaseType; } public void setDatabaseType(String databaseType) { if (!databaseType.equalsIgnoreCase(MYSQL) && !databaseType.equalsIgnoreCase(ORACLE)) { throw new PageNotSupportException("Page not support for the type of database, database type [" + databaseType + "]"); } this.databaseType = databaseType; } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { String databaseType = properties.getProperty("databaseType"); if (databaseType != null) { setDatabaseType(databaseType); } } @Override @SuppressWarnings({ "unchecked", "rawtypes" }) public Object intercept(Invocation invocation) throws Throwable { if (invocation.getTarget() instanceof StatementHandler) {// 控制SQL和查询总数的地方 Page page = pageThreadLocal.get(); if (page == null) { //不是分页查询 return invocation.proceed(); } RoutingStatementHandler handler = (RoutingStatementHandler) invocation.getTarget(); StatementHandler delegate = (StatementHandler) ReflectUtil.getFieldValue(handler, "delegate"); BoundSql boundSql = delegate.getBoundSql(); Connection connection = (Connection) invocation.getArgs()[0]; prepareAndCheckDatabaseType(connection); // 准备数据库类型 if (page.getTotalPage() > -1) { if (log.isTraceEnabled()) { log.trace("已经设置了总页数, 不需要再查询总数."); } } else { Object parameterObj = boundSql.getParameterObject(); MappedStatement mappedStatement = (MappedStatement) ReflectUtil.getFieldValue(delegate, "mappedStatement"); queryTotalRecord(page, parameterObj, mappedStatement, connection); } String sql = boundSql.getSql(); String pageSql = buildPageSql(page, sql); if (log.isDebugEnabled()) { log.debug("分页时, 生成分页pageSql: " + pageSql); } ReflectUtil.setFieldValue(boundSql, "sql", pageSql); return invocation.proceed(); } else { // 查询结果的地方 // 获取是否有分页Page对象 Page<?> page = findPageObject(invocation.getArgs()[1]); if (page == null) { if (log.isTraceEnabled()) { log.trace("没有Page对象作为参数, 不是分页查询."); } return invocation.proceed(); } else { if (log.isTraceEnabled()) { log.trace("检测到分页Page对象, 使用分页查询."); } } //设置真正的parameterObj invocation.getArgs()[1] = extractRealParameterObject(invocation.getArgs()[1]); pageThreadLocal.set(page); try { Object resultObj = invocation.proceed(); // Executor.query(..) if (resultObj instanceof List) { /* @SuppressWarnings({ "unchecked", "rawtypes" }) */ page.setResults((List) resultObj); } return resultObj; } finally { pageThreadLocal.remove(); } } } protected Page<?> findPageObject(Object parameterObj) { if (parameterObj instanceof Page<?>) { return (Page<?>) parameterObj; } else if (parameterObj instanceof Map) { for (Object val : ((Map<?, ?>) parameterObj).values()) { if (val instanceof Page<?>) { return (Page<?>) val; } } } return null; } /** * <pre> * 把真正的参数对象解析出来 * Spring会自动封装对个参数对象为Map<String, Object>对象 * 对于通过@Param指定key值参数我们不做处理,因为XML文件需要该KEY值 * 而对于没有@Param指定时,Spring会使用0,1作为主键 * 对于没有@Param指定名称的参数,一般XML文件会直接对真正的参数对象解析, * 此时解析出真正的参数作为根对象 * </pre> * @author jundong.xu_C * @param parameterObj * @return */ protected Object extractRealParameterObject(Object parameterObj) { if (parameterObj instanceof Map<?, ?>) { Map<?, ?> parameterMap = (Map<?, ?>) parameterObj; if (parameterMap.size() == 2) { boolean springMapWithNoParamName = true; for (Object key : parameterMap.keySet()) { if (!(key instanceof String)) { springMapWithNoParamName = false; break; } String keyStr = (String) key; if (!"0".equals(keyStr) && !"1".equals(keyStr)) { springMapWithNoParamName = false; break; } } if (springMapWithNoParamName) { for (Object value : parameterMap.values()) { if (!(value instanceof Page<?>)) { return value; } } } } } return parameterObj; } protected void prepareAndCheckDatabaseType(Connection connection) throws SQLException { if (databaseType == null) { String productName = connection.getMetaData().getDatabaseProductName(); if (log.isTraceEnabled()) { log.trace("Database productName: " + productName); } productName = productName.toLowerCase(); if (productName.indexOf(MYSQL) != -1) { databaseType = MYSQL; } else if (productName.indexOf(ORACLE) != -1) { databaseType = ORACLE; } else { throw new PageNotSupportException("Page not support for the type of database, database product name [" + productName + "]"); } if (log.isInfoEnabled()) { log.info("自动检测到的数据库类型为: " + databaseType); } } } /** * <pre> * 生成分页SQL * </pre> * * @author jundong.xu_C * @param page * @param sql * @return */ protected String buildPageSql(Page<?> page, String sql) { if (MYSQL.equalsIgnoreCase(databaseType)) { return buildMysqlPageSql(page, sql); } else if (ORACLE.equalsIgnoreCase(databaseType)) { return buildOraclePageSql(page, sql); } return sql; } /** * <pre> * 生成Mysql分页查询SQL * </pre> * * @author jundong.xu_C * @param page * @param sql * @return */ protected String buildMysqlPageSql(Page<?> page, String sql) { // 计算第一条记录的位置,Mysql中记录的位置是从0开始的。 int offset = (page.getPageNo() - 1) * page.getPageSize(); return new StringBuilder(sql).append(" limit ").append(offset).append(",").append(page.getPageSize()).toString(); } /** * <pre> * 生成Oracle分页查询SQL * </pre> * * @author jundong.xu_C * @param page * @param sql * @return */ protected String buildOraclePageSql(Page<?> page, String sql) { // 计算第一条记录的位置,Oracle分页是通过rownum进行的,而rownum是从1开始的 int offset = (page.getPageNo() - 1) * page.getPageSize() + 1; StringBuilder sb = new StringBuilder(sql); sb.insert(0, "select u.*, rownum r from (").append(") u where rownum < ").append(offset + page.getPageSize()); sb.insert(0, "select * from (").append(") where r >= ").append(offset); return sb.toString(); } /** * <pre> * 查询总数 * </pre> * * @author jundong.xu_C * @param page * @param parameterObject * @param mappedStatement * @param connection * @throws SQLException */ protected void queryTotalRecord(Page<?> page, Object parameterObject, MappedStatement mappedStatement, Connection connection) throws SQLException { BoundSql boundSql = mappedStatement.getBoundSql(page); String sql = boundSql.getSql(); String countSql = this.buildCountSql(sql); if (log.isDebugEnabled()) { log.debug("分页时, 生成countSql: " + countSql); } List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); BoundSql countBoundSql = new BoundSql(mappedStatement.getConfiguration(), countSql, parameterMappings, parameterObject); ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject, countBoundSql); PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = connection.prepareStatement(countSql); parameterHandler.setParameters(pstmt); rs = pstmt.executeQuery(); if (rs.next()) { long totalRecord = rs.getLong(1); page.setTotalRecord(totalRecord); } } finally { if (rs != null) try { rs.close(); } catch (Exception e) { if (log.isWarnEnabled()) { log.warn("关闭ResultSet时异常.", e); } } if (pstmt != null) try { pstmt.close(); } catch (Exception e) { if (log.isWarnEnabled()) { log.warn("关闭PreparedStatement时异常.", e); } } } } /** * 根据原Sql语句获取对应的查询总记录数的Sql语句 * * @param sql * @return */ protected String buildCountSql(String sql) { int index = sql.indexOf("from"); return "select count(*) " + sql.substring(index); } /** * 利用反射进行操作的一个工具类 * */ 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) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block 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(); } } } } public static class PageNotSupportException extends RuntimeException { public PageNotSupportException() { super(); } public PageNotSupportException(String message, Throwable cause) { super(message, cause); } public PageNotSupportException(String message) { super(message); } public PageNotSupportException(Throwable cause) { super(cause); } }}
- 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
- 318
- 319
- 320
- 321
- 322
- 323
- 324
- 325
- 326
- 327
- 328
- 329
- 330
- 331
- 332
- 333
- 334
- 335
- 336
- 337
- 338
- 339
- 340
- 341
- 342
- 343
- 344
- 345
- 346
- 347
- 348
- 349
- 350
- 351
- 352
- 353
- 354
- 355
- 356
- 357
- 358
- 359
- 360
- 361
- 362
- 363
- 364
- 365
- 366
- 367
- 368
- 369
- 370
- 371
- 372
- 373
- 374
- 375
- 376
- 377
- 378
- 379
- 380
- 381
- 382
- 383
- 384
- 385
- 386
- 387
- 388
- 389
- 390
- 391
- 392
- 393
- 394
- 395
- 396
- 397
- 398
- 399
- 400
- 401
- 402
- 403
- 404
- 405
- 406
- 407
- 408
- 409
- 410
- 411
- 412
- 413
- 414
- 415
3. spring配置文件(mybatis已和spring整合)
<!-- 配置mybatis的sqlSessionFactory --> <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"></property> <!-- 配置了typeAliasesPackage之后,在映射文件中,这个包下的实体类可以不写全名 --> <property name="typeAliasesPackage" value="com.sm.model"></property> <!-- 配置映射映射文件的位置 --> <property name="mapperLocations" value="classpath:resources/mapper/*.xml"></property> <property name="plugins"> <!-- 分页拦截器 --> <bean class="com.sm.model.PageInterceptor"></bean> </property> </bean>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
4. mapper.xml
<select id="getUsers" resultType="User" parameterType="Map"> select * from user where username=#{user.username}</select>
- 1
- 2
- 3
6. DAO
List<User> getUsers(Map map);
- 1
7. 测试
Page page = new Page();//配置分页参数page.setPageNo(1);page.setPageSize(3);//条件查询,传参User user = new User();user.setUsername("2");Map map = new HashMap<>();map.put("user", user);map.put("page", page);List<User> list = userDAO.getUsers(map);System.out.println(list);System.out.println(page);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
8. 总结
上面的分页拦截器,拷下来直接用就好了。如果想了解实现原理,可以看慕课网的视频通过自动回复机器人学Mybatis—加强版