SpringBoot版本:2.1.6.RELEASE
SpringMVC版本:5.1.8.RELEASE
当遇到前端没有填写的表单字段被作为空字符串传到后端时,在业务逻辑中处理显得有点蹩脚,那正常的解法应该是扩展Spring,毕竟Spring扩展性很强,这是基本思路。
注:这些解决问题的办法都是解决由Spring进行绑定的操作,比如自动创建一个类,将参数绑定上去。你自己通过HttpServletRequest.getParamenter("key")
是需要自己封装处理的的。
解决办法:
- 自己扩展实现一个ConfigurableWebBindingInitializer,注册为Bean,需要设置为较高优先级(不建议使用,因为SpringBoot中预留的口子不明显)
@InitBinder
+@ControllerAdvice
实现。@ControllerAdvice
标注的类中的方法被@InitBinder
标注后,所有Controller可用。(解决request.getParameter(“key”)的问题,如果是@RequestBody则无效)- @RequestBody的处理在
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#resolveArgument
,默认采用MappingJackson2HttpMessageConverter
进行解析,Jackson的配置是通过JacksonAutoConfiguration
,其中有Jackson2ObjectMapperBuilderCustomizer
可以配置jackson初始化时的ObjectMapper。
由于SpringBoot已经初始化了RequestMappingHandlerAdapter,因此不建议手动初始化覆盖,建议采用方案2进行扩展。
https://docs.spring.io/spring/docs/4.3.24.RELEASE/spring-framework-reference/htmlsingle/#mvc-ann-webbindinginitializer
SpringMVC接收参数后处理(前端空参数转为null)
第一种:普通的参数
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.context.request.WebRequest;
import java.util.Locale;
/**
* 请求参数处理
*
* @author obiteaaron
* @since 2019/12/26
*/
@ControllerAdvice
public class WebMvcControllerAdvice {
@InitBinder
public void initBinder(WebDataBinder binder, WebRequest webRequest, Locale locale) {
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
}
}
第二种:@RequestBody参数
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StringDeserializer;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import java.io.IOException;
/**
* @author obiteaaron
* @since 2019/12/26
*/
@Configuration
public class JacksonConfiguration {
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return new Jackson2ObjectMapperBuilderCustomizer() {
@Override
public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
jacksonObjectMapperBuilder.deserializerByType(String.class, new StringDeserializer() {
@Override
public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String deserialize = super.deserialize(p, ctxt);
if (deserialize != null && deserialize.equals("")) {
return null;
}
return deserialize;
}
});
}
};
}
}
此处有坑:SpringMVC在默认情况下,会在org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#addDefaultHttpMessageConverters
加上new MappingJackson2HttpMessageConverter()
出来的对象,并不是HttpMessageConvertersAutoConfiguration
创建出来的对象,导致Jackson2ObjectMapperBuilderCustomizer
不生效,这是个大坑啊。
解决办法:
第一种(推荐):通过org.springframework.web.servlet.config.annotation.WebMvcConfigurer#extendMessageConverters
扩展,剔除这个错误的,然后注入一个正确的。
或者直接通过org.springframework.web.servlet.config.annotation.WebMvcConfigurer#configureMessageConverters
注入正确的。
第二种:虽然new
的对象有问题,但是在Builder类中,设置了applicationContext,而org.springframework.http.converter.json.Jackson2ObjectMapperBuilder#configure
的最后一行,通过applicationContext设置了一个拦截器。这个拦截器是Jackson的拦截器,所以要自己实现,这里不实现,有兴趣可以自己看看。
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.removeIf(next -> next instanceof MappingJackson2HttpMessageConverter);
converters.add(mappingJackson2HttpMessageConverter);
}
}
重要的Spring类(自己去学习吧):
org.springframework.web.bind.support.WebBindingInitializer
org.springframework.web.bind.support.ConfigurableWebBindingInitializer#propertyEditorRegistrars
org.springframework.beans.PropertyEditorRegistrar
org.springframework.beans.propertyeditors.StringTrimmerEditor
org.springframework.format.support.DefaultFormattingConversionService
org.springframework.core.convert.support.GenericConversionService#converters
org.springframework.web.bind.annotation.InitBinder
org.springframework.web.bind.annotation.ControllerAdvice
参考:
https://chenzhihao.cc/2019/06/13/Springmvc%E8%AF%B7%E6%B1%82%E5%8F%82%E6%95%B0%E7%9A%84%E4%BC%98%E9%9B%85%E5%A4%84%E6%96%B9%E5%BC%8F/
https://blog.youkuaiyun.com/u012165930/article/details/78942938