需求
公司要求记录操作日志,这里使用的aop正常返回通知以及自定义注解实现的需求,话不多说,直接贴代码。
1.首先创建实体类,接收参数保存到数据库
import lombok.Data;
import javax.persistence.Table;
import java.io.Serializable;
/**
* 操作日志
*/
@Table(name = "operation_log")
@Data
public class OperationLog implements Serializable {
private static final long serialVersionUID = 1;
/**
* 系统模块
*/
private String systemModule;
/**
* 操作类型: 1:新增 2:修改 3:删除
*/
private Integer operationType;
/**
* 用户id
*/
private Long userId;
/**
* 用户姓名
*/
private String userName;
/**
* 用户IP地址
*/
private String ipAddress;
/**
* 操作描述
*/
private String operationDescription;
/**
* 入参
*/
private String requParam;
/**
*出参
*/
private String respParam;
/**
*请求地址
*/
private String url;
/**
*调用方法
*/
private String method;
}
2.定义常量,也就是操作类型
/**
* 新增
*/
public static final String SAVE = "新增";
/**
* 修改
*/
public static final String UPDATE = "修改";
/**
* 删除
*/
public static final String DEL = "删除";
/**
* 导入
*/
public static final String IMPORT = "导入";
/**
* 导出
*/
public static final String EXPORT = "导出";
3.自定义做操日志注解@OperLog
import java.lang.annotation.*;
/**
* 自定义注解 保存操作日志
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OperLog {
String systemModule() default ""; // 系统模块
String operationType() default ""; // 操作类型 1:新增 2:修改 3:删除
String operationDescription() default ""; // 操作描述
}
4.AOP
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
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 javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* 切面 保存操作日志
*/
@Aspect
@Component
public class OperationLogAop {
@Autowired
private OperationLogFrontService operationLogFrontService;
/**
* 设置操作日志切入点 记录操作日志 在注解的位置切入代码
*/
@Pointcut("@annotation(com.xxxx.user.aspect.OperLog)")
public void operLogPoinCut() {
}
/**
* 正常返回通知,拦截用户操作日志,连接点正常执行完成后执行, 如果连接点抛出异常,则不会执行
*
* @param joinPoint 切入点
*/
@AfterReturning(value = "operLogPoinCut()",returning = "keys")
public void saveOperLog(JoinPoint joinPoint,Object keys) throws Throwable {
// 获取RequestAttributes
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
// 从获取RequestAttributes中获取HttpServletRequest的信息
HttpServletRequest request = (HttpServletRequest) requestAttributes
.resolveReference(RequestAttributes.REFERENCE_REQUEST);
//获取当前登录的用户信息
UserDTO userDTO = getUserDTO(request);
OperationLog operlog = new OperationLog();
try {
operlog.setId(IdTemplate.nextId()); // 主键ID
// 从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// 获取切入点所在的方法
Method method = signature.getMethod();
// 获取操作
OperLog opLog = method.getAnnotation(OperLog.class);
if (opLog != null) {
String systemModule = opLog.systemModule();
String operationType = opLog.operationType();
String operationDescription = opLog.operationDescription();
operlog.setSystemModule(systemModule); // 操作模块
operlog.setOperationType(OperationTypeEnum.getCodeByDesc(operationType)); // 操作类型
operlog.setOperationDescription(operationDescription); // 操作描述
}
//获取ip
String ip = IpAdrressUtil.getIpAdrress(request);
// 请求的参数
Map<String, String> rtnMap = converMap(request.getParameterMap());
// 将参数所在的数组转换成json
String params = JSON.toJSONString(rtnMap);
// 获取请求的类名
String className = joinPoint.getTarget().getClass().getName();
// 获取请求的方法名
String methodName = method.getName();
methodName = className + "." + methodName;
operlog.setMethod(methodName); // 请求方法
operlog.setRequParam(params);//入参
operlog.setRespParam(JSON.toJSONString(keys));//出参
operlog.setIpAddress(ip == null ? "" : ip); // 请求IP
operlog.setUrl(request.getRequestURI()); // 请求URI
operlog.setCreateTime(new Date()); // 创建时间
operlog.setModifyTime(new Date()); // 修改时间
if(userDTO != null){
operlog.setUserId(userDTO.getId()); // 请求用户ID
operlog.setUserName(userDTO.getName()); // 请求用户名称
operlog.setCreator(userDTO.getId()); // 创建人
operlog.setModifier(userDTO.getId()); // 修改人
}
operationLogFrontService.save(operlog);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 转换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;
}
private UserDTO getUserDTO(HttpServletRequest request) {
return LoginUserInfoUtil.getUserDTO(request);
}
}
实际应用
@ApiOperation("根据id删除")
@PostMapping("/del")
@OperLog(systemModule = "XX模块",operationType = Const.DEL, operationDescription = "删除xx信息")
public AjaxResult<String> del(@NotNull(title = "id") Long id) {
return relUserRoleFrontService.del(id);
}