快速上手:SpingBoot+AOP demo案例

164 阅读3分钟

本文为小白快速上手SpingBoot+AOP日志记录demo,相关理论知识请移步百度。

话不多少,直接开始。

首先,我们创建一个简单的切点。

@Target({ElementType.PARAMETER,ElementType.METHOD}) //切面的切入点(方法)
@Retention(RetentionPolicy.RUNTIME) //切入的时间(运行时)
public @interface SystemLog(){
    //操作类型
    SystemLogEnum type();
    /*
    *要执行的操作,或者描述
    */
    public String description() default "";
}

然后根据切点,来进行不同的处理。

@Component //自动注入
@Aspect
public class SysLogAspect{
    
    @Pointcut("@annotation(com.xxx.xxx.SystemLog)")
    public void logPointcut(){}
    
    /*
    *此处可以实现各种通知,前置通知,后置通知,环绕通知等。
    *本例使用后置通知和异常通知
    */
    
    //后置通知(带有两个参数,将在返回值返回时执行)
    @AfterReturning(pointcut = "logPointcut()", returning = "jsonResult")
    public void afterLog(JoinPoint joinPoint, Object jsonResult){
        SysLog sysLog=warpSysLog(joinPoint);
        //可根据业务需求对返回值进行处理。
        System.out.println(JSON.toJSONString(jsonResult));
        /*
        *这里可以进行后续操作,入库或者传入队列
        */
    }
    
    //异常通知,当发生异常时触发
    @AfterThrowing(value = "logPointcut()", throwing = "e")
    public void throwingLog(JoinPoint joinPoint,Exception e){
        SysLog sysLog=warpSysLog(joinPoint);
        
        /*
        *这里可以进行后续操作,入库或者传入队列
        */
    }
    
    public SysLog warpSysLog(JoinPoint joinPoint){
        //获取请求响应对象
        ServletRequestAttributes attributes=(ServletRequestAttributes)RequestContexHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        SysLog sysLog= new SysLog();
        //获取方法返回请求行中的参数部分(参数名+值)
        //System.out.println(request.getQueryString());
        sysLog.setParams(request.getQueryString());
        //返回发出请求的客户机的完整主机名。
        //System.out.println(request.getRemoteHost());
        //返回发出请求的客户机的IP地址。
        //System.out.println(request.getRemoteAddr());
        //获取方法全路径
        String methodName = signature.getDeclaringTypeName()+"."+signature.getName();
        //获取注解参数值
        SystemLog systemLog = signature.getMethod().getAnnotation(SysLog.class);
        //获取注解的操作描述
        String description=sysLog.description();
        sysLog.setDescription(description);
        //从header取出token(此处是在含有tocken的情况下,无tocken可不写。)
        String token = request.getHeader("Authorization");
        if (!StringUtils.isEmpty(token)) {
            //操作人信息(根据tocken,获取tocken中的信息)
            String username = JwtTokenUtil.getUsername(token);
            String userRole = JwtTokenUtil.getUserRole(token);
            sysLog.setUser_name(username);
            sysLog.setUser_role(userRole);
        }
        if (!StringUtils.isEmpty(systemLog.type())){
            sysLog.setType(systemLog.type().getType());
        }
        sysLog.setMethod(methodName);
        sysLog.setCreate_time(new Date());
        return sysLog;
    }
    
}

因实际开发需要,本篇demo加入了token,无开发需要可忽略。

public class JwtTokenUtil {
        /**
        * 获得token中的信息无需secret解密也能获得
        * @return token中包含的用户名
        */
        public static String getUsername(String token) {
            try {
                DecodedJWT jwt = JWT.decode(token);
                return jwt.getClaim("userName").asString();
            } catch (JWTDecodeException e) {
                return null;
            }
        }

        /**
         * 获取登陆用户角色
         * @param token
         * @return
         * 因业务需求,为一个用户多个角色
         */
        //此处代码无法输入采用图片格式。

下面为日志实体类和枚举类

实体类

@ApiModel("日志实体类")
@Data
public class SysLog {
    @ApiModelProperty("日志编号")
    private String log_id;
    @ApiModelProperty("用户名")
    private String user_name;
    @ApiModelProperty("用户权限")
    private String user_role;
    @ApiModelProperty("请求IP")
    private String ip;
    @ApiModelProperty("操作描述")
    private String description;
    @ApiModelProperty("传入参数")
    private String params;
    @ApiModelProperty("用户浏览器")
    private String browser;
    @ApiModelProperty("执行时间")
    private String time;
    @ApiModelProperty("日志类型")
    private String type;
    @ApiModelProperty("执行方法")
    private String method;
    @ApiModelProperty("创建时间")
    private Date create_time;
    @ApiModelProperty("异常详细信息")
    private String exception_detail;

}

枚举类

public enum SystemLogEnum {
            //可自行添加修改
            SAVE_LOG("添加"),
            UPDATE_LOG("修改"),
            SELECT_LOG("查询"),
            DELETE_LOG("删除"),
            REGISTER_LOG("注册"),
            LOGIN_LOG("登录"),
            OPERATION_LOG("操作"),
            THROW_LOG("异常");
        
            private String type;
        
            SystemLogEnum(String type) {
                this.type = type;
            }
        
            public String getType() {
                return type;
            }
        
            public void setType(String type) {
                this.type = type;
            }
        }

使用方法,可以直接在方法上进行注解。

@SystemLog(description = "测试message",type = SystemLogEnum.OPERATION_LOG)
         public void test(String message)  {
              System.out.println(message);
         }

到此,小伙伴就可以愉快的进行日志记录开发了~~~

初次发布,如有问题,请多多包涵。