Java利用Aop切面记录操作日志(注解方式)

前提需求


之前收到一个新需求,要求对已有的系统上新增一个记录操作日志的功能,对于这类功能大家应该也看的很多了,必然是AOP进行解决,方便快捷,就是需要一个个方法加注释比较麻烦,说到AOP,就先粗略的介绍下AOP

AOP的概念


1.1 什么是AOP?

AOP(Aspect Oriented Programming):⾯向切⾯编程,它是⼀种思想,它是对某⼀类事情的 集中处理。

1.2 什么是SpringAOP?

⽽ AOP 是⼀种思想,⽽ Spring AOP 是⼀个框架,提供了⼀种对 AOP 思想的实现,它们的关系和 IoC 与 DI 类似。

1.3 为什要⽤ AOP?

在开发中,我们对于公共方法的处理分为三个阶段:

  1. 每个方法都去实现(初级)
  2. 抽取公共方法(中级)
  3. 采用AOP的方式,对代码进行无侵入是实现(高级)

因此,对于这种功能统⼀,且使⽤的地⽅较多的功能,在之前我们会抽取公共方法去实现,但是现在有更好的一个办法来处理这个问题,就是AOP。

也就是使⽤ AOP 可以扩充多个对象的某个能⼒,所以 AOP 可以说是 OOP(Object Oriented Programming,⾯向对象编程)的补充和完善。

1.4 AOP的作用?

提供声明式事务;允许用户自定义切面

开始敲代码利用AOP实现这个需求功能


 1. 添加 Spring AOP 框架⽀持。

首先我们建立一个新的Springboot项目,在配置文件中添加AOP框架。

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
 </dependency>

2.自定义注解

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Mapping
@Documented
public @interface LogRecord {

    /**
     * 操作具体某个功能的描述
     * @return
     */
    String desc() default "";

    /**
     * 操作类型
     * @return
     */
    int type() default 1;
}

3.定义一个切面: 

@Aspect
@Component
@Order(100)
public class LogAop {

    @Value("${customer.name}")
    private String customerName;

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private BuLogMapper buLogMapper;

@Autowired
private BuErrorLogServiceImpl buErrorLogService;

    @Autowired
    private RedisUtils redisUtils;
    @Pointcut("@annotation(com.maizhiyu.yzt.annotation.LogRecord)")
    public void logAop() {
    }

    @Around("logAop()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = null;
        BuLog buLog =new BuLog();
            // 获取request对象
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            String networkIp = getIpAddr(request);
            networkIp = "0:0:0:0:0:0:0:1".equals(networkIp) ? InetAddress.getLocalHost().getHostAddress() : networkIp;
            String ip =  InetAddress.getLocalHost().getHostAddress();
            String path = request.getRequestURL().toString();
            String string1 = request.getRequestURI().toString();
            String mac = NetUtil.getMacAddress(InetAddress.getLocalHost());
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            String interfaceName = method.getName();
            String name = joinPoint.getSignature().getName();
            Object[] args = joinPoint.getArgs();
            String para = new String();
            if (ObjectUtil.isNotEmpty(args)) {
                if (args[0] instanceof MultipartFile) {
                    para = ((MultipartFile) joinPoint.getArgs()[0]).getOriginalFilename();
                } else {
                    if ((args[0].getClass().isArray() && args[0].getClass().getComponentType() == MultipartFile.class)) {
                        StringBuffer asd = new StringBuffer();
                        for (MultipartFile file : (MultipartFile[]) joinPoint.getArgs()[0]) {
                            if (asd == null) asd.append(file.getOriginalFilename());
                            else asd.append("," + file.getOriginalFilename());
                        }
                        para = asd.toString();
                    } else {
                        para = JSONArray.toJSONString(Arrays.stream(args).filter(e->!(e instanceof BindingResult)).toArray());
                    }
                }
                String idcard = "\\d{18}";
                String phone = "\\d{11}";
                String password = "password";
                Pattern phoneC = Pattern.compile(phone);
                Pattern idcardC = Pattern.compile(idcard);
                if (para.contains(password)) {
                    int i = para.indexOf('"', para.indexOf(password) + 11);
                    String substring = para.substring(para.indexOf(password) + 11, i);
                    para = para.replace(substring, "***");
                    System.out.println(i);
                }
                ;
                Matcher idcardM = idcardC.matcher(para);
                if (idcardM.find()) {
                    para = para.replace(idcardM.group(), IdcardUtil.hide(idcardM.group(), 6, 14));
                }
                ;
                Matcher phoneM = phoneC.matcher(para);
                if (phoneM.find()) {
                    para = para.replace(phoneM.group(), PhoneUtil.hideBetween(phoneM.group()));
                };
            }
        buLog.setReqPara(para);
        buLog.setIp(ip);
        buLog.setMac(mac);
        buLog.setReqUrl(path);
        LogRecord anno = signature.getMethod().getAnnotation(LogRecord.class);
        buLog.setType(anno.type());
        buLog.setOperateTime(new Date());
        BuErrorLog log = new BuErrorLog();
        try {
            result = joinPoint.proceed();
            if (!result.toString().contains("请输入正确的")&&!result.toString().contains("您的账户被锁定,请稍后尝试")){
                HsUser currentUser = jwtUtil.getCurrentUser();
                log.setCustomerId(currentUser.getCustomerId());
                buLog.setUserId(jwtUtil.getCurrentUser().getId().toString());
                buLog.setUserName(jwtUtil.getCurrentUser().getRealName());
                buLog.setCustomerId(jwtUtil.getCurrentUser().getCustomerId());
                buLog.setOperateInfor(jwtUtil.getCurrentUser().getRealName()+"进行了"+anno.desc());
            }else buLog.setOperateInfor("登陆失败");
        } catch (Throwable e) {
                log.setCustomerName(customerName);
                log.setClassName(joinPoint.getTarget().getClass().getName());
                log.setMethodName(method.getName());
                log.setErrorName(e.getClass().getName());
                log.setErrorMessage(e.getMessage());
                log.setErrorStack(stackTraceToString(e.getClass().getName(), e.getMessage(), e.getStackTrace()));
                log.setReqUrl(request.getRequestURL().toString());
                log.setReqPara(para);
                log.setIsDel(0);
                log.setCustomerId(jwtUtil.getCurrentUser().getCustomerId());
                log.setCreateTime(new Date());
                log.setUpdateTime(log.getCreateTime());
                buErrorLogService.save(log);
                buLog.setErrInformation(log.getId().toString());
                throw new RuntimeException(e);
        }finally {
            buLogMapper.insert(buLog);
        }
        return result;
    }

    /**
     * 获取请求IP
     * @param request
     * @return
     */
    public static String getIpAddr(HttpServletRequest request) {
        if (request.getHeader("x-forwarded-for") == null) {
            return request.getRemoteAddr();
        }
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    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;
    }

    public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {
        StringBuffer strbuff = new StringBuffer();
        for (StackTraceElement stet : elements) {
            if(stet.getClassName().contains("com.maizhiyu.yzt"))
                strbuff.append(stet + "<br/>");
        }
        String message = exceptionName + ":" + exceptionMessage + "<br/>" + strbuff.toString();
        return message;
    }

4.使用注解

    @ApiOperation(value = "增加用户", notes = "增加用户")
    @PostMapping("/addUser")
    @LogRecord(type = LogTypeConstant.XZ,desc = "增加用户")
    public Result addUser(@RequestBody HsUser user) {
        Integer res = service.addUser(user);
        return Result.success(user);
    }

5. 执行后结果,成功记录

  • 21
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java自定义注解AOP切面是两个不同的概念,但它们可以结合使用来实现一些非常有用的功能。 Java自定义注解Java语言中的一种特殊的语法结构,它允许开发者在代码中添加一些元数据,以便后续处理程序能够基于这些元数据来进行特定的操作Java自定义注解可以在类、方法、属性等各种代码元素上进行声明,并且可以指定注解的属性,以提供更多的元数据信息。 AOP(面向切面编程)是一种编程思想,它允许开发者在不改变原有代码的情况下,通过添加额外的代码来实现某些横切关注点的功能。AOP切面是一个包含一组通知(Advice)和切点(Pointcut)的类,它可以在程序运行时自动拦截指定的方法或类,并执行相应的通知。 在Java中,我们可以通过将自定义注解AOP切面结合使用,来实现一些非常有用的功能。例如,我们可以定义一个名为 @Log 的注解,在程序中使用该注解来标记需要记录日志的方法,然后编写一个AOP切面来拦截这些方法,并在方法执行前后记录日志。这样,我们就可以轻松地实现统一的日志记录功能,而不需要在每个方法中都编写日志记录代码。 下面是一个简单的示例代码,演示了如何使用Java自定义注解AOP切面来实现统一的日志记录功能: ```java // 定义一个名为 @Log 的注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Log { } // 编写一个AOP切面,拦截带有 @Log 注解的方法,并记录日志 @Aspect @Component public class LogAspect { @Around("@annotation(log)") public Object around(ProceedingJoinPoint joinPoint, Log log) throws Throwable { String methodName = joinPoint.getSignature().getName(); System.out.println("方法 " + methodName + " 开始执行..."); Object result = joinPoint.proceed(); System.out.println("方法 " + methodName + " 执行完成,返回值为:" + result); return result; } } // 在程序中使用 @Log 注解标记需要记录日志的方法 @Service public class UserService { @Log public String getUserInfo(String userId) { // ... } } ``` 在上面的代码中,我们首先定义了一个名为 @Log 的注解,并指定了它的作用范围为方法。然后,我们编写了一个AOP切面 LogAspect,使用 @Around 注解来指定切点为所有带有 @Log 注解的方法。在切面的 around 方法中,我们通过 ProceedingJoinPoint 对象获取当前执行的方法名,并在方法执行前后打印日志。最后,我们在 UserService 类的 getUserInfo 方法上使用了 @Log 注解,表示这个方法需要记录日志。 当程序运行时,LogAspect 切面会自动拦截 UserService 类的 getUserInfo 方法,并执行 around 方法中的逻辑,从而实现了统一的日志记录功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值