使用aop实现注解接口日志

该文介绍了如何使用SpringAOP和自定义注解来记录操作日志,包括创建枚举定义操作类型,创建日志注解,日志实体类,Mapper接口以及切面逻辑,用于捕获接口请求信息并保存到数据库中。
摘要由CSDN通过智能技术生成

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) {
     。。。。。。
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值