mybaits攔截器+自定義註解+PageHelper
阿新 • • 發佈:2020-12-04
1.今天遇到個問題,有個專案要分為不同企業顯示不同資料,如果直接在原sql修改工作量太大,看了網上的
mybatis攔截器,很適用於當前的問題,不僅能減少工作量
CompanyIntercept.class
package com.sale.config.mybatisintercept;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration;
import com.sale.config.annotation.InterceptAnnotation;
import com.sale.entity.acl.ACLCompany;
import com.sale.entity.acl.ACLUser;
import com.sale.util.session.CompanySession;
import com.sale.util.session.UserSession;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
importorg.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.ResultHandler;
importorg.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.Properties;
/*@AutoConfigureAfter(PageHelperAutoConfiguration.class)*/
@Component
@Intercepts({
@Signature(
type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class
})
/* @Signature(type = Executor.class, method = "query", args = {
MappedStatement.class, Object.class, RowBounds.class,
ResultHandler.class })*/
})
/*@Import(PageHelperAutoConfiguration.class)*/
@Slf4j
public class CompanyIntercept implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 方法一
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());
//先攔截到RoutingStatementHandler,裡面有個StatementHandler型別的delegate變數,其實現類是BaseStatementHandler,然後就到BaseStatementHandler的成員變數mappedStatement
MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
//id為執行的mapper方法的全路徑名,如com.uv.dao.UserMapper.insertUser
String id = mappedStatement.getId();
//sql語句型別 select、delete、insert、update
String sqlCommandType = mappedStatement.getSqlCommandType().toString();
BoundSql boundSql = statementHandler.getBoundSql();
//獲取到原始sql語句
String sql = boundSql.getSql();
String mSql = sql;
//TODO 修改位置
//註解邏輯判斷 添加註解了才攔截
Class<?> classType = Class.forName(mappedStatement.getId().substring(0, mappedStatement.getId().lastIndexOf(".")));
String mName = mappedStatement.getId().substring(mappedStatement.getId().lastIndexOf(".") + 1, mappedStatement.getId().length());
for (Method method : classType.getDeclaredMethods()) {
if (method.isAnnotationPresent(InterceptAnnotation.class) && mName.equals(method.getName())) {
InterceptAnnotation interceptorAnnotation = method.getAnnotation(InterceptAnnotation.class);
if (interceptorAnnotation.flag()) {
//此處應為你的sql拼接,替換第一個where可以實現絕大多數sql,當然複雜sql除外,所以複雜sql還是需要例外處理
ACLCompany company = null;
company = CompanySession.sessionCompany();
if (company != null) {
if (sql.contains("WHERE")) {
//originalSql = replace(originalSql, "where", "where "+atv+"='"+tid+"' and");
mSql = sql.replace("WHERE", "INNER JOIN acl_user_company auc ON a.user_id = auc.user_id LEFT JOIN acl_company ac ON auc.company_id=ac.id WHERE ac.id='" + company.getId() + "' and");
} else {
if (sql.contains("LIMIT")) {
mSql = sql.replace("LIMIT", "INNER JOIN acl_user_company auc ON a.user_id = auc.user_id LEFT JOIN acl_company ac ON auc.company_id=ac.id WHERE ac.id='" + company.getId() + "' LIMIT");
} else {
mSql = sql + "INNER JOIN acl_user_company auc ON a.user_id = auc.user_id LEFT JOIN acl_company ac ON auc.company_id=ac.id WHERE ac.id='" + company.getId() + "'";
}
}
}
/*
mSql = sql + " limit 2";*/
}
}
}
//通過反射修改sql語句
Field field = boundSql.getClass().getDeclaredField("sql");
field.setAccessible(true);
field.set(boundSql, mSql);
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
if (target instanceof StatementHandler) {
return Plugin.wrap(target, this);
} else {
return target;
}
}
@Override
public void setProperties(Properties properties) {
}
}
InterceptAnnotation.class
package com.sale.config.annotation;
import java.lang.annotation.*;
/**
* Mybatis租戶過濾註解,攔截StatementHandler的prepare方法 攔截器見TenantInterceptor
* 無值表示不過濾 有值表示過濾的租戶欄位 如a.tenant_id
* @author bbq
*/
/**
* Mybatis租戶過濾註解,攔截StatementHandler的prepare方法 攔截器見TenantInterceptor
* 無值表示不過濾 有值表示過濾的租戶欄位 如a.tenant_id
* @author bbq
*/
@Target({ElementType.METHOD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface InterceptAnnotation {
boolean flag() default true;
}
MybatisDatasourceConfig.class
package com.sale.config; import com.fasterxml.jackson.databind.annotation.JsonAppend; import com.sale.config.mybatisintercept.CompanyIntercept; import com.sale.config.mybatisintercept.GenerateTimeIntercepter; import com.sale.util.common.MyMapper; import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import javax.annotation.Resource; import javax.sql.DataSource; /** * @author wjn * @version 1.0, 2020/6/17 * @description */ @Configuration // 精確到 mapper 目錄,以便跟其他資料來源隔離 @MapperScan(basePackages = "com.sale.dao", markerInterface = MyMapper.class, sqlSessionFactoryRef = "sqlSessionFactory") /*.setting.acl*/ public class MybatisDatasourceConfig { @Resource CompanyIntercept mybatisSqlInterceptor; /*@Resource GenerateTimeIntercepter generateTimeIntercepter;*/ @Resource @Qualifier("dataSource") private DataSource ds; @Bean public SqlSessionFactory sqlSessionFactory() throws Exception { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(ds); //指定mapper xml目錄 ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); factoryBean.setMapperLocations(resolver.getResources("classpath:mapper/**/*.xml")); factoryBean.setPlugins(new Interceptor[]{mybatisSqlInterceptor}); /*factoryBean.setPlugins(new Interceptor[]{generateTimeIntercepter});*/ return factoryBean.getObject(); }
}
自定義註解主要作用於dao層
SysLogController.class
package com.sale.controller.sysconfig.acl; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.sale.config.annotation.SysLogAnnotation; import com.sale.entity.SysLog; import com.sale.entity.acl.ACLUser; import com.sale.service.setting.acl.SysLogService; import com.sale.util.common.Comment; import com.sale.util.session.UserSession; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.propertyeditors.CustomDateEditor; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.*; import java.text.ParseException; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.*; @RestController @CrossOrigin public class SysLogController { @Autowired private SysLogService sysLogService; @RequiresPermissions(value = {"system-log/select"}) @GetMapping("/selectSysLogByUserId") public Object selectSysLogByUserId(@RequestParam(required = false, defaultValue = "1") int pageIndex, @RequestParam(required = false, defaultValue = "10") int pageSize, SysLog sysLog) throws ParseException { Map<String, Object> map = new HashMap<>(); if (sysLog != null) { if (sysLog.getStartTime() != null && sysLog.getEndTime() != null) { sysLog.setStartTime(Comment.getStartTime(sysLog.getStartTime())); sysLog.setEndTime(Comment.getnowEndTime(sysLog.getEndTime())); } } List<SysLog> sysLogList = sysLogService.selectSysLogByUserId(sysLog); Page page = PageHelper.startPage(pageIndex, pageSize); map.put("currpage", String.valueOf(page.getPageNum())); map.put("totalpages", String.valueOf(page.getPages())); map.put("totalrecords", String.valueOf(page.getTotal())); map.put("sysLogList", sysLogList); return map; } @InitBinder public void init(WebDataBinder binder) { binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true)); } }