关于HttpServletRequestWrapper及Filter过滤器的使用

1.介绍

解决HttpServletRequest只能读取一次流后无法获取的问题,采用HttpServletRequestWrapper进行包装,通过继承HttpServletRequestWrapper类实现读取流的操作。
解决整合Filter过滤器时遇到的问题:过滤器urlPatterns不生效、过滤器不起作用。

2.应用场景

基于客户对安全性的考虑,部分请求中存在敏感数据需要进行加密传输,故采用过滤器对特定URL进行解密。
将整串json格式请求加密过的字符串进行解密,解析出正确的json字符串后进行业务处理。
目前接口响应不存在敏感信息未进行处理,若需要处理响应数据可以使用ResponseWrapper进行加密处理。

3.实操

3.1 创建RequestWrapper继承HttpServletRequestWrapper

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;


public class RequestWrapper extends HttpServletRequestWrapper {
    private byte[] bytes;

    private HttpServletRequest request;

    /**
     * @param request
     */
    public RequestWrapper(HttpServletRequest request) {
        super(request);
        this.request = request;
    }

    public String getRequestBody() throws IOException {
        try (BufferedInputStream bis = new BufferedInputStream(request.getInputStream());
             ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            byte[] buffer = new byte[1024];
            int len;
            while ((len = bis.read(buffer)) > 0) {
                baos.write(buffer, 0, len);
            }
            bytes = baos.toByteArray();
            String body = new String(bytes);
            return body;
        } catch (IOException ex) {
            throw ex;
        }
    }

    public void setRequestBody(String body){
        bytes = body.getBytes();
    }



    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        return 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();
            }
        };
    }


}
3.2 创建ResponseWrapper继承HttpServletResponseWrapper
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;

public class ResponseWrapper extends HttpServletResponseWrapper {
    private ByteArrayOutputStream outputStream;
    public byte[] getResponseData(){

        try {
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return outputStream.toByteArray();
    }

    public ResponseWrapper(HttpServletResponse response) {
        super(response);
        this.outputStream =new ByteArrayOutputStream();

    }

    @Override
    public PrintWriter getWriter() throws IOException {
        return new PrintWriter(outputStream);
    }

    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return new ServletOutputStream() {
            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setWriteListener(WriteListener listener) {

            }

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


}
3.3新增过滤器实现Filter类
  1. @WebFilter不得与@Component一起使用,会导致双重注册,urlPatterns失效会对全部请求过滤
  2. @WebFilter的urlPatterns不支持 /** ,会导致过滤器失效,请求无法进入过滤器
  3. 使用@WebFilter应在启动类加@ServletComponentScan注解
  4. 使用@ServletComponentScan需要过滤器包名,否则无法加载到过滤器
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;


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


@WebFilter(filterName="TtFilter", urlPatterns="/api/tt/*")
@Order(0)
@Slf4j
public class TtFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        //log.info("进入过滤器");
        // 请求解密
        if (("POST".equals(((HttpServletRequest)request).getMethod().trim().toUpperCase())) && "application/json".equals(request.getContentType().trim().toLowerCase())){
            RequestWrapper requestWrapper = new RequestWrapper((HttpServletRequest) request);
            String bodyStr =  requestWrapper.getRequestBody();
            if(StringUtils.isNotBlank(bodyStr)){
                log.info("解密前 API 请求消息:type={}, requestBody={}", requestWrapper.getMethod(), bodyStr);
                //解密
                String plainText = PBEUtils.decrypt(bodyStr);
                int lastIndex = plainText.lastIndexOf(":");
                int secondLastIndex = plainText.lastIndexOf(":", lastIndex - 1);
                plainText = plainText.substring(0, secondLastIndex);
                log.info("解密后requestBody={}",plainText);
                requestWrapper.setRequestBody(plainText);
            }
            chain.doFilter(requestWrapper, response);
        }else{
            // 处理业务逻辑
            chain.doFilter(request, response);
        }


    }

    @Override
    public void destroy() {

    }
}

加密工具

import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;


public class PBEUtils {
    public static String decrypt(String cipher) {
        StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
        encryptor.setAlgorithm("PBEWithMD5AndDES");//基于 MD5 和 DES 的密码算法
        encryptor.setPassword("xxxx");//密码
        return encryptor.decrypt(cipher);
    }


    public static String encrypt(String cipher) {
        StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
        encryptor.setAlgorithm("PBEWithMD5AndDES");
        encryptor.setPassword("xxxx");
        return encryptor.encrypt(cipher);
    }
}
3.4 启动类添加注解@ServletComponentScan("自己的包名")
@SpringBootApplication(scanBasePackages = {"com.xxx.xxx.bsp", "com.xxx.hfmis", "com.xxx.wxdb"})
@EnableFusionAuth
@ServletComponentScan("com.xxx.xxx.filter")
public class HfmisUiSpringBootApplication {
    public static void main(String[] args) {
        SpringApplication.run(HfmisUiSpringBootApplication.class, args);
    }

    @Bean
    public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer() {
        return factory -> {
            ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/ui/index.html");
            factory.addErrorPages(error404Page);
        };
    }
}

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在进行 POST 请求时,可以使用 filter 进行拦截和处理。具体步骤如下: 1. 创建一个实现了 javax.servlet.Filter 接口的类,重写其中的 doFilter 方法。 2. 在 doFilter 方法中,可以通过 request.getParameter 方法获取请求中的参数,根据参数进行相应的处理,并将处理结果封装成一个新的 request 对象。 3. 最后调用 filterChain.doFilter 方法,将处理后的请求对象和响应对象传递给下一个过滤器Servlet 进行处理。 示例代码如下: ```java public class PostFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { if (request instanceof HttpServletRequest) { HttpServletRequest httpServletRequest = (HttpServletRequest) request; if ("POST".equalsIgnoreCase(httpServletRequest.getMethod())) { // 获取请求参数 String param1 = request.getParameter("param1"); String param2 = request.getParameter("param2"); // 进行处理 // ... // 封装处理结果 HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(httpServletRequest) { @Override public String getParameter(String name) { if ("param1".equalsIgnoreCase(name)) { return "newParam1"; } else if ("param2".equalsIgnoreCase(name)) { return "newParam2"; } return super.getParameter(name); } }; // 调用下一个过滤器Servlet 进行处理 filterChain.doFilter(requestWrapper, response); return; } } filterChain.doFilter(request, response); } } ``` 在 web.xml 文件中配置 filter: ```xml <filter> <filter-name>PostFilter</filter-name> <filter-class>com.example.PostFilter</filter-class> </filter> <filter-mapping> <filter-name>PostFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ``` 这样,当 POST 请求到达时,就会被 PostFilter 拦截并进行处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值