filter 拦截器 获取http请求参数

本文详细介绍了如何在Spring Boot应用中创建并配置自定义的日志拦截器,包括设置拦截器的启动、管理拦截器的启用状态及顺序、获取请求参数及返回值等关键步骤。通过具体代码示例,展示了如何实现前置和后置的日志记录,以及如何处理请求体和响应内容。

里面一些方法使用了hutool的工具类 可以替换成你自己习惯的 工具类不是记录的主要东西。

记录点
1.怎么创建拦截器
2.怎么统一管理拦截器是否启用和输用顺序
3.怎么获取传入的参数
4.怎么获取返回值

直接上代码===================================================

filter配置

@Configuration 	
public class FilterConfig { 	  //log拦截器启动
    @Bean
    public FilterRegistrationBean logFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setDispatcherTypes(DispatcherType.REQUEST);
        registration.setFilter(new LogFilter());
        registration.addUrlPatterns("/*");
        registration.setName("logFilter");
        registration.setOrder(Integer.MAX_VALUE-1);
        return registration;
    } 	}

LogFilter

/**
 * log过滤
 *
 * @author Teler
 */
public class LogFilter implements Filter {


    @Override
    public void init(FilterConfig config) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
            throws IOException, ServletException {

        //为了在post的时候能继续传递
        LogHttpServletRequestWrapper request = new LogHttpServletRequestWrapper((HttpServletRequest) servletRequest);
        MyResponseWrapper response = new MyResponseWrapper((HttpServletResponse) servletResponse);

        StaticLog.info("=====================LogFilter前置start=====================>");

        //封装log实体类
         Map<String, Object> parameterMap=new LinkedHashMap<>();
        if("GET".equals(request.getMethod())){
            parameterMap= JSONUtil.parseObj(ServletUtil.getParams(request));
        }else{
            parameterMap= JSONUtil.parseObj(request.getBody());
        }
        StaticLog.info("请求来源: =》{}", request.getRemoteAddr());
        StaticLog.info("请求URI:{}", request.getRequestURI());
        StaticLog.info("请求方式:{}", request.getMethod());
        StaticLog.info("请求参数:{}", parameterMap);
        StaticLog.info("=====================LogFilter前置  end=====================>");
        //消耗时间
        long start = System.currentTimeMillis();

        // 执行主体方法start==================================================================
        chain.doFilter(request, response);
        // 执行主体方法  end==================================================================

        //耗时
        long time = System.currentTimeMillis() - start;
        StaticLog.info("=====================LogFilter后置start=====================>");
        byte[] content=response.getContent();
        String resultParams=new String();
        if (content.length > 0) {
            resultParams= new String(content, "UTF-8");
        }
             StaticLog.info("返回值:{}", resultParams);
        StaticLog.info("耗时(毫秒):", time);
        //返回消息 否则前台收不到消息
        servletResponse.getOutputStream().write(resultParams.getBytes());
        StaticLog.info("=====================LogFilter后置  end=====================>");
    }

    @Override
    public void destroy() {
    }
}

LogHttpServletRequestWrapper.java

public class LogHttpServletRequestWrapper extends HttpServletRequestWrapper {
    private final String body;

    public LogHttpServletRequestWrapper(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 bytesRead = -1;
                while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                    stringBuilder.append(charBuffer, 0, bytesRead);
                }
            } else {
                stringBuilder.append("");
            }
        } catch (IOException ex) {

        } 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;
    }

}

MyResponseWrapper.java

public class MyResponseWrapper extends HttpServletResponseWrapper {
    private ByteArrayOutputStream buffer;

    private ServletOutputStream out;

    public MyResponseWrapper(HttpServletResponse httpServletResponse) {
        super(httpServletResponse);
        buffer = new ByteArrayOutputStream();
        out = new WrapperOutputStream(buffer);
    }

    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return out;
    }

    @Override
    public void flushBuffer()
            throws IOException {
        if (out != null) {
            out.flush();
        }
    }

    public byte[] getContent() throws IOException {
        flushBuffer();
        return buffer.toByteArray();
    }

    class WrapperOutputStream extends ServletOutputStream {
        private ByteArrayOutputStream bos;

        public WrapperOutputStream(ByteArrayOutputStream bos) {
            this.bos = bos;
        }

        @Override
        public void write(int b)
                throws IOException {
            bos.write(b);
        }

        @Override
        public boolean isReady() {

            // TODO Auto-generated method stub
            return false;

        }

        @Override
        public void setWriteListener(WriteListener arg0) {

            // TODO Auto-generated method stub

        }
    }
}
<think>我们正在讨论如何在Java中通过拦截器获取请求参数。根据引用内容,主要涉及在SpringBoot或SpringMVC中使用拦截器获取HTTP请求参数的方法。关键点:1.拦截器需要实现HandlerInterceptor接口,并重写preHandle方法。2.在preHandle方法中,我们可以通过HttpServletRequest对象获取请求参数。3.获取参数的方式有两种:一种是获取URL中的查询参数(即?后的参数),另一种是获取请求体(如POST请求的表单数据或JSON)。4.需要注意的是,请求体(InputStream)只能被读取一次,如果重复读取可能会导致问题(如引用[3]中提到的Requiredrequestbodyismissing错误)。根据引用[1]和[2],我们可以通过以下方式获取参数:-对于查询参数:使用request.getParameterMap()或request.getParameterNames()等。-对于请求体:如果是表单数据,同样可以使用request.getParameter系列方法;如果是JSON等数据,则需要从InputStream读取,但要注意不能重复读取。引用[3]提醒我们,在拦截器中读取请求体时,如果后续还需要使用(例如在Controller中),我们需要将请求体内容缓存下来,以便多次读取。因此,我们可以编写一个拦截器,在preHandle方法中获取请求参数并打印或处理。下面是一个示例:示例代码:我们将创建一个拦截器,用于获取GET请求的查询参数和POST请求的表单参数。对于JSON等请求体,我们可以通过包装HttpServletRequest来实现多次读取(使用ContentCachingRequestWrapper)。但是注意:在拦截器中直接读取请求体可能会影响性能,且需要谨慎处理。这里我们主要展示如何获取查询参数和表单参数,对于JSON请求体,我们使用缓存的方式。步骤:1.创建拦截器类,实现HandlerInterceptor接口。2.在preHandle方法中,使用HttpServletRequest获取参数。3.注册拦截器。我们先展示一个简单的版本,只获取查询参数和表单参数(不处理JSON请求体):```javaimportjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importorg.springframework.web.servlet.HandlerInterceptor;publicclassParamsInterceptorimplementsHandlerInterceptor{@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{//获取所有请求参数(包括查询参数和表单参数)System.out.println("请求参数:");request.getParameterMap().forEach((key,value)->{System.out.println(key+":"+String.join(",",value));});returntrue;}}```但是,上述代码无法获取请求体中的JSON数据。为了能够获取JSON请求体,我们需要将请求包装成可缓存的请求,然后读取缓存的内容。我们可以使用ContentCachingRequestWrapper来缓存请求体。但是注意,这个类在Spring中提供,我们需要在拦截器中对原始请求进行包装。然而,在拦截器中,我们通常不会修改请求对象。因此,我们可以通过过滤器(Filter)来包装请求,然后在拦截器中使用包装后的请求。但是,问题要求使用拦截器,所以我们这里有两种选择:1.在拦截器中,如果请求是JSON类型,我们可以通过读取InputStream来获取请求体,但这样会消耗掉InputStream,导致后续无法读取。所以不推荐。2.使用ContentCachingRequestWrapper,但需要在过滤器中进行包装,这样拦截器就可以使用包装后的请求。这里我们假设已经有一个过滤器做了包装。由于引用[3]提到了读取两次的问题,我们采用第二种方式,即通过过滤器包装请求。因此,我们首先创建一个过滤器,将请求包装为ContentCachingRequestWrapper:```javaimportjavax.servlet.*;importjavax.servlet.http.HttpServletRequest;importjava.io.IOException;importorg.springframework.web.util.ContentCachingRequestWrapper;publicclassCachingRequestBodyFilterimplementsFilter{@OverridepublicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{HttpServletRequesthttpServletRequest=(HttpServletRequest)request;ContentCachingRequestWrapperwrappedRequest=newContentCachingRequestWrapper(httpServletRequest);chain.doFilter(wrappedRequest,response);//将包装后的请求传递下去}}```然后,在拦截器中,我们就可以从ContentCachingRequestWrapper中获取请求体:```javaimportorg.springframework.web.servlet.HandlerInterceptor;importorg.springframework.web.util.ContentCachingRequestWrapper;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.nio.charset.StandardCharsets;publicclassParamsInterceptorimplementsHandlerInterceptor{@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{//如果请求已经被包装为ContentCachingRequestWrapperif(requestinstanceofContentCachingRequestWrapper){ContentCachingRequestWrapperwrappedRequest=(ContentCachingRequestWrapper)request;//获取查询参数System.out.println("QueryStringParameters:");request.getParameterMap().forEach((key,value)->{System.out.println(key+":"+String.join(",",value));});//获取请求体byte[]contentAsByteArray=wrappedRequest.getContentAsByteArray();if(contentAsByteArray.length>0){Stringbody=newString(contentAsByteArray,StandardCharsets.UTF_8);System.out.println("RequestBody:"+body);}}else{//如果没有包装,只获取查询参数和表单参数System.out.println("RequestParameters:");request.getParameterMap().forEach((key,value)->{System.out.println(key+":"+String.join(",",value));});}returntrue;}}```最后,我们需要注册过滤器和拦截器。在SpringBoot中注册过滤器:```javaimportorg.springframework.boot.web.servlet.FilterRegistrationBean;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;@ConfigurationpublicclassFilterConfig{@BeanpublicFilterRegistrationBean<CachingRequestBodyFilter>filterRegistrationBean(){FilterRegistrationBean<CachingRequestBodyFilter>registrationBean=newFilterRegistrationBean<>();registrationBean.setFilter(newCachingRequestBodyFilter());registrationBean.addUrlPatterns("/*");returnregistrationBean;}}```注册拦截器:```javaimportorg.springframework.context.annotation.Configuration;importorg.springframework.web.servlet.config.annotation.InterceptorRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;@ConfigurationpublicclassInterceptorConfigimplementsWebMvcConfigurer{@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){registry.addInterceptor(newParamsInterceptor());}}```这样,我们就可以在拦截器获取请求参数(包括查询参数请求体)了。注意:ContentCachingRequestWrapper是Spring提供的,所以需要引入spring-web模块。总结:1.使用过滤器将请求包装为ContentCachingRequestWrapper,以便多次读取请求体。2.在拦截器中,通过ContentCachingRequestWrapper的getContentAsByteArray方法获取请求体内容。3.同时,通过getParameterMap获取查询参数和表单参数。但是,需要注意的是,getParameterMap只能获取到查询参数和表单参数(application/x-www-form-urlencoded或multipart/form-data),对于JSON(application/json)等,getParameterMap是获取不到的,所以需要从请求体中读取。因此,我们在拦截器中同时打印了查询参数请求体,这样就能覆盖大多数情况。引用说明:引用[1]和[2]提到了在拦截器获取请求参数,引用[3]提醒了请求体只能读取一次的问题,因此我们采用包装请求的方式解决。注意:这个示例可能会影响性能,因为缓存请求体会消耗内存,特别是大文件上传时。因此,在实际应用中,需要根据情况决定是否缓存请求体。以上就是在Java中通过拦截器获取请求参数的示例。§§相关问题§§1.拦截器和过滤器有什么区别?2.除了拦截器,还有哪些方式可以获取HTTP请求参数?3.如何解决拦截器中读取请求体导致后续Controller无法读取的问题?</think>在 Java 中通过拦截器获取 HTTP 请求参数的实现步骤如下,结合 Spring Boot 示例代码说明: ### 实现步骤 1. **创建拦截器类**:实现 `HandlerInterceptor` 接口 2. **重写 `preHandle` 方法**:在请求处理前获取参数 3. **处理不同参数类型**: - **查询参数**:`request.getParameterMap()` - **表单参数**:`request.getParameter()` - **JSON 请求体**:使用缓存请求包装器 4. **注册拦截器**:配置拦截规则 ### 完整示例代码 ```java import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Map; public class ParamsInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { // 1. 获取URL查询参数 (?key=value) Map<String, String[]> queryParams = request.getParameterMap(); System.out.println("URL参数: " + queryParams); // 2. 获取表单参数 (application/x-www-form-urlencoded) String formParam = request.getParameter("formKey"); System.out.println("表单参数: " + formParam); // 3. 获取JSON请求体 (application/json) if ("POST".equalsIgnoreCase(request.getMethod()) && request.getContentType() != null && request.getContentType().contains("application/json")) { // 使用缓存包装器解决多次读取问题[^3] CachedBodyHttpServletRequest cachedRequest = new CachedBodyHttpServletRequest(request); try { String jsonBody = new String( cachedRequest.getInputStream().readAllBytes(), StandardCharsets.UTF_8 ); System.out.println("JSON请求体: " + jsonBody); } catch (IOException e) { e.printStackTrace(); } return true; // 继续执行后续处理 } return true; } } ``` ### 关键点说明 1. **请求体缓存包装器**(解决多次读取问题) ```java import javax.servlet.*; import javax.servlet.http.*; import java.io.*; public class CachedBodyHttpServletRequest extends HttpServletRequestWrapper { private byte[] cachedBody; public CachedBodyHttpServletRequest(HttpServletRequest request) throws IOException { super(request); this.cachedBody = request.getInputStream().readAllBytes(); } @Override public ServletInputStream getInputStream() { return new CachedBodyServletInputStream(this.cachedBody); } // 内部实现 static class CachedBodyServletInputStream extends ServletInputStream { private final ByteArrayInputStream buffer; public CachedBodyServletInputStream(byte[] body) { this.buffer = new ByteArrayInputStream(body); } // 实现必要方法... } } ``` 2. **注册拦截器** ```java import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new ParamsInterceptor()) .addPathPatterns("/api/**"); // 拦截指定路径 } } ``` ### 注意事项 1. **请求体只能读取一次**:未缓存时读取后 InputStream 会关闭,导致后续处理报错 `Required request body is missing`[^3] 2. **性能影响**:大文件上传时谨慎使用缓存 3. **参数类型判断**:根据 `Content-Type` 头区分表单/JSON 4. **拦截器与过滤器区别**:拦截器在 Controller 前执行,过滤器在更早阶段处理 > 最佳实践:对于 JSON 请求体,建议在过滤器层进行缓存包装,再在拦截器获取内容[^2][^3]。
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值