512 lines
23 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<String, String> rtnMap = converMap(request.getParameterMap());
// 将参数所在的数组转换成json
String params = JSON.toJSONString(rtnMap);
// 请求参数
operlog.setOperRequParam(params);
Object[] args = joinPoint.getArgs();
if (ArrayUtils.isNotEmpty(args)) {
List<Object> 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<OperLogDataChange> beforeList = ThreadLocalUtil.getByKey(Cts.TL_UPDATE_DEL_BEFORE_PARAM, List.class);
List<OperLogInsertChange> insertList = ThreadLocalUtil.getByKey(Cts.TL_INSERT_BEFORE_PARAM, List.class);
if (beforeList != null || insertList != null) {
if (beforeList == null) {
beforeList = new ArrayList<>();
}
List<OperLogDataChange> 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<Object> 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<String, String> 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<String, String> getBeforeAndAfterDataChange(List<OperLogDataChange> beforeList, List<OperLogDataChange> afterList) {
Map<String, List<OperLogDataChange>> beforeMapperNameMap = beforeList.stream().collect(Collectors.groupingBy(OperLogDataChange::getMapperName));
Map<String, List<OperLogDataChange>> afterMapperNameMap = afterList.stream().collect(Collectors.groupingBy(OperLogDataChange::getMapperName));
Set<String> mapperNames = new HashSet<>(CollUtil.addAll(new HashSet<>(beforeMapperNameMap.keySet()), new HashSet<>(afterMapperNameMap.keySet())));
List<OperLogInsertChange> insertList = ThreadLocalUtil.getByKey(Cts.TL_INSERT_BEFORE_PARAM, List.class);
Map<String, List<OperLogInsertChange>> insertMapperNameMap = new HashMap<>();
if (CollUtil.isNotEmpty(insertList)) {
List<String> 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<List<OperLogDataChangeField>> resultBeforeList = new ArrayList<>();
List<List<OperLogDataChangeField>> resultAfterList = new ArrayList<>();
for (String mapperName : mapperNames) {
List<OperLogDataChange> 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<OperLogInsertChange> operLogInsertChanges = insertMapperNameMap.get(mapperName);
idField = getIdField((List) operLogInsertChanges.get(0).getResult());
}
List afterDataList = getAfterDataList(idField, afterMapperNameMap.get(mapperName), insertMapperNameMap.get(mapperName));
Map<String, Object> beforeDataIdMap = (Map<String, Object>) beforeDataList.stream().collect(Collectors.toMap(o -> {
try {
return idField.get(o).toString();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return "";
}, Function.identity()));
Map<String, Object> afterDataIdMap = (Map<String, Object>) afterDataList.stream().collect(Collectors.toMap(o -> {
try {
return idField.get(o).toString();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return "";
}, Function.identity()));
//对比集合的数据
Field finalIdField = idField;
List<String> 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<OperLogDataChangeField> resultBeforeOneObjList = new ArrayList<>();
List<OperLogDataChangeField> 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<OperLogDataChange> afterList, List<OperLogInsertChange> 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<OperLogDataChange> 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<String, String> converMap(Map<String, String[]> paramMap) {
Map<String, String> rtnMap = new HashMap<String, String>();
for (String key : paramMap.keySet()) {
rtnMap.put(key, paramMap.get(key)[0]);
}
return rtnMap;
}
}