(mybatis拦截器)统一增加表字段,mybatis拦截器统一修改表公共字段

5 篇文章 0 订阅
1 篇文章 0 订阅

1.powerdesigner设置表公共字段

powerdesigner:这是一个还没有进行添加公共字段的数据库模型(pdm)
在这里插入图片描述
接下来我们需要在每一个表中添加公共属性,需要用到vbs脚本 统一添加字段脚本下载 下载完成后在powerdesigner中点击 工具->Execute Commands->Edit/Run Script…(或者可以使用快捷键 Ctrl+Shift+X)在弹出的框中选择文件打开下载好的vbs脚本,run之后会动态生成。

2.pdm生成数据库脚本

统一增加公共属性后,点击顶部DataBase->Generate DataBase,弹出框选择要创建sql脚本的路径和文件名称
在这里插入图片描述
点击确定后生成脚本。
在这之前可以通过Preview查看将要生成的sql
在这里插入图片描述
生成sql后,可以直接通过脚本创建库表。

通过Mybatis拦截器做公共属性的自动赋值

mybatis拦截器是在sql执行之前后将sql进行拦截,修改sql
具体内容👇

package com.yunyu.base.plugin;

import com.yunyu.base.constant.SessionKey;
import com.yunyu.base.dto.ILoginDto;
import com.yunyu.base.entity.AbstractEntity;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.*;

/**
 * @create 2018-03-24 0:11
 *
 * @Signature(type = ParameterHandler.class, method = "setParameters", args = PreparedStatement.class),
 * @Signature(type = Executor.class, method = "createCacheKey", args = {MappedStatement.class, Object.class, RowBounds.class, BoundSql.class}),
 * @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 })
 */
@Component
@Intercepts({
		@Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }),
		@Signature(type = Executor.class, method = "createCacheKey", args = {MappedStatement.class, Object.class, RowBounds.class, BoundSql.class})
})
public class MyBatisInterceptor implements Interceptor {

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

	/** Mybatis全局公共参数变量名 */
	private static final String COMMON_FIELDS_KEY = "commonFields";

	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		Object[] args = invocation.getArgs();
		MappedStatement ms = (MappedStatement) args[0];
		Object parameter = args[1];
		Executor executor = (Executor) invocation.getTarget();

		if (args.length == 2) {
			// 插入、更新、删除时拦截处理
			invokeUpdate(ms, parameter);

			return executor.update(ms, parameter);
		} else {
			// 查询时拦截处理
			RowBounds rowBounds = (RowBounds) args[2];
			BoundSql boundSql = (BoundSql) args[3];
			invokeQuery(parameter, boundSql);

			return executor.createCacheKey(ms, parameter, rowBounds, boundSql);
		}
	}

	@Override
	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}

	@Override
	public void setProperties(Properties properties) {
	}

	/**
	 * 执行INSERT、UPDAT、DELETEE时填充公共字段
	 * @param ms Mapper映射
	 * @param parameter 入参对象
	 */
	private void invokeUpdate(MappedStatement ms, Object parameter) throws InvocationTargetException, IllegalAccessException {

		if (parameter != null && parameter instanceof AbstractEntity) {	// Mapper操作
			AbstractEntity entity = (AbstractEntity) parameter;

			// 提取公共参数并填充
			Map<String, Object> commonFieldsMap = buildCommonFields();
			SqlCommandType sqlCommandType = ms.getSqlCommandType();
			if (sqlCommandType == sqlCommandType.INSERT) {
				entity.setAddAction((String) commonFieldsMap.get("action"));
				entity.setAddTermIp((String) commonFieldsMap.get("termIp"));
				entity.setAddUserId((Long) commonFieldsMap.get("userId"));
				entity.setAddDt((Long) commonFieldsMap.get("dt"));
			} else if (sqlCommandType == sqlCommandType.UPDATE) {
				entity.setVersion((entity.getVersion() != null ? entity.getVersion() : 1) + 1);
				entity.setUpdAction((String) commonFieldsMap.get("action"));
				entity.setUpdTermIp((String) commonFieldsMap.get("termIp"));
				entity.setUpdUserId((Long) commonFieldsMap.get("userId"));
				entity.setUpdDt((Long) commonFieldsMap.get("dt"));
			}
		} else {	// Dao操作
			BoundSql boundSql = ms.getBoundSql(parameter);
			invokeQuery(parameter, boundSql);
		}
	}

	/**
	 * 执行SELECT时填充公共字段
	 * @param parameter 入参对象
	 * @param boundSql 参数绑定关系
	 */
	private void invokeQuery(Object parameter, BoundSql boundSql) throws InvocationTargetException, IllegalAccessException {

		// 若参数映射没有包含的key直接返回
		List<String> paramNames = new ArrayList<>();
		boolean hasKey = hasParamKey(paramNames, boundSql.getParameterMappings());
		if (!hasKey) {
			return;
		}

		// 改写参数
		processParams(parameter, paramNames);
	}

	/**
	 * 通过Dao设置参数时
	 * @param invocation 目标方法
	 */
	private void invokeSetParameter(Invocation invocation) throws NoSuchFieldException, IllegalAccessException, InvocationTargetException, SQLException {
		ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();
		PreparedStatement ps = (PreparedStatement) invocation.getArgs()[0];

		// 反射获取 BoundSql 对象,此对象包含生成的sql和sql的参数map映射
		Field boundSqlField = parameterHandler.getClass().getDeclaredField("boundSql");
		boundSqlField.setAccessible(true);
		BoundSql boundSql = (BoundSql) boundSqlField.get(parameterHandler);

		// 若参数映射没有包含的key直接返回
		List<String> paramNames = new ArrayList<>();
		boolean hasKey = hasParamKey(paramNames, boundSql.getParameterMappings());
		if (!hasKey) {
			return;
		}

		// 反射获取 参数对像
		Field parameterField = parameterHandler.getClass().getDeclaredField("parameterObject");
		parameterField.setAccessible(true);
		Object parameterObject = parameterField.get(parameterHandler);

		// 改写参数
		parameterObject = processParams(parameterObject, paramNames);

		// 改写的参数设置到原parameterHandler对象
		parameterField.set(parameterHandler, parameterObject);
		parameterHandler.setParameters(ps);
	}

	/**
	 * 判断已生成SQL参数映射中是否包含commonFields
	 * @param paramNames 参数名列表
	 * @param parameterMappings 参数映射表
	 * @return true:已包含,false:未包含
	 */
	private boolean hasParamKey(List<String> paramNames, List<ParameterMapping> parameterMappings) {
		boolean hasKey = false;
		for (ParameterMapping parameterMapping : parameterMappings) {
			if (parameterMapping.getProperty().startsWith(COMMON_FIELDS_KEY)) {
				hasKey = true;
			} else {
				paramNames.add(parameterMapping.getProperty());
			}
		}
		return hasKey;
	}

	/**
	 * 对原参数对象做处理,植入公共参数信息
	 * @param paramObj 原参数对象
	 * @param paramNames 参数名列表
	 * @return 新参数对象
	 * @throws InvocationTargetException
	 * @throws IllegalAccessException
	 */
	private Object processParams(Object paramObj, List<String> paramNames) throws InvocationTargetException, IllegalAccessException {
		// 提取公共字段信息
		Map<String, Object> commonFields = buildCommonFields();

		if (paramObj == null) {
			// 无参数时,添加Map参数对象
			Map<String, Object> paramMap = new MapperMethod.ParamMap<>();
			paramMap.put(COMMON_FIELDS_KEY, commonFields);
			paramObj = paramMap;

		} else if ((ClassUtils.isPrimitiveOrWrapper(paramObj.getClass())
				|| String.class.isAssignableFrom(paramObj.getClass())
				|| Number.class.isAssignableFrom(paramObj.getClass()))
				&& paramNames.size() == 1) {
			// 单参数时,将参数转为Map
			Map<String, Object> paramMap = new MapperMethod.ParamMap<>();
			paramMap.put(paramNames.iterator().next(), paramObj);
			paramMap.put(COMMON_FIELDS_KEY, commonFields);
			paramObj = paramMap;

		} else if (paramObj instanceof Map) {
			// 原参数为Map,且Map的key中没有commonFields,添加到参数Map中
			((Map) paramObj).putIfAbsent(COMMON_FIELDS_KEY, commonFields);

		} else {
			// 参数是Bean,反射设置值
			PropertyDescriptor ps = BeanUtils.getPropertyDescriptor(paramObj.getClass(), COMMON_FIELDS_KEY);
			if (ps != null && ps.getReadMethod() != null && ps.getWriteMethod() != null) {
				Object value = ps.getReadMethod().invoke(paramObj);
				if (value == null) {
					ps.getWriteMethod().invoke(paramObj, commonFields);
				}
			}
		}

		return paramObj;
	}

	/**
	 * 提取公共字段信息
	 * @return 公共字段信息
	 */
	private Map<String, Object> buildCommonFields() {
		Map<String, Object> commonFieldsMap = new HashMap<>();
		String action = null;
		Long userId = null;
		String termIp = "127.0.0.1";
		Long mchId = null;

		// web环境下
		RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
		if (requestAttributes != null) {
			// 提取请求来源、终端IP
			HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
			action = request.getRequestURI().toString();
			termIp = request.getRemoteHost();
			if (LOGGER.isDebugEnabled()) {
				LOGGER.debug(String.format("客户端IP地址:%s, 客户端请求URI:%s", termIp, action));
			}

			// 提取来访用户信息
			HttpSession session = request.getSession();
			ILoginDto loginInfo = (ILoginDto) session.getAttribute(SessionKey.LOGIN_INFO);
			if (loginInfo != null) {	// 已登录
				userId = loginInfo.getUserId();
				mchId = loginInfo.getMchId();
			}
		}
		
		commonFieldsMap.put("action", action);					// 来访URL
		commonFieldsMap.put("userId", userId);					// 会话用户ID
		commonFieldsMap.put("termIp", termIp);					// 来访终端IP
		commonFieldsMap.put("dt", System.currentTimeMillis());	// 当前时间
		commonFieldsMap.put("mchId", mchId);					// 会话商户ID
		return commonFieldsMap;
	}

}

PageHelper分页就是通过mybatis的拓展点(拦截器)做的分页,通过拦截器还可以做数据权限的控制……

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要在 MyBatis-Plus 中拦截 XML 文件的 select 方法并针对特定字段添加 where 条件,可以在自定义的 SQL 解析器中获取到查询语句中的所有字段,然后根据需要添加 where 条件。以下是实现步骤: 1. 创建一个类,实现 com.baomidou.mybatisplus.extension.parsers.JsqlParserCustomizer 接口,并重写该接口中的 customize 方法。 2. 在 customize 方法中,获取到 JSqlParser 解析出来的 SQL AST(抽象语法树),遍历 AST 找到 Select 对象。 3. 获取 Select 对象中的 Where 对象,如果没有,则创建一个 Where 对象,并添加到 Select 对象中。 4. 遍历 Select 对象中的所有字段,找到需要添加条件的字段,并添加 where 条件。 5. 最后,将修改后的 SQL 写回到 mappedStatement 中。 以下是一个示例代码,可以在 MyBatis-Plus 的配置文件中配置该拦截器: ```java public class MyJsqlParserCustomizer implements JsqlParserCustomizer { @Override public void customize(SelectStatement selectStatement) { Select select = selectStatement.getSelectBody(); if (select instanceof PlainSelect) { PlainSelect plainSelect = (PlainSelect) select; Where where = plainSelect.getWhere(); if (where == null) { where = new Where(); plainSelect.setWhere(where); } // 遍历 Select 对象中的所有字段 List<SelectItem> selectItems = plainSelect.getSelectItems(); for (SelectItem selectItem : selectItems) { if (selectItem instanceof SelectExpressionItem) { SelectExpressionItem selectExpressionItem = (SelectExpressionItem) selectItem; Expression expression = selectExpressionItem.getExpression(); if (expression instanceof Column) { Column column = (Column) expression; // 根据需要添加 where 条件 if ("name".equals(column.getColumnName())) { Expression whereExpr = new EqualsTo(new Column("name"), new StringValue("张三")); if (where.getExpr() == null) { where.setExpr(whereExpr); } else { where.setExpr(new AndExpression(where.getExpr(), whereExpr)); } } } } } } // 将修改后的 SQL 写回到 mappedStatement 中 selectStatement.toString(); } } ``` 然后在 MyBatis-Plus 的配置文件中添加以下配置即可: ```xml <bean id="myJsqlParserCustomizer" class="com.example.MyJsqlParserCustomizer"/> <bean id="mybatisConfiguration" class="com.baomidou.mybatisplus.core.MybatisConfiguration"> <property name="sqlParserCustomizers"> <list> <ref bean="myJsqlParserCustomizer"/> </list> </property> </bean> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值