springboot項目攔截前端請求中的特殊字符串(解決方案)
項目場景:
springboot項目中,需要對前端請求數(shù)據(jù)進(jìn)行過濾,攔截特殊字符。
問題描述
GET請求可以很方便的通過處理URL判斷是否包含特殊字符,POST類型請求需要對form-data/json特殊處理,使用@RequestBody注解的controller獲取不到數(shù)據(jù)
原因分析:
request中的getInputStream()方法和getReader()方法只能獲取一次數(shù)據(jù),通過@RequestBody注解再次獲取getInputStream()拿到結(jié)果為空,此處通過重寫getInputStream()方法和getReader()解決。貼出完整代碼如下。
解決方案:
1、注冊攔截器
package com.xxx; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * @author lsh * @version 1.0 * @date 2022/4/1 16:54 */ @Configuration public class SpecialCharConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { if(registry!=null){ registry.addInterceptor(new SpecialCharInterceptor()).addPathPatterns("/**"); } } }
2、注冊過濾器
package com.xxx; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import java.io.IOException; /** * @author lsh * @version 1.0 * @date 2022/4/1 17:03 */ @Component @WebFilter(filterName="specialCharFilter",urlPatterns="/*") public class SpecialCharFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException { ServletRequest requestWrapper = null; if (request instanceof HttpServletRequest){ requestWrapper = new SpecialCharHttpServletRequestWrapper((HttpServletRequest) request); } // 獲取請求中的流,將取出來的字符串,再次轉(zhuǎn)換成流,然后把它放入到新request對象中 // 在chain.doFiler方法中傳遞新的request對象 if(requestWrapper == null) { chain.doFilter(request, response); } else { chain.doFilter(requestWrapper, response); } } @Override public void destroy() { } }
3、自定義保存流數(shù)據(jù)
package com.xxx; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.Charset; import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; /** * 自定義保存流數(shù)據(jù) * @author lsh * @version 1.0 * @date 2022/4/1 16:56 */ public class SpecialCharHttpServletRequestWrapper extends HttpServletRequestWrapper { public final HttpServletRequest request; private final String bodyStr; public SpecialCharHttpServletRequestWrapper(HttpServletRequest request) throws IOException { super(request); this.request = request; this.bodyStr = getBodyString(); } /** * 獲取請求Body * @return */ public String getBodyString() { StringBuilder sb = new StringBuilder(); InputStream inputStream = null; BufferedReader reader = null; try { inputStream = cloneInputStream(request.getInputStream()); reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8"))); String line = ""; while ((line = reader.readLine()) != null) { sb.append(line); } } catch (IOException e) { e.printStackTrace(); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } return sb.toString(); } /** * 復(fù)制輸入流 * @param inputStream 輸入流 * @return */ public InputStream cloneInputStream(ServletInputStream inputStream) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len; try { while ((len = inputStream.read(buffer)) > -1) { byteArrayOutputStream.write(buffer, 0, len); } byteArrayOutputStream.flush(); } catch (IOException e) { e.printStackTrace(); } InputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); return byteArrayInputStream; } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream())); } @Override public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream bais = new ByteArrayInputStream(bodyStr.getBytes(Charset.forName("UTF-8"))); return new ServletInputStream() { @Override public int read() throws IOException { return bais.read(); } @Override public void setReadListener(ReadListener listener) { } @Override public boolean isReady() { return false; } @Override public boolean isFinished() { return false; } }; } }
4、特殊字符攔截類(application/json的數(shù)據(jù)格式只能為json和json數(shù)組,根據(jù)業(yè)務(wù)場景自行調(diào)整)
package com.xxx; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.TypeReference; import org.apache.commons.lang3.StringUtils; import javax.servlet.http.HttpServletRequest; import java.io.*; import java.net.URLDecoder; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * 攔截請求中包含的特殊字符 * @author lsh * @version 1.0 * @date 2022/4/1 16:27 */ public class UrlFilter { /** * 特殊字符正則表達(dá)式 */ private final static String REG_EX = "[`~!@#$%^*()+|{}\\[\\].<>/??。ǎ尽俊?;:”“'。,、\\\\]"; /** * 判斷url中是否含有特殊字符 * @param urls 前端請求鏈接 * @return 是否包含特殊字符 */ public static boolean checkSpecials(String urls) { try { if (StringUtils.isNotEmpty(urls)) { // url參數(shù)轉(zhuǎn)義 urls = URLDecoder.decode(urls, "utf-8"); if (Pattern.compile(REG_EX).matcher(urls).find()) { return true; } } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return false; } /** * 判斷formData值對象中是否包含特殊字符 * @param map formData值對象 * @return 是否包含特殊字符 */ public static boolean checkSpecials(Map<String,String[]> map){ if(!map.isEmpty()){ for(String[] paraArray : map.values()){ for(String paraStr : paraArray){ if(Pattern.compile(REG_EX).matcher(paraStr).find()){ return true; } } } } return false; } /** * 判斷前端傳過來的json和json數(shù)組中是否含有特殊字符 * @param request 前端請求(包含json數(shù)據(jù)) * @return 是否包含特殊字符 */ public static boolean checkSpecials(HttpServletRequest request) { try { SpecialCharHttpServletRequestWrapper wrapper = new SpecialCharHttpServletRequestWrapper(request); InputStream is = wrapper.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); StringBuilder sb = new StringBuilder(); String line; while ((line = br.readLine()) != null) { sb.append(line); } if (sb.length() > 0) { //判斷json是否包含list數(shù)組,包含則先遍歷數(shù)組再遍歷對象值 if (sb.toString().contains("[")){ List<Object> objectList = JSONObject.parseObject(sb.toString(), new TypeReference<List<Object>>() {}); for(Object objTemp:objectList){ Map<String, Object> map = JSONObject.parseObject(JSONObject.parseObject(objTemp.toString()).toJSONString(), new TypeReference<Map<String, Object>>() {}); for (Object object : map.values()) { if (object != null) { Matcher m = Pattern.compile(REG_EX).matcher(object.toString()); if (m.find()) { return true; } } } } }else{ Map<String, Object> map = JSONObject.parseObject(JSONObject.parseObject(sb.toString()).toJSONString(), new TypeReference<Map<String, Object>>() {}); for (Object object : map.values()) { if (object != null) { Matcher m = Pattern.compile(REG_EX).matcher(object.toString()); if (m.find()) { return true; } } } } } } catch (IOException e) { e.printStackTrace(); } return false; } }
5、實現(xiàn)攔截器
package com.xxx; import org.springframework.lang.Nullable; import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.MultipartResolver; import org.springframework.web.multipart.commons.CommonsMultipartResolver; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 特殊字符過濾 * @author lsh * @version 1.0 * @date 2022/4/1 16:25 */ public class SpecialCharInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { if("GET".equals(httpServletRequest.getMethod())){ if(UrlFilter.checkSpecials(httpServletRequest.getQueryString())){ throw new Exception("url中包含特殊字符"); } }else{ String contentType = httpServletRequest.getContentType(); //處理form-data請求類型數(shù)據(jù)值 if (contentType != null && contentType.contains("multipart/form-data")) { MultipartResolver resolver = new CommonsMultipartResolver(httpServletRequest.getSession().getServletContext()); MultipartHttpServletRequest multipartRequest = resolver.resolveMultipart(httpServletRequest); if(UrlFilter.checkSpecials(multipartRequest.getParameterMap())){ throw new Exception("請求參數(shù)中包含特殊字符"); } } else{ if(UrlFilter.checkSpecials(httpServletRequest)){ throw new Exception("請求的數(shù)據(jù)中包含特殊字符 "); } } } return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { } }
到此這篇關(guān)于springboot項目攔截前端請求中的特殊字符串的文章就介紹到這了,更多相關(guān)springboot攔截特殊字符串內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何從eureka獲取服務(wù)的ip和端口號進(jìn)行Http的調(diào)用
這篇文章主要介紹了如何從eureka獲取服務(wù)的ip和端口號進(jìn)行Http的調(diào)用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03一文教你利用Stream?API批量Mock數(shù)據(jù)的方法
在日常開發(fā)的過程中我們經(jīng)常會遇到需要mock一些數(shù)據(jù)的場景,比如說?mock?一些接口的返回或者說?mock?一些測試消息用于隊列生產(chǎn)者發(fā)送消息。本文將教你如何通過?Stream?API?批量?Mock?數(shù)據(jù),需要的可以參考一下2022-09-09詳解SpringBoot如何實現(xiàn)多環(huán)境配置
在實際的軟件開發(fā)過程中,一個應(yīng)用程序通常會有多個環(huán)境,pring?Boot?提供了一個非常靈活和強(qiáng)大的方式來管理這些環(huán)境配置,下面就跟隨小編一起學(xué)習(xí)一下吧2023-07-07java統(tǒng)計漢字字?jǐn)?shù)的方法示例
這篇文章主要介紹了java統(tǒng)計漢字字?jǐn)?shù)的方法,結(jié)合實例形式分析了java正則判定、字符串遍歷及統(tǒng)計相關(guān)操作技巧,需要的朋友可以參考下2017-05-05java 查找list中重復(fù)數(shù)據(jù)實例詳解
這篇文章主要介紹了java 查找list中重復(fù)數(shù)據(jù)實例詳解的相關(guān)資料,需要的朋友可以參考下2017-01-01SpringCloud Config連接git與數(shù)據(jù)庫流程分析講解
springcloud config是一個解決分布式系統(tǒng)的配置管理方案。它包含了 client和server兩個部分,server端提供配置文件的存儲、以接口的形式將配置文件的內(nèi)容提供出去,client端通過接口獲取數(shù)據(jù)、并依據(jù)此數(shù)據(jù)初始化自己的應(yīng)用2022-12-12Reactor定制一個生產(chǎn)的WebClient實現(xiàn)示例
這篇文章主要為大家介紹了Reactor定制一個生產(chǎn)的WebClient實現(xiàn)示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08