org.springframework.boot
spring-boot-starter-aop
package com.plat.sysLog.logEnum;
/**
* @author xxs
* @date 2022年08月10日 16:44
*/
public interface OpType {
/**
* 新增
*/
public static final int ADD = 1;
/**
* 修改
*/
public static final int UPDATE = 2;
/**
* 删除
*/
public static final int DELETE = 3;
/**
* 查询-分页
*/
public static final int QUERY_PAGE = 4;
/**
* 其他
*/
public static final int OTHER = 5;
/**
* 登录
*/
public static final int LOGIN = 6;
/**
* 登出
*/
public static final int LOGOUT = 7;
/**
* 导出
*/
public static final int EXPORT = 8;
/**
* 导入
*/
public static final int IMPORT = 9;
/**
* 保存
*/
public static final int SAVE = 10;
/**
* 发送邮件
*/
public static final int SEND_EMAIL = 11;
/**
* 发送短信
*/
public static final int SMS = 12;
/**
* 查询-不分页
*/
public static final int QUERY_NO_PAGE = 13;
/**
* 查询明细
*/
public static final int QUERY_DETAIL = 14;
/**
* 审核
*/
public static final int AUDIT = 15;
/**
* 反审核
*/
public static final int UN_AUDIT = 16;
/**
* 下载
*/
public static final int DOWNLOAD = 17;
/**
* 上传
*/
public static final int UPLOAD = 18;
/**
* 校验
*/
public static final int CHECK = 19;
/**
* 安装
*/
public static final int INSTALL = 20;
/**
* 卸载
*/
public static final int UN_INSTALL = 21;
/**
* 启动
*/
public static final int START = 22;
/**
* 停止
*/
public static final int STOP = 23;
/**
* 重启
*/
public static final int RESTART = 24;
/**
* 暂停
*/
public static final int PAUSE = 25;
/**
* 恢复
*/
public static final int RESUME = 26;
/**
* 刷新
*/
public static final int REFRESH = 27;
/**
* 生成
*/
public static final int GENERATE = 28;
/**
* 统计
*/
public static final int STATISTICS = 29;
/**
* 同步
*/
public static final int SYNC = 30;
/**
* 定时调度
*/
public static final int SCHEDULE = 31;
}
package com.plat.sysLog.logEnum;
import java.util.ArrayList;
import java.util.List;
/**
* @author hz
*/
public enum OpTypeEnum {
/*
1. 增加
2. 删除
3. 修改
4. 查询
5. 其他
*/
ADD(OpType.ADD, "新增"),
UPDATE(OpType.UPDATE, "修改"),
DELETE(OpType.DELETE, "删除"),
QUERY_PAGE(OpType.QUERY_PAGE, "查询-分页", true),
OTHER(OpType.OTHER, "其他"),
LOGIN(OpType.LOGIN, "登录"),
LOGOUT(OpType.LOGOUT, "登出"),
EXPORT(OpType.EXPORT, "导出"),
IMPORT(OpType.IMPORT, "导入"),
SAVE(OpType.SAVE, "保存"),
SEND_EMAIL(OpType.SEND_EMAIL, "发送邮件"),
SMS(OpType.SMS, "发送短信"),
QUERY_NO_PAGE(OpType.QUERY_NO_PAGE, "查询-不分页", true),
QUERY_DETAIL(OpType.QUERY_DETAIL, "查询明细", true),
AUDIT(OpType.AUDIT, "审核"),
UN_AUDIT(OpType.UN_AUDIT, "反审核"),
DOWNLOAD(OpType.DOWNLOAD, "下载"),
UPLOAD(OpType.UPLOAD, "上传"),
CHECK(OpType.CHECK, "校验"),
INSTALL(OpType.INSTALL, "安装"),
UN_INSTALL(OpType.UN_INSTALL, "卸载"),
START(OpType.START, "启动"),
STOP(OpType.STOP, "停止"),
RESTART(OpType.RESTART, "重启"),
PAUSE(OpType.PAUSE, "暂停"),
RESUME(OpType.RESUME, "恢复"),
REFRESH(OpType.REFRESH, "刷新"),
GENERATE(OpType.GENERATE, "生成"),
STATISTICS(OpType.STATISTICS, "统计"),
SYNC(OpType.SYNC, "同步"),
SCHEDULE(OpType.SCHEDULE, "定时调度"),
last(0, "最后一个");
final int key;
final String desc;
//是否忽略返回结果
final boolean ignoreResult;
OpTypeEnum(int key, String desc) {
this.key = key;
this.desc = desc;
this.ignoreResult = false;
}
OpTypeEnum(int key, String desc, boolean ignoreResult) {
this.key = key;
this.desc = desc;
this.ignoreResult = ignoreResult;
}
/**
* 根据key获取desc
*/
public static String getDesc(Integer key) {
for (OpTypeEnum opTypeEnum : OpTypeEnum.values()) {
if (opTypeEnum.getKey() == key) {
return opTypeEnum.getDesc();
}
}
return "";
}
/**
* 获取所有忽略返回结果的Key集合
*/
public static List getIgnoreResultKeys() {
List keys = new ArrayList<>();
for (OpTypeEnum opTypeEnum : OpTypeEnum.values()) {
if (opTypeEnum.isIgnoreResult()) {
keys.add(opTypeEnum.getKey());
}
}
return keys;
}
public int getKey() {
return key;
}
public String getDesc() {
return desc;
}
public boolean isIgnoreResult() {
return ignoreResult;
}
}
package com.plat.sysLog.logEnum;
/**
* @author xxs
* @date 2022年08月10日 16:50
*/
public interface SysType {
/**
* WEB服务
*/
public static final int WEB = 1;
}
package com.plat.sysLog.model;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class SysLog {
private static final long serialVersionUID = 1L;
/**
*
*/
private Long id;
/**
* 操作人
*/
private String operationUser;
/**
* 请求路径
*/
private String path;
/**
* 开始时间
*/
private String startTime;
/**
* 结束时间
*/
private String endTime;
/**
* 方法入参
*/
private String parameter;
/**
* 返回参数
*/
private String result;
/**
* 操作方法
*/
private String title;
/**
* 方法描述
*/
private String action;
/**
* 系统类型
*/
private Integer sysType;
/**
* 操作类型
*/
private Integer opType;
/**
* 请求ip
*/
private String sourceIp;
/**
* 方法名称
*/
private String method;
/**
* 请求方式
*/
private String requestMethod;
/**
* 操作状态(0正常 1异常)
*/
private Integer status;
/**
* 错误信息
*/
private String errorMsg;
public SysLog() {
}
}
package com.plat.sysLog.config;
import com.plat.sysLog.logEnum.OpType;
import com.plat.sysLog.logEnum.SysType;
import java.lang.annotation.*;
/**
* @author xxs
* @date 2022年08月10日 16:01
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface OperationLog {
//功能模块
String title() default "";
//详情
String desc() default "";
//操作类型
int opType() default OpType.OTHER;
//接口调用方系统类型
int sysType() default SysType.WEB;
//是否忽略返回结果,0跟随默认,1忽略,2不忽略
int ignoreResult() default 0;
//是否忽略请求参数
boolean ignoreParam() default false;
//是否来源于定时任务
boolean fromTask() default false;
}
package com.hz.plat.sysLog.logAspect;
import com.alibaba.fastjson.JSONObject;
import com.plat.common.util.DateUtil;
import com.plat.common.util.IpAddressUtil;
import com.plat.shiro.TokenManager;
import com.plat.sysLog.config.OperationLog;
import com.plat.sysLog.dao.SysLogMapper;
import com.plat.sysLog.logEnum.OpTypeEnum;
import com.plat.sysLog.model.SysLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.CodeSignature;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* @author xxs
* @date 2022年08月10日 16:01
* @description 操作日志切面
*/
@Aspect
@Component
@EnableAsync
@Order(-1)
@Slf4j
public class SystemLogAspect {
SysLog sysLog = null;
//日志 mapper
@Resource
private SysLogMapper logMapper;
//请求
private HttpServletRequest request = null;
//是否忽略返回结果
private int ignoreResult = 0;
//是否来源定时任务
private boolean isScheduledTask = false;
/**
* 注解的位置
*/
@Pointcut("@annotation(com.plat.sysLog.config.OperationLog)")
public void logPointCut() {
}
@Around(value = "logPointCut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
try {
sysLog = new SysLog();
sysLog.setStartTime(DateUtil.getCurrentDateString("yyyy-MM-dd HH:mm:ss.SSS"));
//通过uuid关联请求参数和返回参数
// String uuid = UUID.randomUUID().toString().replaceAll("-", "");
String user = null;
try {
user = TokenManager.getNickname();
} catch (Exception e) {
user = "未登录用户";
}
// sysLog.setId(uuid);
sysLog.setOperationUser(user);
methodBefore(pjp);
Object proceed = pjp.proceed();
methodAfter(proceed);
sysLog.setStatus(0);
return proceed;
} catch (Exception e) {
sysLog.setStatus(1);
sysLog.setErrorMsg(sysLog.getErrorMsg() + "errMsg:" + e.getMessage() + "\n" + "errStackTrace:" + e.getStackTrace()[0].toString() + "\n");
log.error("【AOP日志管理】=========》", e);
throw e;
} finally {
sysLog.setEndTime(DateUtil.getCurrentDateString("yyyy-MM-dd HH:mm:ss.SSS"));
if (isScheduledTask) {
sysLog.setRequestMethod("定时任务");
sysLog.setSourceIp("定时任务");
sysLog.setPath("定时任务");
} else {
String requestMethod = null;
String requestPath = null;
String ipAddress = null;
try {
request = getHttpServletRequest();
requestMethod = request.getMethod();
requestPath = request.getServletPath();
ipAddress = IpAddressUtil.getIpAddress(request);
} catch (Exception e) {
sysLog.setErrorMsg(sysLog.getErrorMsg() + "errMsg:" + e.getMessage() + "\n" + "errStackTrace:" + e.getStackTrace()[0].toString() + "\n");
log.error("【AOP日志管理】=========》", e);
}
sysLog.setSourceIp(ipAddress);
sysLog.setRequestMethod(requestMethod);
sysLog.setPath(requestPath);
}
logMapper.insert(sysLog);
}
}
/**
* 处理返回结果
* @param proceed
*/
private void methodAfter(Object proceed) {
if (ObjectUtils.nullSafeEquals(ignoreResult, 0)) {
if (proceed != null) {
String resultParamJsonStr = JSONObject.toJSONString(proceed);
if (OpTypeEnum.getIgnoreResultKeys().contains(sysLog.getOpType())) {
sysLog.setResult("忽略返回结果");
} else {
sysLog.setResult(resultParamJsonStr);
}
}
} else if (ObjectUtils.nullSafeEquals(ignoreResult, 1)) {
sysLog.setResult("忽略返回结果");
}else if (ObjectUtils.nullSafeEquals(ignoreResult, 2)) {
if (proceed != null) {
String resultParamJsonStr = JSONObject.toJSONString(proceed);
sysLog.setResult(resultParamJsonStr);
}
}
}
public void methodBefore(JoinPoint joinPoint) {
// 打印请求内容
try {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class> targetClass = null;
try {
targetClass = Class.forName(targetName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Method[] methods = new Method[0];
if (targetClass != null) {
methods = targetClass.getMethods();
}
Class>[] clazzs;
for (Method method : methods) {
if (method.getName().equals(methodName)) {
clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length && method.getAnnotation(OperationLog.class) != null) {
String title = method.getAnnotation(OperationLog.class).title();
int sysType = method.getAnnotation(OperationLog.class).sysType();
int opType = method.getAnnotation(OperationLog.class).opType();
String action = method.getAnnotation(OperationLog.class).desc();
ignoreResult = method.getAnnotation(OperationLog.class).ignoreResult();
isScheduledTask = method.getAnnotation(OperationLog.class).fromTask();
boolean ignoreParam = method.getAnnotation(OperationLog.class).ignoreParam();
if (!ignoreParam) {
Map nameAndValue = getNameAndValue(joinPoint);
String paramJsonStr = JSONObject.toJSONString(nameAndValue);
sysLog.setParameter(paramJsonStr);
} else {
sysLog.setParameter("忽略请求参数");
}
String thisMethodName = targetName + "." + methodName;
sysLog.setTitle(title);
sysLog.setSysType(sysType);
sysLog.setOpType(opType);
sysLog.setAction(action);
sysLog.setMethod(thisMethodName);
}
}
}
} catch (Exception e) {
sysLog.setErrorMsg(sysLog.getErrorMsg() + "errMsg:" + e.getMessage() + "\n" + "errStackTrace:" + e.getStackTrace()[0].toString() + "\n");
}
}
/**
* @param joinPoint
* @return
* @Description 获取入参方法参数
*/
public Map getNameAndValue(JoinPoint joinPoint) {
Map param = new HashMap<>();
Object[] paramValues = joinPoint.getArgs();
String[] paramNames = ((CodeSignature) joinPoint.getSignature()).getParameterNames();
for (int i = 0; i < paramNames.length; i++) {
if (paramValues[i] instanceof MultipartFile || paramValues[i] instanceof HttpSession || paramValues[i] instanceof ServletRequest || paramValues[i] instanceof ServletResponse) {
param.put(paramNames[i], "忽略请求参数:" + paramValues[i].getClass().getTypeName());
} else {
param.put(paramNames[i], paramValues[i]);
}
}
return param;
}
/**
* @Description: 获取request
*/
public HttpServletRequest getHttpServletRequest() {
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
HttpServletRequest request = null;
if (sra != null) {
request = sra.getRequest();
}
return request;
}
}
CREATE TABLE `plat_sys_log` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(50) DEFAULT NULL COMMENT '操作方法',
`action` varchar(50) DEFAULT NULL COMMENT '方法描述',
`opType` int(2) DEFAULT NULL COMMENT '操作类型',
`operationUser` varchar(50) DEFAULT NULL COMMENT '操作人',
`path` varchar(255) DEFAULT NULL COMMENT '请求路径',
`startTime` varchar(50) DEFAULT NULL COMMENT '方法执行耗时',
`endTime` varchar(50) DEFAULT NULL COMMENT '操作时间',
`parameter` varchar(2000) DEFAULT NULL COMMENT '方法入参',
`result` text COMMENT '返回参数',
`status` int(1) DEFAULT NULL COMMENT '操作状态(0正常 1异常)',
`sourceIp` varchar(128) DEFAULT NULL COMMENT '请求ip',
`errorMsg` varchar(2000) DEFAULT NULL COMMENT '错误信息',
`requestMethod` varchar(10) DEFAULT '' COMMENT '请求方式',
`method` varchar(100) DEFAULT NULL COMMENT '方法名称',
`sysType` int(2) DEFAULT NULL COMMENT '系统类型',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=170 DEFAULT CHARSET=utf8;
至于mapper和dao层代码我就不赘述了。给大家看一下效果图
@OperationLog(title = "看板统计", opType = OpType.STATISTICS,desc = "获取看板统计信息")
1、因为项目接口基本使用的Map进行前后端传参,所以无法适用Swagger等主流API文档生成插件。所以另辟蹊径...
import com.alibaba.fastjson.JSONObject;
import com.hz.MubanApplication;
import com.hz.plat.common.util.DateUtil;
import com.hz.plat.sysLog.dao.SysLogMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.stereotype.Component;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.*;
/**
* @author xxs
* @date 2022年11月04日 09:27
*/
@Component
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MubanApplication.class)
@Slf4j
public class PostApiTest {
@Resource
SysLogMapper sysLogMapper;
@Test
public void getJsonFile() {
String path = "C:\\Users\\xxs\\Desktop\\test.json";
try {
creteJsonFile(path);
// File file = new File(path);
// creteJsonFile(file);
} catch (IOException e) {
log.error("生成文件失败", e);
}
}
/**
* 直接生成json文件
*
* @throws IOException
*/
public void creteJsonFile(String filePath) throws IOException {
List
2、将生成的test.json文件导入ApiPost中,效果展示
3、这里只贴出了关键部分代码,如果有哪里不清楚的欢迎留言