• JAVA实现通用日志记录


    原文:http://blog.csdn.net/jinzhencs/article/details/51882751

    前言: 
    之前想在filter层直接过滤httpServerletRequest请求进行日志处理,但是之后再getWriter()的 时候报 
    already been call异常。查了下,才发现原来流形式的只能读取一次。。就好像食物,吃了就没了。。 
    所以在filter和inteceptor里面是没法通过获取request的流来进行日志记录的。

    于是还是准备用通用的方法:controller层aop进行切面记录日志。

    使用Aop记录操作日志

    第一步:添加Aop

    /**
     * 统一日志处理Handler
     * @author Mingchenchen
     *
     */
    public class LogAopHandler {
        @Autowired
        private AuditLogDao auditLogDao;
    
        /**
         * controller层面记录操作日志
         * 注意此处是aop:around的 因为需要得到请求前的参数以及请求后接口返回的结果
         * @throws Throwable 
         */
        public Object doSaveLog(ProceedingJoinPoint joinPoint) throws Throwable { 
            MethodSignature method = (MethodSignature) joinPoint.getSignature();
            String methodName = method.getName();
            Object[] objects = joinPoint.getArgs();
            String requestBody = null;
            if (objects!=null && objects.length>0) {
                for (Object object : objects) {
                    if (object == null) {
                        requestBody = null;//POST接口参数为空 比如删除XXX
                    }else if (object instanceof String) {
                        requestBody = (String) object;//有些接口直接把参数转换成对象了
                    }else {
                        requestBody = JSONObject.toJSONString(object);
                    }
                }
            }
    
            //只记录POST方法的日志
            boolean isNeedSaveLog = false;
            //此处不能用getAnnotationByType 是JAVA8的特性,因为注解能够重名,所以得到的是数组
            RequestMapping annotation = method.getMethod().getAnnotation(RequestMapping.class);
            for (RequestMethod requestMethod : annotation.method()) {
                if (requestMethod==RequestMethod.POST) {
                    isNeedSaveLog = true;
                }
            }
    
            JSONObject requestBodyJson = null;
            try {
                requestBodyJson = JSONObject.parseObject(requestBody);
            } catch (Exception e) {
                //do nothing 即POST请求没传body
            }
            HttpServletRequest request = RequestContextUtil.getRequestByCurrentContext();
            String userName = RequestContextUtil.getUserNameByCurrentContext();
            if (StringUtil.isEmpty(userName)) {
                try {
                    userName = DmsCache.get(requestBodyJson.getString("userName")).getName();
                } catch (Exception e) {
                    userName = RequestContextUtil.getAsynUserInfoByAutoDeploy().getName();
                }
            }
    
            //得到request的参数后让方法执行它 
            //注意around的情况下需要返回result 否则将不会返回值给请求者
            Object result = joinPoint.proceed(objects);
            try {
                JSONObject resultJson = JSONObject.parseObject(result.toString());
                if (isNeedSaveLog) {//如果是POST请求 则记录日志
                    LogTypeEnum logTypeEnum = LogTypeEnum.getDesByMethodName(methodName);
                    if (logTypeEnum != null) {
                        AuditLogEntity auditLogEntity = new AuditLogEntity();
                        auditLogEntity.setUuid(StringUtil.createRandomUuid());
                        auditLogEntity.setOperator(userName);
                        auditLogEntity.setRequestIp(request.getRemoteAddr());
                        auditLogEntity.setRequestUrl(request.getRequestURI().replace("/cloud-master", ""));
                        auditLogEntity.setEventType(logTypeEnum.getKey());
                        auditLogEntity.setEventDesc(logTypeEnum.getDescription());
                        auditLogEntity.setRequest(requestBody);
                        int isSuccess = "200".equals(resultJson.getString("code")) ? 1 : 0;
                        auditLogEntity.setSuccessFlag(isSuccess);
                        auditLogEntity.setResponse(result.toString());
                        auditLogEntity.setCreateTime(new Date());
                        auditLogDao.insert(auditLogEntity);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        }  
    }

    第二步:在spring的xml中声明

    <!-- 记录操作日志 -->
        <bean id="operationLogAop" class="com.ming.learn.core.aop.LogAopHandler"/>
         <aop:config>
           <aop:aspect id="logAOP" ref="operationLogAop">
             <aop:pointcut id="target" expression="execution(* com.ming.learn..*Controller.*(..))"/>
             <aop:around method="doSaveLog" pointcut-ref="target"/>
           </aop:aspect>
         </aop:config>

    如此一来,核心步骤就完成了,剩下的就是自己组装需要记录的东西了。

    第三步:写Dao、Entity、Mapper

    import java.util.Date;
    
    import javax.persistence.Column;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    /**
     * 日志审计
     * @author Mingchenchen
     *
     */
    @Table(name="audit_log")
    public class AuditLogEntity {
        @Id
        private String uuid;
    
        @Column(name="event_type")
        private String eventType;//事件类型
    
        @Column(name="event_desc")
        private String eventDesc;//事件中文描述
    
        @Column(name="operator")
        private String operator;//操作者
    
        @Column(name="request_ip")
        private String requestIp;//客户端地址
    
        @Column(name="request_url")
        private String requestUrl;//请求地址
    
        @Column(name="request")
        private String request;//请求body
    
        @Column(name="response")
        private String response;//请求返回值
    
        @Column(name="create_time")
        private Date createTime;
    
        public String getUuid() {
            return uuid;
        }
    
        public void setUuid(String uuid) {
            this.uuid = uuid;
        }
    
        public String getEventType() {
            return eventType;
        }
    
        public void setEventType(String eventType) {
            this.eventType = eventType;
        }
    
        public String getEventDesc() {
            return eventDesc;
        }
    
        public void setEventDesc(String eventDesc) {
            this.eventDesc = eventDesc;
        }
    
        public String getOperator() {
            return operator;
        }
    
        public void setOperator(String operator) {
            this.operator = operator;
        }
    
        public String getRequestIp() {
            return requestIp;
        }
    
        public void setRequestIp(String requestIp) {
            this.requestIp = requestIp;
        }
    
        public String getRequestUrl() {
            return requestUrl;
        }
    
        public void setRequestUrl(String requestUrl) {
            this.requestUrl = requestUrl;
        }
    
        public String getRequest() {
            return request;
        }
    
        public void setRequest(String request) {
            this.request = request;
        }
    
        public String getResponse() {
            return response;
        }
    
        public void setResponse(String response) {
            this.response = response;
        }
    
        public Date getCreateTime() {
            return createTime;
        }
    
        public void setCreateTime(Date createTime) {
            this.createTime = createTime;
        }
    }

    第四步:根据Controller的方法名称定制响应的事件类型

    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    
    /**
     * 操作日志类型
     * @author Mingchenchen
     *
     */
    public enum LogTypeEnum {
        //用户
        COMMON_LOGIN("login","login","登录");
        //其他
    
        private String methodName;//方法名称与controller一致
        private String key;//保存到数据库的事件类型
        private String description;//保存到数据库的描述
        private LogTypeEnum(String methodName,String key,String description){
            this.methodName = methodName;
            this.key = key;
            this.description = description;
        }
        public String getMethodName() {
            return methodName;
        }
        public void setMethodName(String methodName) {
            this.methodName = methodName;
        }
        public String getKey() {
            return key;
        }
        public void setKey(String key) {
            this.key = key;
        }
        public String getDescription() {
            return description;
        }
        public void setDescription(String description) {
            this.description = description;
        }
    
        /**
         * 根据方法名返回
         * @param methodName
         * @return
         */
        public static LogTypeEnum getDesByMethodName(String methodName){
            return innerMap.map.get(methodName);
        }
    
        /**
         * 内部类 用户保存所有的enum 无须通过Enum.values()每次遍历
         * @author Mingchenchen
         *
         */
        private static class innerMap{
            private static Map<String, LogTypeEnum> map = new ConcurrentHashMap<>(128);
    
            static{
                //初始化整个枚举类到Map
                for (LogTypeEnum logTypeEnum : LogTypeEnum.values()) {
                    map.put(logTypeEnum.getMethodName(), logTypeEnum);
                }
            }
        }
    }
  • 相关阅读:
    bat脚本%cd%和%~dp0的区别
    java测试程序运行时间
    != 的注意事项
    [转载] iptables 防火墙设置
    .NET 创建 WebService
    [转载] 学会使用Web Service上(服务器端访问)~~~
    cygwin 安装 apt-cyg
    在Element节点上进行Xpath
    Element节点输出到System.out
    [转载] 使用StAX解析xml
  • 原文地址:https://www.cnblogs.com/shihaiming/p/6101367.html
Copyright © 2020-2023  润新知