一、问题描述
createBy
、createTime
、updateBy
等字段是我们创建表的时候经常要用到的几个字段,但是我们不可能每一次在增删改查的时候都手动去修改或者添加这几个字段的属性值,我们可以在系统层面统一处理,如何实现呢?
二、实现方法
要实现上述需求的一个办法就是使用mabatis拦截器进行统一处理,步骤如下:
-
创建基础类
BaseEntity.java
/** * Entity基类 */ @Data public class BaseEntity implements Serializable { private static final long serialVersionUID = 1L; /** 搜索值 */ @JsonIgnore private String searchValue; /** 创建者 */ private String createBy; /** 创建时间 */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date createTime; /** 更新者 */ private String updateBy; /** 更新时间 */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date updateTime; }
-
创建需要的实体,并继承基础类
BaseEntity.java
@Data public class CorText extends BaseEntity { private static final long serialVersionUID = 1L; /** * 主键 */ private String id; /** * 用户ID */ @Excel(name = "用户ID") private String userId; // xxxx }
-
创建mabatis拦截器
import com.jugu.common.core.domain.model.LoginUser; import com.jugu.common.utils.SecurityUtils; import com.jugu.common.utils.oConvertUtils; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.binding.MapperMethod.ParamMap; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlCommandType; import org.apache.ibatis.plugin.*; import java.lang.reflect.Field; import java.util.Date; import java.util.Properties; /** * mybatis拦截器,自动注入创建人、创建时间、修改人、修改时间 * * @Author wxz * @Date 2023-5-5 */ @Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) }) @Slf4j public class MybatisInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { LoginUser sysUser = SecurityUtils.getLoginUser(); MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); Object parameter = invocation.getArgs()[1]; if (parameter == null) { return invocation.proceed(); } if (SqlCommandType.INSERT == sqlCommandType) { Field[] fields = oConvertUtils.getAllFields(parameter); for (Field field : fields) { try { if ("createBy".equals(field.getName())) { field.setAccessible(true); Object local_createBy = field.get(parameter); field.setAccessible(false); if (local_createBy == null || local_createBy.equals("")) { if (sysUser != null) { // 登录人账号 field.setAccessible(true); field.set(parameter, sysUser.getUserId()+""); field.setAccessible(false); } } } // 注入创建时间 if ("createTime".equals(field.getName())) { field.setAccessible(true); Object local_createDate = field.get(parameter); field.setAccessible(false); if (local_createDate == null || local_createDate.equals("")) { field.setAccessible(true); field.set(parameter, new Date()); field.setAccessible(false); } } //注入部门编码 if ("deptId".equals(field.getName())) { field.setAccessible(true); Object local_sysOrgCode = field.get(parameter); field.setAccessible(false); if (local_sysOrgCode == null || local_sysOrgCode.equals("")) { // 获取登录用户信息 if (sysUser != null) { field.setAccessible(true); field.set(parameter, sysUser.getDeptId()); field.setAccessible(false); } } } } catch (Exception ignored) { } } } if (SqlCommandType.UPDATE == sqlCommandType) { Field[] fields = null; if (parameter instanceof ParamMap) { ParamMap<?> p = (ParamMap<?>) parameter; if (p.containsKey("et")) { parameter = p.get("et"); } else { parameter = p.get("param1"); } if (parameter == null) { return invocation.proceed(); } fields = oConvertUtils.getAllFields(parameter); } else { fields = oConvertUtils.getAllFields(parameter); } for (Field field : fields) { try { if ("updateBy".equals(field.getName())) { //获取登录用户信息 if (sysUser != null) { // 登录账号 field.setAccessible(true); field.set(parameter, sysUser.getUserId()+""); field.setAccessible(false); } } if ("updateTime".equals(field.getName())) { field.setAccessible(true); field.set(parameter, new Date()); field.setAccessible(false); } } catch (Exception e) { e.printStackTrace(); } } } return invocation.proceed(); } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { // TODO Auto-generated method stub } }
- 依赖工具类
oConvertUtils.java
import lombok.extern.slf4j.Slf4j; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Field; import java.math.BigDecimal; import java.math.BigInteger; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.net.UnknownHostException; import java.sql.Date; import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * * @Author 张代浩 * */ @Slf4j public class oConvertUtils { public static boolean isEmpty(Object object) { if (object == null) { return (true); } if ("".equals(object)) { return (true); } if ("null".equals(object)) { return (true); } return (false); } public static boolean isNotEmpty(Object object) { if (object != null && !object.equals("") && !object.equals("null")) { return (true); } return (false); } /** * 获取本机IP */ public static String getIp() { String ip = null; try { InetAddress address = InetAddress.getLocalHost(); ip = address.getHostAddress(); } catch (UnknownHostException e) { e.printStackTrace(); } return ip; } /** * 判断一个类是否为基本数据类型。 * * @param clazz * 要判断的类。 * @return true 表示为基本数据类型。 */ private static boolean isBaseDataType(Class clazz) throws Exception { return (clazz.equals(String.class) || clazz.equals(Integer.class) || clazz.equals(Byte.class) || clazz.equals(Long.class) || clazz.equals(Double.class) || clazz.equals(Float.class) || clazz.equals(Character.class) || clazz.equals(Short.class) || clazz.equals(BigDecimal.class) || clazz.equals(BigInteger.class) || clazz.equals(Boolean.class) || clazz.equals(Date.class) || clazz.isPrimitive()); } /** * @param request * IP * @return IP Address */ public static String getIpAddrByRequest(HttpServletRequest request) { String ip = request.getHeader("x-forwarded-for"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } return ip; } /** * @return 本机IP * @throws SocketException */ public static String getRealIp() throws SocketException { String localip = null;// 本地IP,如果没有配置外网IP则返回它 String netip = null;// 外网IP Enumeration<NetworkInterface> netInterfaces = NetworkInterface.getNetworkInterfaces(); InetAddress ip = null; boolean finded = false;// 是否找到外网IP while (netInterfaces.hasMoreElements() && !finded) { NetworkInterface ni = netInterfaces.nextElement(); Enumeration<InetAddress> address = ni.getInetAddresses(); while (address.hasMoreElements()) { ip = address.nextElement(); if (!ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && ip.getHostAddress().indexOf(":") == -1) {// 外网IP netip = ip.getHostAddress(); finded = true; break; } else if (ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && ip.getHostAddress().indexOf(":") == -1) {// 内网IP localip = ip.getHostAddress(); } } } if (netip != null && !"".equals(netip)) { return netip; } else { return localip; } } /** * java去除字符串中的空格、回车、换行符、制表符 * * @param str * @return */ public static String replaceBlank(String str) { String dest = ""; if (str != null) { Pattern p = Pattern.compile("\\s*|\t|\r|\n"); Matcher m = p.matcher(str); dest = m.replaceAll(""); } return dest; } public static boolean isInnerIP(String ipAddress) { boolean isInnerIp = false; long ipNum = getIpNum(ipAddress); /** * 私有IP:A类 10.0.0.0-10.255.255.255 B类 172.16.0.0-172.31.255.255 C类 192.168.0.0-192.168.255.255 当然,还有127这个网段是环回地址 **/ long aBegin = getIpNum("10.0.0.0"); long aEnd = getIpNum("10.255.255.255"); long bBegin = getIpNum("172.16.0.0"); long bEnd = getIpNum("172.31.255.255"); long cBegin = getIpNum("192.168.0.0"); long cEnd = getIpNum("192.168.255.255"); isInnerIp = isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd) || ipAddress.equals("127.0.0.1"); return isInnerIp; } private static long getIpNum(String ipAddress) { String[] ip = ipAddress.split("\\."); long a = Integer.parseInt(ip[0]); long b = Integer.parseInt(ip[1]); long c = Integer.parseInt(ip[2]); long d = Integer.parseInt(ip[3]); long ipNum = a * 256 * 256 * 256 + b * 256 * 256 + c * 256 + d; return ipNum; } private static boolean isInner(long userIp, long begin, long end) { return (userIp >= begin) && (userIp <= end); } /** * 获取类的所有属性,包括父类 * * @param object * @return */ public static Field[] getAllFields(Object object) { Class<?> clazz = object.getClass(); List<Field> fieldList = new ArrayList<>(); while (clazz != null) { fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields()))); clazz = clazz.getSuperclass(); } Field[] fields = new Field[fieldList.size()]; fieldList.toArray(fields); return fields; } }
- 依赖工具类
-
创建
mybatis-config.xml
配置文件,使上面的拦截器生效<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!--mybatis拦截器--> <plugins> <plugin interceptor="com.xxx.mybatis.MybatisInterceptor"/> </plugins> </configuration>
其中,
mybatis-config.xml
结构路径如下:
经过以上步骤,就可以实现使用mabatis拦截器
统一处理创建人/创建时间/更新人/更新时间等字段了