• SpringBoot实现注解方式日志log记录


    需求:在项目中需要针对接口去实现定制化日志,有的接口要记录日志,有的不需要,所以要实现一个注解的定制化日志,直接作用到接口上。

    1、定义拦截器

    
    import org.springframework.stereotype.Component;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * BaseInterceptorAdapter.
     *
     * @author cf
     * @version 1.0
     */
    @Component
    public abstract class AbstractHandlerInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
            return preHandles(request, response, handler);
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
            postHandles(request, response, handler, modelAndView);
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
            afterCompletions(request, response, handler, ex);
        }
    
        public abstract boolean preHandles(HttpServletRequest request, HttpServletResponse response, Object handler) ;
    
        protected abstract void postHandles(HttpServletRequest r, HttpServletResponse re, Object ha, ModelAndView mo) ;
    
        protected abstract void afterCompletions(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) ;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    2、定义拦截器配置

    
    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    import java.util.Map;
    
    /**
     * @author cf
     * @date 2021/10/2216:13
     */
    
    @Configuration
    public class InterceptorAdapterConfig implements WebMvcConfigurer, ApplicationContextAware {
    
        private ApplicationContext applicationContext;
    
        @Override
        public void addInterceptors(InterceptorRegistry interceptorRegistry) {
            final Map<String, AbstractHandlerInterceptor> beansOfType = applicationContext.getBeansOfType(AbstractHandlerInterceptor.class);
            if (!beansOfType.isEmpty()) {
                beansOfType.forEach((k,v) -> interceptorRegistry.addInterceptor(v));
            }
        }
    
        @Override
        public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    3、实现注解解析

    注意有些实体和入库操作需要自己实现,直接粘贴会报错。

    
    import cn.hutool.core.util.IdUtil;
    import cn.hutool.core.util.ObjectUtil;
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
     
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.web.method.HandlerMethod;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.util.ContentCachingRequestWrapper;
    import org.springframework.web.util.ContentCachingResponseWrapper;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.UnsupportedEncodingException;
    import java.sql.Timestamp;
    import java.time.Instant;
    import java.util.concurrent.CompletableFuture;
    
    /**
     * 系统中的拦截器配置
     */
    @Component
    @Slf4j
    public class LogInterceptorConfigurer extends AbstractHandlerInterceptor {
        public static final String GET_METHOD = "get";
        public static final String POST_METHOD = "post";
        public static final String TRUE_STR = "true";
        public static final String FALSE_STR = "false";
        @Autowired
        private LogServiceClient logServiceClient;
    
    
        @Override
        public boolean preHandles(HttpServletRequest request, HttpServletResponse response, Object handler) {
            return true;
        }
    
        @Override
        public void postHandles(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o,
                                ModelAndView modelAndView) {
            // Do nothing because of X and Y.
        }
    
        @Override
        public void afterCompletions(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                                     Object handler, Exception e) {
            try {
                if (!(handler instanceof HandlerMethod)) {
                    return;
                }
                HandlerMethod handlerMethod = (HandlerMethod) handler;
                ApiLog logAnnotation = handlerMethod.getMethodAnnotation(ApiLog.class);
                if (logAnnotation == null) {
                    return;
                }
    
                SystemLog systemLog = fillLogEntity(e, handlerMethod, logAnnotation, httpServletResponse);
                //收集方法参数
                fillParam(httpServletRequest, logAnnotation, systemLog);
    
                //参数整合完成,日志落库
                CompletableFuture.runAsync(() -> {
                    logServiceClient.saveLog(systemLog);
                });
            } catch (Exception ex) {
                log.error(ex.getMessage(), ex);
            }
        }
    
        /**
         * ThreadLocalUserConfigurer.getUserId()
         *
         * @param e
         * @param handlerMethod
         * @param logAnnotation
         * @return
         */
        private SystemLog fillLogEntity(Exception e, HandlerMethod handlerMethod, ApiLog logAnnotation, HttpServletResponse httpServletResponse) {
            final String responseBody = getResponseBody(httpServletResponse);
    
            SystemLog systemLog = new SystemLog();
            systemLog.setId(IdUtil.objectId());
            systemLog.setCreateTime(Timestamp.from(Instant.now()));
    
            systemLog.setSystem(logAnnotation.system());
            systemLog.setModule(logAnnotation.module());
            systemLog.setName(logAnnotation.name());
            systemLog.setMethod(handlerMethod.getMethod().getName());
            systemLog.setType(logAnnotation.type().getValue());
            systemLog.setOpera(logAnnotation.opera());
            UserInfo user = UserInfoContext.getUser();
            if (user != null) {
                systemLog.setUserId(user.getId());
                systemLog.setUserName(user.getUserName());
                systemLog.setRoleName(logServiceClient.getUserRole(user.getId()));
                log.info("-----------------fillLogEntity------------------------" + JSON.toJSONString(systemLog));
            } else {
                systemLog.setUserId(" ");
                systemLog.setUserName(" ");
                systemLog.setRoleName(" ");
            }
            //处理接口请求结果
            try {
                //响应结果转json
                JSONObject jsonObject = JSON.parseObject(responseBody);
                if (jsonObject.get("success") == null) {
                    int status = httpServletResponse.getStatus();
                    if (status >= 200 && status < 300) {
                        systemLog.setFlag(TRUE_STR);
                        systemLog.setRemark("成功");
                    } else {
                        systemLog.setFlag(FALSE_STR);
                        systemLog.setRemark("失败");
                    }
                } else {
                    final boolean status = jsonObject.getBoolean("success");
                    if (ObjectUtil.isEmpty(responseBody)) {
                        systemLog.setFlag(TRUE_STR);
                        systemLog.setRemark("成功");
                    } else {
                        systemLog.setFlag(status ? TRUE_STR : FALSE_STR);
                        systemLog.setRemark(status ? "成功" : "失败");
                    }
                }
    
                if (e != null) {
                    systemLog.setFlag(FALSE_STR);
                    systemLog.setRemark(e.getMessage());
                }
            } catch (Exception exception) {
                if (isJSON2(responseBody)) {
                    log.error(exception.getMessage(), exception);
                    systemLog.setFlag(FALSE_STR);
                    systemLog.setRemark("失败");
                }else{
                    int status = httpServletResponse.getStatus();
                    if (status >= 200 && status < 300) {
                        systemLog.setFlag(TRUE_STR);
                        systemLog.setRemark("成功");
                    } else {
                        systemLog.setFlag(FALSE_STR);
                        systemLog.setRemark("失败");
                    }
                }
    
            }
    
            return systemLog;
        }
    
        private void fillParam(HttpServletRequest httpServletRequest, ApiLog logAnnotation, SystemLog systemLog) {
            //是否需要记录参数
            if (logAnnotation.params()) {
                if (httpServletRequest.getMethod().equalsIgnoreCase(GET_METHOD)) {
                    //如果是GET请求,直接取参数map
                    String body = JSON.toJSONString(httpServletRequest.getParameterMap());
                    systemLog.setParams(body);
                    log.info("请求体:{}", body);
                }
                if (httpServletRequest.getMethod().equalsIgnoreCase(POST_METHOD)) {
                    String body = null;
                    try {
                        byte[] bodyBytes = ((ContentCachingRequestWrapper) httpServletRequest).getContentAsByteArray();
                        body = new String(bodyBytes, httpServletRequest.getCharacterEncoding());
                    } catch (UnsupportedEncodingException e) {
                        log.error("com.qax.tsgz.toolbox.system.api.adapter.LogInterceptorConfigurer.fillParam ERROR:{}", e);
                        body = "";
                    }
                    systemLog.setParams(body);
                    log.info("请求体=======================:{}", body);
                }
            }
        }
    
        private String getResponseBody(HttpServletResponse servletResponseWrapper) {
            if (servletResponseWrapper instanceof ContentCachingResponseWrapper) {
                ContentCachingResponseWrapper responseWrapper = (ContentCachingResponseWrapper) servletResponseWrapper;
                String responseBody = "";
                responseBody = new String(responseWrapper.getContentAsByteArray());
                return responseBody;
            } else {
                return "";
            }
        }
    
    
        private String getRequest(HttpServletRequest httpServletRequest) throws UnsupportedEncodingException {
            if (httpServletRequest instanceof ContentCachingRequestWrapper) {
                ContentCachingRequestWrapper requestWrapper = (ContentCachingRequestWrapper) httpServletRequest;
                return "new String(requestWrapper.getBody(), httpServletRequest.getCharacterEncoding())";
            } else {
                return "";
            }
        }
    
        public static boolean isJSON2(String str) {
            boolean result = false;
            try {
                JSON.parse(str);
                result = true;
            } catch (Exception e) {
                result = false;
            }
            return result;
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209

    4、注解

    import  
    
    import java.lang.annotation.*;
    
    /**
     * ApiLog.
     *
     * @author cf
     * @version 1.0
     */
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface ApiLog {
        //项目名字
        String system() default "";
    	//模块名字
        String module() default "";
    	//接口名字
        String name() default "";
        //接口动作
        String opera() default "";
        //操作日志类型
        SysLogType type() default SysLogType.OPER;
        //请求参数
        boolean params() default false;
    }
    
    
    /**
     * 基础常量接口操作标识 
     */
    public class OperaConstant {
        private OperaConstant(){}
    
        public static final String ADD = "新增";
        public static final String DELETE = "删除";
        public static final String UPDATE = "修改";
        public static final String QUERY = "查询";
        public static final String LOGIN = "登录";
        public static final String IMPORT = "导入";
        public static final String EXPORT = "导出";
        public static final String OTHER = "其他";
        public static final String UPLOAD = "上传文件";
        public static final String DOWNLOAD = "下载文件";
    }
    
    /**
     * 操作日志类型
     */
    public enum SysLogType {
        LOGIN("1"),
        AECCESS("2"),
        OPER("3"),
        EXCEPTION("4");
    
        public String value;
    
        private SysLogType(String value) {
            this.value = value;
        }
    
        public String getValue() {
            return this.value;
        }
    
        public void setValue(String value) {
            this.value = value;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    5、应用

        /**
         * 根据字典类型查询字典
         *
         * @param dictType
         * @return
         */
        @ResponseBody
        @ResponseResult(exclude = {"children","isDefault"})
        @GetMapping(value = "/*****")
        @ApiLog(system = "*****", userId = "",module = "系统管理", name = "根据字典类型查询字典", opera = OperaConstant.QUERY, type = SysLogType.OPER, params = true)
        public ApiResult getDictByType(@RequestParam String dictType) {
            return ApiResult.success(dictDataService.getDictByType(dictType));
        }
    
       /**
         * 保存配置
         */
        @PostMapping(value = "/*****")
        @ApiLog(system = "*****", module = "通用配置", name = "保存配置", opera = OperaConstant.UPDATE, type = SysLogType.OPER, params = true)
        public ApiResult saveConfig(@Validated @RequestBody SystemConfigReq systemConfigReq) {
            systemConfigService.saveConfig(systemConfigReq);
            return ApiResult.success(new Object());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
  • 相关阅读:
    Kubernetes(k8s第二部分)
    SpringBoot集成腾讯云云点播服务/视频上传
    Linux友人帐之系统管理与虚拟机相关
    【分割链表】
    2022系统分析师下午卷(案例分析)
    【图像修复】基于改进的Criminisi算法实现图像修复附matlab代码
    美国访问学者签证有哪些要求?
    【SpringCloud】认识微服务
    设计模式——装饰器模式
    详解为什么v-if和v-for不能同时使用
  • 原文地址:https://blog.csdn.net/daohangtaiqian/article/details/127771439