zoukankan      html  css  js  c++  java
  • Spring_AOP 记录系统关键操作日志用法

    问题:

      系统需要记录用户的关键操作日志,以便后期的系统维护,方便的查看问题,及时排除

    分析:

      (1)保存字段:作为一个日志记录功能,首先数据库新建一张表保存用户的操作关键字段,

              用户名,ip,操作描述,时间,日志id

      (2)采用技术:

          第一种:新建一个日志业务实现,在操作发生时进行联动

              缺点是耦合太紧密,无用代码增多,后期代码臃肿,改动时地方分散,不利于维护

          第二种:使用spring 的 aop 技术进行切面切入

              由于本身系统结构不规范,参数,方法名没有一致的样式,使用正则匹配方法名不是很方便

              本身日志记录也只是记录关键操作,api全部切入的话,就不需要这个功能了

              必须有针对性的记录关键操作日志

          第三种:使用spring 的 aop 技术切到自定义注解上,针对不同注解标志进行参数解析,记录日志

              缺点是要针对每个不同的注解标志进行分别取注解标志,获取参数进行日志记录输出

             

    解决:

      由于本身系统的不规范,个人技术能力的欠缺,目前采用第三种办法进行关键日志的记录

      (1)首先新建 注解类【MethodLog】

    package org.triber.portal.service.logAop;
    
    import java.lang.annotation.*;
    
    /**
     * 日志切面注解
     */
    
    @Target({ ElementType.METHOD, ElementType.TYPE })
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface MethodLog {
    
        String remark() default "";
        String operType() default "0";
        // String desc() default "";
    }

      (2)新建切面实现类【LogService】

    package org.triber.portal.service.logAop;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    import org.triber.common.helper.StringUtil;
    import org.triber.common.helper.UserUtil;
    import org.triber.common.model.menu.MenuModel;
    import org.triber.common.model.user.User;
    import org.triber.portal.dao.mapper.operateLog.OperateLogMapper;
    import org.triber.portal.model.area.Area;
    
    import javax.servlet.http.HttpServletRequest;
    import java.lang.reflect.Method;
    import java.text.SimpleDateFormat;
    import java.util.Calendar;
    
    /**
     * 日志切面实现
     */
    
    @Component
    @Aspect
    public class LogService {
    
        @Autowired
        private OperateLogMapper dao;
    
        public LogService() {
            System.out.println("Aop");
        }
    
        /**
         * 切点
         */
        @Pointcut("@annotation(org.triber.portal.service.logAop.MethodLog)")
        public void methodCachePointcut() { }
    
    
        /**
         * 切面
         *
         * @param point
         * @return
         * @throws Throwable
         */
        @Around("methodCachePointcut()")
        public Object around(ProceedingJoinPoint point) throws Throwable {
    
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
                    .getRequestAttributes()).getRequest();
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E");
            Calendar ca = Calendar.getInstance();
            String operDate = df.format(ca.getTime());
            String ip = getIp(request);
            User user = UserUtil.getCurrentUser(request);
            String loginName;
            String name;
            if (user != null) {
                loginName = user.getLoginName();
            } else {
                loginName = "匿名用户";
            }
            String methodRemark = getMthodRemark(point);
            String methodName = point.getSignature().getName();
            String packages = point.getThis().getClass().getName();
            if (packages.indexOf("$$EnhancerByCGLIB$$") > -1) { // 如果是CGLIB动态生成的类
                try {
                    packages = packages.substring(0, packages.indexOf("$$"));
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
            String operatingcontent = "";
            Object[] method_param = null;
    
            Object object;
            try {
                method_param = point.getArgs(); //获取方法参数
                // String param=(String) point.proceed(point.getArgs());
                object = point.proceed();
            } catch (Exception e) {
                // 异常处理记录日志..log.error(e);
                throw e;
            }
            Syslog sysLog = new Syslog();
            sysLog.setOptId(org.triber.common.util.StringUtil.getRandNum(11));
            sysLog.setLoginId(user.getLoginId());
            sysLog.setLoginName(loginName);
            sysLog.setIpAddress(ip);
            sysLog.setMethodName(packages + "." + methodName);
            sysLog.setMethodRemark(methodRemark);
            sysLog.setOptDate(operDate);
    
            /**
             * 用户操作
             */
            if("新增用户".equals(methodRemark)){
                HttpServletRequest req = (HttpServletRequest) method_param[0];
                sysLog.setOperatingcontent("新增用户: 用户名为 " + req.getParameter("userName"));
    
            }
            if("删除用户".equals(methodRemark)){
                String loginId = (String) method_param[1];
                sysLog.setOperatingcontent("删除用户: 用户id为 " + loginId);
            }
            if("修改用户".equals(methodRemark)){
                HttpServletRequest req = (HttpServletRequest) method_param[0];
                sysLog.setOperatingcontent("修改用户: 用户名为 " + req.getParameter("loginName"));
            }
    
            /**
             * 角色操作
             */
            if("新增角色".equals(methodRemark)){
                HttpServletRequest req = (HttpServletRequest) method_param[0];
                sysLog.setOperatingcontent("新增角色: 角色名为 " + req.getParameter("roleDesc"));
            }
            if("删除角色".equals(methodRemark)){
                String roleId = (String) method_param[1];
                sysLog.setOperatingcontent("新增角色: 角色id为 " + roleId);
            }
            if("修改角色".equals(methodRemark)){
                HttpServletRequest req = (HttpServletRequest) method_param[0];
                sysLog.setOperatingcontent("修改角色: 角色名为 " + req.getParameter("roleDesc"));
            }
    
            /**
             * 菜单操作
             */
            if("新增菜单".equals(methodRemark)){
                MenuModel menuModel = (MenuModel) method_param[0];
                sysLog.setOperatingcontent("新增菜单: 菜单名为 " + menuModel.getMenuName());
            }
            if("删除菜单".equals(methodRemark)){
                String menuId = (String) method_param[0];
                sysLog.setOperatingcontent("删除菜单: 菜单id为 " + menuId);
            }
            if("修改菜单".equals(methodRemark)){
                MenuModel menuModel = (MenuModel) method_param[0];
                sysLog.setOperatingcontent("修改菜单: 菜单名为 " + menuModel.getMenuName());
            }
    
            /**
             * 部门操作
             */
            if("新增部门".equals(methodRemark)){
                String deptDesc = (String) method_param[1];
                sysLog.setOperatingcontent("新增部门: 部门名为 " + deptDesc);
    
            }
            if("修改部门".equals(methodRemark)){
                String deptDesc = (String) method_param[2];
                sysLog.setOperatingcontent("修改部门: 部门名为 " + deptDesc);
            }
    
            /**
             * 地区操作
             */
            if("新增地区".equals(methodRemark)){
                Area area = (Area) method_param[0];
                sysLog.setOperatingcontent("新增地区: 地区名为 " + area.getAreaDscr().trim());
            }
            if("删除地区".equals(methodRemark)){
                String areaId = (String) method_param[0];
                sysLog.setOperatingcontent("删除地区: 地区id为 " + areaId);
            }
            if("修改地区".equals(methodRemark)){
                Area area = (Area) method_param[0];
                sysLog.setOperatingcontent("修改地区: 地区名为 " + area.getAreaDscr().trim());
            }
    
            /**
             * 机构操作
             */
            if("新增机构".equals(methodRemark)){
                String isAdd = (String) method_param[1];
                if(isAdd.equals("1")){
                    String addOrgDscrPancy = (String) method_param[5];
                    sysLog.setOperatingcontent("新增机构: 机构名为 " + addOrgDscrPancy);
                }else{
                    String addOrgDscrPancy = (String) method_param[5];
                    sysLog.setOperatingcontent("修改机构: 机构名为 " + addOrgDscrPancy);
                }
    
            }
            if("删除机构".equals(methodRemark)){
                String orgId = (String) method_param[3];
                sysLog.setOperatingcontent("删除机构: 机构id为 " + orgId);
            }
    
            /**
             * 空参数
             */
            if("".equals(methodRemark) || null == methodRemark){
                sysLog.setOperatingcontent("操作参数: " + method_param[0]);
            }
    
            dao.saveSysLog(sysLog);
    //        System.out.println("日志实体:"+sysLog.getLoginName()+sysLog.getMethodRemark()+sysLog.getOperatingcontent());
            return object;
    
        }
    
        /**
         * 方法异常时调用
         *
         * @param ex
         */
        public void afterThrowing(Exception ex) {
            System.out.println("afterThrowing");
            System.out.println(ex);
        }
    
        /**
         * 获取方法中的中文备注
         *
         * @param joinPoint
         * @return
         * @throws Exception
         */
        public static String getMthodRemark(ProceedingJoinPoint joinPoint) throws Exception {
    
            String targetName = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();
            Object[] arguments = joinPoint.getArgs();
    
            Class targetClass = Class.forName(targetName);
            Method[] method = targetClass.getMethods();
            String methode = "";
            for (Method m : method) {
                if (m.getName().equals(methodName)) {
                    Class[] tmpCs = m.getParameterTypes();
                    if (tmpCs.length == arguments.length) {
                        MethodLog methodCache = m.getAnnotation(MethodLog.class);
                        if (methodCache != null) {
                            methode = methodCache.remark();
                        }
                        break;
                    }
                }
            }
            return methode;
        }
    
        /**
         * 获取请求ip
         *
         * @param request
         * @return
         */
        public static String getIp(HttpServletRequest request) {
            String ip = request.getHeader("X-Forwarded-For");
            if (StringUtil.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
                int index = ip.indexOf(",");
                if (index != -1) {
                    return ip.equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip.substring(0, index);
                } else {
                    return ip.equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip;
                }
            }
            ip = request.getHeader("X-Real-IP");
            if (StringUtil.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
                return ip;
            }
            return request.getRemoteAddr().equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip;
        }
    
    
    }

      (3)新建日志实体【Syslog】

    package org.triber.portal.service.logAop;
    
    import lombok.Getter;
    import lombok.Setter;
    
    import java.io.Serializable;
    
    /**
     * 操作日志实体类
     */
    public class Syslog implements Serializable{
    
        @Setter@Getter private String optId;
        @Setter@Getter private String loginId;
        @Setter@Getter private String loginName;
        @Setter@Getter private String ipAddress;
        @Setter@Getter private String methodName;
        @Setter@Getter private String methodRemark;
        @Setter@Getter private String operatingcontent;
        @Setter@Getter private String optDate;
        //模糊条件
        @Setter@Getter private String serchCondition;
    }

      (4)日志切入【添加注解标志即可】

     /**
         * 删除金融机构
         * @param request
         * @param response
         * @param operateVersionId 机构版本
         * @param orgId 机构iD
         * @param orgLvl 机构层级
         * @return
         * @throws Exception
         */
        @RequestMapping(value = "delOrgByFlagAndOrgId", method = RequestMethod.POST, produces = {"application/json"})
        @MethodLog(remark = "删除机构")
        public String delOrgByFlagAndOrgId(HttpServletRequest request,
                                         HttpServletResponse response,
                                         @RequestParam(value = "operateVersionId", required = false) String operateVersionId,
                                         @RequestParam(value = "orgId", required = false) String orgId,
                                         @RequestParam(value = "orgLvl", required = false) String orgLvl) throws Exception{
            orgService.delOrgByFlagAndOrgId(areaIdPrefix,orgId, orgLvl, operateVersionId);
            return "0";
        }

      (5)maven注入aop依赖

    <!--spring切面aop依赖-->
    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    
    在application.properties文件里加这样一条配置
    spring.aop.auto=true
    
    在springboot项目里加这两条配置即可,就可以开启aop功能

    总结:

      至此,大功告成,可以开始加注解标志,获取参数,记录关键信息,输出日志了。。。

      

  • 相关阅读:
    Apache mod_rewrite
    vim 常用设置
    ssh 和 scp 命令访问非默认22端口。
    gulp常用插件
    gulp+Babel 搭建ES6环境
    ES6类与模块
    Autoprefixer处理CSS3属性前缀
    js模块方案
    ES6转码器babel的使用
    window.history.pushState与ajax实现无刷新更新页面url
  • 原文地址:https://www.cnblogs.com/hackxiyu/p/8072314.html
Copyright © 2011-2022 走看看