springBoot过滤器去除请求参数前后空格

本文讲述了作者如何处理一起因用户在微信参数中多输入了一个空格导致的充值失败和订单生成失败的事故。通过排查日志,发现问题在于参数比对时的空格差异。解决方案是在SpringBoot项目中添加过滤器,去除请求参数的前后空格,以防止类似问题再次发生。代码示例给出了过滤器的配置和实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

springBoot过滤器去除请求参数前后空格

在一个阳光明媚的早晨,客服小姐姐甜美的声音照常的响起:”昨天客户平台数千条用户充值失败,钱打到客户手中了,但是订单生成失败“

啊这…这……阳光逐渐暗淡,温馨的画面变成了黑白,甜美的声音也逐渐变的刺耳。脑子中出现了四个字【重大事故】

细细思索一番,昨天?? 近一周都没有了新版本上线,怎么昨天出现问题???? 带着满脑子问号冲向工位

在这里插入图片描述

迅速走过以下操作
  1. 不信任原则 迅速验证消息的真实性(消息属实)
  2. 查错误数据,查看数据范围,评定事故等级(还好:51条失败订单)
  3. 回复客服以及上级,说明事情已经开始处理
  4. 根据上面出错数据查询日志,定位问题
    1. 经过比对用户更改了微信参数【前面多打一个空格】
    2. 微信回调参数与数据库中保存进行比对【多一个空格必定比对不成功】
    3. 结局就是,回调失败,订单生成失败
  5. 立刻联系客户修复错误参数(保证不再扩大事故范围)
  6. 立即着手修复错误数据,保证平台运行
  7. 随后进行程序优化【即增加过滤器去除请求参数前后空格】
是时候站起来喝杯茶,客户很好说话,没有问责,没有争吵。看看窗外的天,乌云散去,阳光逐渐洒满大地,依旧是温馨和谐的日常~

在这里插入图片描述

随后,附上代码

每个SpringBoot项目增加过滤器(对外提供API的模块,web网站模块,微信小程序模块。。。)

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterConfig {

    /**
     * 去除参数头尾空格过滤器
     *
     * @return
     */
    @Bean
    public FilterRegistrationBean trimFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setDispatcherTypes(DispatcherType.REQUEST);
        registration.setFilter(new TrimFilter());
        registration.addUrlPatterns("/*");
        registration.setName("TrimFilter");
        registration.setOrder(Integer.MAX_VALUE - 1);
        return registration;
    }
}

common(公共组件)中增加过滤器

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

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

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        filterChain.doFilter(new TrimHttpServletRequestWrapper((HttpServletRequest) servletRequest), servletResponse);
    }

    @Override
    public void destroy() {

    }
}
import org.apache.commons.io.IOUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class TrimHttpServletRequestWrapper extends javax.servlet.http.HttpServletRequestWrapper {

    private Map<String , String[]> params = new HashMap<>();

    public TrimHttpServletRequestWrapper(HttpServletRequest request) {
        // 将request交给父类,以便于调用对应方法的时候,将其输出,其实父亲类的实现方式和第一种new的方式类似
        super(request);
        //将参数表,赋予给当前的Map以便于持有request中的参数
        this.params.putAll(request.getParameterMap());
        this.modifyParameterValues();
    }
    /**
     * 重写getInputStream方法  post类型的请求参数必须通过流才能获取到值
     */
    @Override
    public ServletInputStream getInputStream() throws IOException {
        //非json类型,直接返回
        if(!super.getHeader(HttpHeaders.CONTENT_TYPE).equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE)){
            return super.getInputStream();
        }
        //为空,直接返回
        String json = IOUtils.toString(super.getInputStream(), "utf-8");
        if (!StringUtils.hasLength(json)) {
            return super.getInputStream();
        }
        ByteArrayInputStream bis = new ByteArrayInputStream(JsonTrimUtils.jsonTrim(json).getBytes("utf-8"));
        return new MyServletInputStream(bis);
    }
    /**
     * 将parameter的值去除空格后重写回去
     */
    public void modifyParameterValues(){
        Set<String> set =params.keySet();
        Iterator<String> it=set.iterator();
        while(it.hasNext()){
            String key= it.next();
            String[] values = params.get(key);
            for (int i = 0; i < values.length; i++) {
                values[i] = values[i].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);
    }

    class MyServletInputStream extends  ServletInputStream{
        private ByteArrayInputStream bis;
        public MyServletInputStream(ByteArrayInputStream bis){
            this.bis=bis;
        }
        @Override
        public boolean isFinished() {
            return true;
        }

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

        @Override
        public void setReadListener(ReadListener listener) {

        }
        @Override
        public int read() {
            return bis.read();
        }
    }

}

工具类,去除JSON中值前后空格

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONValidator;

import java.util.Iterator;
import java.util.Map;

/**
 * json工具类
 * @Version 1.0
 */
public final class JsonTrimUtils {
    /**
     * 构造器
     */
    private JsonTrimUtils() {
    }
 
    /**
     * 去除json值前后空格
     * @param jsonStr jsonStr
     * @return
     */
    public static JSON jsonTrim(String jsonStr) throws Exception {
        if (JSONValidator.from(jsonStr).getType() == JSONValidator.Type.Object) {
            return  jsonTrim(JSONObject.parseObject(jsonStr));
        } else if (JSONValidator.from(jsonStr).getType() == JSONValidator.Type.Array) {
            JSONArray array = JSONArray.parseArray(jsonStr);
            jsonTrimArray(array);
            return array;
        }
        //前后端联调传值类型不同,及早的暴露问题,避免隐藏问题。
        throw new Exception("非JSON参数");
    }
 
    /**
     * 去除json值前后空格
     * @param json jsonStr
     * @return
     */
    public static JSON jsonTrim(JSON json) throws Exception {
        if (json instanceof JSONObject) {
            return  jsonTrim(json);
        } else if (json instanceof JSONArray) {
            jsonTrimArray((JSONArray) json);
            return json;
        }
        throw new Exception("非JSON参数");
    }
 
    /**
     * 去除value的空格
     *
     * @param jsonObject jsonObject
     * @return
     */
    public static JSONObject jsonTrim(JSONObject jsonObject) {
        Iterator<Map.Entry<String, Object>> iterator = jsonObject.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Object> next = iterator.next();
            Object value = next.getValue();
            if (value != null) {
                if (value instanceof String) {
                    //清空值前后空格
                    jsonObject.put(next.getKey(), ((String) value).trim());
                } else if (value instanceof JSONObject) {
                    jsonTrim((JSONObject) value);
                } else if (value instanceof JSONArray) {
                    jsonTrimArray((JSONArray) value);
                }
            }
        }
 
        return jsonObject;
    }
 
    /**
     * 清空JSONArray 值前后空格
     * @param array
     */
    private static void jsonTrimArray(JSONArray array) {
        if (array.size() > 0) {
            for (int i = 0; i < array.size(); i++) {
                Object object = array.get(i);
                if (object != null) {
                    if (object instanceof String) {
                        array.set(i, ((String) object).trim());
                    } else if (object instanceof JSONObject) {
                        jsonTrim((JSONObject) object);
                    } else if (object instanceof JSONArray) {
                        jsonTrimArray((JSONArray) object);
                    }
                }
            }
        }
    }
}

JSON 的支持使用的JAR

<!-- Json解析 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.69_sec11</version>
</dependency>

在这里插入图片描述

在此就全部搞定了,有需要的复制即可使用,有用就关注一下吧
可以通过编写一个自定义的过滤器来实现过滤参数前后空格。具体步骤如下: 1. 创建一个过滤器类,实现javax.servlet.Filter接口。 2. 在过滤器类中实现doFilter方法,在方法中对请求参数进行处理,去除前后空格,并将处理后的参数重新设置到请求对象中。 3. 在Spring Boot应用中注册该过滤器,可以通过在@Configuration注解的配置类中添加一个@Bean注解来实现。 下面是一个示例代码: ```java import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Component; @Component public class TrimFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; TrimmedHttpServletRequest trimmedRequest = new TrimmedHttpServletRequest(httpRequest); chain.doFilter(trimmedRequest, response); } private static class TrimmedHttpServletRequest extends HttpServletRequestWrapper { public TrimmedHttpServletRequest(HttpServletRequest request) { super(request); } @Override public String getParameter(String name) { String value = super.getParameter(name); return value != null ? value.trim() : null; } } } ``` 在上面的代码中,我们使用了一个内部类TrimmedHttpServletRequest来封装原始的HttpServletRequest对象,并重写了其getParameter方法来实现参数前后空格过滤。 最后,我们在@Configuration注解的配置类中添加一个@Bean注解来注册该过滤器: ```java import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FilterConfig { @Bean public FilterRegistrationBean<TrimFilter> trimFilter() { FilterRegistrationBean<TrimFilter> registration = new FilterRegistrationBean<>(); registration.setFilter(new TrimFilter()); registration.addUrlPatterns("/*"); return registration; } } ``` 在上面的代码中,我们使用了FilterRegistrationBean来注册TrimFilter过滤器,并将其应用于所有的请求路径。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值