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<String, String[]> params = new HashMap<String, String[]>();


    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<String, String[]> 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<String> set = params.keySet();
        Iterator<String> 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原稿和原圖片。其它情況一律禁止轉載!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章