前言
ps:在接收
String
类型参数时,前后可能存在一些空格,如果未曾去除就直接保存的话,可能会对一些特殊的业务场景造成致命影响。为了杜绝这种情况,需要在接收参数时进行前后空格清除处理
1. 配置
1.1 接收 url 或 form 表单中的参数(get请求
)
对于这种情况,Spring MVC 提供了一个 org.springframework.beans.propertyeditors.StringTrimmerEditor
类,我们只需要在参数绑定中进行注册就行,方式如下
// 必须标记 @ControllerAdvice
@ControllerAdvice
public class ControllerStringParamTrimConfig {
@InitBinder
public void initBinder(WebDataBinder binder) {
StringTrimmerEditor stringTrimmerEditor = new StringTrimmerEditor(true);
binder.registerCustomEditor(String.class, stringTrimmerEditor);
}
}
1.2 接收Request Body中JSON或XML对象参数(post请求
)
Spring MVC 是使用 Jackson 对参数进行反序列化,所以对于 String 的处理是在 Jackson 中配置
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer2() {
return jacksonObjectMapperBuilder -> {
// 为 String 类型自定义反序列化操作
jacksonObjectMapperBuilder
.deserializerByType(String.class, new StdScalarDeserializer<String>(String.class) {
@Override
public String deserialize(JsonParser jsonParser, DeserializationContext ctx)
throws IOException {
// 去除前后空格
String data = StringUtils.trimWhitespace(jsonParser.getValueAsString());
// 如果为空返回 null
return StrUtil.isBlank(data) ? null : data;
}
});
};
}
2. 测试
2.1 Controller
@RestController
public class SpringTrimController {
@GetMapping("/url")
public String urlParam(String name) {
return name;
}
@PostMapping("/form")
public User formParam(User u) {
return u;
}
@PostMapping(value = "/body")
public User bodyParam(@RequestBody User u) {
return u;
}
}
2.2 对象
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2.3 测试类
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class SpringMvcStringTrimSamplesApplicationTests {
@Autowired
private MockMvc mockMvc;
private static final String PARAM = " test ";
private static final String RESULT = PARAM.trim();
@Test
public void url() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/url?name=" + PARAM))
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().string(RESULT));
}
@Test
public void form() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/form")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.content("name=" + PARAM)
)
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(MockMvcResultMatchers.jsonPath("$.name").value(RESULT));
}
@Test
public void body() throws Exception {
String json = "{\"name\":\"" + PARAM + "\"}";
mockMvc.perform(MockMvcRequestBuilders.post("/body")
.contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
.content(json)
)
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(MockMvcResultMatchers.jsonPath("$.name").value(RESULT));
}
@Test
public void xmlBody() throws Exception {
String json = "<root><name>" + PARAM + "</name></root>";
mockMvc.perform(MockMvcRequestBuilders.post("/body")
.contentType(MediaType.APPLICATION_XML_VALUE)
.content(json)
)
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(MockMvcResultMatchers.jsonPath("$.name").value(RESULT));
}
}
3. 重构
对与这种所有项目都需要的通用配置,我们应该抽取一个公共模块,然后通过引入依赖来实现自动配置
创建 commons 模块
创建自动配置类 WebMvcStringTrimAutoConfiguration
3.1 自动配置类:WebMvcStringTrimAutoConfiguration
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
public class WebMvcStringTrimAutoConfiguration {
@ControllerAdvice
public static class ControllerStringParamTrimConfig {
@InitBinder
public void initBinder(WebDataBinder binder) {
// 参数:去除两端空格后 空串是否转换为 null true:null false:""
StringTrimmerEditor stringTrimmerEditor = new StringTrimmerEditor(true);
// 为 String 类对象注册编辑器
binder.registerCustomEditor(String.class, stringTrimmerEditor);
}
}
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder
.deserializerByType(String.class, new StdScalarDeserializer<String>(String.class) {
@Override
public String deserialize(JsonParser jsonParser, DeserializationContext ctx)
throws IOException {
String res = StringUtils.trimWhitespace(jsonParser.getValueAsString());
return StrUtil.isBlank(res) ? null : res;
}
});
}
}
配置引入依赖后存在 SpringBootApplication ,EnableAutoConfiguration注解时自动配置
3.2 在 resurces 创建 META-INF/spring.factories 文件
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
自动配置类的路径.WebMvcStringTrimAutoConfiguration