spring boot 自定义参数过滤器,把传入的空字符转换成null方式

目录
  • spring boot 滤器,把传入的空字符转换成null
    • 自定义参数处理器
    • 应用启动类
  • springboot过滤器对请求参数去空格处理
    • 使用 FilterRegistrationBean 注册过滤器
    • 使用@WebFilter注册过滤器
    • 增加JSON字符串的处理

spring boot 滤器,把传入的空字符转换成null

废话不多说直接上代码

自定义参数处理器

public class MyStringArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
    @Override
    protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
        return  new NamedValueInfo("", false, ValueConstants.DEFAULT_NONE);
    }
    @Override
    protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
        String[] param = request.getParameterValues(name);
        if(param==null){
            return null;
        }
        if(StringUtils.isEmpty(param[0])){
            return null;
        }
        return param[0];
    }
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterType().equals(String.class);
    }
}

应用启动类

public class Applicaction extends WebMvcConfigurerAdapter {
    public static void main(String[] ags) {
        SpringApplication.run(Applicaction.class, ags);
    }
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        super.addArgumentResolvers(argumentResolvers);
        argumentResolvers.add(new MyStringArgumentResolver());
    }
}

springboot过滤器对请求参数去空格处理

测试人员提出,对所有接口的请求参数去空格处理。 因为接口比较多,所以考虑使用spring mvc的拦截器来实现,但是使用拦截器能获取到请求参数,却无法将修改后的参数返给HttpServletRequest 对象。

HttpServletRequest 提供的获取参数的方法:

String getParameter(String name);//键值对参数
Map<String,String[]> getParameterMap();//键值对参数
Enumeration <String> getParameterNames();//键值对参数
String[] getParameterValues(String name);//键值对参数
ServletInputStream getInputStream();// 文本参数,例如类型 application/json 等
BufferedReader getReader(); //文本参数,例如类型 application/json 等
Collection<Part> getParts();//表单提交, multipart/form-data 

之后考虑使用过滤器,在网上找到了方案。使用自定义Request对象继承HttpServletRequestWrapper,获取从过滤器传入的HttpServletRequest对象提取参数,并重写HttpServletRequestWrapper获取参数的方法。

springboot添加过滤器有两种方式:

  • 1、通过创建FilterRegistrationBean的方式
  • 2、 使用@WebFilter

在spring中这些过滤器的创建都需要交给spring容器管理

使用 FilterRegistrationBean 注册过滤器

1、封装request对象实体

继承HttpServletRequestWrapper 类用于扩展request。同时如果修改了原来request中参数内容,需要将其修改后的数据返回,所以需要重写获取参数的方法。

	package com.demo.springBootProject;
	import java.io.ByteArrayInputStream;
	import java.io.IOException;
	import java.io.InputStream;
	import java.util.Enumeration;
	import java.util.HashMap;
	import java.util.Map;
	import java.util.Map.Entry;
	import java.util.Set;
	import java.util.Vector;
	import javax.servlet.ReadListener;
	import javax.servlet.ServletInputStream;
	import javax.servlet.http.HttpServletRequest;
	import javax.servlet.http.HttpServletRequestWrapper;
	import org.apache.http.entity.ContentType;
	import org.apache.poi.util.IOUtils;

	/**
	 *重新封装request,并对请求参数做去空格处理
	 */
	public class ParameterTrimRequest  extends HttpServletRequestWrapper{

		 private Map<String, String[]> params = new HashMap<String, String[]>();//保存处理后的参数
		 private byte[] content; 

		    public ParameterTrimRequest(HttpServletRequest request) {
		        super(request);
		        this.params.putAll(request.getParameterMap());
		        this.modifyParameterValues(); //自定义方法,用于参数去重
		        if(ContentType.APPLICATION_JSON.getMimeType().equals(request.getContentType())){//对application/json数据格式的数据进行去空格处理
		        	this.content=IOUtils.toByteArray(request.getInputStream());//获取文本数据;
					// 对json字符串进行处理
					//....................
		        	}
		    }

			public void modifyParameterValues() {//将parameter的值去除空格后重写回去
				Set<Entry<String,String[]>> entrys=params.entrySet();
				for(Entry<String,String[]> entry :entrys) {
					String[] values=entry.getValue();
					for(int i=0;i<values.length;i++) {
						values[i] = values[i].trim();
					}
					this.params.put(entry.getKey(), values);
				}
		    }

		    @Override
		    public Enumeration<String> getParameterNames() {//重写getParameterNames()
		        return new Vector<String>(params.keySet()).elements();
		    }

		    @Override
		    public String getParameter(String name) {//重写getParameter()
		        String[] values = params.get(name);
		        if (values == null || values.length == 0) {
		            return null;
		        }
		        return values[0];
		    }

		    @Override
		    public String[] getParameterValues(String name) {//重写getParameterValues()
		        return params.get(name);
		    }

		   @Override
		   public Map<String,String[]> getParameterMap(){ //重写getParameterMap()
			   return this.params;
		   }
		@Override
  		public ServletInputStream getInputStream() throws IOException {
      	//  这种获取的参数的方式针对于内容类型为文本类型,比如Content-Type:text/plain,application/json,text/html等
      	//在springmvc中可以使用@RequestBody 来获取 json数据类型
  	 	//其他文本类型不做处理,重点处理json数据格式
			if(!super.getHeader("Content-Type").equalsIgnoreCase("application/json")){
            	   return super.getInputStream();
        	 }else{
        	 //根据自己的需要重新指定方法
        	 	ByteArrayInputStream in =new ByteArrayInputStream(this.content);
				return new ServletInputStream() {
					@Override
					public int read() throws IOException {
						return in.read();
					}

					@Override
					public int read(byte[] b, int off, int len) throws IOException {
						return in.read(b, off, len);
					}

					@Override
					public int read(byte[] b) throws IOException {
						return in.read(b);
					}

					@Override
					public void setReadListener(ReadListener listener) {
					}

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

					@Override
					public boolean isFinished() {
						return false;
					}

					@Override
					public long skip(long n) throws IOException {
						return in.skip(n);
					}

					@Override
					public void close() throws IOException {
						in.close();
					}

					@Override
					public synchronized void mark(int readlimit) {
						in.mark(readlimit);
					}

					@Override
					public synchronized void reset() throws IOException {
						in.reset();
					}
					};
        	 }
     	}
	}

返回结果是一个ServletInputStream它是InputStream的子类,因为没有重写reset方法,所以该字节流只能被获取一次。所以如果需要对表单提交的json参数处理,则getInputStream()方法需要重写。网上比较流行的做法是,将字节数据保存,然后封装成字节流。

ServletRequest 源码中获取字节流和字符流的方法

/**
*  Either this method or {@link #getInputStream} may be called to read the body, not both.
*  @exception IllegalStateException
*       if {@link #getInputStream} method has been called on this request
**/
public ServletInputStream getInputStream() throws IOException;
public BufferedReader getReader() throws IOException;

getInputSteam和getReader()方法是互斥的,只能调用一次。同时调用会抛出异常 IllegalStateException。

getInputSteam 方法重写最好限定数据类型。比如说文本类型(application/json,text/plain)。

对于Multipart/form-data提交类型,Tomcat会先调用了getInputStream方法获取请求体中的数据。

//Request.class      parseParameters
 if ("multipart/form-data".equals(contentType)) {
                parseParts(false);
                success = true;
                return;
   }

这样在后边再使用getInputSteam方法流中的数据就已经被读取完了。如果再不小心调用了getReader 方法 ,就会抛出异常。

java.lang.IllegalStateException: getInputStream() has already been called for this request

:::本地测试的结果,在filter中和spring mvc的拦截器中可以反复获取流数据。但是在controller中无法获取到空数据,很疑惑。 最后发现导错包了 【苦笑】

2、自定义过滤器

package com.demo.springBootProject.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
/**
 * 自定义过滤器,用于对请求参数去空格处理。
 */
public class ParameterTrimFilter implements Filter{
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
	}
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		ParameterTrimRequest trimReqeust= new ParameterTrimRequest((HttpServletRequest)request);
		chain.doFilter(trimReqeust, response);
	}
	@Override
	public void destroy() {
	}
}

3、创建Java配置类

有多个filter就创建多个FilterRegistrationBean ,若需注明filter的执行顺序,可通过registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE )配置,值越大,执行顺序越靠后

package com.demo.springBootProject.config;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.DispatcherType;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.demo.springBootProject.filter.ParameterTrimFilter;
/**
 * 用于添加自定义的bean
 */
@Configuration
public class CustomBean {
	/**
	 *该过滤器用于对请求参数做去空格处理
	 *@return FilterRegistrationBean<ParameterTrimFilter>
	 */
	@Bean(name="parameterTrimFilter") //不写name属性,默认beanName为方法名
	public FilterRegistrationBean<ParameterTrimFilter> parameterTrimFilter() {
		FilterRegistrationBean<ParameterTrimFilter> filter=new FilterRegistrationBean<>();
		filter.setDispatcherTypes(DispatcherType.REQUEST);
		filter.setFilter(new ParameterTrimFilter()); //必须设置
		filter.addUrlPatterns("/*"); //拦截所有请求,如果没有设置则默认“/*”
		filter.setName("parameterTrimFilter"); //设置注册的名称,如果没有指定会使用Bean的名称。此name也是过滤器的名称
		filter.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE);//该filter在filterChain中的执行顺序
		return filter;
	}
}

注意: 以上配置类所在包或者过滤器所在包必须在spring boot注解可以扫描的包或者子包下。如果springboot没有设置扫描包,则springboot会扫描启动类所在的包及其子包。

FilterRegistrationBean提供了多种方式来注册拦截的请求。

 void addUrlPatterns(String... urlPatterns)//向filter追加注册url
 void setUrlPatterns(Collection<String> urlPatterns)//覆盖之前已注册的url
 void addServletNames(String... servletNames)// 添加过滤的servletName
 void setServletNames(Collection<String> servletNames)//覆盖之前的拦截的servletName

拦截url和拦截servlet可以一起使用

使用@WebFilter注册过滤器

package com.demo.springBootProject.controller;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebFilter(filterName="test",urlPatterns= {"/*"})
public class TestFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
		//doSomthing
        chain.doFilter(request, response);
    }
    @Override
    public void destroy() {
	}
}

增加JSON字符串的处理

以上处理的是简单的数据类型,如果是json字符串,应当先解析json字符串,将其中的value字符串前后去空格。可以参考以下代码处理。

     public static void main(String[] args) {
               String str = "[\" 1\" ,\"2  \",\"4  \"]";
//        str = "{\"name\":\"张三  \"}";
//        str = "{\"name\":  {\"first_name\": \"张  \",\"last_name\":\"  三  \"}}";
        str = "[{'name':'  张三  '},{'name':'  李四  '},{'name':19}]";

        Object jsonObj = JSON.parse(str);
        if (jsonObj instanceof JSONObject) {
            JSONObject jsonObject = (JSONObject) jsonObj;
            parseJsonObject(jsonObject);
        } else if (jsonObj instanceof JSONArray) {
            JSONArray jsonArray = (JSONArray) jsonObj;
            parseJSONArray(jsonArray);
        }
        System.out.println(jsonObj);
    }
    public static void parseJsonObject(JSONObject jsonObject) {
        Set<String> keySet = jsonObject.keySet();
        for (String key : keySet) {
            parseObject(jsonObject, key);
        }
    }
    public static void parseJSONArray(JSONArray jsonArray) {
        if (jsonArray == null || jsonArray.isEmpty()) {
            return;
        }
        for (int i = 0; i < jsonArray.size(); i++) {
            parseArray(jsonArray, i);
        }
    }
    public static void parseObject(JSONObject jsonObject, String key) {
        Object keyObj = jsonObject.get(key);
        if (keyObj == null) {
            return;
        }
        if (keyObj instanceof String) {
            jsonObject.put(key, ((String) keyObj).trim());
        } else if (keyObj instanceof JSONObject) {
            //解析json 对象
            parseJsonObject(((JSONObject) keyObj));
        } else if (keyObj instanceof JSONArray) {
            //解析json 数组
            parseJSONArray(((JSONArray) keyObj));
        }
    }
    public static void parseArray(JSONArray jsonArray, int index) {
        Object keyObj = jsonArray.get(index);
        if (keyObj == null) {
            return;
        }
        if (keyObj instanceof String) {
            jsonArray.set(index, ((String) keyObj).trim());
        } else if (keyObj instanceof JSONObject) {
            //解析json 对象
            parseJsonObject(((JSONObject) keyObj));
        } else if (keyObj instanceof JSONArray) {
            //解析json 数组
            parseJSONArray(((JSONArray) keyObj));
        }
    }

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • SpringCloud Gateway自定义filter获取body中的数据为空的问题

    最近在使用SpringCloud Gateway进行网关的开发,我使用的版本是:SpringBoot的2.3.4.RELEASE+SpringCloud的Hoxton.SR8,在自定义过滤器时需要获取ServerHttpRequest中body的数据,发现一直无法获取到数据,经过各种百度.谷歌,再加上自己的实践,终于找到解决方案: 1.首先创建一个全局过滤器把body中的数据缓存起来 package com.cloudpath.gateway.portal.filter; import lomb

  • SpringBoot项目如何把接口参数中的空白值替换为null值(推荐)

    问题发生 我们公司代码生成的时候,查询列表统一都是使用了setEntity() ,查询写法如下: public List<BasReservoirArea> selectList(BasReservoirArea basReservoirArea) { QueryWrapper<BasReservoirArea> where = new QueryWrapper<>(); where.setEntity(basReservoirArea); return baseMap

  • 解决SpringBoot返回结果如果为null或空值不显示处理问题

    SpringBoot返回结果如果为null或空值不显示处理 第一种方法:自定义消息转换器 @Configuration public class WebMvcConfig extends WebMvcConfigurerAdapter{ // /** // * 利用fastjson替换掉jackson // * @param converters // */ @Override public void configureMessageConverters(List<HttpMessageConv

  • 使用Springboot自定义转换器实现参数去空格功能

    目录 自定义转换器实现参数去空格 1.自定义转换器类 2.将转换器交给spring容器处理 SpringBoot请求参数过滤空格 1.参数修改SpaceHttpServletRequestWrapper 2.空格过滤器 3.过滤器初始化 自定义转换器实现参数去空格 1.自定义转换器类 实现Converter<S, T>类,重写convert()方法,直接上代码. /** * 自定义转换器 * 去掉前后空格 * @author liuy * @version 2018年11月13日 */ pub

  • SpringBoot项目中处理返回json的null值(springboot项目为例)

    在后端数据接口项目开发中,经常遇到返回的数据中有null值,导致前端需要进行判断处理,否则容易出现undefined的情况,如何便捷的将null值转换为空字符串? 以SpringBoot项目为例,SSM同理. 1.新建配置类(JsonConfig.java) import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.f

  • spring boot 自定义参数过滤器,把传入的空字符转换成null方式

    目录 spring boot 滤器,把传入的空字符转换成null 自定义参数处理器 应用启动类 springboot过滤器对请求参数去空格处理 使用 FilterRegistrationBean 注册过滤器 使用@WebFilter注册过滤器 增加JSON字符串的处理 spring boot 滤器,把传入的空字符转换成null 废话不多说直接上代码 自定义参数处理器 public class MyStringArgumentResolver extends AbstractNamedValueM

  • Spring Boot 自定义 Shiro 过滤器无法使用 @Autowired问题及解决方法

    在 Spring Boot 中集成 Shiro,并使用 JWT 进行接口认证. 为了统一对 Token 进行过滤,所以自定义了一个 JwtTokenFilter 过滤器. 期间遇到了以下几个问题,这里逐一进行记录,以备日后查阅. 问题一:JwtTokenFilter 无法使用 @Autowired 因为自定义了一个 JWT Token 工具类,用来解析和创建 Token,JwtTokenFilter 中需要用到此工具类,这里本来可以直接手动进行 new 一个新的实例,但由于在 Spring 配置

  • Spring Boot 接口参数加密解密的实现方法

    因为有小伙伴刚好问到这个问题,松哥就抽空撸一篇文章和大家聊聊这个话题. 加密解密本身并不是难事,问题是在何时去处理?定义一个过滤器,将请求和响应分别拦截下来进行处理也是一个办法,这种方式虽然粗暴,但是灵活,因为可以拿到一手的请求参数和响应数据.不过 SpringMVC 中给我们提供了 ResponseBodyAdvice 和 RequestBodyAdvice,利用这两个工具可以对请求和响应进行预处理,非常方便. 所以今天这篇文章有两个目的: 分享参数/响应加解密的思路. 分享 Response

  • spring boot自定义log4j2日志文件的实例讲解

    背景:因为从 spring boot 1.4开始的版本就要用log4j2 了,支持的格式有json和xml两种格式,此次实践主要使用的是xml的格式定义日志说明. spring boot 1.5.8.RELEASE 引入log4j2的开发步骤如下: 1.首先把spring-boot-starter-web以及spring-boot-starter包下面的spring-boot-starter-logging排除,然后引入spring-boot-starter-log4j2包. <dependen

  • Spring boot进行参数校验的方法实例详解

    Spring boot开发web项目有时候我们需要对controller层传过来的参数进行一些基本的校验,比如非空.整数值的范围.字符串的长度.日期.邮箱等等.Spring支持JSR-303 Bean Validation API,可以方便的进行校验. 使用注解进行校验 先定义一个form的封装对象 class RequestForm { @Size(min = 1, max = 5) private String name; public String getName() { return n

  • spring boot+自定义 AOP 实现全局校验的实例代码

    最近公司重构项目,重构为最热的微服务框架 spring boot, 重构的时候遇到几个可以统一处理的问题,也是项目中经常遇到,列如:统一校验参数,统一捕获异常... 仅凭代码 去控制参数的校验,有时候是冗余的,但通过框架支持的 去控制参数的校验,是对于开发者很友好,先看下面的例子 @NotEmpty(message="手机号不能为空") @Size(min=11,max=11,message="手机号码长度不正确") @Pattern(regexp=StringUt

  • spring boot validation参数校验实例分析

    本文实例讲述了spring boot validation参数校验.分享给大家供大家参考,具体如下: 对于任何一个应用而言在客户端做的数据有效性验证都不是安全有效的,这时候就要求我们在开发的时候在服务端也对数据的有效性进行验证. Spring Boot自身对数据在服务端的校验有一个比较好的支持,它能将我们提交到服务端的数据按照我们事先的约定进行数据有效性验证. 1 pom依赖 <dependency> <groupId>org.springframework.boot</gr

  • Kotlin + Spring Boot 请求参数验证的代码实例

    编写 Web 应用程序的时候,经常要做的事就是要对前端传回的数据进行简单的验证,比如是否非空.字符长度是否满足要求,邮箱格式是否正确等等.在 Spring Boot 中,可以使用 Bean Validation (JSR-303) 技术通过注解的方式来进行参数验证. 准备 DTO 对象 data class UserRegisterModel( @get: NotEmpty(message = "User name is required") @get: Size(message =

  • spring boot 自定义starter的实现教程

    spring boot 使用 starter 解决了很多配置问题, 但是, 他是怎么来解决这些问题的呢? 这里通过一个简单的例子, 来看一下, starter是怎么来设置默认配置的. 一. 建 starter 项目 自定义的starter, 项目命名规范是: 自定义名-spring-boot-starter 先来看一下, 我最后的目录结构 1. 修改pom.xml文件 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns

  • Spring Boot自定义配置实现IDE自动提示功能

    一.背景 官方提供的spring boot starter的配置项,我们用IDE配置的时候一般都有自动提示的,如下图所示 而我们自己自定义的配置却没有,对开发非常不友好容易打错配置, 那这个是怎样实现的呢? 二.提示原理 IDE是通过读取配置信息的元数据而实现自动提示的,而元数据在目录 META-INF 中的 spring-configuration-metadata.json 或者 additional-spring-configuration-metadata.json 三.实现自动提示 以

随机推荐