springBoot 过滤器去除请求参数前后空格实例详解
雨点的名字 人气:0背景
用户在前端页面中不小心输入的前后空格,为了防止因为前后空格原因引起业务异常,所以我们需要去除参数的前后空格!
如果我们手动去除参数前后空格,我们可以这样做
@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注解是无效的。
既然是通过过滤器获取请求参数去除参数的首尾空格,那我们应该考虑几种情况的请求参数
- Get请求,请求参数放到url后面
- Post请求 请求参数放到url后面
- 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":"张三"}
说明首尾去空格成功!
加载全部内容