• springBoot 过滤器去除请求参数前后空格(附源码)


    背景 : 用户在前端页面中不小心输入的前后空格,为了防止因为前后空格原因引起业务异常,所以我们需要去除参数的前后空格!

    如果我们手动去除参数前后空格,我们可以这样做

        @GetMapping(value = "/manualTrim")
        public void helloGet(String userName) {
            //手动去空格
            userName = userName == null ? null : userName.trim();
            //或者通过谷歌工具类手动去空格
             String trim = StringUtils.trim(userName);
        }
    

    这种方式需要每个接口参数都进行手动的去除首尾空格,显然会让代码冗余,并不友好!所以我们应该从项目整体思考,这里通过过滤器的方式去除请求参数前后空格。

    我们来看下大致实现的流程

    在SpringBoot中有两种方式实现自定义Filter:

    第一种是使用 @WebFilter@ServletComponentScan 组合注解。

    第二种是通过配置类注入 FilterRegistrationBean对象。

    通过FilterRegistrationBean对象可以通过Order属性改变顺序,使用@WebFilter注解的方式只能根据过滤器名的类名顺序执行,添加@Order注解是无效的。

    既然是通过过滤器获取请求参数去除参数的首尾空格,那我们应该考虑几种情况的请求参数

    1. Get请求,请求参数放到url后面
    2. Post请求 请求参数放到url后面
    3. Post请求 请求参数放到body里面

    第一种和第二种其实可以通过一种方式实现就是request.getParameter()方法。

    Post中body请求参数我们可以通过使用流的方式,调用request.getInputStream()获取流,然后从流中读取参数。


    一、实现代码

    1、注册过滤器

    /**
     *  通过FilterRegistrationBean注册自定义过滤器TrimFilter
     */
    @Configuration
    public class FilterConfig {
    
        /**
         * 注册去除参数头尾空格过滤器
         */
        @Bean
        public FilterRegistrationBean trimFilterRegistration() {
            FilterRegistrationBean registration = new FilterRegistrationBean();
            registration.setDispatcherTypes(DispatcherType.REQUEST);
            //注册自定义过滤器
            registration.setFilter(new TrimFilter());
            //过滤所有路径
            registration.addUrlPatterns("/*");
            //过滤器名称
            registration.setName("trimFilter");
            //优先级越低越优先,这里说明最低优先级
            registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE);
            return registration;
        }
    }
    

    2、自定义过滤器TrimFilter

    /**
     *  自定义过滤器  通过继承OncePerRequestFilter实现每次请求该过滤器只被执行一次
     */
    public class TrimFilter extends OncePerRequestFilter {
        @Override
        protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain)
                throws ServletException, IOException {
            //自定义TrimRequestWrapper,在这里实现参数去空
            TrimRequestWrapper requestWrapper = new TrimRequestWrapper(httpServletRequest);
            filterChain.doFilter(requestWrapper, httpServletResponse);
        }
    }
    

    3、自定义TrimRequestWrapper类

    TrimRequestWrapper类,其实也是最重要的一个类,继承HttpServletRequestWrapper重写getParameter,getParameterValues方法,getInputStream方法,前面的重写

    可以解决非json的参数首尾去空格,但如果是json请求的参数那就必须重写getInputStream方法,从流中获取参数进行处理。

    注意: request的输入流只能读取一次

    /**
     * 自定义TrimRequestWrapper类
     */
    @Slf4j
    public class TrimRequestWrapper extends HttpServletRequestWrapper {
    
        /**
         * 保存处理后的参数
         */
        private Map params = new HashMap();
    
    
        public TrimRequestWrapper(HttpServletRequest request) {
            //将request交给父类,以便于调用对应方法的时候,将其输出
            super(request);
            //对于非json请求的参数进行处理
            if (super.getHeader(HttpHeaders.CONTENT_TYPE) == null ||
                    (!super.getHeader(HttpHeaders.CONTENT_TYPE).equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE) &&
                            !super.getHeader(HttpHeaders.CONTENT_TYPE).equalsIgnoreCase(MediaType.APPLICATION_JSON_UTF8_VALUE))) {
                setParams(request);
            }
        }
    
        private void setParams(HttpServletRequest request) {
            //将请求的的参数转换为map集合
            Map requestMap = request.getParameterMap();
            log.info("kv转化前参数:" + JSON.toJSONString(requestMap));
            this.params.putAll(requestMap);
            //去空操作
            this.modifyParameterValues();
            log.info("kv转化后参数:" + JSON.toJSONString(params));
        }
    
        /**
         * 将parameter的值去除空格后重写回去
         */
        public void modifyParameterValues() {
            Set set = params.keySet();
            Iterator it = set.iterator();
            while (it.hasNext()) {
                String key = it.next();
                String[] values = params.get(key);
                values[0] = values[0].trim();
                params.put(key, values);
            }
    
        }
    
        /**
         * 重写getParameter 参数从当前类中的map获取
         */
        @Override
        public String getParameter(String name) {
            String[] values = params.get(name);
            if (values == null || values.length == 0) {
                return null;
            }
            return values[0];
        }
    
        /**
         * 重写getParameterValues
         */
        @Override
        public String[] getParameterValues(String name) {
            return params.get(name);
        }
    
    
        /**
         * 重写getInputStream方法  post类型的请求参数必须通过流才能获取到值
         * 这种获取的参数的方式针对于内容类型为文本类型,比如Content-Type:text/plain,application/json,text/html等
         * 在springmvc中可以使用@RequestBody 来获取 json数据类型
         * 其他文本类型不做处理,重点处理json数据格式
         * getInputStream() ,只有当方法为post请求,且参数为json格式是,会被默认调用
         */
        @Override
        public ServletInputStream getInputStream() throws IOException {
            //
            if (!super.getHeader(HttpHeaders.CONTENT_TYPE).equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE) &&
                    !super.getHeader(HttpHeaders.CONTENT_TYPE).equalsIgnoreCase(MediaType.APPLICATION_JSON_UTF8_VALUE)) {
                //如果参数不是json格式则直接返回
                return super.getInputStream();
            }
            //为空,直接返回
            String json = IOUtils.toString(super.getInputStream(), "utf-8");
            if (StringUtils.isEmpty(json)) {
                return super.getInputStream();
            }
            log.info("json转化前参数:" + json);
            //json字符串首尾去空格
            JSONObject jsonObject = StringJsonUtils.JsonStrTrim(json);
            log.info("json转化后参数:" + jsonObject.toJSONString());
            ByteArrayInputStream bis = new ByteArrayInputStream(jsonObject.toJSONString().getBytes("utf-8"));
            return new MyServletInputStream(bis);
        }
        
    }
    

    二、测试

    因为上面说了三种情况,所以这里提供了3个接口来进行测试

    /**
     * 测试接口
     *
     * @author xub
     * @date 2022/10/24 下午5:06
     */
    @Slf4j
    @RestController
    public class ParamController {
    
        /**
         * 1、Get请求测试首尾去空格
         */
        @GetMapping(value = "/getTrim")
        public String getTrim(@RequestParam String username, @RequestParam String phone) {
            return username + "&" + phone;
        }
    
        /**
         * 2、Post方法测试首尾去空格
         */
        @PostMapping(value = "/postTrim")
        public String postTrim(@RequestParam String username, @RequestParam String phone) {
            return username + "&" + phone;
        }
    
        /**
         * 3、post方法 json入参 测试首尾去空格
         */
        @PostMapping(value = "/postJsonTrim")
        public String helloUser(@RequestBody UserDO userDO) {
            return JSONObject.toJSONString(userDO);
        }
    }
    
    

    1、Get请求测试首尾去空格

    请求url

    http://localhost:8080/getTrim?username=张三 &phone= 18812345678
    

    后台输出日志

    : kv转化前参数:{"username":["张三 "],"phone":[" 18812345678"]}
    : kv转化后参数:{"phone":["18812345678"],"username":["张三"]}
    

    接口返回

    张三&18812345678
    

    说明首尾去空格成功!

    2、Post方法测试首尾去空格

    请求url

    http://127.0.0.1:8080/postTrim?username=张三 &phone= 18812345678
    

    后台输出日志

    : kv转化前参数:{"username":["张三 "],"phone":[" 18812345678"]}
    : kv转化后参数:{"phone":["18812345678"],"username":["张三"]}
    

    接口返回

    张三&18812345678
    

    说明首尾去空格成功!

    3、post方法 json参数测试首尾去空格

    请求url

    http://127.0.0.1:8080/postJsonTrim
    

    请求参数和返回参数

    注意 这个请求头为Content-Type:application/json

    后台输出日志

    json转化前参数:{"phone":"18812345678 " ,"username":" 张三 "}
    json转化后参数:{"phone":"18812345678","username":"张三"}
    

    说明首尾去空格成功!

    项目示例源码: https://github.com/yudiandemingzi/spring-boot-study



    声明: 公众号如需转载该篇文章,发表文章的头部一定要 告知是转至公众号: 后端元宇宙。同时也可以问本人要markdown原稿和原图片。其它情况一律禁止转载!

  • 相关阅读:
    知识蒸馏原理与PVKD论文阅读
    uniapp配置了pages.json 的 tabbar 国际化,小程序切换语言没有实时切换
    好物周刊#11:远程桌面软件
    【云原生】Dcoker实战:Linux环境安装mysql8.0.27安装步骤
    深入理解安卓ARouter:集成与应用
    AI应用开发:pgvector能帮你解决什么问题
    【ICer的脚本练习】通过perl脚本来检查仿真log的结果
    【自动驾驶】碰撞检测算法
    PDCA循环
    SpringBoot入门
  • 原文地址:https://www.cnblogs.com/qdhxhz/p/16826233.html