美文网首页java学习
Spring Boot利用AOP获取用户操作实现日志记录

Spring Boot利用AOP获取用户操作实现日志记录

作者: MaLizhi | 来源:发表于2018-12-19 19:31 被阅读129次

    环境:IDEA版本2017.3.1 x64, JDK1.8, SpringBoot2.1.1, Druid1.1.8, mybatis1.3.2,Security5.1.2,thymeleaf3.0.11

    思路总结:首先在需要做日志记录的方法中添加一个自定义注解,再去实现一个日志AOP类,AOP类把自定义注解设置为切点,所以当系统执行某一个添加了自定义注解的方法时,AOP会自动获取该方法名称以及用户信息实现日志记录。

    编写自定义注解

    /**
     * 自定义注解类  定义controller方法的中文含义
     * @Target({METHOD,TYPE}) 表示这个注解可以用用在类/接口上,还可以用在方法上
     * @Retention(RetentionPolicy.RUNTIME) 表示这是一个运行时注解,即运行起来之后,才获取注解中的相关信息,而不像基本注解如@Override 那种不用运行,在编译时eclipse就可以进行相关工作的编译时注解。
     * @Inherited 表示这个注解可以被子类继承
     * @Documented 表示当执行javadoc的时候,本注解会生成相关文档
     */
    
    @Target({METHOD, TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    public @interface Operation {
        String value() default "";
    }
    

    日志AOP类会用到获取IP地址的工具类,也用到json工具类,实现工具类如下

    实现必要工具类

    获取ip地址工具类
            /**
         * 获取用户真实的ip地址
         * @param request
         * @return
         */
    public class IpAdrressUtil {
        
        public static String getIpAdrress(HttpServletRequest request) {
                String ip = null;
    
                //X-Forwarded-For:Squid 服务代理
                String ipAddresses = request.getHeader("X-Forwarded-For");
                String unknown = "unknown";
                if (ipAddresses == null || ipAddresses.length() == 0 || unknown.equalsIgnoreCase(ipAddresses)) {
                    //Proxy-Client-IP:apache 服务代理
                    ipAddresses = request.getHeader("Proxy-Client-IP");
                }
    
                if (ipAddresses == null || ipAddresses.length() == 0 || unknown.equalsIgnoreCase(ipAddresses)) {
                    //WL-Proxy-Client-IP:weblogic 服务代理
                    ipAddresses = request.getHeader("WL-Proxy-Client-IP");
                }
    
                if (ipAddresses == null || ipAddresses.length() == 0 || unknown.equalsIgnoreCase(ipAddresses)) {
                    //HTTP_CLIENT_IP:有些代理服务器
                    ipAddresses = request.getHeader("HTTP_CLIENT_IP");
                }
    
                if (ipAddresses == null || ipAddresses.length() == 0 || unknown.equalsIgnoreCase(ipAddresses)) {
                    //X-Real-IP:nginx服务代理
                    ipAddresses = request.getHeader("X-Real-IP");
                }
    
                //有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP
                if (ipAddresses != null && ipAddresses.length() != 0) {
                    ip = ipAddresses.split(",")[0];
                }
    
                //还是不能获取到,最后再通过request.getRemoteAddr();获取
                if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ipAddresses)) {
                    ip = request.getRemoteAddr();
                }
                return ip;
          }
        
        
    }
    
    
    实现json工具类
    public class JacksonUtil {
    
        private final static ObjectMapper objectMapper = new ObjectMapper();
    
        private JacksonUtil() {
    
        }
    
        public static ObjectMapper getInstance() {
            return objectMapper;
        }
    
        /**
         * javaBean、列表数组转换为json字符串
         */
        public static String obj2json(Object obj) throws Exception {
            return objectMapper.writeValueAsString(obj);
        }
    
        /**
         * json 转JavaBean
         */
    
        public static <T> T json2pojo(String jsonString, Class<T> clazz) throws Exception {
            objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
            return objectMapper.readValue(jsonString, clazz);
        }
    
        /**
         * json字符串转换为map
         */
        public static <T> Map<String, Object> json2map(String jsonString) throws Exception {
            ObjectMapper mapper = new ObjectMapper();
            mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            return mapper.readValue(jsonString, Map.class);
        }
    }
    

    实现日志AOP类

    /**
     * 系统日志:切面处理类
     */
    @Aspect
    @Component
    public class SysLogAspect {
    
        @Autowired
        private SysLogService sysLogService;
    
        //定义切点 @Pointcut
        //在注解的位置切入代码
        @Pointcut("@annotation(cn.springboot.util.Operation)")
        public void logPoinCut() {
        }
    
        //切面 配置通知
        @AfterReturning("logPoinCut()")
        public void saveSysLog(JoinPoint joinPoint) {
            //保存日志
            SysLog sysLog = new SysLog();
    
            //从切面织入点处通过反射机制获取织入点处的方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            //获取切入点所在的方法
            Method method = signature.getMethod();
    
    
            //获取操作
            Operation operation = method.getAnnotation(Operation.class);
            if (operation != null) {
                String value = operation.value();
                sysLog.setOperation(value);//保存获取的操作
            }
    
            //获取请求的类名
            String className = joinPoint.getTarget().getClass().getName();
    
            //获取请求的方法名
            String methodName = method.getName();
            sysLog.setMethod(className + "." + methodName);
    
            //请求的参数
            Object[] args = joinPoint.getArgs();
            //将参数所在的数组转换成json
            String params = null;
            try {
                params = JacksonUtil.obj2json(args);
            } catch (Exception e) {
                e.printStackTrace();
            }
            sysLog.setParams(params);
    
            //请求的时间
            sysLog.setCreateDate(new Date());
    
            //获取用户名
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (!(authentication instanceof AnonymousAuthenticationToken)) {
                sysLog.setUsername(authentication.getName());
            }
    
            //获取用户ip地址
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                    .getRequest();
            sysLog.setIp(IpAdrressUtil.getIpAdrress(request));
    
            //调用service保存SysLog实体类到数据库
            sysLogService.saveLog(sysLog);
        }
    
    }
    

    最后,我是调用service保存SysLog实体类到数据库,你也可以直接输出到控制台,要保存到数据库,还要实现service类,mapper类和javeBean。
    我就简单贴个javaBean,其他类就不具体贴出了。

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class SysLog implements Serializable {
        private Long id;
    
        private String username; //用户名
    
        private String operation; //操作
    
        private String method; //方法名
    
        private String params; //参数
    
        private String ip; //ip地址
    
        private Date createDate; //操作时间
        //创建getter和setter方法
    }
    

    javaBean中使用lombok的注解实现了get、set等方法。

    以下是存进数据库的数据,关于IP的问题是因为本地测试,部署在服务器上就会有正常的IP地址了。

    image

    更多Spring Boot整合可浏览此博客:malizhi.cn

    相关文章

      网友评论

        本文标题:Spring Boot利用AOP获取用户操作实现日志记录

        本文链接:https://www.haomeiwen.com/subject/hskskqtx.html