package com.zhgd.xmgl.config; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.zhgd.annotation.OperLog; import com.zhgd.jeecg.common.util.SpringContextUtils; import com.zhgd.xmgl.constant.Cts; import com.zhgd.xmgl.entity.dto.OperLogDataChange; import com.zhgd.xmgl.entity.dto.OperLogDataChangeField; import com.zhgd.xmgl.entity.dto.OperLogInsertChange; import com.zhgd.xmgl.modules.basicdata.entity.OperationLog; import com.zhgd.xmgl.modules.basicdata.service.IOperationLogService; import com.zhgd.xmgl.security.util.SecurityUtils; import com.zhgd.xmgl.util.IpUtil; import com.zhgd.xmgl.util.ThreadLocalUtil; import io.swagger.annotations.ApiModelProperty; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.Serializable; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.*; import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; /** * @program: wisdomSite * @description: 切面处理类,操作日志记录处理 * @author: Mr.Peng * @create: 2021-05-06 18:04 **/ @Aspect @Component @Slf4j public class OperLogAspect { Pattern logNamePattern = Pattern.compile("(.+):(\\d+:.+;)+"); Pattern logNamePattern1 = Pattern.compile("(\\d+)(\\D+)"); @Autowired private IOperationLogService operationLogService; /** * 设置操作日志切入点 记录操作日志 在注解的位置切入代码 */ @Pointcut("@annotation(com.zhgd.annotation.OperLog)") public void operLogPoinCut() { } /** * 设置操作异常切入点记录异常日志 扫描所有controller包下操作 */ @Pointcut("execution(* com.*.*.*.*.controller..*.*(..))") public void operExceptionLogPoinCut() { } /** * 正常返回通知,拦截用户操作日志,连接点正常执行完成后执行, 如果连接点抛出异常,则不会执行 * * @param joinPoint 切入点 * @param keys 返回结果 */ @AfterReturning(value = "operLogPoinCut()", returning = "keys") public void saveOperLog(JoinPoint joinPoint, Object keys) { // 获取RequestAttributes RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); // 从获取RequestAttributes中获取HttpServletRequest的信息 HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST); OperationLog operlog = new OperationLog(); try { // 主键ID //operlog.setOperId(IdGenerator.getUUID()); // 从切面织入点处通过反射机制获取织入点处的方法 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); // 获取切入点所在的方法 Method method = signature.getMethod(); // 获取操作 OperLog opLog = method.getAnnotation(OperLog.class); if (opLog != null) { String operModul = opLog.operModul(); String operType = opLog.operType(); String operDesc = opLog.operDesc(); // 操作模块 operlog.setOperModul(operModul); // 操作类型 operlog.setOperType(operType); // 操作描述 operlog.setOperDesc(operDesc); } // 获取请求的类名 String className = joinPoint.getTarget().getClass().getName(); // 获取请求的方法名 String methodName = method.getName(); methodName = className + "." + methodName; operlog.setOperMethod(methodName); // 请求的参数 Map rtnMap = converMap(request.getParameterMap()); // 将参数所在的数组转换成json String params = JSON.toJSONString(rtnMap); // 请求参数 operlog.setOperRequParam(params); Object[] args = joinPoint.getArgs(); if (ArrayUtils.isNotEmpty(args)) { List logArgs = Arrays.stream(args).filter(arg -> (!(arg instanceof HttpServletRequest) && !(arg instanceof HttpServletResponse) && !(arg instanceof MultipartFile))).collect(Collectors.toList()); operlog.setBody(JSON.toJSONString(logArgs)); } else { log.info("Request Args : null"); } // 请求用户ID String operUserId = request.getHeader("operateId"); operlog.setOperUserId(operUserId); if (StringUtils.isBlank(operUserId) && SecurityUtils.getUser() != null) { operlog.setOperUserId(String.valueOf(SecurityUtils.getUser().getUserId())); } //operlog.setOperUserName(); // 请求用户名称 // 请求IP operlog.setOperIp(IpUtil.getRemortIP(request)); // 请求URI operlog.setOperUri(request.getRequestURI()); // 请求方法 operlog.setOperMethod(request.getMethod()); // 创建时间 operlog.setOperCreateTime(new Date()); if ("com.zhgd.xmgl.modules.basicdata.controller.LoginController.login".equals(operlog.getOperMethod())) { if (keys != null) { JSONObject json = JSONUtil.parseObj(keys); if ("200".equals(json.getStr("code"))) { JSONObject jsonObject = json.getJSONObject("result"); String userId = jsonObject.getStr("userId"); operlog.setOperUserId(userId); } } } try { //前后数据变化 List beforeList = ThreadLocalUtil.getByKey(Cts.TL_UPDATE_DEL_BEFORE_PARAM, List.class); List insertList = ThreadLocalUtil.getByKey(Cts.TL_INSERT_BEFORE_PARAM, List.class); if (beforeList != null || insertList != null) { if (beforeList == null) { beforeList = new ArrayList<>(); } List afterList = new ArrayList<>(); for (OperLogDataChange jo : beforeList) { String mapperName = jo.getMapperName(); String whereSql = jo.getWhereSql(); List result = (List) jo.getResult(); if (CollUtil.isEmpty(result)) { continue; } //根据修改之前的数据,取出id列表查询之后的数据 Field idField = this.getIdField(result); List idList = (List) result.stream().map(o -> { try { return idField.get(o); } catch (IllegalAccessException e) { log.error("", e); } return null; }).collect(Collectors.toList()); QueryWrapper wrapper = Wrappers.query().in(StrUtil.toUnderlineCase(idField.getName()), idList); Object mapperObj = SpringContextUtils.getBean(Class.forName(mapperName)); Method selectListMethod = ReflectUtil.getMethod(mapperObj.getClass(), "selectList", QueryWrapper.class); Object queryResult = ReflectUtil.invoke(mapperObj, selectListMethod, wrapper); OperLogDataChange operLogDataChange = new OperLogDataChange(); operLogDataChange.setMapperName(mapperName); operLogDataChange.setWhereSql(whereSql); operLogDataChange.setResult(queryResult); operLogDataChange.setTimestamp(System.currentTimeMillis()); afterList.add(operLogDataChange); } if (insertList != null) { //补充完整 insertList,根据主键id查询插入后的数据 for (OperLogInsertChange change : insertList) { String mapperName = change.getMapperName(); List result = (List) change.getResult(); Object mapperObj = SpringContextUtils.getBean(Class.forName(mapperName)); Method selectIdMethod = ReflectUtil.getMethod(mapperObj.getClass(), "selectById", Serializable.class); Field idField = this.getIdField(result); Object obj = result.get(0); BeanUtil.copyProperties(ReflectUtil.invoke(mapperObj, selectIdMethod, idField.get(obj)), obj); } } Pair changePair = getBeforeAndAfterDataChange(beforeList, afterList); operlog.setDataChangeBefore(changePair.getLeft()); operlog.setDataChangeAfter(changePair.getRight()); } } catch (Exception e) { log.error("处理前后数据异常", e); } operationLogService.save(operlog); } catch (Exception e) { log.error("error:", e); } } /** * 获取前后数据变化 * * @param beforeList * @param afterList * @return */ private Pair getBeforeAndAfterDataChange(List beforeList, List afterList) { Map> beforeMapperNameMap = beforeList.stream().collect(Collectors.groupingBy(OperLogDataChange::getMapperName)); Map> afterMapperNameMap = afterList.stream().collect(Collectors.groupingBy(OperLogDataChange::getMapperName)); Set mapperNames = new HashSet<>(CollUtil.addAll(new HashSet<>(beforeMapperNameMap.keySet()), new HashSet<>(afterMapperNameMap.keySet()))); List insertList = ThreadLocalUtil.getByKey(Cts.TL_INSERT_BEFORE_PARAM, List.class); Map> insertMapperNameMap = new HashMap<>(); if (CollUtil.isNotEmpty(insertList)) { List names = insertList.stream().map(OperLogInsertChange::getMapperName).collect(Collectors.toList()); mapperNames = new HashSet<>(CollUtil.addAll(mapperNames, names)); insertMapperNameMap = insertList.stream().collect(Collectors.groupingBy(OperLogInsertChange::getMapperName)); } List> resultBeforeList = new ArrayList<>(); List> resultAfterList = new ArrayList<>(); for (String mapperName : mapperNames) { List befores = beforeMapperNameMap.get(mapperName); Field idField; List beforeDataList = new ArrayList(); if (befores != null) { //更新或删除时候 idField = getIdField((List) befores.get(0).getResult()); beforeDataList = getBeforeDataList(befores, idField); } else { //新增时候 List operLogInsertChanges = insertMapperNameMap.get(mapperName); idField = getIdField((List) operLogInsertChanges.get(0).getResult()); } List afterDataList = getAfterDataList(idField, afterMapperNameMap.get(mapperName), insertMapperNameMap.get(mapperName)); Map beforeDataIdMap = (Map) beforeDataList.stream().collect(Collectors.toMap(o -> { try { return idField.get(o).toString(); } catch (IllegalAccessException e) { e.printStackTrace(); } return ""; }, Function.identity())); Map afterDataIdMap = (Map) afterDataList.stream().collect(Collectors.toMap(o -> { try { return idField.get(o).toString(); } catch (IllegalAccessException e) { e.printStackTrace(); } return ""; }, Function.identity())); //对比集合的数据 Field finalIdField = idField; List idList = (List) CollUtil.addAll(beforeDataList, afterDataList).stream().map(o -> { try { return finalIdField.get(o).toString(); } catch (IllegalAccessException e) { e.printStackTrace(); } return ""; }).distinct().collect(Collectors.toList()); for (String id : idList) { Object afterObj = afterDataIdMap.get(id); Object beforeObj = beforeDataIdMap.get(id); List resultBeforeOneObjList = new ArrayList<>(); List resultAfterOneObjList = new ArrayList<>(); if (beforeObj != null && afterObj != null) { //更新时候,都不为null Field[] fields = afterObj.getClass().getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); if (!field.isAnnotationPresent(ApiModelProperty.class)) { continue; } try { Object oldValue = field.get(beforeObj); Object newValue = field.get(afterObj); if (!Objects.equals(newValue, oldValue) || idField.getName().equals(field.getName())) { resultBeforeOneObjList.add(getOperLogDataChangeField(field, oldValue)); resultAfterOneObjList.add(getOperLogDataChangeField(field, newValue)); } } catch (Exception e) { log.error("更新时候报错", e); } } } else if (beforeObj != null && afterObj == null) { //删除时候 Field[] fields = beforeObj.getClass().getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); if (!field.isAnnotationPresent(ApiModelProperty.class)) { continue; } try { Object oldValue = field.get(beforeObj); if (oldValue != null) { resultBeforeOneObjList.add(getOperLogDataChangeField(field, oldValue)); } } catch (Exception e) { log.error("删除时候报错", e); } } } else if (beforeObj == null && afterObj != null) { //新增时候 Field[] fields = afterObj.getClass().getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); if (!field.isAnnotationPresent(ApiModelProperty.class)) { continue; } try { Object newValue = field.get(afterObj); if (newValue != null) { resultAfterOneObjList.add(getOperLogDataChangeField(field, newValue)); } } catch (Exception e) { log.error("新增时候报错", e); } } } if (CollUtil.isNotEmpty(resultBeforeOneObjList) && resultBeforeOneObjList.size() > 1) { resultBeforeList.add(resultBeforeOneObjList); } if (CollUtil.isNotEmpty(resultAfterOneObjList) && resultAfterOneObjList.size() > 1) { resultAfterList.add(resultAfterOneObjList); } } } return new ImmutablePair(StrUtil.join(";", resultBeforeList.stream().map(fields -> StrUtil.join(",", fields.stream().map(map -> map.getName() + ":" + map.getVal()).collect(Collectors.toList()))).collect(Collectors.toList())), StrUtil.join(";", resultAfterList.stream().map(fields -> StrUtil.join(",", fields.stream().map(map -> map.getName() + ":" + map.getVal()).collect(Collectors.toList()))).collect(Collectors.toList()))); } /** * 获取前后变化的字段名和值 * * @param field * @param val * @return */ private OperLogDataChangeField getOperLogDataChangeField(Field field, Object val) { OperLogDataChangeField bm = new OperLogDataChangeField(); String name = field.getAnnotation(ApiModelProperty.class).value(); String v = null; if (val instanceof Integer) { Matcher matcher = logNamePattern.matcher(name); if (matcher.matches()) { //如:类型:1:人员;2:人员照片;3:人员权限;4:固定车辆;5:固定车辆群组;6:临时车;7:车辆布防; for (String s : matcher.group(2).split(";")) { String[] split = s.split(":"); if (Objects.equals(split[0], val.toString())) { // v = split[1]; name = name.split(":")[0]; break; } } } else { boolean isMatch = false; Matcher matcher1 = logNamePattern1.matcher(name); while (matcher1.find()) { isMatch = true; if (matcher1.group(1).equals(val.toString())) { if (name.contains(":")) { name = StrUtil.subBefore(name, ":", false); } else { name = field.getName(); } // v = matcher1.group(2); break; } } if (!isMatch) { name = field.getName(); } } } if (v == null) { v = getVal(val); } bm.setName(name); bm.setVal(v); return bm; } /** * 获取值 * * @param val * @return */ private String getVal(Object val) { if (val instanceof Date) { return DateUtil.formatDateTime((Date) val); } else { return Convert.toStr(val); } } /** * 获取主键id的属性 * * @param result * @return */ private Field getIdField(List result) { Field idField = null; Object obj = result.get(0); Field[] fields = obj.getClass().getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); if (field.isAnnotationPresent(TableId.class)) { idField = field; break; } } return idField; } /** * 获取之后的数据 * * @param idField * @param afterList * @param insertList * @return */ private List getAfterDataList(Field idField, List afterList, List insertList) { Stream stream1; if (afterList != null) { stream1 = afterList.stream().flatMap(map -> ((List) map.getResult()).stream()); } else { stream1 = Collections.emptyList().stream(); } if (CollUtil.isNotEmpty(insertList)) { Stream stream2 = insertList.stream().flatMap(map -> ((List) map.getResult()).stream()); stream1 = Stream.concat(stream1, stream2); } List rtList = (List) stream1.collect(Collectors.collectingAndThen( Collectors.toCollection(() -> new TreeSet<>( Comparator.comparing( o -> { try { return idField.get(o).toString(); } catch (IllegalAccessException e) { e.printStackTrace(); } return ""; }))), ArrayList::new)); return rtList; } /** * 获取之前的数据 * * @param list * @param idField * @return */ private List getBeforeDataList(List list, Field idField) { return (List) list.stream().flatMap(map -> ((List) map.getResult()).stream()).collect(Collectors.collectingAndThen( Collectors.toCollection(() -> new TreeSet<>( Comparator.comparing( o -> { try { return idField.get(o).toString(); } catch (IllegalAccessException e) { e.printStackTrace(); } return ""; }))), ArrayList::new)); } /** * 转换request 请求参数 * * @param paramMap request获取的参数数组 */ public Map converMap(Map paramMap) { Map rtnMap = new HashMap(); for (String key : paramMap.keySet()) { rtnMap.put(key, paramMap.get(key)[0]); } return rtnMap; } }