一 定义相关的常量
public class DatabaseConstants {
public static final String ET = "et";
public static final String PARAM1 = "param1";
public static final String INSERT = "INSERT";
public static final String UPDATE = "UPDATE";
public static final List<String> SQL_COMMAND_TYPE_LIST = Arrays.asList("INSERT", "UPDATE");
public static final String CREATE_TIME = "createTime";
public static final String CREATE_USER_ID = "createUserId";
public static final String CREATE_USER_NAME = "createUserName";
public static final String UPDATE_TIME = "updateTime";
public static final String UPDATE_USER_ID = "updateUserId";
public static final String UPDATE_USER_NAME = "updateUserName";
public static final String TENANT_ID = "tenantId";
public static final String DELETE_FLAG = "deleteFlag";
public DatabaseConstants() {
}
}
二 编写配置拦截器
2.1插入或更新是自动填充数据
package com.mdgyl.hussar.basic.config;
import com.jxdinfo.hussar.common.security.BaseSecurityUtil;
import com.jxdinfo.hussar.common.security.SecurityUser;
import com.mdgyl.common.constants.DatabaseConstants;
import com.mdgyl.common.enums.DeleteStatusEnum;
import com.mdgyl.common.util.ReflectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.Properties;
/**
* description: mybatis全局拦截器
* author: wuyc
* createTime: 2023-12-02 14:03:19
*/
@Slf4j
@Component
@Intercepts({
@Signature(
type = Executor.class, method = "update",
args = {MappedStatement.class, Object.class}
)
})
public class MybatisParamInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
// 获取Mybatis的当前操作方法名称
String sqlCommandType = mappedStatement.getSqlCommandType().name();
if (!DatabaseConstants.SQL_COMMAND_TYPE_LIST.contains(sqlCommandType)) {
return invocation.proceed();
}
if (invocation.getArgs().length < 2) {
return invocation.proceed();
}
// 获取Mybatis插入或更新时传入的参数对象
Object paramEntity = invocation.getArgs()[1];
this.interceptInsertOrUpdateMethod(sqlCommandType, paramEntity);
return invocation.proceed();
}
/**
* 插入或更新时的参数拦截方法
*
* @param methodName Mybatis方法名称
* @param paramEntity 参数实体类
*/
private void interceptInsertOrUpdateMethod(String methodName, Object paramEntity) {
SecurityUser securityUser = getSecurityUser();
LocalDateTime systemTime = LocalDateTime.now();
// 若Mybatis的当前方法为INSERT
if (DatabaseConstants.INSERT.equals(methodName)) {
fillInsertMethodProperties(paramEntity, securityUser, systemTime);
return;
}
// 若Mybatis的当前方法为UPDATE
if (DatabaseConstants.UPDATE.equals(methodName)) {
fillUpdateMethodProperties(paramEntity, securityUser, systemTime);
}
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
// -------------------------------------- private method start, 私有方法放公有方法下面 --------------------------------------------
/**
* 新增数据时填充创建人、创建时间
*
* @param paramEntity 新增数据参数对象
* @param securityUser 用户信息
* @param systemTime 当前系统时间
*/
private void fillInsertMethodProperties(Object paramEntity, SecurityUser securityUser, LocalDateTime systemTime) {
fillProperties(paramEntity, DatabaseConstants.CREATE_TIME, systemTime);
fillProperties(paramEntity, DatabaseConstants.CREATE_USER_ID, securityUser.getUserId());
fillProperties(paramEntity, DatabaseConstants.CREATE_USER_NAME, securityUser.getUserName());
fillProperties(paramEntity, DatabaseConstants.UPDATE_TIME, systemTime);
fillProperties(paramEntity, DatabaseConstants.UPDATE_USER_ID, securityUser.getUserId());
fillProperties(paramEntity, DatabaseConstants.UPDATE_USER_NAME, securityUser.getUserName());
fillProperties(paramEntity, DatabaseConstants.DELETE_FLAG, DeleteStatusEnum.NORMAL.getCode());
fillProperties(paramEntity, DatabaseConstants.TENANT_ID, securityUser.getTenantId());
}
/**
* 编辑数据时填充创建人、创建时间
*
* @param paramEntity 新增数据参数对象
* @param securityUser 登录用户信息
* @param systemTime 当前系统时间
*/
private void fillUpdateMethodProperties(Object paramEntity, SecurityUser securityUser, LocalDateTime systemTime) {
if (!(paramEntity instanceof MapperMethod.ParamMap)) {
return;
}
MapperMethod.ParamMap<?> paramMap = (MapperMethod.ParamMap<?>) paramEntity;
Object updateEntity = paramMap.containsKey(DatabaseConstants.ET) ? paramMap.get(DatabaseConstants.ET) : paramMap.get(DatabaseConstants.PARAM1);
if (Objects.isNull(updateEntity)) {
return;
}
fillProperties(updateEntity, DatabaseConstants.UPDATE_TIME, systemTime);
fillProperties(updateEntity, DatabaseConstants.UPDATE_USER_ID, securityUser.getUserId());
fillProperties(updateEntity, DatabaseConstants.UPDATE_USER_NAME, securityUser.getUserName());
}
/**
* 校验字段在数据是否存在,存在的话设置默认值
*
* @param paramEntity 操作对象
* @param propertiesKey 数据库的key
* @param propertiesValue 默认赋的值
*/
private void fillProperties(Object paramEntity, String propertiesKey, Object propertiesValue) {
if (!ReflectionUtils.existsField(paramEntity, propertiesKey)) {
return;
}
try {
ReflectionUtils.invokeSetterMethod(paramEntity, propertiesKey, propertiesValue);
} catch (Exception e) {
log.error("MybatisParamInterceptor fillProperties error,propertiesKey: {}, propertiesValue: {}, failReason: {}",
propertiesKey, propertiesValue, e.getMessage());
}
}
/**
* 获取系统登录用户信息
*
* @return SecurityUser
*/
private SecurityUser getSecurityUser() {
SecurityUser securityUser = BaseSecurityUtil.getUser();
return Objects.isNull(securityUser) ? new SecurityUser() : securityUser;
}
}
2.2 查询时处理逻辑删除的数据
package com.mdgyl.hussar.basic.config;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.Properties;
@Slf4j
@Component
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare",
args = {Connection.class, Integer.class})})
public class LogicalDeleteInterceptor implements Interceptor {
public static final String TARGET_TABLE ="t_exchange_rate";
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
// 获取原始的 SQL 语句
String originalSql = statementHandler.getBoundSql().getSql();
// 检查 SQL 是否是 SELECT 查询
if (originalSql != null && originalSql.trim().toLowerCase().startsWith("select")) {
// 检查表名是否为目标表
if (originalSql.contains(TARGET_TABLE)) {
// 修改 SQL,添加逻辑删除字段的条件
String[] sqlStrArr = originalSql.split("WHERE");
StringBuilder stringBuilder = new StringBuilder(originalSql);
// 判断数据库是否有删除标识字段,如果有的话,就拼接
if (sqlStrArr.length <= 1) {
stringBuilder.append(" WHERE delete_flag = 0");
log.info("拼接后的sql是: {}", stringBuilder);
}
else if (! sqlStrArr[1].contains("delete_flag")) {
stringBuilder.append(" and delete_flag = 0");
}
String modifiedSql = stringBuilder.toString();
// 设置修改后的 SQL
ReflectUtil.setFieldValue(statementHandler.getBoundSql(), "sql", modifiedSql);
}
}
// 执行拦截的方法
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// 这里可以用来设置插件的属性
}
public static class ReflectUtil {
public static Object getFieldValue(Object obj, String fieldName) throws NoSuchFieldException, IllegalAccessException {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(obj);
}
public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
}
}
三 数据源绑定配置拦截器
package com.mdgyl.hussar.basic.config;
import org.apache.ibatis.plugin.Interceptor;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.boot.autoconfigure.SqlSessionFactoryBeanCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
import javax.sql.DataSource;
/**
* description: mybatis拦截器配置
* author: wuyc
* createTime: 2023-12-02 14:13:54
*/
@Configuration
public class DataSourceConfig {
// 注入数据源
@Resource
private DataSource dataSource;
// 注入自定义参数拦截器
@Resource
private MybatisParamInterceptor paramInterceptor;
@Resource
LogicalDeleteInterceptor logicalDeleteInterceptor;
// 官方推荐的实现方式
@Bean
SqlSessionFactoryBeanCustomizer sqlSessionFactoryBeanCustomizer() {
return new SqlSessionFactoryBeanCustomizer() {
@Override
public void customize(SqlSessionFactoryBean customizeFactoryBean) {
// 设置数据源
customizeFactoryBean.setDataSource(dataSource);
// 设置自定义拦截器(可设置多个)
Interceptor[] plugins = {logicalDeleteInterceptor,paramInterceptor};
customizeFactoryBean.setPlugins(plugins);
}
};
}
}