当前位置:   article > 正文

mybatis-3.5.0使用插件拦截sql以及通用字段赋值

mybatis-3.5.0使用插件拦截sql以及通用字段赋值

1、添加插件配置类

  1. import org.apache.commons.lang3.StringUtils;
  2. import org.apache.commons.lang3.reflect.FieldUtils;
  3. import org.apache.ibatis.executor.Executor;
  4. import org.apache.ibatis.mapping.BoundSql;
  5. import org.apache.ibatis.mapping.MappedStatement;
  6. import org.apache.ibatis.mapping.SqlCommandType;
  7. import org.apache.ibatis.mapping.SqlSource;
  8. import org.apache.ibatis.plugin.*;
  9. import org.apache.ibatis.session.defaults.DefaultSqlSession;
  10. import org.slf4j.Logger;
  11. import org.slf4j.LoggerFactory;
  12. import org.springframework.stereotype.Component;
  13. import tk.mybatis.mapper.annotation.LogicDelete;
  14. import tk.mybatis.mapper.annotation.Version;
  15. import java.io.File;
  16. import java.lang.reflect.Field;
  17. import java.util.*;
  18. import java.util.regex.Matcher;
  19. import java.util.regex.Pattern;
  20. @Component
  21. @Intercepts({@Signature(
  22. type = Executor.class,
  23. method = "update",
  24. args = {MappedStatement.class, Object.class}
  25. )})
  26. public class MybatisInterception implements Interceptor {
  27. public MybatisInterception() {
  28. }
  29. public Object intercept(Invocation invocation) throws Throwable {
  30. MappedStatement mappedStatement = (MappedStatement)invocation.getArgs()[0];
  31. SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
  32. Object parameter = invocation.getArgs()[1];
  33. if (parameter == null) {
  34. return invocation.proceed();
  35. } else {
  36. Field[] declaredFields = this.getAllFields(parameter);
  37. Date now = new Date();
  38. String userId = ContextUtil.getUserId();
  39. Integer dteptId = ContextUtil.getDteptId();
  40. Field[] var9 = declaredFields;
  41. if (SqlCommandType.DELETE.equals(sqlCommandType)) {
  42. BoundSql boundSql = mappedStatement.getBoundSql(parameter);
  43. //转换DELETE语句为逻辑删除语句
  44. String logicDeleteSql = convertToLogicDelete(boundSql.getSql());
  45. FieldUtils.writeField(boundSql, "sql", logicDeleteSql, true);
  46. MappedStatement newMappedStatement = new MappedStatement.Builder(mappedStatement.getConfiguration(),
  47. mappedStatement.getId(), new BoundSqlSqlSource(boundSql), mappedStatement.getSqlCommandType())
  48. .build();
  49. invocation.getArgs()[0] = newMappedStatement;
  50. return invocation.proceed();
  51. }
  52. if(parameter instanceof DefaultSqlSession.StrictMap) {
  53. DefaultSqlSession.StrictMap strictMap = (DefaultSqlSession.StrictMap) parameter;
  54. Object collection = strictMap.get("collection");
  55. if(collection instanceof Collection) {
  56. for (Object obj : ((Collection<Object>) collection)) {
  57. Field[] fields = this.getAllFields(obj);
  58. for (Field field : fields) {
  59. extracted(sqlCommandType, obj, now, userId, dteptId, field);
  60. }
  61. }
  62. }
  63. } else {
  64. for (Field field : var9) {
  65. extracted(sqlCommandType, parameter, now, userId, dteptId, field);
  66. }
  67. }
  68. return invocation.proceed();
  69. }
  70. }
  71. private void extracted(SqlCommandType sqlCommandType, Object parameter, Date now, String userId, Integer dteptId, Field field) throws IllegalAccessException {
  72. if (field.getAnnotation(NotAutoFill.class) == null) {
  73. Class clazz;
  74. if (SqlCommandType.INSERT.equals(sqlCommandType)) {
  75. if (field.getAnnotation(CreateTime.class) != null || Objects.equals(field.getName(), "createTime")) {
  76. field.setAccessible(true);
  77. field.set(parameter, now);
  78. }
  79. if (field.getAnnotation(Version.class) != null || Objects.equals(field.getName(), "version")) {
  80. field.setAccessible(true);
  81. field.set(parameter, 1);
  82. }
  83. if (field.getAnnotation(LogicDelete.class) != null || Objects.equals(field.getName(), "isDeleted")) {
  84. field.setAccessible(true);
  85. field.set(parameter, 0);
  86. }
  87. if (Objects.equals(field.getName(), "status")) {
  88. field.setAccessible(true);
  89. if (field.getType() == Integer.class) {
  90. field.set(parameter, 0);
  91. }
  92. }
  93. if (Objects.equals(field.getName(), "createBy")) {
  94. field.setAccessible(true);
  95. if (StringUtils.isNotEmpty(userId)) {
  96. clazz = field.getType();
  97. if (clazz == Integer.class) {
  98. field.set(parameter, Integer.parseInt(userId));
  99. } else {
  100. field.set(parameter, userId);
  101. }
  102. }
  103. }
  104. if (Objects.equals(field.getName(), "createDeptId")) {
  105. field.setAccessible(true);
  106. field.set(parameter, dteptId);
  107. }
  108. }
  109. if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) {
  110. if (field.getAnnotation(UpdateTime.class) != null || Objects.equals(field.getName(), "updateTime")) {
  111. field.setAccessible(true);
  112. field.set(parameter, now);
  113. }
  114. if (Objects.equals(field.getName(), "updateBy")) {
  115. field.setAccessible(true);
  116. clazz = field.getType();
  117. if (StringUtils.isNotEmpty(userId)) {
  118. if (clazz == Integer.class) {
  119. field.set(parameter, Integer.parseInt(userId));
  120. } else {
  121. field.set(parameter, userId);
  122. }
  123. }
  124. }
  125. }
  126. }
  127. }
  128. public static Class<?> findEntityClassByTableName(String tableName, String basePackage) {
  129. ClassPathScanningCandidateComponentProvider scanner =
  130. new ClassPathScanningCandidateComponentProvider(false);
  131. scanner.addIncludeFilter(new AnnotationTypeFilter(Table.class));
  132. Set<BeanDefinition> beanDefinitions = scanner.findCandidateComponents(basePackage);
  133. for (BeanDefinition beanDefinition : beanDefinitions) {
  134. try {
  135. Class<?> clazz = Class.forName(beanDefinition.getBeanClassName());
  136. Table table = clazz.getAnnotation(Table.class);
  137. if (table != null && table.name().equals(tableName)) {
  138. return clazz;
  139. }
  140. } catch (ClassNotFoundException e) {
  141. continue;
  142. }
  143. }
  144. return null;
  145. }
  146. private String convertToLogicDelete(String sql) throws NoSuchFieldException {
  147. Pattern pattern = Pattern.compile("DELETE\\s+FROM\\s+(\w+)\\s+WHERE\\s+(.*)", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
  148. Matcher matcher = pattern.matcher(sql);
  149. if (matcher.matches()) {
  150. String tableName = matcher.group(1); //获取表名
  151. Class<?> classByTableName = findEntityClassByTableName(tableName, "com.demo.entity");
  152. if(classByTableName == null) {
  153. return sql;
  154. }
  155. Field isDeletedField = getDeletedField(classByTableName);
  156. if(isDeletedField == null || isDeletedField.getAnnotation(LogicDelete.class) == null) {
  157. return sql;
  158. }
  159. String whereClause = matcher.group(2).trim(); //获取WHERE子句并去除两端空白字符
  160. // 构建逻辑删除的UPDATE语句
  161. StringBuilder logicDeleteSql = new StringBuilder();
  162. logicDeleteSql.append("UPDATE ").append(tableName).append(" SET ").append("is_deleted").append(" = ").append(1);
  163. //如果WHERE子句不为空或不全为空白字符,则加上WHERE子句
  164. if (!whereClause.isEmpty()) {
  165. logicDeleteSql.append(" WHERE ").append(whereClause);
  166. }
  167. return logicDeleteSql.toString();
  168. } else {
  169. // 如果SQL语句格式不匹配,则返回原始SQL或抛出异常,这里为了简单起见,直接返回原始 SQL
  170. return sql;
  171. }
  172. }
  173. public Object plugin(Object o) {
  174. return Plugin.wrap(o, this);
  175. }
  176. public void setProperties(Properties properties) {
  177. }
  178. private Field getDeletedField(Class clazz) {
  179. String isDeleted = "isDeleted";
  180. Field isDeletedField = null;
  181. for (Class<?> c = clazz; c != null; c = c.getSuperclass()) {
  182. Field[] declaredFields = c.getDeclaredFields();
  183. for (Field field : declaredFields) {
  184. if(field.getName().equals(isDeleted)) {
  185. isDeletedField = field;
  186. break;
  187. }
  188. }
  189. }
  190. return isDeletedField;
  191. }
  192. private Field[] getAllFields(Object object) {
  193. Class<?> clazz = object.getClass();
  194. ArrayList fieldList;
  195. for(fieldList = new ArrayList(); clazz != null; clazz = clazz.getSuperclass()) {
  196. fieldList.addAll(new ArrayList(Arrays.asList(clazz.getDeclaredFields())));
  197. }
  198. Field[] fields = new Field[fieldList.size()];
  199. fieldList.toArray(fields);
  200. return fields;
  201. }
  202. public class BoundSqlSqlSource implements SqlSource {
  203. private BoundSql boundSql;
  204. public BoundSqlSqlSource(BoundSql boundSql) {
  205. this.boundSql = boundSql;
  206. }
  207. @Override
  208. public BoundSql getBoundSql(Object parameterObject) {
  209. return boundSql;
  210. }
  211. }
  212. }

2、修改mybatis-config.xml

切身经历但不一定是真相:项目已经有拦截器和mybatis-config.xml比如在公共依赖中,再新建mybatis-config.xml会存在覆盖xml配置的情况,虽然拦截器都生效了。如果命名为mybatis-config-xxx.xml等拦截器就没有生效。通过采用配置类的形式,暂时未发现不良影响。

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
  3. <configuration>
  4. <!-- 插件配置... -->
  5. <plugins>
  6. <plugin interceptor="xxx.xxx.MybatisInterceptor">
  7. <!-- 插件可以配置属性,如果需要的话 -->
  8. <!-- <property name="someProperty" value="someValue"/> -->
  9. </plugin>
  10. </plugins>
  11. <!-- 其他配置... -->
  12. </configura

3、配置类,一般叫MybatisConfig,显然不可重名。于是另起炉灶。

  1. @Configuration
  2. @AutoConfigureAfter({PageHelperAutoConfiguration.class})
  3. public class MybatisFeatureConfig {
  4. @Autowired
  5. private List<SqlSessionFactory> sqlSessionFactoryList;
  6. public MybatisFeatureConfig() {
  7. }
  8. @PostConstruct
  9. public void addMyInterceptor() {
  10. MybatisInterception e = new MybatisInterception();
  11. Iterator var2 = this.sqlSessionFactoryList.iterator();
  12. while(var2.hasNext()) {
  13. SqlSessionFactory sqlSessionFactory = (SqlSessionFactory)var2.next();
  14. sqlSessionFactory.getConfiguration().addInterceptor(e);
  15. }
  16. }
  17. }

4、基本思路,如果使用mybatis-plus我尚未注意过批量操作的问题,所以不知会有什么坑

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/487972
推荐阅读
相关标签
  

闽ICP备14008679号