MyBatis拦截器及分页插件(3)

2019-05-18 12:48

45. return totalPage; 46. } 47.

48. public void setTotalPage(int totalPage) { 49. this.totalPage = totalPage; 50. } 51.

52. public List getResults() { 53. return results; 54. } 55.

56. public void setResults(List results) { 57. this.results = results; 58. } 59.

60. public Map getParams() { 61. return params; 62. } 63.

64. public void setParams(Map params) { 65. this.params = params; 66. } 67.

68. @Override

69. public String toString() {

70. StringBuilder builder = new StringBuilder();

71. builder.append(\72. .append(pageSize).append(\73. \74. \75. return builder.toString(); 76. } 77. 78. }

对于需要进行分页的Mapper映射,我们会给它传一个Page对象作为参数,我们可以看到Page对象里面包括了一些分页的基本信息,这些信息我们可以在拦截器里面用到,然后我们把除分页的基本信息以外的其他参数用一个Map对象进行包装,这样在Mapper映射语句中的其他参数就可以从Map中取值了。接着来看一下我们的PageInterceptor的定义,对于PageInterceptor我就不做过多的说明,代码里面附有很详细的注释信息: Java代码

1. package com.tiantian.mybatis.interceptor; 2.

3. import java.lang.reflect.Field; 4. import java.sql.Connection; 5. import java.sql.PreparedStatement; 6. import java.sql.ResultSet; 7. import java.sql.SQLException; 8. import java.util.List; 9. import java.util.Properties; 10.

11. import org.apache.ibatis.executor.parameter.ParameterHandler; 12. import org.apache.ibatis.executor.statement.RoutingStatementHandler; 13. import org.apache.ibatis.executor.statement.StatementHandler; 14. import org.apache.ibatis.mapping.BoundSql; 15. import org.apache.ibatis.mapping.MappedStatement; 16. import org.apache.ibatis.mapping.ParameterMapping; 17. import org.apache.ibatis.plugin.Interceptor; 18. import org.apache.ibatis.plugin.Intercepts; 19. import org.apache.ibatis.plugin.Invocation; 20. import org.apache.ibatis.plugin.Plugin; 21. import org.apache.ibatis.plugin.Signature;

22. import org.apache.ibatis.scripting.defaults.DefaultParameterHandler; 23.

24. import com.tiantian.mybatis.model.Page; 25. 26. /** 27. *

28. * 分页拦截器,用于拦截需要进行分页查询的操作,然后对其进行分页处理。 29. * 利用拦截器实现Mybatis分页的原理:

30. * 要利用JDBC对数据库进行操作就必须要有一个对应的Statement对象,Mybatis

在执行Sql语句前就会产生一个包含Sql语句的Statement对象,而且对应的Sql语句

31. * 是在Statement之前产生的,所以我们就可以在它生成Statement之前对用来生

成Statement的Sql语句下手。在Mybatis中Statement语句是通过RoutingStatementHandler对象的

32. * prepare方法生成的。所以利用拦截器实现Mybatis分页的一个思路就是拦截

StatementHandler接口的prepare方法,然后在拦截器方法中把Sql语句改成对应的分页查询Sql语句,之后再调用

33. * StatementHandler对象的prepare方法,即调用invocation.proceed()。 34. * 对于分页而言,在拦截器里面我们还需要做的一个操作就是统计满足当前条件的

记录一共有多少,这是通过获取到了原始的Sql语句后,把它改为对应的统计语句再利用Mybatis封装好的参数和设

35. * 置参数的功能把Sql语句中的参数进行替换,之后再执行查询记录数的Sql语句

进行总记录数的统计。 36. * 37. */

38. @Intercepts( {

39. @Signature(method = \

onnection.class}) })

40. public class PageInterceptor implements Interceptor { 41.

42. private String databaseType;//数据库类型,不同的数据库有不同的分页方法 43. 44. /**

45. * 拦截后要执行的方法 46. */

47. public Object intercept(Invocation invocation) throws Throwable { 48. //对于StatementHandler其实只有两个实现类,一个是

RoutingStatementHandler,另一个是抽象类BaseStatementHandler, 49. //BaseStatementHandler有三个子类,分别是SimpleStatementHandler,

PreparedStatementHandler和CallableStatementHandler, 50. //SimpleStatementHandler是用于处理Statement的,

PreparedStatementHandler是处理PreparedStatement的,而CallableStatementHandler是

51. //处理CallableStatement的。Mybatis在进行Sql语句处理的时候都是建立的

RoutingStatementHandler,而在RoutingStatementHandler里面拥有一个

52. //StatementHandler类型的delegate属性,RoutingStatementHandler会依据

Statement的不同建立对应的BaseStatementHandler,即SimpleStatementHandler、

53. //PreparedStatementHandler或CallableStatementHandler,在

RoutingStatementHandler里面所有StatementHandler接口方法的实现都是调用的delegate对应的方法。

54. //我们在PageInterceptor类上已经用@Signature标记了该Interceptor只拦截

StatementHandler接口的prepare方法,又因为Mybatis只有在建立RoutingStatementHandler的时候

55. //是通过Interceptor的plugin方法进行包裹的,所以我们这里拦截到的目标对

象肯定是RoutingStatementHandler对象。

56. RoutingStatementHandler handler = (RoutingStatementHandler) invocation.

getTarget();

57. //通过反射获取到当前RoutingStatementHandler对象的delegate属性 58. StatementHandler delegate = (StatementHandler)ReflectUtil.getFieldValue(h

andler, \

59. //获取到当前StatementHandler的 boundSql,这里不管是调用

handler.getBoundSql()还是直接调用delegate.getBoundSql()结果是一样的,因为之前已经说过了

60. //RoutingStatementHandler实现的所有StatementHandler接口方法里面都是

调用的delegate对应的方法。

61. BoundSql boundSql = delegate.getBoundSql();

62. //拿到当前绑定Sql的参数对象,就是我们在调用对应的Mapper映射语句时所

传入的参数对象

63. Object obj = boundSql.getParameterObject();

64. //这里我们简单的通过传入的是Page对象就认定它是需要进行分页操作的。 65. if (obj instanceof Page) { 66. Page page = (Page) obj;

67. //通过反射获取delegate父类BaseStatementHandler的mappedStatement

属性

68. MappedStatement mappedStatement = (MappedStatement)ReflectUtil.ge

tFieldValue(delegate, \

69. //拦截到的prepare方法参数是一个Connection对象

70. Connection connection = (Connection)invocation.getArgs()[0]; 71. //获取当前要执行的Sql语句,也就是我们直接在Mapper映射语句中写的

Sql语句

72. String sql = boundSql.getSql();

73. //给当前的page参数对象设置总记录数 74. this.setTotalRecord(page,

75. mappedStatement, connection); 76. //获取分页Sql语句

77. String pageSql = this.getPageSql(page, sql);

78. //利用反射设置当前BoundSql对应的sql属性为我们建立好的分页Sql语

79. ReflectUtil.setFieldValue(boundSql, \80. }

81. return invocation.proceed(); 82. } 83. 84. 85. /**

86. * 拦截器对应的封装原始对象的方法 87. */

88. public Object plugin(Object target) { 89. return Plugin.wrap(target, this); 90. } 91. 92. /**

93. * 设置注册拦截器时设定的属性 94. */

95. public void setProperties(Properties properties) {

96. this.databaseType = properties.getProperty(\97. } 98. 99. /**

100. * 根据page对象获取对应的分页查询Sql语句,这里只做了两种数据库类型,

Mysql和Oracle

101. * 其它的数据库都 没有进行分页 102. *

103. * @param page 分页对象 104. * @param sql 原sql语句 105. * @return 106. */

107. private String getPageSql(Page page, String sql) {


MyBatis拦截器及分页插件(3).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:俺来也案例分析 - 图文

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: