1. 程式人生 > 實用技巧 >mybaits攔截器+自定義註解+PageHelper

mybaits攔截器+自定義註解+PageHelper


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;
import
org.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;
import
org.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語句型別 selectdeleteinsertupdate
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租戶過濾註解,攔截StatementHandlerprepare方法 攔截器見TenantInterceptor
* 無值表示不過濾 有值表示過濾的租戶欄位 如a.tenant_id
* @author bbq
*/
/**
* Mybatis租戶過濾註解,攔截StatementHandlerprepare方法 攔截器見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));
    }
}