springBoot 過濾器去除請(qǐng)求參數(shù)前后空格實(shí)例詳解
背景
用戶在前端頁面中不小心輸入的前后空格,為了防止因?yàn)榍昂罂崭裨蛞饦I(yè)務(wù)異常,所以我們需要去除參數(shù)的前后空格!
如果我們手動(dòng)去除參數(shù)前后空格,我們可以這樣做
@GetMapping(value = "/manualTrim") public void helloGet(String userName) { //手動(dòng)去空格 userName = userName == null ? null : userName.trim(); //或者通過谷歌工具類手動(dòng)去空格 String trim = StringUtils.trim(userName); }
這種方式需要每個(gè)接口參數(shù)都進(jìn)行手動(dòng)的去除首尾空格,顯然會(huì)讓代碼冗余,并不友好!所以我們應(yīng)該從項(xiàng)目整體思考,這里通過過濾器的方式去除請(qǐng)求參數(shù)前后空格。
我們來看下大致實(shí)現(xiàn)的流程
在SpringBoot中有兩種方式實(shí)現(xiàn)自定義Filter:
第一種是使用 @WebFilter 和 @ServletComponentScan 組合注解。
第二種是通過配置類注入 FilterRegistrationBean對(duì)象。
通過FilterRegistrationBean對(duì)象可以通過Order屬性改變順序,使用@WebFilter注解的方式只能根據(jù)過濾器名的類名順序執(zhí)行,添加@Order注解是無效的。
既然是通過過濾器獲取請(qǐng)求參數(shù)去除參數(shù)的首尾空格,那我們應(yīng)該考慮幾種情況的請(qǐng)求參數(shù)
- Get請(qǐng)求,請(qǐng)求參數(shù)放到url后面
- Post請(qǐng)求 請(qǐng)求參數(shù)放到url后面
- Post請(qǐng)求 請(qǐng)求參數(shù)放到body里面
第一種和第二種其實(shí)可以通過一種方式實(shí)現(xiàn)就是request.getParameter()方法。
Post中body請(qǐng)求參數(shù)我們可以通過使用流的方式,調(diào)用request.getInputStream()獲取流,然后從流中讀取參數(shù)。
一、實(shí)現(xiàn)代碼
1、注冊(cè)過濾器
/** * 通過FilterRegistrationBean注冊(cè)自定義過濾器TrimFilter */ @Configuration public class FilterConfig { /** * 注冊(cè)去除參數(shù)頭尾空格過濾器 */ @Bean public FilterRegistrationBean trimFilterRegistration() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setDispatcherTypes(DispatcherType.REQUEST); //注冊(cè)自定義過濾器 registration.setFilter(new TrimFilter()); //過濾所有路徑 registration.addUrlPatterns("/*"); //過濾器名稱 registration.setName("trimFilter"); //優(yōu)先級(jí)越低越優(yōu)先,這里說明最低優(yōu)先級(jí) registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE); return registration; } }
2、自定義過濾器TrimFilter
/** * 自定義過濾器 通過繼承OncePerRequestFilter實(shí)現(xiàn)每次請(qǐng)求該過濾器只被執(zhí)行一次 */ public class TrimFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { //自定義TrimRequestWrapper,在這里實(shí)現(xiàn)參數(shù)去空 TrimRequestWrapper requestWrapper = new TrimRequestWrapper(httpServletRequest); filterChain.doFilter(requestWrapper, httpServletResponse); } }
3、自定義TrimRequestWrapper類
TrimRequestWrapper類,其實(shí)也是最重要的一個(gè)類,繼承HttpServletRequestWrapper重寫getParameter,getParameterValues方法,getInputStream方法,前面的重寫
可以解決非json的參數(shù)首尾去空格,但如果是json請(qǐng)求的參數(shù)那就必須重寫getInputStream方法,從流中獲取參數(shù)進(jìn)行處理。
注意: request的輸入流只能讀取一次
/** * 自定義TrimRequestWrapper類 */ @Slf4j public class TrimRequestWrapper extends HttpServletRequestWrapper { /** * 保存處理后的參數(shù) */ private Map<String, String[]> params = new HashMap<String, String[]>(); public TrimRequestWrapper(HttpServletRequest request) { //將request交給父類,以便于調(diào)用對(duì)應(yīng)方法的時(shí)候,將其輸出 super(request); //對(duì)于非json請(qǐng)求的參數(shù)進(jìn)行處理 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) { //將請(qǐng)求的的參數(shù)轉(zhuǎn)換為map集合 Map<String, String[]> requestMap = request.getParameterMap(); log.info("kv轉(zhuǎn)化前參數(shù):" + JSON.toJSONString(requestMap)); this.params.putAll(requestMap); //去空操作 this.modifyParameterValues(); log.info("kv轉(zhuǎn)化后參數(shù):" + 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 參數(shù)從當(dāng)前類中的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類型的請(qǐng)求參數(shù)必須通過流才能獲取到值 * 這種獲取的參數(shù)的方式針對(duì)于內(nèi)容類型為文本類型,比如Content-Type:text/plain,application/json,text/html等 * 在springmvc中可以使用@RequestBody 來獲取 json數(shù)據(jù)類型 * 其他文本類型不做處理,重點(diǎn)處理json數(shù)據(jù)格式 * getInputStream() ,只有當(dāng)方法為post請(qǐng)求,且參數(shù)為json格式是,會(huì)被默認(rèn)調(diào)用 */ @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)) { //如果參數(shù)不是json格式則直接返回 return super.getInputStream(); } //為空,直接返回 String json = IOUtils.toString(super.getInputStream(), "utf-8"); if (StringUtils.isEmpty(json)) { return super.getInputStream(); } log.info("json轉(zhuǎn)化前參數(shù):" + json); //json字符串首尾去空格 JSONObject jsonObject = StringJsonUtils.JsonStrTrim(json); log.info("json轉(zhuǎn)化后參數(shù):" + jsonObject.toJSONString()); ByteArrayInputStream bis = new ByteArrayInputStream(jsonObject.toJSONString().getBytes("utf-8")); return new MyServletInputStream(bis); } }
二、測(cè)試
因?yàn)樯厦嬲f了三種情況,所以這里提供了3個(gè)接口來進(jìn)行測(cè)試
/** * 測(cè)試接口 * * @author xub * @date 2022/10/24 下午5:06 */ @Slf4j @RestController public class ParamController { /** * 1、Get請(qǐng)求測(cè)試首尾去空格 */ @GetMapping(value = "/getTrim") public String getTrim(@RequestParam String username, @RequestParam String phone) { return username + "&" + phone; } /** * 2、Post方法測(cè)試首尾去空格 */ @PostMapping(value = "/postTrim") public String postTrim(@RequestParam String username, @RequestParam String phone) { return username + "&" + phone; } /** * 3、post方法 json入?yún)?測(cè)試首尾去空格 */ @PostMapping(value = "/postJsonTrim") public String helloUser(@RequestBody UserDO userDO) { return JSONObject.toJSONString(userDO); } }
1、Get請(qǐng)求測(cè)試首尾去空格
請(qǐng)求url
http://localhost:8080/getTrim?username=張三 &phone= 18812345678
后臺(tái)輸出日志
: kv轉(zhuǎn)化前參數(shù):{"username":["張三 "],"phone":[" 18812345678"]}
: kv轉(zhuǎn)化后參數(shù):{"phone":["18812345678"],"username":["張三"]}
接口返回
張三&18812345678
說明首尾去空格成功!
2、Post方法測(cè)試首尾去空格
請(qǐng)求url
http://127.0.0.1:8080/postTrim?username=張三 &phone= 18812345678
后臺(tái)輸出日志
: kv轉(zhuǎn)化前參數(shù):{"username":["張三 "],"phone":[" 18812345678"]}
: kv轉(zhuǎn)化后參數(shù):{"phone":["18812345678"],"username":["張三"]}
接口返回
張三&18812345678
說明首尾去空格成功!
3、post方法 json參數(shù)測(cè)試首尾去空格
請(qǐng)求url
http://127.0.0.1:8080/postJsonTrim
請(qǐng)求參數(shù)和返回參數(shù)
注意 這個(gè)請(qǐng)求頭為Content-Type:application/json
后臺(tái)輸出日志
json轉(zhuǎn)化前參數(shù):{"phone":"18812345678 " ,"username":" 張三 "}
json轉(zhuǎn)化后參數(shù):{"phone":"18812345678","username":"張三"}
說明首尾去空格成功!
項(xiàng)目示例源碼: https://github.com/yudiandemingzi/spring-boot-study
以上就是springBoot 過濾器去除請(qǐng)求參數(shù)前后空格實(shí)例詳解的詳細(xì)內(nèi)容,更多關(guān)于springBoot 過濾器去除空格的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- spring?boot常見get?、post請(qǐng)求參數(shù)處理、參數(shù)注解校驗(yàn)、參數(shù)自定義注解校驗(yàn)問題解析
- SpringBoot如何獲取Get請(qǐng)求參數(shù)詳解
- springboot如何設(shè)置請(qǐng)求參數(shù)長(zhǎng)度和文件大小限制
- springboot整合logback打印日志,分文件
- Springboot2.x 使用 Log4j2 異步打印日志的實(shí)現(xiàn)
- Spring Boot配置AOP打印日志的全過程
- Spring Boot項(xiàng)目中如何對(duì)接口請(qǐng)求參數(shù)打印日志
相關(guān)文章
詳解JUC并發(fā)編程中的進(jìn)程與線程學(xué)習(xí)
這篇文章主要為大家詳細(xì)介紹了JUC并發(fā)編程中的進(jìn)程與線程學(xué)習(xí),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-03-03SpringBoot監(jiān)聽Nacos動(dòng)態(tài)修改日志級(jí)別的操作方法
線上系統(tǒng)的日志級(jí)別一般都是 INFO 級(jí)別,有時(shí)候需要查看 WARN 級(jí)別的日志,所以需要?jiǎng)討B(tài)修改日志級(jí)別,微服務(wù)項(xiàng)目中使用 Nacos 作為注冊(cè)中心,我們可以監(jiān)聽 Nacos 配置,修改日志級(jí)別,這篇文章主要介紹了SpringBoot監(jiān)聽Nacos動(dòng)態(tài)修改日志級(jí)別的操作方法,需要的朋友可以參考下2023-12-12Java使用System.currentTimeMillis()方法計(jì)算程序運(yùn)行時(shí)間的示例代碼
System.currentTimeMillis() 方法的返回類型為 long ,表示毫秒為單位的當(dāng)前時(shí)間,文中通過示例代碼介紹了計(jì)算 String 類型與 StringBuilder 類型拼接字符串的耗時(shí)情況,對(duì)Java計(jì)算程序運(yùn)行時(shí)間相關(guān)知識(shí)感興趣的朋友一起看看吧2022-03-03Spring 校驗(yàn)(validator,JSR-303)簡(jiǎn)單實(shí)現(xiàn)方式
這篇文章主要介紹了Spring 校驗(yàn)(validator,JSR-303)簡(jiǎn)單實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10Java設(shè)計(jì)模式之策略模式(Strategy模式)介紹
這篇文章主要介紹了Java設(shè)計(jì)模式之策略模式(Strategy模式)介紹,Strategy是屬于設(shè)計(jì)模式中對(duì)象行為型模式,要是定義一系列的算法,這些算法一個(gè)個(gè)封裝成單獨(dú)的類,需要的朋友可以參考下2015-03-03ArrayList詳解和使用示例_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
ArrayList 是一個(gè)數(shù)組隊(duì)列,相當(dāng)于 動(dòng)態(tài)數(shù)組。與Java中的數(shù)組相比,它的容量能動(dòng)態(tài)增長(zhǎng)。接下來通過本文給大家介紹arraylist詳解和使用示例代碼,需要的的朋友一起學(xué)習(xí)吧2017-05-05Intellij IDEA 添加jar包的三種方式(小結(jié))
這篇文章主要介紹了Intellij IDEA 添加jar包的三種方式(小結(jié)),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-08-08java.net.SocketException: Connection reset 解決方法
最近糾結(jié)致死的一個(gè)java報(bào)錯(cuò)java.net.SocketException: Connection reset 終于得到解決2013-03-03