我的编程空间,编程开发者的网络收藏夹
学习永远不晚

springboot打印接口调用日志的实例

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

springboot打印接口调用日志的实例

概述

请求日志几乎是所有大型企业级项目的必要的模块,请求日志对于我们来说后期在项目运行上线一段时间用于排除异常、请求分流处理、限制流量等。

请求日志一般都会记录请求参数、请求地址、请求状态(Status Code)、SessionId、请求方法方式(Method)、请求时间、客户端IP地址、请求返回内容、耗时等等。如果你得系统还有其他个性化的配置,也可以完成记录。

记录请求参数时,由于servlet.getInputStream的数据只能读取一次,因此需要先把数据缓存下来,构造返回流,保证之后的Controller可以正常读取到请求体的数据。

方案思路

  • 封装HttpServletRequest请求类,改类在构造方法中将请求的输入流中的数据缓存了起来,保证之后的处理可以重复读取输入流中的数据。
  • 实现过滤器,把上步封装的请求类传下去,保证Controller可以正常读取输入流中的数据。
  • 添加拦截器,读取输入流中的数据。
  • 读取返回参数。

封装HttpServletRequest请求

package com.example.demo.intercept;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;

public class RequestWrapper extends HttpServletRequestWrapper {
    private final String body;
    public RequestWrapper(HttpServletRequest request) {
        super(request);
        StringBuilder stringBuilder = new StringBuilder();
        BufferedReader bufferedReader = null;
        InputStream inputStream = null;
        try {
            inputStream = request.getInputStream();
            if (inputStream != null) {
                bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                char[] charBuffer = new char[128];
                int bytesBody = -1;
                while ((bytesBody = bufferedReader.read(charBuffer)) > 0) {
                    stringBuilder.append(charBuffer, 0, bytesBody);
                }
            } else {
                stringBuilder.append("");
            }
        } catch (IOException e) {
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        body = stringBuilder.toString();
    }
    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
        ServletInputStream servletInputStream = new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }
            @Override
            public boolean isReady() {
                return false;
            }
            @Override
            public void setReadListener(ReadListener readListener) {
            }
            @Override
            public int read() throws IOException {
                return byteArrayInputStream.read();
            }
        };
        return servletInputStream;
    }
    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }
    public String getBody() {
        return this.body;
    }
}

把可重复读请求体通过过滤器往下传

防止请求流读取一次后就没有了,之后的不管是过滤器、拦截器、处理器都是读的已经缓存好的数据,实现可重复读。

package com.example.demo.intercept;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@Component
@WebFilter(urlPatterns = "
@Component
public class OperationLogInterceptor implements HandlerInterceptor {
    
    public static final String JWT_SECERT = "23142d7a9s7d66970ad07d8sa";
    
    private static List<String> pathList = new ArrayList<>();
    static {
        pathList.add("/mdms/model");
    }
    @Resource
    private FunctionDOMapper functionDOMapper;//菜单动能sql
    @Resource
    private UserOperationHistoryDOMapper historyDOMapper;//操作日志记录表
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String servletPath = "" + request.getServletPath();
        String method = request.getMethod();
        pathList.forEach(path -> {
            if (servletPath.contains(path)){
                Cookie[] cookies = request.getCookies();
                if (cookies != null) {
                    for (Cookie cookie : cookies) {
                        //获取token在请求中
                        if (cookie.getName().equals("_qjt_ac_")) {
                            String token = cookie.getValue();
                            
                            byte[] encodeKey = Base64.decode(JWT_SECERT);
                            Claims claims = null;
                            try {
                                SecretKeySpec keySpec = new SecretKeySpec(encodeKey, 0, encodeKey.length, "AES");
                                claims = Jwts.parser().setSigningKey(keySpec).parseClaimsJws(token).getBody();
                            } catch (Exception e) {
                                return;
                            }
                            //用户账号
                            String account = claims.getSubject();
                            //查询URL在功能表中的功能
                            functionDOMapper.selectOne(servletPath, method);
                            //获取入参
                            RequestWrapper requestWrapper = null;
                            if (request instanceof HttpServletRequest) {
                                requestWrapper = new RequestWrapper(request);
                            }
                            Map<String,Object> map = new HashMap<>();
                            map.put("parameter", JSONObject.parse(requestWrapper.getBody()));
                            historyDOMapper.insert(map);//将操作信息入库
                        }
                    }
                } 
            }
        });
        return true;
    }
}

注册拦截器

package com.example.demo.config;
import com.example.demo.intercept.OperationLogInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

public class WebConfig implements WebMvcConfigurer {
    @Bean
    public HandlerInterceptor getOperationLogInterceptor() {
        return new OperationLogInterceptor();
    }
    @Override
    public void addInterceptors(InterceptorRegistry registry){
        registry.addInterceptor(getOperationLogInterceptor()).addPathPatterns("
@ControllerAdvice(basePackages = "项目包")
public class GetResponseBody implements ResponseBodyAdvice<Object> {
    
    public static final String JWT_SECERT = "23142d7a9s7d66970ad07d8sa";
    
    private static List<String> pathList = new ArrayList<>();
    static {
        pathList.add("/mdms/model");
    }
    @Resource
    private FunctionDOMapper functionDOMapper;//菜单动能sql
    @Resource
    private UserOperationHistoryDOMapper historyDOMapper;//操作日志记录表
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return false;
    }
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        String path = serverHttpRequest.getURI().getPath();
        String methodValue = serverHttpRequest.getMethodValue();
        pathList.forEach(serverPath -> {
            if (path.contains(serverPath)) {
                HashMap<String, String> cookieMap = new HashMap<>();
                HttpHeaders headers = serverHttpRequest.getHeaders();
                List<String> cookieList = headers.get("cookie");
                if (CollectionUtils.isEmpty(cookieList)) {
                    return;
                }
                String replaceAll = cookieList.get(0).replaceAll(";", "").replaceAll(";", "");
                String[] split = replaceAll.split(";");
                for (String cookie : split) {
                    String[] param = cookie.split("=");
                    cookieMap.put(param[0], param[1]);
                }
                String token = cookieMap.get("_qjt_ac_");
                byte[] encodeKey = Base64.decode(JWT_SECERT);
                Claims claims = null;
                try {
                    SecretKeySpec keySpec = new SecretKeySpec(encodeKey, 0, encodeKey.length, "AES");
                    claims = Jwts.parser().setSigningKey(keySpec).parseClaimsJws(token).getBody();
                } catch (Exception e) {
                    return;
                }
                //用户账号
                String account = claims.getSubject();
                //查询URL在功能表中的功能
                functionDOMapper.selectOne(servletPath, method);
                //获取返参
                List<Object> list = historyDOMapper.select("功能表参数", account);
                list.sort((Object1,Object2)->Object2.getTime().compareTo(Object1.getTime()));//将查询到的操作记录按时间降序排列
                Object history = list.get(0);
                if (body instanceof Response) {
                    Response response = (Response) body;
                    JSONObject jsonObject = JSONObject.parseObject(history.getParam());
                    jsonObject.put("message",response.getMessage());
                    jsonObject.put("body",response.getData());
                    history.setParam(jsonObject.toString());
                    history.setDes(response.getMessage());
                }
                historyDOMapper.updateByPrimaryKeySelective(history);//将操作信息更新
            }
        });
        return body;
    }
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。 

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

springboot打印接口调用日志的实例

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Node.js利用debug模块打印出调试日志的方法

前言 大家都知道在node程序开发中时,经常需要打印调试日志。用的比较多的是debug模块,比如express框架中就用到了。下文简单举几个例子进行说明。文中相关代码示例,可在这里找到。 备注:node在0.11.3版本也加入了util.d
2022-06-04

SpringBoot+MDC实现链路调用日志的方法

MDC是log4j、logback及log4j2提供的一种方便在多线程条件下记录日志的功能,这篇文章主要介绍了SpringBoot+MDC实现链路调用日志,需要的朋友可以参考下
2022-12-20

SpringBoot使用AOP记录接口操作日志的方法

日志记录量是很大的,所以只记录关键地方并按期归档,最好是存在如elasticsearch中,如果存在数据库中,分表是不错的选择,这篇文章主要介绍了SpringBoot使用AOP记录接口操作日志的方法,需要的朋友可以参考下
2022-11-13

输出执行操作和打印日志的shell脚本实例

cat /mnt/log_function.sh #!/bin/bash #log function####log_correct函数打印正确的输出到日志文件 function log_correct () { DATE=`date
2022-06-04

使用HttpClient调用接口的实例讲解

一,编写返回对象public class HttpResult {// 响应的状态码private int code;// 响应的响应体private String body;get/set…}
2023-05-31

怎么在接口回调中的使用接口对象的实例化

本篇文章为大家展示了怎么在接口回调中的使用接口对象的实例化,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。接口回调:可以把实现某一接口类创建的对象的引用赋给该接口声明的接口变量,那么该接口变量就可以调
2023-05-31

Java调用CXF WebService接口的两种方式实例

方式一:使用CXF提供的工具生成客户端代码。1. 在项目中添加CXF的依赖。2. 使用CXF提供的命令行工具生成客户端代码,命令如下:```wsdl2java -d -p ```其中,``为生成的代码存放的目录,``为生成的代码所在的包
2023-09-16

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录