Advertisement
Guest User

Untitled

a guest
Aug 25th, 2019
177
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.33 KB | None | 0 0
  1. package mybatis.plugins;
  2.  
  3. import mybatis.pojo.PageParams;
  4. import org.apache.ibatis.executor.parameter.ParameterHandler;
  5. import org.apache.ibatis.executor.statement.StatementHandler;
  6. import org.apache.ibatis.mapping.BoundSql;
  7. import org.apache.ibatis.mapping.MappedStatement;
  8. import org.apache.ibatis.plugin.*;
  9. import org.apache.ibatis.reflection.MetaObject;
  10. import org.apache.ibatis.reflection.SystemMetaObject;
  11. import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
  12. import org.apache.ibatis.session.Configuration;
  13. import org.apache.log4j.Logger;
  14.  
  15. import java.beans.PropertyDescriptor;
  16. import java.lang.reflect.Field;
  17. import java.lang.reflect.Method;
  18. import java.sql.Connection;
  19. import java.sql.PreparedStatement;
  20. import java.sql.ResultSet;
  21. import java.util.Iterator;
  22. import java.util.Map;
  23. import java.util.Properties;
  24. import java.util.Set;
  25.  
  26. /**
  27. * Created by zuoxiao
  28. * on 2019/8/13.
  29. */
  30. @Intercepts({@Signature(type = StatementHandler.class,method = "prepare",args = {Connection.class,Integer.class})})
  31. public class MyPlugin implements Interceptor {
  32.  
  33. private Logger logger =Logger.getLogger(MyPlugin.class);
  34. /**
  35. * 插件默认参数,可配置默认值.
  36. */
  37. private Integer defaultPage; // 默认页码
  38. private Integer defaultPageSize;// 默认每页条数
  39.  
  40. @Override
  41. public Object intercept(Invocation invocation) throws Throwable {
  42. //目标可能被多个拦截器拦截,所以需要循环追溯,找到最原始的目标类
  43. StatementHandler statementHandler = (StatementHandler) getUnProxyObject(invocation.getTarget());
  44.  
  45. MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);
  46. String sql =(String) metaStatementHandler.getValue("delegate.boundSql.sql");
  47. MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");
  48. // 不是select语句
  49. if (!checkSelect(sql)) {
  50. return invocation.proceed();
  51. }
  52.  
  53. BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql");
  54. Object parameterObject = boundSql.getParameterObject();
  55. PageParams pageParams = getPageParamsForParamObj(parameterObject);
  56. if (pageParams == null) { // 无法获取分页参数,不进行分页
  57. return invocation.proceed();
  58. }
  59.  
  60. // 获取相关配置的参数
  61. Integer pageNum = pageParams.getPage() == null ? defaultPage : pageParams.getPage();
  62. Integer pageSize = pageParams.getPageSize() == null ? defaultPageSize : pageParams.getPageSize();
  63.  
  64. // 计算总条数
  65. int total = getTotal(invocation, metaStatementHandler, boundSql);
  66. // 回填总条数到分页参数
  67. pageParams.setTotal(total);
  68. // 计算总页数.
  69. int totalPage = total % pageSize == 0 ? total / pageSize : total / pageSize + 1;
  70. // 回填总页数到分页参数
  71. pageParams.setTotalPage(totalPage);
  72.  
  73. // 修改sql
  74. return preparedSQL(invocation, metaStatementHandler, boundSql, pageNum, pageSize);
  75. }
  76.  
  77. @Override
  78. public Object plugin(Object o) {
  79. return Plugin.wrap(o,this);
  80. }
  81.  
  82. @Override
  83. public void setProperties(Properties properties) {
  84. // 从配置中获取参数
  85. String strDefaultPage = properties.getProperty("default.page", "1");
  86. String strDefaultPageSize = properties.getProperty("default.pageSize", "8");
  87. // 设置默认参数.
  88. this.defaultPage = Integer.parseInt(strDefaultPage);
  89. this.defaultPageSize = Integer.parseInt(strDefaultPageSize);
  90. }
  91.  
  92. /**
  93. * 从代理对象中分离出真实对象
  94. *
  95. * @param
  96. * --Invocation
  97. * @return 非代理StatementHandler对象
  98. */
  99. private Object getUnProxyObject(Object target) {
  100. MetaObject metaStatementHandler = SystemMetaObject.forObject(target);
  101. // 分离代理对象链(由于目标类可能被多个拦截器拦截,从而形成多次代理,通过循环可以分离出最原始的目标类)
  102. Object object = null;
  103.  
  104. // 可以分离出最原始的的目标类)
  105. while (metaStatementHandler.hasGetter("h")) {
  106. object = metaStatementHandler.getValue("h");
  107. metaStatementHandler = SystemMetaObject.forObject(object);
  108. }
  109.  
  110. if (object == null) {
  111. return target;
  112. }
  113. return object;
  114. }
  115.  
  116. /**
  117. * 判断sql是不是select语句
  118. *
  119. * @param sql
  120. *
  121. * @return true/false
  122. */
  123. private boolean checkSelect(String sql) {
  124. String trimSql = sql.trim();
  125. int idx = trimSql.toLowerCase().indexOf("select");
  126. return idx == 0;
  127. }
  128.  
  129. /**
  130. * 从入参列表中获取分页对象PageParams
  131. *
  132. * @param parameterObject
  133. *
  134. * @return PageParams
  135. */
  136. public PageParams getPageParamsForParamObj(Object parameterObject) throws Exception {
  137. PageParams pageParams = null;
  138. if (parameterObject == null) {
  139. return null;
  140. }
  141. // 处理map参数,多个匿名参数和@Param注解参数,都是map
  142. if (parameterObject instanceof Map) {
  143. @SuppressWarnings("unchecked")
  144. Map<String, Object> paramMap = (Map<String, Object>) parameterObject;
  145. Set<String> keySet = paramMap.keySet();
  146. Iterator<String> iterator = keySet.iterator();
  147. while (iterator.hasNext()) {
  148. String key = iterator.next();
  149. Object value = paramMap.get(key);
  150. if (value instanceof PageParams) {
  151. return (PageParams) value;
  152. }
  153. }
  154. } else if (parameterObject instanceof PageParams) { // 参数是或者继承PageParams
  155. return (PageParams) parameterObject;
  156. } else { // 从POJO属性尝试读取分页参数
  157. Field[] fields = parameterObject.getClass().getDeclaredFields();
  158. // 尝试从POJO中获得类型为PageParams的属性
  159. for (Field field : fields) {
  160. if (field.getType() == PageParams.class) {
  161. PropertyDescriptor pd = new PropertyDescriptor(field.getName(), parameterObject.getClass());
  162. Method method = pd.getReadMethod();
  163. return (PageParams) method.invoke(parameterObject);
  164. }
  165. }
  166. }
  167. return pageParams;
  168. }
  169.  
  170. /**
  171. * 获取总条数.
  172. *
  173. * @param ivt
  174. * Invocation 入参
  175. * @param metaStatementHandler
  176. * statementHandler
  177. * @param boundSql
  178. * sql
  179. * @return sql查询总数.
  180. * @throws Throwable
  181. * 异常.
  182. */
  183. private int getTotal(Invocation ivt, MetaObject metaStatementHandler, BoundSql boundSql)
  184. throws Throwable {
  185. // 获取当前的mappedStatement
  186. MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");
  187. // 配置对象
  188. Configuration cfg = mappedStatement.getConfiguration();
  189. // 当前需要执行的SQL
  190. String sql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");
  191.  
  192. // 改写为统计总数的SQL
  193. String countSql = "select count(1) as total from (" + sql + ") $_paging";
  194. // 获取拦截方法参数,根据插件签名,知道是Connection对象
  195. Connection connection = (Connection) ivt.getArgs()[0];
  196. PreparedStatement ps = null;
  197. int total = 0;
  198. try {
  199. // 预编译统计总数SQL
  200. ps = connection.prepareStatement(countSql);
  201. // 构建统计总数BoundSql
  202. BoundSql countBoundSql = new BoundSql(cfg, countSql, boundSql.getParameterMappings(),
  203. boundSql.getParameterObject());
  204. // 构建MyBatis的ParameterHandler用来设置总数Sql的参数
  205. ParameterHandler handler = new DefaultParameterHandler(mappedStatement, boundSql.getParameterObject(),
  206. countBoundSql);
  207. // 设置总数SQL参数
  208. handler.setParameters(ps);
  209. // 执行查询.
  210. ResultSet rs = ps.executeQuery();
  211. while (rs.next()) {
  212. total = rs.getInt("total");
  213. }
  214. } finally {
  215. // 这里不能关闭Connection,否则后续的SQL就没法继续了
  216. if (ps != null) {
  217. ps.close();
  218. }
  219. }
  220. return total;
  221. }
  222. /**
  223. * 预编译改写后的SQL,并设置分页参数
  224. *
  225. * @param invocation
  226. * 入参
  227. * @param metaStatementHandler
  228. * MetaObject绑定的StatementHandler
  229. * @param boundSql
  230. * boundSql对象
  231. * @param pageNum
  232. * 当前页
  233. * @param pageSize
  234. * 最大页
  235. * @throws IllegalAccessException
  236. * 异常
  237. */
  238. private Object preparedSQL(Invocation invocation, MetaObject metaStatementHandler, BoundSql boundSql, int pageNum,
  239. int pageSize) throws Exception {
  240. // 获取当前需要执行的SQL
  241. String sql = boundSql.getSql();
  242. String newSql = "select * from (" + sql + ") $_paging_table limit ?, ?";
  243. // 修改当前需要执行的SQL
  244. metaStatementHandler.setValue("delegate.boundSql.sql", newSql);
  245. // 执行编译,相当于StatementHandler执行了prepared()方法,这个时候,就剩下两个分页参数没有设置
  246. Object statementObj = invocation.proceed();
  247. // 设置两个分页参数
  248. this.preparePageDataParams((PreparedStatement) statementObj, pageNum, pageSize);
  249. return statementObj;
  250. }
  251.  
  252. /**
  253. * 使用PreparedStatement预编译两个分页参数,如果数据库的规则不一样,需要改写设置的参数规则
  254. *
  255. *
  256. */
  257. private void preparePageDataParams(PreparedStatement ps, int pageNum, int pageSize) throws Exception {
  258. // prepared()方法编译SQL,由于MyBatis上下文没有分页参数的信息,所以这里需要设置这两个参数
  259. // 获取需要设置的参数个数,由于参数是最后的两个,所以很容易得到其位置
  260. int idx = ps.getParameterMetaData().getParameterCount();
  261. // 最后两个是我们的分页参数
  262. ps.setInt(idx - 1, (pageNum - 1) * pageSize);// 开始行
  263. ps.setInt(idx, pageSize); // 限制条数
  264. }
  265. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement