开发笔记 | JAVA过滤器Filter实现全局接口入参去除前后空格

这篇具有很好参考价值的文章主要介绍了开发笔记 | JAVA过滤器Filter实现全局接口入参去除前后空格。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

思考过程

遇到的问题

过滤器Filter使用步骤

全局去除入参前后空格代码实现

处理过程中自己造成的一些问题


需求背景:

前端所有的条件查询去除前后空格,如搜 【"   测试    "】后端将其转为【测试】。之前都是前端统一处理的,但是这次要后端处理,那么就得考虑全局对入参进行去前后空格再进一步去查询,所以通过滤器Filter来实现。

思考过程

最开始想到的是拦截器Interceptor,但是拦截器一般用于对接口参数进行取值的一些操作,对于GET请求,如果进行入参修改好像更复杂,个人暂时定论拦截器对于GET入参只能取不能改(不确定),但是对于POST请求,不管是拦截器还是过滤器,都会面临请求体丢失问题,所以用到拦截器最终还是用到过滤器来配合解决这个问题,下文再详细说明,所以本文采用拦截器Filter进行解决

遇到的问题

1.POST请求 Required request body is missing

对于GET请求,通过request.getParameterMap()获取所有参数,进行处理后能正常传给接口,但是对于POST请求,通过request.getInputStream()获取流从而读取流获取参数。但request.getInputStream()只能读取一次,所以到接口的时候,@RequestBody注解也是通过该方法获取参数,所以此时如果没有做处理就没参数可以读,就会报错。所以自定义HttpServletRequestWrapper,重写getInputStream方法,把处理完的数据流保存下来传给接口获取

2.@WebFilter中urlPatterns = {"/test/*","/test2/*"}配置过滤规则失效

原因是同时添加了@Component与@WebFilter导致拦截不起作用,就默认所有接口都进过滤器。解决方法去掉@Component保留@WebFilter,在启动类添加@ServletComponentScan即可解决。如果保留@Component去除@WebFilter,则需要单独建一个配置类配置拦截规则。

过滤器Filter使用步骤

实现Filter接口,重写doFilter方法,通过@WebFilter进行拦截路径配置即可

全局去除入参前后空格代码实现

@WebFilter中urlPatterns表示需要过滤得接口,如果是全部则用/*,
 单个规则写法urlPatterns = "/test/*", 多个规则用{}
 filterName 表示过滤器名字,可采用@WebFilter配置也可以单独写个配置类

/**
 * 请求参数去除前后空格过滤器
 */
@Log4j2
@WebFilter(urlPatterns = {"/test/*","/test2/*"}, filterName = "ParameterTrimFilter")
public class ParameterTrimFilter implements Filter {

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

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("进入请求参数去前后空格过滤器");
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        //防止流读取一次就没,自定义HttpServletRequestWrapper处理
        ParameterTrimWrapper parameterTrimWrapper = new ParameterTrimWrapper(request);
        filterChain.doFilter(parameterTrimWrapper, servletResponse);
        log.info("参数去空格过滤器处理完成");
    }

    @Override
    public void destroy() {
    }
}
/**
 * 请求参数去除前后空格HttpServletRequestWrapper
 */
@Log4j2
public class ParameterTrimWrapper extends HttpServletRequestWrapper {

    //用于存放post请求体数据
    private byte[] body;

    //用于存放get请求参数
    private Map<String, String[]> params = new HashMap<>();

    private static final String CONTENT_TYPE = "Content-Type";

    private static final String GET = "GET";

    private static final String POST = "POST";

    public ParameterTrimWrapper(HttpServletRequest request) throws IOException {
        super(request);
        //处理get请求 url路径携带参数情况
        if(GET.equals(request.getMethod())){
            //获取到所有入参
            Map<String, String[]> requestMap = request.getParameterMap();
            if(ObjectUtil.isNotEmpty(requestMap)){
                this.params.putAll(requestMap);
                //对每个入参进行去除前后空格
                this.dealUrlParameter();
            }
        }
        //处理post请求 对请求体进行情况
        if(POST.equals(request.getMethod())){
            //getInputStream()读取请求体数据流
            String bodyJson = new String(IOUtils.toByteArray(super.getInputStream()), StandardCharsets.UTF_8);
            if(StringUtils.isNotEmpty(bodyJson)){
                //处理每个参数去除前后空格
                Map<String, Object> finalMap = dealJson(bodyJson);
                //将处理完的结果再次塞进body
                this.body = JSON.toJSONString(finalMap).getBytes(StandardCharsets.UTF_8);
            }
        }
    }

    /**
     * get请求参数处理 将参数中的值去除前后空格后写回
     */
    public void dealUrlParameter(){
        params.forEach((k,v) ->{
            for(int i = 0 ;i < v.length ; i++ ){
                v[i] = v[i].trim();
            }
            params.put(k,v);
        });
    }

    /**
     * post请求参数处理 处理json参数 去除前后空格
     * @param bodyJson json
     * @return map
     */
    public static Map<String, Object> dealJson(String bodyJson){
        Map<String, Object> jsonMap = new HashMap<>();
        //将body字符串转为json对象
        JSONObject jsonObject = JSONObject.parseObject(bodyJson);
        if (jsonObject != null) {
            //对键值对进行处理
            jsonObject.forEach((k,v) -> {
                //根据字段类型进行处理
                if(v instanceof JSONArray){
                    //如果第一层字段为数组,再对数组中每个元素类型判断递归处理
                    List<Object> list = new ArrayList<>();
                    for (Object obj : (JSONArray) v){
                        if(obj instanceof JSONObject){
                            list.add(dealJson(obj.toString()));
                        }else if(obj instanceof String){
                            list.add(obj.toString().trim());
                        }else {
                            list.add(obj);
                        }
                    }
                    jsonMap.put(k , list);
                }else if(v instanceof JSONObject){
                    //第一层字段为对象 对象内部进行递归处理
                    jsonMap.put(k , dealJson(v.toString()));
                }else if(v instanceof String){
                    //第一层字段为字符串 直接处理
                    jsonMap.put(k , v.toString().trim());
                }else {
                    //其他
                    jsonMap.put(k , v);
                }
            });
        }
        return jsonMap;
    }

    //重写getInputStream(),最后程序回来调用这个方法
    @Override
    public ServletInputStream getInputStream() throws IOException {
        //bais处理过后的最新数据流
        final ByteArrayInputStream bais =new ByteArrayInputStream(body);
        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() {
                return bais.read();
            }
        };

    }

    //已下几个方法是设计参数读写处理 照着写就行
    public String getBody() {
        return new String(this.body, StandardCharsets.UTF_8);
    }

    @Override
    public String[] getParameterValues(String name) {
        return params.get(name);
    }

    @Override
    public Map<String,String[]> getParameterMap(){
        return this.params;
    }

    @Override
    public String getParameter(String name) {
        String[]values = params.get(name);
        if(values == null || values.length == 0) {
            return null;
        }
        return values[0];
    }

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

处理过程中自己造成的一些问题

1.本地测试get请求与post请求都可以,但是一部署到测试环境,还是会造成body丢失

解决:在自定义的ParameterTrimWrapper.getInputStream() 方法中,为了之过滤application/json的post请求,加了判断

public ServletInputStream getInputStream() throws IOException {
    //其他非application/json类型不做处理
    if(!super.getHeader("Content-Type").equalsIgnoreCase("application/json")){
         return super.getInputStream();
     }else{
         ByteArrayInputStream bais =new ByteArrayInputStream(this.body);

......

本地测试正常,但是测试环境中,Content-Type传的是application/json;charset=UTF-8导致一直调用原来的getInputStream(),所以导致到达接口的时候body丢失文章来源地址https://www.toymoban.com/news/detail-520490.html

到了这里,关于开发笔记 | JAVA过滤器Filter实现全局接口入参去除前后空格的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 033-安全开发-JavaEE应用&SQL预编译&Filter过滤器&Listener监听器&访问控制

    1、JavaEE-JDBC-SQL预编译 2、JavaEE-HTTP-Filter过滤器 3、JavaEE-对象域-Listen监听器 演示案例: ➢JavaEE-预编译-SQL ➢JavaEE-过滤器-Filter ➢JavaEE-监听器-Listen 提前编译好执行逻辑,你注入的语句不会改变原有逻辑! 预编译写法: safesql 是一个预编译的 SQL 查询语句,其中 ? 是一个占位符

    2024年02月22日
    浏览(51)
  • Filter 过滤器

    Filter过滤器介绍 这里我们讲解Filter的执行流程,从下图可以大致了解到,当客户端发送请求的时候,会经过过滤器,然后才能到我们的servlet,当我们的servlet处理完请求之后,我们的response还是先经过过滤器才能到达我们的客户端,这里我们进行一个代码的演示,看看具体执

    2024年02月02日
    浏览(46)
  • 认识Filter(过滤器)

    Filter介绍 在计算机编程中,Filter(过滤器)是一种用于对数据流进行处理的软件组件。Filter 的作用是从输入流中获取数据,对其进行处理后再将其写入输出流中。Filter 组件通常用于数据校验、数据转换、数据压缩等方面,以及对网络通信进行处理。在 Web 开发中,Filter 是

    2024年02月02日
    浏览(47)
  • 过滤器Filter

    什么是Filter? Filter表示过滤器,是JavaWeb三大组件(Servlet、FIlter、Listener)之一。 过滤器可以把对资源的请求拦截下来,总而实现一些特殊的功能 使用过滤器后,要想访问web服务器上的资源,必须先经过过滤器,过滤器处理完毕后,才可以访问对应的资源。 过滤器一般完成

    2023年04月12日
    浏览(40)
  • 结果过滤器—MVC项目中结果过滤器(Result Filter)使用

    结果过滤器( ResultFilter ),是对执行的Action结果进行处理的一种AOP思想,适用于任何需要直接环绕 View 或格式化处理的逻辑。结果过滤器可以 替换或更改 Action 结果 。在 IActionResult 执行的前后执行,使用它能够控制Action的执行结果,比如:格式化结果等。需要注意的是,它只

    2024年02月12日
    浏览(55)
  • 高级数据结构与算法 | 布谷鸟过滤器(Cuckoo Filter):原理、实现、LSM Tree 优化

    如果对布隆过滤器不太了解,可以看看往期博客:海量数据处理(一) :位图与布隆过滤器的概念以及实现 布隆过滤器 局限 对于需要处理海量数据的时候,如果我们需要快速判断一条记录是否,通常会使用过滤器来进行验证,而其中最常见的就是布隆过滤器(Bloom Filter)—

    2024年02月19日
    浏览(51)
  • SpringCloudGateway--过滤器(内置filter)

    目录 一、概览 二、内置过滤器 1、StripPrefix 2、AddRequestHeader 3、AddResponseHeader 4、DedupeResponseHeader 5、AddRequestParameter 6、CircuitBreaker 7、FallbackHeaders 8、RequestRateLimiter 9、RedirectTo 10、RemoveRequestHeader 11、RemoveResponseHeader 12、RemoveRequestParameter 13、RewritePath  14、RewriteResponseHeader  15、S

    2024年02月01日
    浏览(68)
  • JavaWeb 中 Filter过滤器

    @ 目录 Filter过滤器 每博一文案 1. Filter 过滤器的概述 2. Filter 过滤器的编写 3. Filter 过滤器的执行过程解析 3.1 Filter 过滤结合 Servlet 的使用 4. Filter 过滤器的拦截路径: 4.1 精确匹配路径 4.2 目录匹配 4.3 前后缀名路径匹配 4.4 所有路径匹配 5. 设置 Filter 执行顺序 6. Filter 过滤器中

    2024年02月03日
    浏览(52)
  • 布隆过滤器(Bloom Filter)

    通常我们会遇到很多要判断一个元素是否在某个集合中的业务场景,一般想到的是将集合中所有元素保存起来,然后通过比较确定。链表、树、散列表(又叫哈希表,Hash table)等等数据结构都是这种思路。但是随着集合中元素的增加,我们需要的存储空间也会呈现线性增长,

    2024年02月08日
    浏览(46)
  • gateway之过滤器(Filter)详解

    在Spring Cloud中,过滤器(Filter)是一种关键的组件,用于在微服务架构中处理和转换传入请求以及传出响应。过滤器位于服务网关或代理中,并通过拦截请求和响应流量来提供各种功能。 过滤器在请求的不同生命周期阶段执行特定的操作,例如鉴权、认证、请求转发、限流、

    2024年02月05日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包