Springboot如何利用 * 拦截请求信息收集到日志详解

作者:Leil_blogs 时间:2023-03-09 02:30:57 

目录
  • 1、需求

  • 2、问题

  • 2、获取

    • 1)导入依赖为了获取客户端类型、操作系统类型、ip、port

    • 2)封装获取body字符串的工具类

    • 3) * 类

    • 4)继承 HttpServletRequestWrapper类

    • 5)过滤器类

    • 6) * 过滤器配置类

  • 总结

    1、需求

    最近在工作中遇到的一个需求,将请求中的客户端类型、操作系统类型、ip、port、请求方式、URI以及请求参数值收集到日志中,网上找资料说用 * 拦截所有请求然后收集信息,于是就开始了操作:

    2、问题

    试了之后发现当请求方式为POST,前端发送数据json时只能用request.getReader()流获取,自信满满从流中获取之后发现请求之后报错:


    getInputStream() has already been called for this request...

    于是网上找答案,发现是ServletRequest的getReader()和getInputStream()两个方法只能被调用一次,而且不能两个都调用。那么如果Filter中调用了一次,在Controller里面就不能再调用了。

    然后又开始找解决方法,说既然ServletInputStream不支持重新读写,就把流读出来后用容器存储起来,后面就可以多次利用了。

    于是继承 HttpServletRequestWrapper类(http请求包装器,其基于装饰者模式实现了HttpServletRequest界面)并实现想要重新定义的方法以达到包装原生HttpServletRequest对象。还需要在过滤器里将原生的HttpServletRequest对象替换成我们的RequestWrapper对象。

    测试发现POST请求参数值可以在 * 类中获取到了,本以为大功告成,又发现GET请求不好使了,开始报错Stream closed,一顿操作发现需要在过滤器进行判断,如果是POST请求走自己的继承的HttpServletRequestWrapper类请求,否则走普通的请求。终于成功!突然舒服了。

    2、获取

    1)导入依赖为了获取客户端类型、操作系统类型、ip、port


    <dependency>
               <groupId>eu.bitwalker</groupId>
               <artifactId>UserAgentUtils</artifactId>
               <version>1.21</version>
    </dependency>

    2)封装获取body字符串的工具类


    package com.btrc.access.util;

    import javax.servlet.http.HttpServletRequest;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.nio.charset.Charset;

    public class RequestUtil {
       public static String getBodyString(HttpServletRequest request) {
           StringBuilder sb = new StringBuilder();
           try (
                   InputStream inputStream = request.getInputStream();
                  BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")))
           ) {
               String line;
               while ((line = reader.readLine()) != null) {
                   sb.append(line);
               }
           } catch (IOException e) {
               e.printStackTrace();
           }
           return sb.toString();
       }
    }

    3) * 类


    package com.btrc.access.filter;

    import com.btrc.access.util.RequestUtil;
    import eu.bitwalker.useragentutils.UserAgent;
    import org.apache.commons.lang.StringUtils;
    import org.springframework.http.HttpMethod;
    import org.springframework.web.servlet.HandlerInterceptor;

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    /**
    * 请求 * :拦截请求目的是将请求的信息收集到日志
    */
    public class RequestInterceptor implements HandlerInterceptor {

    @Override
       public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

    UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("user-agent"));
           //客户端类型
           String clientType = userAgent.getOperatingSystem().getDeviceType().getName();
           //客户端操作系统类型
           String osType = userAgent.getOperatingSystem().getName();
           //客户端ip
           String clientIp = request.getRemoteAddr();
           //客户端port
           int clientPort = request.getRemotePort();
           //请求方式
           String requestMethod = request.getMethod();
           //客户端请求URI
           String requestURI = request.getRequestURI();
           //客户端请求参数值
           String requestParam;
           //如果请求是POST获取body字符串,否则GET的话用request.getQueryString()获取参数值
           if(StringUtils.equalsIgnoreCase(HttpMethod.POST.name(), requestMethod)){
               requestParam = RequestUtil.getBodyString(request);
           }else{
               requestParam = request.getQueryString();
           }
           //客户端整体请求信息
           StringBuilder clientInfo = new StringBuilder();
           clientInfo.append("客户端信息:[类型:").append(clientType)
                   .append(", 操作系统类型:").append(osType)
                   .append(", ip:").append(clientIp)
                   .append(", port:").append(clientPort)
                   .append(", 请求方式:").append(requestMethod)
                   .append(", URI:").append(requestURI)
                   .append(", 请求参数值:").append(requestParam.replaceAll("\\s*", ""))
                   .append("]");

    //***这里的clientInfo就是所有信息了,请根据自己的日志框架进行收集***
           System.out.println(clientInfo);

    //返回ture才会继续执行,否则一直拦截住
           return true;
       }
    }

    4)继承 HttpServletRequestWrapper类


    package com.btrc.access.filter;

    import com.btrc.access.util.RequestUtil;

    import javax.servlet.ReadListener;
    import javax.servlet.ServletInputStream;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    import java.io.*;
    import java.nio.charset.Charset;

    public class AccessRequestWrapper extends HttpServletRequestWrapper {
       private final byte[] body;

    public AccessRequestWrapper(HttpServletRequest request) {
           super(request);
           body = RequestUtil.getBodyString(request).getBytes(Charset.forName("UTF-8"));
       }

    @Override
       public BufferedReader getReader() throws IOException {
           return new BufferedReader(new InputStreamReader(getInputStream()));
       }

    @Override
       public ServletInputStream getInputStream() throws IOException {

    final ByteArrayInputStream bais = new ByteArrayInputStream(body);

    return new ServletInputStream() {

    @Override
               public int read() throws IOException {
                   return bais.read();
               }

    @Override
               public boolean isFinished() {
                   return false;
               }

    @Override
               public boolean isReady() {
                   return false;
               }

    @Override
               public void setReadListener(ReadListener readListener) {

    }
           };
       }
    }

    5)过滤器类


    package com.btrc.access.filter;

    import org.apache.commons.lang.StringUtils;
    import org.springframework.http.HttpMethod;

    import javax.servlet.*;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;

    public class AccessFilter implements Filter {
       @Override
       public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
       public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
           HttpServletRequest request = (HttpServletRequest) servletRequest;
           //如果是POST走自己的继承的HttpServletRequestWrapper类请求,否则走正常的请求
           if(StringUtils.equalsIgnoreCase(HttpMethod.POST.name(), request.getMethod())){
               //一定要在判断中new对象,否则还会出现Stream closed问题
               filterChain.doFilter(new AccessRequestWrapper(request),servletResponse);
           }else{
               filterChain.doFilter(servletRequest,servletResponse);
           }
       }

    @Override
       public void destroy() {

    }
    }

    6) * 过滤器配置类


    package com.btrc.access.config;

    import com.btrc.access.filter.AccessFilter;
    import com.btrc.access.filter.RequestInterceptor;
    import org.springframework.boot.web.servlet.FilterRegistrationBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

    import javax.servlet.Filter;

    /**
    * * 过滤器配置类
    */
    @Configuration
    public class WebMvcConfig implements WebMvcConfigurer {
       @Bean
       public FilterRegistrationBean httpServletRequestReplacedFilter() {
           FilterRegistrationBean registration = new FilterRegistrationBean();
           registration.setFilter(new AccessFilter());
           // /* 是全部的请求拦截,和Interceptor的拦截地址/**区别开
           registration.addUrlPatterns("/*");
           registration.setName("accessRequestFilter");
           registration.setOrder(1);
           return registration;
       }

    @Override
       public void addInterceptors(InterceptorRegistry registry) {
           registry.addInterceptor(new RequestInterceptor()).addPathPatterns("/**");
       }
    }

    来源:https://www.cnblogs.com/leilcoding/p/15131470.html

    标签:springboot, , ,请求
    0
    投稿

    猜你喜欢

  • Java 详解Collection集合之ArrayList和HashSet

    2021-09-10 06:27:02
  • android 多点触摸图片缩放的具体实现方法

    2023-03-14 05:49:31
  • java判断list不为空的实现,和限制条数不要在一起写

    2022-01-24 13:14:38
  • Java 函数编程详细介绍

    2022-07-18 14:31:15
  • C#类中方法的执行顺序是什么

    2022-07-01 03:55:15
  • 通过JDK源码角度分析Long类详解

    2022-03-11 19:26:38
  • Android使用系统自带的相机实现一键拍照功能

    2023-06-05 10:27:23
  • Android中Intent组件的入门学习心得

    2023-09-03 00:23:29
  • Android RecyclerView item选中放大被遮挡问题详解

    2023-04-11 17:58:31
  • Spring定时任务使用及如何使用邮件监控服务器

    2023-01-12 16:38:58
  • android studio编译jar包或者aar包的方法教程详解

    2023-06-18 17:22:32
  • 深入理解Java中的接口

    2023-11-08 23:52:43
  • Spring Cloud + Nacos + Seata整合过程(分布式事务解决方案)

    2021-08-31 04:26:52
  • Android 利用 APT 技术在编译期生成代码

    2023-12-20 14:46:23
  • 详解Java分布式事务的 6 种解决方案

    2022-06-19 13:33:49
  • Spring Security实现自动登陆功能示例

    2023-01-29 15:31:55
  • C#中的==运算符

    2022-08-19 21:50:56
  • C语言实现BMP图像处理(哈夫曼编码)

    2022-10-08 02:04:02
  • Android 监听手机GPS打开状态实现代码

    2022-09-28 08:56:38
  • 一篇带你解析入门LongAdder源码

    2023-11-28 20:17:52
  • asp之家 软件编程 m.aspxhome.com