@Log注解实现接口操作日志保存
1.日志注解类@Log
package com.dstcar.entitys.sys;
import com.dstcar.common.constant.BusinessModelEnum;
import com.dstcar.common.constant.BusinessTypeEnum;
import java.lang.annotation.*;
/**
* 包名路径: com.dstcar.entitys.sys
* 功能说明:
* 开发人员:liu wei ping
* 开发时间:2022年08月05日 09:29
* 修改记录:修改日期 修改人员 修改说明
*/
@Target({ ElementType.METHOD ,ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
/**
* 模块
*/
// BusinessModelEnum businessModel() default BusinessModelEnum.OTHER;
/**
* 模块_常量
* @return
*/
String businessModelConstant() default "OTHER";
/**
* 功能
*/
BusinessTypeEnum businessType() default BusinessTypeEnum.NORMAL;
/**
* 功能_常量
* @return
*/
String businessTypeConstant() default "NORMAL";
/**
* 备注
*/
String remark() default "";
/**
* 是否保存请求的参数
*/
boolean isSaveRequestData() default true;
}
2.业务操作日志切面类
package com.dstcar.common.log;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import com.dstcar.common.constant.LogConstant;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.dstcar.common.base.ApiController;
import com.dstcar.common.base.Results;
import com.dstcar.common.constant.BusinessModelEnum;
import com.dstcar.common.constant.BusinessStatusEnum;
import com.dstcar.common.constant.BusinessTypeEnum;
import com.dstcar.common.utils.http.NetworkUtil;
import com.dstcar.common.utils.string.StringUtil;
import com.dstcar.entitys.sso.SSOUser;
import com.dstcar.entitys.sys.Log;
import com.dstcar.entitys.sys.LogResult;
import com.dstcar.entitys.sys.SysOperLog;
import lombok.extern.slf4j.Slf4j;
/**
* 包名路径: com.dstcar.common.utils.log 功能说明: 开发人员:liu wei ping
* 开发时间:2022年08月15日 14:02
* 修改记录:修改日期 修改人员 修改说明
*/
@Slf4j
@Aspect
@Component
public class SysOperLogAspect extends ApiController {
@Autowired
SysOperLogService sysOperLogService;
@Pointcut("@annotation(com.dstcar.entitys.sys.Log)")
public void logPointCut() {
}
/**
* 处理完请求后执行
*
* @param joinPoint 切点
*/
@AfterReturning(pointcut = "logPointCut()", returning = "results")
public void doAfterReturning(JoinPoint joinPoint, Object results) {
handleLog(joinPoint, null, results, null);
}
/**
* 作用于所有类
*
* @param joinPoint
* @param l
*/
@AfterReturning(pointcut = "@within(l)", returning = "results")
public void bindTypeAnno(JoinPoint joinPoint, Log l, Object results) {
if (results != null && results instanceof Results && ((Results)
results).getLogResult() != null
&& getAnnotationLog(joinPoint) == null) {
LogResult logResult = ((Results) results).getLogResult();
if (!CollectionUtils.isEmpty(logResult.getLogResultList())
|| !StringUtil.isEmpty(logResult.getBusinessId()))
handleLog(joinPoint, null, results, l);
}
}
/**
* 拦截异常操作
*
* @param joinPoint
* @param e
*/
@AfterThrowing(value = "logPointCut()", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
handleLog(joinPoint, e, null, null);
}
protected void handleLog(final JoinPoint joinPoint, final Exception e, Object results, Log l) {
// 获取当前的用户
SSOUser currentUser = null;
try {
currentUser = getCurrentUser();
} catch (Exception e1) {
// log.error("切面获取token异常捕获"); 屏蔽登录错误日志
}
// 日志
SysOperLog sysOperLog = new SysOperLog();
boolean isFlag = true;
try {
String operIp = NetworkUtil.getIpAddress(request); // 记录ip
sysOperLog.setOperIp(operIp);
sysOperLog.setOperUrl(request.getServletPath());
sysOperLog.setOperLocation(operIp);
} catch (Exception e1) {
sysOperLog.setOperIp("127.0.0.1");
sysOperLog.setOperUrl("/job");
sysOperLog.setOperLocation("127.0.0.1");
isFlag = false;
}
try {
if (l == null) {
l = getAnnotationLog(joinPoint);
}
// 获得注解
Log controllerLog = l;
if (controllerLog == null) {
return;
}
sysOperLog.setStatus(BusinessStatusEnum.SUCCESS.name());
// 处理设置注解上的参数
getControllerMethodDescription(controllerLog, sysOperLog);
// 操作人员
sysOperLog.setOperNameId("1");
sysOperLog.setOperName("系统管理员");
if (currentUser != null) {
sysOperLog.setOperNameId(getCurrentUserId() + "");
sysOperLog.setOperName(getOperationUserName());
}
// 设置方法名称
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
sysOperLog.setMethod(className + "." + methodName + "()");
// 异常
if (e != null) {
sysOperLog.setStatus(BusinessStatusEnum.FAIL.name());
String error = ExceptionUtils.getStackTrace(e);
sysOperLog.setErrorMsg(StringUtil.substring(error, 0, 2000));
log.error("[模块:{}]-[方法:{}]-[发生异常:{}]", sysOperLog.getModel(), sysOperLog.getMethod(),
sysOperLog.getErrorMsg());
return; // 不保存
}
// 业务
Boolean flag = false;
if (results != null && controllerLog.businessType().getKey().equals(BusinessTypeEnum.NORMAL.getKey())) {
if (results instanceof Results) {
Results temp = (Results) results;
if (temp.getLogResult() != null) {
LogResult logResult = temp.getLogResult();
// 单条日志
setSysOperLog(sysOperLog, logResult);
// 批量日志
setSysOperLogList(sysOperLog, logResult);
flag = true;
}
}
if (results instanceof LogResult) {
LogResult logResult = (LogResult) results;
// 单条日志
setSysOperLog(sysOperLog, logResult);
if (!isNull(logResult.getBusinessModel())) {
sysOperLog.setModel(logResult.getBusinessModel());
}
// 批量日志
setSysOperLogList(sysOperLog, logResult);
flag = true;
}
}
if (flag) {
// 保存数据
// AsyncManager.me().execute(AsyncFactory.recordOper(sysOperLog));
sysOperLogService.addSysLog(sysOperLog);
}
} catch (Exception exp) {
// 记录本地异常日志
log.error("异常信息:{}", exp.getMessage());
exp.printStackTrace();
}
}
/**
* 单条
*
* @param sysOperLog
*/
private void setSysOperLog(SysOperLog sysOperLog, LogResult logResult) {
sysOperLog.setBusinessId(logResult.getBusinessId());
sysOperLog.setRemark(logResult.getRemark());
// 操作人及操作人id
if (!isNull(logResult.getOperName())) {
sysOperLog.setOperName(logResult.getOperName());
}
if (!isNull(logResult.getOperNameId())) {
sysOperLog.setOperNameId(logResult.getOperNameId());
}
}
/**
* 批量
*/
private void setSysOperLogList(SysOperLog sysOperLog, LogResult logResult) {
List<LogResult> logResultList = logResult.getLogResultList();
if (logResultList != null && logResultList.size() > 0) {
List<SysOperLog> sysOperLogList = new ArrayList<>();
for (int i = 0; i < logResultList.size(); i++) {
SysOperLog temp = new SysOperLog();
BeanUtils.copyProperties(sysOperLog, temp);
LogResult log = logResultList.get(i);
temp.setBusinessId(log.getBusinessId());
temp.setRemark(log.getRemark());
if (!isNull(log.getBusinessModel())) {
temp.setModel(log.getBusinessModel());
}
sysOperLogList.add(temp);
}
sysOperLog.setSysOperLogList(sysOperLogList);
}
}
/**
* 是否存在注解,如果存在就获取
*/
private Log getAnnotationLog(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null) {
return method.getAnnotation(Log.class);
}
return null;
}
/**
* 获取注解中对方法的描述信息 用于Controller层注解
*
* @param log 日志
* @param operLog 操作日志
* @throws Exception
*/
private void getControllerMethodDescription(Log log, SysOperLog operLog) {
// 设置模块
operLog.setModel(log.businessModelConstant());
// 业务
operLog.setBusinessType(log.businessType().getKey());
// 备注
operLog.setRemark(log.remark());
// 设置模块_使用常量
if (!LogConstant.OTHER.equals(log.businessModelConstant())) {
operLog.setModel(log.businessModelConstant());
}
// 设置业务_使用常量
if (!BusinessTypeEnum.NORMAL.getKey().equals(log.businessTypeConstant())) {
operLog.setBusinessType(log.businessTypeConstant());
}
}
}
3.操作日志执行发送mq
package com.dstcar.common.log;
import com.alibaba.fastjson.JSONObject;
import com.dstcar.apis.base.log.SysOperLogApi;
import com.dstcar.common.mq.constant.QueueExchangeContant;
import com.dstcar.entitys.sys.SysOperLog;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 包名路径: com.dstcar.common.utils.log
* 功能说明:
* 开发人员:liu wei ping
* 开发时间:2022年08月15日 13:57
* 修改记录:修改日期 修改人员 修改说明
*/
@Slf4j
@Service
public class SysOperLogService {
@Autowired
private SysOperLogApi sysOperLogApi;
@Autowired
AmqpTemplate amqpTemplate;
@Value("-${spring.profiles.active}")
private String active;
@Async
public void addSysLog(SysOperLog sysOperLog) {
// AsyncManager.me().execute(AsyncFactory.recordOper(sysOperLog));
Message message = MessageBuilder
.withBody(JSONObject.toJSONBytes(sysOperLog))
.setContentType(MessageProperties.CONTENT_TYPE_JSON)
.build();
amqpTemplate.convertAndSend(QueueExchangeContant.BASIC_BASE_LOG_QUEUE + active,
message);
}
public List<SysOperLog> selectList(SysOperLog sysOperLog) {
return sysOperLogApi.selectList(sysOperLog);
}
public PageInfo<SysOperLog> selectListPage(SysOperLog sysOperLog) {
return sysOperLogApi.selectListPage(sysOperLog);
}
}
4.在Controller方法上加上@Log注解即可
@OSSExport(moduleName = "车辆档案",fileName = "车辆档案工单",dataUrl = "/operatingVehicleArchive/task/vehicleArchiveExportTask")
@Log(businessModelConstant = BusinessModelConstant.VEHICLE_ITEM_EXPORT, businessType = BusinessTypeEnum.EXPORT, remark =
"车辆档案工单导出")
@GetMapping(value = "/vehicleArchiveExport")
public Results vehicleArchiveExport(VehicleArchiveVO archiveVO) {
return succeed();
}
5.日志表表结构
CREATE TABLE `sys_oper_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '日志主键',
`model` varchar(100) DEFAULT '' COMMENT '操作模块(BusinessModelEnum)',
`business_id` varchar(64) DEFAULT '' COMMENT '业务id(表id)',
`business_type` varchar(100) DEFAULT '' COMMENT '业务类型(BusinessTypeEnum)',
`oper_name` varchar(100) DEFAULT '' COMMENT '操作人员',
`oper_name_id` varchar(20) NOT NULL DEFAULT '' COMMENT '操作人员id',
`oper_url` varchar(255) DEFAULT '' COMMENT '请求URL',
`oper_ip` varchar(50) DEFAULT '' COMMENT '主机地址',
`oper_location` varchar(255) DEFAULT '' COMMENT '操作地点',
`remark` mediumtext COMMENT '备注信息',
`oper_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '操作时间',
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`) USING BTREE,
KEY `index` (`model`,`business_id`,`business_type`,`oper_name_id`)
) ENGINE=InnoDB AUTO_INCREMENT=108625 DEFAULT CHARSET=utf8mb4 COMMENT='操作日志记录';
6.效果如图:
