1.创建枚举
@Getter
public enum OperationEnum {
删除,查询,新增,更新,上传,编辑;
}
说明: “删除”,“查询”,“新增”,"编辑"都很好理解。"上传"用在文件上传接口,"更新"指的是同一个接口通过是否传递主键来实现新增和编辑。
2.创建日志注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SimpleLog {
String remark() default "";
OperationEnum operation() default OperationEnum.更新;
String id() default "id";
}
注解的默认操作就是"更新"。
3.创建日志的实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("sys_web_operation_log")
public class OperationInfo {
private Long id;
private String ip;
private String url;
private String httpMethod;
private String classMethod;
private String requestParams;
private String result;
private Long timeCost;
private String exception;
private String remark;
private String userId;
private String userName;
private Date createTime;
private String operation;
}
数据库创建一个表"sys_web_operation_log"字段和实体类一致就行了。
4.创建一个mapper
@Mapper
public interface OperationInfoMapper extends BaseMapper<OperationInfo> {
}
5.切面业务
@Aspect
@Component
@Slf4j
public class LogAspect {
@Autowired
OperationInfoMapper operationInfoMapper;
@Around("@annotation(simpleLog)")
public Object around(ProceedingJoinPoint joinPoint, SimpleLog simpleLog) throws Throwable {
OperationInfo requestInfo = new OperationInfo();
Object result = null;
long start = 0;
try {
start = System.currentTimeMillis();
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
requestInfo.setId(IdWorker.getId());
if (null != attributes) {
HttpServletRequest request = attributes.getRequest();
requestInfo.setIp(request.getRemoteAddr());
requestInfo.setUrl(request.getRequestURL().toString());
requestInfo.setHttpMethod(request.getMethod());
}
requestInfo.setClassMethod(String.format("%s.%s", joinPoint.getSignature().getDeclaringTypeName(),
joinPoint.getSignature().getName()));
requestInfo.setRemark(simpleLog.remark());
String operation = simpleLog.operation().name();
requestInfo.setOperation(operation);
Object[] args = joinPoint.getArgs();
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
String[] params = methodSignature.getParameterNames();
Map<String,Object> request=new HashMap<>();
UserInfoVo user = UserContext.getUserInfoVO();
if (ObjectUtils.isNotEmpty(user)){
requestInfo.setUserId(user.getLoginName());
requestInfo.setUserName(user.getUserName());
}
for (int i=0;i<args.length;i++){
Object arg=args[i];
String param = params[i];
if (arg instanceof UserInfoVo){
continue;
}
else if (arg instanceof MultipartFile){
requestInfo.setOperation(OperationEnum.上传.name());
MultipartFile file = (MultipartFile) arg;
request.put(param,file.getOriginalFilename());
}else if (arg instanceof MultipartFile[]){
requestInfo.setOperation(OperationEnum.上传.name());
MultipartFile[] files = (MultipartFile[]) arg;
List<String> list=new ArrayList<>();
for (MultipartFile file:files){
list.add(file.getOriginalFilename());
}
request.put(param,String.join("#",list));
}
else {
Object o = JSONObject.toJSON(arg);
if (o instanceof JSONObject){
JSONObject arg1 = (JSONObject) o;
if (OperationEnum.更新.name().equals(operation)){
String idName = simpleLog.id();
String id = arg1.getString(idName);
if (ObjectUtils.isEmpty(id)){
requestInfo.setOperation(OperationEnum.新增.name());
}else {
requestInfo.setOperation(OperationEnum.编辑.name());
}
}
request.put(param,arg1);
}else if (o instanceof JSONArray){
JSONArray arg1 = (JSONArray) o;
request.put(param,arg1);
}
else {
if (OperationEnum.更新.name().equals(operation)){
String idName = simpleLog.id();
if (param.equals(idName)&&ObjectUtils.isEmpty(o)){
requestInfo.setOperation(OperationEnum.新增.name());
}else if (param.equals(idName)&&ObjectUtils.isNotEmpty(o)){
requestInfo.setOperation(OperationEnum.编辑.name());
}
}
request.put(param,o);
}
}
}
requestInfo.setRequestParams(JSON.toJSONString(request));
} catch (Exception e) {
requestInfo.setException("aop日志异常:"+e.getMessage());
}
try {
result = joinPoint.proceed();
} catch (Throwable e) {
requestInfo.setException("接口异常:"+e.getMessage());
throw new RuntimeException(e);
}finally {
try {
requestInfo.setResult(JSON.toJSONString(result));
requestInfo.setTimeCost(System.currentTimeMillis() - start);
requestInfo.setCreateTime(new Date());
operationInfoMapper.insert(requestInfo);
} catch (Exception e) {
}
}
return result;
}
}
这个日志信息会保存你加了注解的接口请求信息,如果这个接口异常,它就会保留这次请求的异常信息。
需要注意的是"UserInfoVo user = UserContext.getUserInfoVO();",你需要根据自己的框架去容器获取登录人信息。
使用方法
1.删除(参数任意形式都行不限制死对象或数组)
@SimpleLog(remark = "删除",operation = OperationEnum.删除)
@ApiOperation(value = "删除", notes = "删除")
@PostMapping("/delete")
public ReturnVo delete(@RequestParam String id) throws MesReturnException {
。。。。。。
}
2.新增(参数任意形式都行不限制死对象或数组)
@SimpleLog(remark = "批量新增",operation = OperationEnum.新增)
@ApiOperation(value = "批量新增", notes = "批量新增")
@PostMapping("/addBatch")
public Result addBatch(@RequestBody List<Scan> scanList) {
。。。。。。
}
3.更新(参数任意形式都行不限制死对象或数组)
@SimpleLog(remark = "入库单",id = "productId", operation = OperationEnum.更新)
@ApiOperation(value = "入库单",notes="入库单")
@PostMapping("/entrySaveData")
public ReturnVo entrySaveData(@RequestBody entrySaveDataVo vo){
。。。。。。
}
id的值是你更新对象的主键字段名,如果你的主键刚好就是"id"可以直接写为"@SimpleLog(remark = “入库单”,operation = OperationEnum.更新)"。
4.上传(只能是MultipartFile 形式的文件上传)
@SimpleLog(remark = "上传文件",operation = OperationEnum.上传)
@SneakyThrows
@ApiOperation(value = "上传文件",notes="上传文件")
@PostMapping("/upload")
public ReturnVo upload(@RequestPart("file") MultipartFile file) {
。。。。。。
}