MYBATIS和JPA拦截器
架构图如下:
通过实现Mybatis和JPA拦截器,重写待执行SQL
Mybatis
拦截器
import java.io.File; import java.io.FileWriter; import java.lang.reflect.Field; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.Properties; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.executor.statement.StatementHandler; import org.apache.ibatis.javassist.Modifier; 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.reflection.MetaObject; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.springframework.stereotype.Component; import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; //Executo 拦截 @Intercepts({ @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}), @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}), @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}) }) /** * * @功能描述: 动态替换sql中的指定字符串,比如多法人标识 * @名称: ExecutorInterceptor.java * @路径 com.daimeng.framework.mybatis * @作者 daimeng.fun * @E-Mail * @创建时间 2020年12月31日 上午11:24:08 * @version V1.0 */ @Slf4j @Component public class ExecutorInterceptor implements Interceptor { /** * 根目录 */ public String sqllogpath = "D:\\java_test\\mybatis"; @Override public Object intercept(Invocation invocation) throws Throwable { log.error("MybatisExecutorInterceptor start====="); //当前sql String sql = getSql(invocation); log.error("ExecutorInterceptor SQL:\n"+sql); //重写sql String newsql = sql.replace("$duofaren$", "001"); log.error("ExecutorInterceptor newsql:\n"+newsql); resetSql( invocation, newsql); log.error("MybatisExecutorInterceptor end====="); return invocation.proceed(); } @Override public Object plugin(Object o) { return Plugin.wrap(o, this); } @Override public void setProperties(Properties properties) { } private String getSql(Invocation invocation) { BoundSql boundSql = getBoundSql(invocation); if(boundSql != null && boundSql.getSql() != null && !"".equals(boundSql.getSql())) { return boundSql.getSql(); }else return ""; } private BoundSql getBoundSql(Invocation invocation) { final Object[] args = invocation.getArgs(); BoundSql boundSql = (BoundSql) args[5]; if(boundSql != null) { return boundSql; }else return null; } private void resetSql(Invocation invocation, String newsql) { BoundSql boundSql = getBoundSql(invocation); if(boundSql != null) { modify(boundSql,"sql",newsql); } } private static void modify(Object object, String fieldName, Object newFieldValue){ try { Field field = object.getClass().getDeclaredField(fieldName); Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); if(!field.isAccessible()) { field.setAccessible(true); } field.set(object, newFieldValue); } catch (Exception e) { e.printStackTrace(); } } }
注册bean
import org.apache.ibatis.session.SqlSessionFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MybatisInterceptorConfig { @Bean public String myInterceptor(SqlSessionFactory sqlSessionFactory) { sqlSessionFactory.getConfiguration().addInterceptor(new ExecutorInterceptor()); return "interceptor"; } }
mapper.xml
select * from user_$duofaren$
SQL执行结果
select * from user_001
JPA
拦截器
import javax.persistence.Table; import org.hibernate.resource.jdbc.spi.StatementInspector; import com.daimeng.util.SqlFormatterUtils; import lombok.extern.slf4j.Slf4j; /** * * @功能描述: JPA拦截器 * entity类中增加注解:@Table(name = "label_info$duofaren$") * spring.jpa.properties.hibernate.hbm2ddl.auto = none * spring.jpa.properties.hibernate.session_factory.statement_inspector=当前类 * @名称: MyStatementInspector.java * @路径 com.daimeng.framework.hibernate * @作者 daimeng.fun * @E-Mail * @创建时间 2020年12月31日 下午2:28:28 * @version V1.0 */ @Slf4j public class MyStatementInspector implements StatementInspector{ @Override public String inspect(String sql) { log.error("MyStatementInspector start====="); //当前sql SqlFormatterUtils sfu = new SqlFormatterUtils(); log.error("MyStatementInspector JpaSQL:\n"+sfu.format(sql)); //return sql; //重写sql String newsql = sql.replace("$duofaren$", ""); log.error("拦截器ExecutorInterceptor newsql:\n"+sfu.format(newsql)); log.error("MyStatementInspector end====="); return newsql; } }
application配置文件jpa相关修改
spring.jpa.properties.hibernate.hbm2ddl.auto = none spring.jpa.properties.hibernate.session_factory.statement_inspector=拦截器类
jpa对应的entity实体类增加注解
@Table(name = "user_$duofaren$")
则拦截器可自动替换$duofaren$为对应值,效果跟Mybatis一致
多数据源多法人架构