SpringAOP + 注解实现日志管理

SpringAOP + 注解实现日志管理

1. 什么是AOP?

AOP(Aspect Orient Programming),翻译过来就是面向切面编程,面向对象编程是将程序抽象成多个层次的对象,面向切面是将程序抽象成多个切面

2. 为什么要使用AOP(场景说明)

在时间开发中,我们有很多模块中会使用到重复的代码,我们肯定不会通过复制的形式来复用代码.当然解决方式也是多种的,通常我们会将重复的代码抽离出来,提取成一个方法或者是一个抽象的类.然后在需要调用的地方,调用这个方法即可.但是随着我们的业务改变,加入改方法被删除不需要使用,我们需要对所有调用的地方进行单独的删除,这就增加了工作的难度,此时便有了AOP.AOP的原理是代理模式

3. 实际案例

使用AOP的方式,完成日志管理

1. 日志管理数据结构

CREATE TABLE `sys_log` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `operation` varchar(50) DEFAULT NULL COMMENT '操作',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `method_name` varchar(100) DEFAULT NULL COMMENT '方法名',
  `param_name` varchar(500) DEFAULT NULL COMMENT '参数',
  `ip` varchar(100) DEFAULT NULL COMMENT 'ip地址',
  `username` varchar(50) DEFAULT NULL COMMENT '用户名',
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8
复制代码

日志表对应的实体类,mapper,service,controller 可以通过mybatisplus自动生成,这里就省略不写了.

2. 日志管理切入面(代码加强)

/**
 * @ClassName LoginLogAspect
 * @Description  操作日志切入面
 * @Author xiongchao
 * @Date 2020/9/27 10:22
 **/
@Aspect
@Component
public class SysLogAspect {

    @Autowired
    private ISysLogService logService;

    @Autowired
    private ApplicationProperties properties;

    @Autowired
    private JwtTokenUtil util;

    //定义切点 @Pointcut
    //在注解的位置切入代码
    @Pointcut("@annotation( com.adingxiong.cft.aop.Mylog)")
    public void logPoinCut() {

    }

    //切面 配置通知
    @AfterReturning("logPoinCut()")
    public void savaLog(JoinPoint joinpoin){

        SysLog sysLog = new SysLog();

        //从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinpoin.getSignature();
        //获取切入点所在的方法
        Method method = signature.getMethod();
        Mylog myLog = method.getAnnotation(Mylog.class);

        if(myLog != null){
            String value  = myLog.value();
            sysLog.setOperation(value);
        }

        //获取请求的类名
        String className = joinpoin.getTarget().getClass().getName();

        //获取请求的方法名
        String methodName = method.getName();
        sysLog.setMethodName(className + "." + methodName);

        HttpServletRequest request=((ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes()).getRequest();

        String token  = request.getHeader(properties.getTokenHeader());

        String authToken = token.substring(properties.getTokenHead().length());
        String username = util.getUserNameFromToken(authToken);

        sysLog.setUsername(username);

        String ip = IpUtils.getRealIp(request);
        sysLog.setIp(ip);

        //请求参数
        Object args [] = joinpoin.getArgs();
        String param = JSON.toJSONString(args);
        sysLog.setParamName(param);
        sysLog.setCreateTime(new Date());
        logService.save(sysLog);
    }

}

复制代码

3. 获取IP的工具类

/**
 * @ClassName IpUtils
 * @Description  获取用户的真实ip
 * @Author xiongchao
 * @Date 2020/9/27 10:08
 **/
public class IpUtils {

    public static String getRealIp(HttpServletRequest request) {
        String ipAddress = request.getHeader("x-forwarded-for");
        if(ipAddress == null || ipAddress.length() ==0 || "unknown".equals(ipAddress)){
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if (StringUtils.isEmpty(ipAddress) || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("HTTP_CLIENT_IP");
        }
        if (StringUtils.isEmpty(ipAddress) || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
            if(ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")){
                //根据网卡取本机配置的IP
                InetAddress inet=null;
                try {
                    inet = InetAddress.getLocalHost();
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
                ipAddress= inet.getHostAddress();
            }
        }
        //对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
        if(ipAddress!=null && ipAddress.length()>15){ //"***.***.***.***".length() = 15
            if(ipAddress.indexOf(",")>0){
                ipAddress = ipAddress.substring(0,ipAddress.indexOf(","));
            }
        }
        return ipAddress;
    }

}

复制代码

4. 自定义注解(通过注解的方式调用切面方法)

/**
 * @ClassName Mylog
 * @Description TODO
 * @Author xiongchao
 * @Date 2020/9/27 10:29
 **/
@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
@Documented //生成文档
public @interface Mylog {
    String value() default "";
}
复制代码

5. 测试

Service层或者controller层添加@MyLog(value="xxxxx")注解完成调用

    @Mylog(value = "获取当前用户信息")
    @ApiOperation(value = "获取当前登录用户信息")
    @GetMapping("/info")
    public Result<Map<String,Object>> getUserInfo(Principal principal){
        if(principal == null){
            return Result.unauthorized(null);
        }
        String username = principal.getName();
        TUser user = userService.getUserByUsername(username);
        List<Role> list = roleService.getUserRole(user.getId());
        Map<String,Object> res = new HashMap<>();
        res.put("userInfo",user);
        res.put("role",list);
        return Result.success(res);
    }

复制代码

本文使用 mdnice 排版

来源:https://juejin.cn/post/6881812630789423117
posted @ 2022-09-24 10:43  程序员小明1024  阅读(130)  评论(0编辑  收藏  举报