好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

MyBatis自定义SQL拦截器示例详解

前言

本文主要是讲通过 MyBaits 的 Interceptor 的拓展点进行对 MyBatis 执行 SQL 之前做一个逻辑拦截实现 自定义 逻辑的插入执行。

适合场景:1. 比如限制数据库查询最大访问条数;2. 限制登录用户只能访问当前机构数据。

定义是否开启注解

定义是否开启注解, 主要做的一件事情就是是否添加 SQL 拦截器 。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

// 全局开启

@Retention (RetentionPolicy.RUNTIME)

@Target (ElementType.TYPE)

@Documented

@Import (MyBatisSqlInterceptorConfiguration. class )

public @interface EnableSqlInterceptor {

 

}

 

// 自定义注解

@Target ({ElementType.METHOD })

@Retention (RetentionPolicy.RUNTIME)

public @interface DataScope {

 

}

注册SQL 拦截器

注册一个 SQL 拦截器,会对符合条件的 SQL 查询操作进行拦截。

?

1

2

3

4

5

6

7

8

public class MyBatisSqlInterceptorConfiguration implements ApplicationContextAware {

 

     @Override

     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

         SqlSessionFactory sqlSessionFactory = applicationContext.getBean(SqlSessionFactory. class );

         sqlSessionFactory.getConfiguration().addInterceptor( new MyBatisInterceptor());

     }

}

处理逻辑

在处理逻辑中,我主要是做一个简单的 limit 1 案例,如果是自己需要做其他的逻辑需要修改

?

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

@Slf4j

@Intercepts (

         {

                 @Signature (type = Executor. class , method = "query" , args = {MappedStatement. class , Object. class , RowBounds. class , ResultHandler. class }),

                 @Signature (type = Executor. class , method = "query" , args = {MappedStatement. class , Object. class , RowBounds. class , ResultHandler. class , CacheKey. class , BoundSql. class }),

         })

public class MyBatisInterceptor implements Interceptor {

 

     private static final Logger LOGGER = LoggerFactory.getLogger(MyBatisInterceptor. class );

 

     @Override

     public Object intercept(Invocation invocation) throws Throwable {

         // TODO Auto-generated method stub

         Object[] args = invocation.getArgs();

         MappedStatement ms = (MappedStatement) args[ 0 ];

         Object parameter = args[ 1 ];

         RowBounds rowBounds = (RowBounds) args[ 2 ];

         ResultHandler resultHandler = (ResultHandler) args[ 3 ];

         Executor executor = (Executor) invocation.getTarget();

         CacheKey cacheKey;

         BoundSql boundSql;

         //由于逻辑关系,只会进入一次

         if (args.length == 4 ) {

             //4 个参数时

             boundSql = ms.getBoundSql(parameter);

             cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql);

         } else {

             //6 个参数时

             cacheKey = (CacheKey) args[ 4 ];

             boundSql = (BoundSql) args[ 5 ];

         }

         DataScope dataScope = getDataScope(ms);

         if (Objects.nonNull(dataScope)) {

             String origSql = boundSql.getSql();

             log.info( "origSql : {}" , origSql);

             // 组装新的 sql

             // todo you weaving business

             String newSql = origSql + " limit 1" ;

 

             // 重新new一个查询语句对象

             BoundSql newBoundSql = new BoundSql(ms.getConfiguration(), newSql,

                     boundSql.getParameterMappings(), boundSql.getParameterObject());

 

             // 把新的查询放到statement里

             MappedStatement newMs = newMappedStatement(ms, new BoundSqlSource(newBoundSql));

             for (ParameterMapping mapping : boundSql.getParameterMappings()) {

                 String prop = mapping.getProperty();

                 if (boundSql.hasAdditionalParameter(prop)) {

                     newBoundSql.setAdditionalParameter(prop, boundSql.getAdditionalParameter(prop));

                 }

             }

 

             args[ 0 ] = newMs;

             if (args.length == 6 ) {

                 args[ 5 ] = newMs.getBoundSql(parameter);

             }

         }

         LOGGER.info( "mybatis intercept sql:{},Mapper方法是:{}" , boundSql.getSql(), ms.getId());

 

 

         return invocation.proceed();

     }

 

     private MappedStatement newMappedStatement(MappedStatement ms, SqlSource newSqlSource) {

         MappedStatement.Builder builder = new

                 MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType());

         builder.resource(ms.getResource());

         builder.fetchSize(ms.getFetchSize());

         builder.statementType(ms.getStatementType());

         builder.keyGenerator(ms.getKeyGenerator());

         if (ms.getKeyProperties() != null && ms.getKeyProperties().length > 0 ) {

             builder.keyProperty(ms.getKeyProperties()[ 0 ]);

         }

         builder.timeout(ms.getTimeout());

         builder.parameterMap(ms.getParameterMap());

         builder.resultMaps(ms.getResultMaps());

         builder.resultSetType(ms.getResultSetType());

         builder.cache(ms.getCache());

         builder.flushCacheRequired(ms.isFlushCacheRequired());

         builder.useCache(ms.isUseCache());

         return builder.build();

     }

 

 

     private DataScope getDataScope(MappedStatement mappedStatement) {

         String id = mappedStatement.getId();

         // 获取 Class Method

         String clazzName = id.substring( 0 , id.lastIndexOf( '.' ));

         String mapperMethod = id.substring(id.lastIndexOf( '.' ) + 1 );

 

         Class<?> clazz;

         try {

             clazz = Class.forName(clazzName);

         } catch (ClassNotFoundException e) {

             return null ;

         }

         Method[] methods = clazz.getMethods();

 

         DataScope dataScope = null ;

         for (Method method : methods) {

             if (method.getName().equals(mapperMethod)) {

                 dataScope = method.getAnnotation(DataScope. class );

                 break ;

             }

         }

         return dataScope;

     }

 

     @Override

     public Object plugin(Object target) {

         // TODO Auto-generated method stub

         LOGGER.info( "MysqlInterCeptor plugin>>>>>>>{}" , target);

         return Plugin.wrap(target, this );

     }

 

     @Override

     public void setProperties(Properties properties) {

         // TODO Auto-generated method stub

         String dialect = properties.getProperty( "dialect" );

         LOGGER.info( "mybatis intercept dialect:>>>>>>>{}" , dialect);

     }

 

     /**

      * 定义一个内部辅助类,作用是包装 SQL

      */

     class BoundSqlSource implements SqlSource {

         private BoundSql boundSql;

 

         public BoundSqlSource(BoundSql boundSql) {

             this .boundSql = boundSql;

         }

 

         public BoundSql getBoundSql(Object parameterObject) {

             return boundSql;

         }

 

     }

 

}

如何使用

我们在 XXXMapper 中对应的数据操作方法只要加入 @DataScope 注解即可。

?

1

2

3

4

5

6

7

8

@Mapper

public interface OrderMapper {

 

    @Select ( "select 1 " )

    @DataScope

    Intger selectOne();

 

}

参考资料

mybatis.org/mybatis-3/z …

总结

到此这篇关于MyBatis自定义SQL拦截器的文章就介绍到这了,更多相关MyBatis自定义SQL拦截器内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

原文链接:https://juejin.cn/post/7021508758777888799

查看更多关于MyBatis自定义SQL拦截器示例详解的详细内容...

  阅读:17次