• Springboot通过Filter过滤HttpServletRequest和HttpServletResponse的数据作为日志并通过@Async异步入库


    R是统一泛型返回对象,Log是日志对象,LogHttpServletResponseWrapper是防止请求数据获取后丢失

    建好数据库即可,表不存在会自动创建,别说什么高并发会怎么怎么样了,高并发不用搜索引擎,还想用数据库记录日志就是疯了

    异步入库结果图

    在这里插入图片描述
    A线程获取完数据,以后入库由B线程去执行,不影响主线程,即是入库失败也不会影响主线程的功能

    LogFilter.java

    过滤请求头和返回内容

    import com.fasterxml.jackson.databind.ObjectMapper;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.Resource;
    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.nio.charset.StandardCharsets;
    import java.util.*;
    
    /**
     * 过滤器
     */
    @Slf4j
    @Component
    @WebFilter(urlPatterns = "/*", filterName = "logFilter")
    public class LogFilter implements Filter {
        @Value("${spring.application.name}")
        private String applicationName;
        @Value("${log-application.ignore-uri}")
        private String ignoreURIs;
        @Resource
        private LogService logService;
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            HttpServletResponse response = (HttpServletResponse) servletResponse;
    
            Map<String, String[]> parameterMap = request.getParameterMap();
            Map<String, Object> map = new HashMap<>();
            if (parameterMap != null) {
                parameterMap.forEach((key, value) -> {
                    map.put(key, value[0]);
                });
            }
    
            LogHttpServletResponseWrapper logHttpServletResponseWrapper = new LogHttpServletResponseWrapper(response);//获取返回内容
            filterChain.doFilter(request, logHttpServletResponseWrapper);//必须放到logHttpServletResponseWrapper.getContent()前面,否则拿不到数据
    
            //异步写入日志入库,用try catch报错就报错,不用管,不影响正常业务逻辑即可,日志并不是特别的重要
            try {
                String content = new String(logHttpServletResponseWrapper.getContent(), StandardCharsets.UTF_8);
    //            log.info("原返回值:{}",content);
                ObjectMapper om = new ObjectMapper();
                R r = om.readValue(content, R.class);
    
    //            log.info(ignoreURI);
                //URI白名单
                boolean haveIgnoreURI = Arrays.stream(ignoreURIs.split(",")).anyMatch(ignoreURI -> request.getRequestURI().contains(ignoreURI));
                if (!haveIgnoreURI) {
                    Log logObj = new Log();
    //            logObj.setId(UUID.randomUUID().toString());
                    logObj.setUserId("1");
                    logObj.setUsername("Meta");
                    logObj.setApplicationName(applicationName);
                    logObj.setMethod(request.getMethod());
                    logObj.setRequestURI(request.getRequestURI());
                    logObj.setRequestData(String.valueOf(map));
                    logObj.setCode(r.getCode());
                    logObj.setRespondData(om.writeValueAsString(r.getData()));
                    logObj.setMsg(r.getMsg());
                    logObj.setErrorMsg(om.writeValueAsString(r.getDetailErrorMsg()));
                    logObj.setCreateTime(new Date());
                    log.info("打印当前A线程名称:{}",Thread.currentThread().getName());
                    logService.insert(logObj);
                    r.setDetailErrorMsg(null);//获取完以后,设置详细异常为null
                }
                String newContent = om.writeValueAsString(r);
    
                //修改返回内容长度,解决返回内容长度不一致导致请求卡住的问题
                response.setContentLength(newContent.getBytes(StandardCharsets.UTF_8).length);//这里要注意:setContentLength(字符串的字节长度,不是字符串的长度)
                //修改完写入输出流,返回给前端
                ServletOutputStream out = response.getOutputStream();
                out.write(newContent.getBytes(StandardCharsets.UTF_8));//写入返回内容
                out.flush();//刷新
                out.close();//关闭流
            } catch (Exception e) {
                log.error("日志入库异常:", e);
            }
        }
    }
    
    • 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

    LogHttpServletResponseWrapper.java

    防止请求数据丢失,回写数据

    import javax.servlet.ServletOutputStream;
    import javax.servlet.WriteListener;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpServletResponseWrapper;
    import java.io.*;
    
    public class LogHttpServletResponseWrapper extends HttpServletResponseWrapper {
        private final ByteArrayOutputStream buffer;
        private final ServletOutputStream out;
    
        public LogHttpServletResponseWrapper(HttpServletResponse httpServletResponse) {
            super(httpServletResponse);
            buffer = new ByteArrayOutputStream();
            out = new WrapperOutputStream(buffer);
        }
    
        @Override
        public ServletOutputStream getOutputStream() {
            return out;
        }
    
        @Override
        public void flushBuffer() throws IOException {
            if (out != null) {
                out.flush();
            }
        }
    
        public byte[] getContent() throws IOException {
            flushBuffer();
            return buffer.toByteArray();
        }
    
        static class WrapperOutputStream extends ServletOutputStream {
            private final ByteArrayOutputStream bos;
    
            public WrapperOutputStream(ByteArrayOutputStream bos) {
                this.bos = bos;
            }
    
            @Override
            public void write(int b) {
                bos.write(b);
            }
    
            @Override
            public boolean isReady() {
                return false;
            }
    
            @Override
            public void setWriteListener(WriteListener arg0) {
            }
        }
    
    }
    
    • 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

    Log.java

    日志对象

    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import java.util.Date;
    
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class Log {
        private Long id;
        private String userId;
        private String username;
        private String applicationName;
        private Integer code;
        private String method;
        private String requestURI;
        private String requestData;
        private String respondData;
        private String msg;
        private String errorMsg;
        private Date createTime;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    LogDTO.java

    日志请求参数

    import lombok.Data;
    
    @Data
    public class LogDTO {
        /**
         * 年月
         */
        private String yyyyMM;
        /**
         * 用户ID
         */
        private String userId;
        /**
         * 用户名
         */
        private String username;
        /**
         * 应用名称
         */
        private String applicationName;
        /**
         * 状态码
         */
        private Integer code;
        /**
         * 请求方法
         */
        private String method;
        /**
         * 请求URI
         */
        private String requestURI;
        /**
         * 请求数据
         */
        private String requestData;
        /**
         * 返回数据
         */
        private String respondData;
        /**
         * 详细错误信息
         */
        private String errorMsg;
        /**
         * 当月时间段-开始时间
         */
        private String startTime;
        /**
         * 当月时间段-结束时间
         */
        private String endTime;
    }
    
    • 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

    LogController.java

    日志控制层

    import javax.annotation.Resource;
    
    import com.fu.work.entity.LogDTO;
    import com.fu.work.entity.R;
    import com.fu.work.service.LogService;
    import org.springframework.web.bind.annotation.*;
    
    
    /**
     * 日志
     */
    @RestController
    @RequestMapping("log")
    public class LogController {
    
        @Resource
        private LogService logService;
    
        /**
         * 根据年月和ID查询
         * @param yyyyMM 年月
         * @param id ID
         */
        @GetMapping("queryById")
        public R queryById(@RequestParam(required = false) String yyyyMM, @RequestParam Long id) {
            return R.ok(logService.queryById(yyyyMM,id));
        }
    
        /**
         * 分页查询
         */
        @PostMapping("findAll")
        public R findAll(@RequestBody LogDTO logDTO) {
            return R.ok(logService.findAll(logDTO));
        }
    
    }
    
    • 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

    LogService.java

    异步线程入库

    import javax.annotation.Resource;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.jdbc.BadSqlGrammarException;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Service;
    import org.springframework.util.StringUtils;
    
    import java.text.SimpleDateFormat;
    import java.util.Calendar;
    import java.util.List;
    
    @Slf4j
    @Service
    public class LogService {
    
        @Resource
        private LogDao logDao;
    
        /**
         * 根据ID查询
         */
        public Log queryById(String tableName, Long id) {
            //不传则默认是当前年月
            if (!StringUtils.hasLength(tableName)) {
                tableName = getYearMonth(0);
            }
            return logDao.queryById(tableName, id);
        }
    
        /**
         * 查询全部
         */
        public List<Log> findAll(LogDTO logDTO) {
            String tableName = logDTO.getYyyyMM();
            //不传则默认是当前年月
            if (!StringUtils.hasLength(tableName)) {
                tableName = getYearMonth(0);
            }
            return logDao.findAll(tableName, logDTO);
        }
    
        /**
         * 异步日志入库
         */
        @Async("logAsync")
        public void insert(Log logObj) {
            log.info("打印当前B线程名称:{}",Thread.currentThread().getName());
            //获取当前年月
            String tableName = getYearMonth(0);
            try {
                logDao.insert(tableName, logObj);
            } catch (BadSqlGrammarException e) {
                log.error("入库异常:", e);
                //如果是不存在表,则创建表
                if (1146 == e.getSQLException().getErrorCode()) {
                    //判断下个月的日志表是否存在,如果不存在则创建
                    logDao.crateTable(getYearMonth(0));
                    //再次入库
                    logDao.insert(tableName, logObj);
                }
            } catch (Exception e) {
                log.error("未知异常:", e);
            }
        }
    
        //自定义方法==============================================================================================================
        /**
         * 获取年月
         * @param addOrReduceMonth 正数表示后几个月,负数表示前几个月,0表示当前月
         */
        public static String getYearMonth(int addOrReduceMonth) {
            //获取当前月份的表
            Calendar cal = Calendar.getInstance();
            cal.add(Calendar.MONTH, addOrReduceMonth);
            SimpleDateFormat dft = new SimpleDateFormat("yyyyMM");
            return dft.format(cal.getTime());
        }
    }
    
    • 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

    AsyncConfig.java

    异步线程参数配置需要在@SpringBootApplication注解上方加上@EnableAsync注解开启异步线程

    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
    
    import java.util.concurrent.Executor;
    import java.util.concurrent.ThreadPoolExecutor;
    
    /**
     * 异步线程配置:确保执行方法和异步执行的方法不在同一个类
     */
    @Configuration
    public class AsyncConfig {
        @Value("${spring.task.execution.pool.core-size}")
        private int corePoolSize;
        @Value("${spring.task.execution.pool.max-size}")
        private int maxPoolSize;
        @Value("${spring.task.execution.pool.queue-capacity}")
        private int queueCapacity;
        @Value("${spring.task.execution.thread-name-prefix}")
        private String threadNamePrefix;
        @Value("${spring.task.execution.pool.keep-alive}")
        private int keepAliveSeconds;
    
        @Bean("logAsync")
        public Executor logAsync() {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            executor.setCorePoolSize(corePoolSize);
            executor.setMaxPoolSize(maxPoolSize);
            executor.setQueueCapacity(queueCapacity);
            executor.setThreadNamePrefix(threadNamePrefix);
            executor.setKeepAliveSeconds(keepAliveSeconds);
            /*
              拒绝处理策略
              CallerRunsPolicy():交由调用方线程运行,比如 main 线程。
              AbortPolicy():直接抛出异常。
              DiscardPolicy():直接丢弃。
              DiscardOldestPolicy():丢弃队列中最老的任务。
             */
            executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
            executor.initialize();
            return executor;
        }
    }
    
    • 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

    LogDao.java

    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Param;
    
    import java.util.List;
    
    @Mapper
    public interface LogDao{
    
        /**
         * 创建日志表
         */
        int crateTable(@Param("tableName") String tableName);
    
        /**
         * 根据ID查询
         */
        Log queryById(@Param("tableName") String tableName,@Param("id") Long id);
    
        /**
         * 查询全部
         */
        List<Log> findAll(@Param("tableName") String tableName,@Param("logDTO") LogDTO logDTO);
    
        /**
         * 新增
         */
        int insert(@Param("tableName") String tableName,@Param("log") Log log);
    
    }
    
    • 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

    LogMapper.xml

    sql创建按月分表日志表和查询日志数据

    
    DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.fu.work.dao.LogDao">
    
        <resultMap type="com.fu.work.entity.Log" id="BaseResultMap">
            <result property="id" column="id" jdbcType="BIGINT"/>
            <result property="userId" column="user_id" jdbcType="VARCHAR"/>
            <result property="username" column="username" jdbcType="VARCHAR"/>
            <result property="applicationName" column="application_name" jdbcType="VARCHAR"/>
            <result property="code" column="code" jdbcType="SMALLINT"/>
            <result property="method" column="method" jdbcType="VARCHAR"/>
            <result property="requestURI" column="request_uri" jdbcType="VARCHAR"/>
            <result property="requestData" column="request_data" jdbcType="VARCHAR"/>
            <result property="respondData" column="respond_data" jdbcType="VARCHAR"/>
            <result property="msg" column="msg" jdbcType="VARCHAR"/>
            <result property="errorMsg" column="error_msg" jdbcType="VARCHAR"/>
            <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
        resultMap>
    
        <sql id="Base_Column_List">id, user_id, username, application_name, code, `method`, request_uri, request_data, respond_data, msg, error_msg, create_timesql>
    
        
        <update id="crateTable" parameterType="String">
            CREATE TABLE IF NOT EXISTS log_${tableName} (
                `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
                `user_id` char(36) DEFAULT NULL COMMENT '用户ID',
                `username` varchar(64) DEFAULT NULL COMMENT '用户名',
                `application_name` varchar(255) DEFAULT NULL COMMENT '应用名称',
                `code` smallint(6) DEFAULT NULL COMMENT '状态码',
                `method` varchar(16) DEFAULT NULL COMMENT '请求方法',
                `request_uri` varchar(2048) DEFAULT NULL COMMENT '请求URI',
                `request_data` longtext DEFAULT NULL COMMENT '请求数据',
                `respond_data` longtext DEFAULT NULL COMMENT '返回数据',
                `msg` text DEFAULT NULL COMMENT '返回信息',
                `error_msg` longtext DEFAULT NULL COMMENT '详细错误信息',
                `create_time` datetime DEFAULT NULL COMMENT '创建时间',
                PRIMARY KEY (`id`),
                KEY `create_time` (`create_time`) USING BTREE COMMENT '创建时间索引',
                KEY `user_id` (`user_id`) COMMENT '用户ID索引',
                KEY `application_name` (`application_name`) COMMENT '应用名称索引'
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
        update>
    
        
        <select id="queryById" resultMap="BaseResultMap">
            select
            <include refid="Base_Column_List"/>
            from log_${tableName} where id = #{id}
        select>
    
        
        <select id="findAll" resultMap="BaseResultMap">
            select
            <include refid="Base_Column_List"/>
            from log_${tableName}
            <where>
                <if test="logDTO.userId != null and logDTO.userId != '' ">
                    AND    user_id = #{logDTO.userId}
                if>
                <if test="logDTO.code != null">
                    AND    code = #{logDTO.code}
                if>
                <if test="logDTO.method != null and logDTO.method != ''">
                    AND    `method` = #{logDTO.method}
                if>
                <if test="logDTO.applicationName != null and logDTO.applicationName != ''">
                    AND    application_name = #{logDTO.applicationName}
                if>
                <if test="logDTO.username != null and logDTO.username != ''">
                    AND    username LIKE CONCAT('%',#{logDTO.username,jdbcType=VARCHAR},'%')
                if>
                <if test="logDTO.requestURI != null and logDTO.requestURI != ''">
                    AND    request_uri LIKE CONCAT('%',#{logDTO.requestURI},'%')
                if>
                <if test="logDTO.requestData != null and logDTO.requestData != ''">
                    AND    request_data LIKE CONCAT('%',#{logDTO.requestData,jdbcType=VARCHAR},'%')
                if>
                <if test="logDTO.respondData != null and logDTO.respondData != ''">
                    AND    respond_data LIKE CONCAT('%',#{logDTO.respondData,jdbcType=VARCHAR},'%')
                if>
                <if test="logDTO.errorMsg != null and logDTO.errorMsg != ''">
                    AND    error_msg LIKE CONCAT('%',#{logDTO.errorMsg,jdbcType=VARCHAR},'%')
                if>
                <if test="logDTO.startTime != null">
                    AND    create_time =]]> #{logDTO.startTime}
                if>
                <if test="logDTO.endTime != null">
                    AND    create_time  #{logDTO.endTime}
                if>
            where>
            ORDER BY create_time DESC
        select>
    
        
        <insert id="insert">
            insert into log_${tableName}
            <trim prefix="(" suffix=")" suffixOverrides=",">
                <if test="log.id != null">
                    id,
                if>
                <if test="log.userId != null">
                    user_id,
                if>
                <if test="log.username != null">
                    username,
                if>
                <if test="log.applicationName != null">
                    application_name,
                if>
                <if test="log.code != null">
                    code,
                if>
                <if test="log.method != null">
                    `method`,
                if>
                <if test="log.requestURI != null">
                    request_uri,
                if>
                <if test="log.requestData != null">
                    request_data,
                if>
                <if test="log.respondData != null">
                    respond_data,
                if>
                <if test="log.msg != null">
                    msg,
                if>
                <if test="log.errorMsg != null">
                    error_msg,
                if>
                <if test="log.createTime != null">
                    create_time,
                if>
            trim>
            <trim prefix="values (" suffix=")" suffixOverrides=",">
                <if test="log.id != null">
                    #{log.id},
                if>
                <if test="log.userId != null">
                    #{log.userId},
                if>
                <if test="log.username != null">
                    #{log.username},
                if>
                <if test="log.applicationName != null">
                    #{log.applicationName},
                if>
                <if test="log.code != null">
                    #{log.code},
                if>
                <if test="log.method != null">
                    #{log.method},
                if>
                <if test="log.requestURI != null">
                    #{log.requestURI},
                if>
                <if test="log.requestData != null">
                    #{log.requestData},
                if>
                <if test="log.respondData != null">
                    #{log.respondData},
                if>
                <if test="log.msg != null">
                    #{log.msg},
                if>
                <if test="log.errorMsg != null">
                    #{log.errorMsg},
                if>
                <if test="log.createTime != null">
                    #{log.createTime},
                if>
            trim>
        insert>
    
    mapper>
    
    • 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

    R.java

    统一泛型返回对象

    import lombok.*;
    import lombok.experimental.Accessors;
    
    import java.io.Serializable;
    
    @Builder
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @Accessors(chain = true)
    public class R<T> implements Serializable {
    
    	private static final long serialVersionUID = 1L;
    
    	@Getter
    	@Setter
    	private int code;
    
    
    	@Setter
    	private String msg;
    	public String getMsg(){
    		if (msg==null){
    			msg=ResultCode.getMsg(this.code);
    		}
    		return msg;
    	}
    
    	@Getter
    	@Setter
    	private T data;
    
    	/**
    	 * 新增详细错误信息
    	 */
    	@Getter
    	@Setter
    	private Exception detailErrorMsg;
    
    	public static <T> R<T> ok() {
    		return restResult(null, 0, null);
    	}
    
    	public static <T> R<T> ok(T data) {
    		return restResult(data, 0, null);
    	}
    
    	public static <T> R<T> ok(T data, String msg) {
    		return restResult(data, 0, msg);
    	}
    
    	public static <T> R<T> failed() {
    		return restResult(null, 1, null);
    	}
    	public static <T> R<T> failed(int code) {
    		return restResult(null, code, null);
    	}
    	public static <T> R<T> failed(String msg) {
    		return restResult(null, 1, msg);
    	}
    
    	public static <T> R<T> failed(T data) {
    		return restResult(data, 1, null);
    	}
    
    	public static <T> R<T> failed(T data, String msg) {
    		return restResult(data, 1, msg);
    	}
    	public static <T> R<T> failed(T data, int code, String msg) {
    		return restResult(data, code, msg);
    	}
    	public static <T> R<T> failed(int code, String msg) {
    		return restResult(null, code, msg);
    	}
    	private static <T> R<T> restResult(T data, int code, String msg) {
    		R<T> apiResult = new R<>();
    		apiResult.setCode(code);
    		apiResult.setData(data);
    		apiResult.setMsg(msg);
    		return apiResult;
    	}
    
    	/**
    	 * 详细错误信息
    	 */
    	public static <T> R<T> failed(String msg,Exception detailErrorMsg) {
    		return restResult(null, 1, msg,detailErrorMsg);
    	}
    
    	/**
    	 * 重载
    	 */
    	private static <T> R<T> restResult(T data, int code, String msg,Exception detailErrorMsg) {
    		R<T> apiResult = new R<>();
    		apiResult.setCode(code);
    		apiResult.setData(data);
    		apiResult.setMsg(msg);
    		apiResult.setDetailErrorMsg(detailErrorMsg);
    		return apiResult;
    	}
    }
    
    • 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

    GlobalExceptionHandler.java

    全局异常处理类

    @Slf4j
    @RestControllerAdvice
    public class GlobalExceptionHandler {
        @ExceptionHandler(Exception.class)
        public R Exception(Exception e) {
            log.error("全局异常信息:", e);
            return R.failed(e.Message(), e);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    ReturnRes.java

    拦截返回内容,把不符合统一泛型返回对象的转成统一泛型返回对象

    import com.fasterxml.jackson.databind.ObjectMapper;
    import lombok.SneakyThrows;
    import org.springframework.core.MethodParameter;
    import org.springframework.http.MediaType;
    import org.springframework.http.converter.HttpMessageConverter;
    import org.springframework.http.server.ServerHttpRequest;
    import org.springframework.http.server.ServerHttpResponse;
    import org.springframework.web.bind.annotation.RestControllerAdvice;
    import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
    
    
    @RestControllerAdvice
    public class ReturnRes implements ResponseBodyAdvice<Object> {
    
        @Override
        public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
            return true;
        }
    
        @SneakyThrows
        @Override
        public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
             if (o instanceof String) {//String要特殊处理
                    return new ObjectMapper().writeValueAsString(R.ok(o));
            } else if (o instanceof R) {//本身是Res直接返回即可
                return o;
            }
            return R.ok(o);
        }
    }
    
    • 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

    application.yml

    配置文件

    #忽略写入日志的URI
    log-application:
      ignore-uri: "/log/findAll,/log/queryById"
    
    server:
      port: 88
    
    spring:
      application:
        name: log
      jackson:
        date-format: yyyy-MM-dd hh:mm:ss
        time-zone: GMT+8
      task:
        execution:
          #异步线程名称
          thread-name-prefix: log-async
          pool:
            core-size: 8
            max-size: 16
            queue-capacity: 500
            keep-alive: 60
    
      datasource:
      	#mariadb和mysql都行,改下驱动即可
        driver-class-name: org.mariadb.jdbc.Driver
        url: jdbc:mariadb://localhost:3306/db_log?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=false
        username: root
        password: 123456
    
    mybatis:
      mapper-locations: classpath:mapper/*.xml
    
    logging:
      level:
        com.fu.work.dao: info
    
    • 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

    build.gradle(和maven的pom.xml差不多)

    依赖

    dependencies {//类似于maven的dependencies
        implementation 'org.springframework.boot:spring-boot-starter-web'//格式为groupId:artifactId:version
        compileOnly 'org.projectlombok:lombok'//仅编译时使用,不参与打包
        annotationProcessor 'org.projectlombok:lombok'
        runtimeClasspath 'org.mariadb.jdbc:mariadb-java-client'//mariadb驱动
        implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.2'//mybatis对象关系映射框架
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 相关阅读:
    PlotlyJs主要配置
    JAVA -华为真题-分奖金
    【程序员英语】【美语从头学】初级篇(入门)(笔记)Lesson 15 At the Department Store 在百货商店
    二刷力扣--二叉树(2)
    04 【布局之Overscroll Behavior 定位偏移量】
    【024】C++对C的扩展之命名空间namespace详解
    MDC轻量化日志链路跟踪的若干种应用场景
    利用eNSP实现telent远程登陆
    SwiftUI 教程之如何呈现不同高度的sheet, 新的视图修改器使工作变得容易。
    Shell编写规范和变量
  • 原文地址:https://blog.csdn.net/weixin_43933728/article/details/127559338