背景
在我们的工程中,要考虑到一些人工的上的错误,一个很常见的错误就是输入参数,前后都有空格,这个在进入controller 的时候,我们就应该去掉。技术背景为ssm框架。
1.考虑AOP
- 在进入controller层的时候做一个切面,在切面的时候进行得到入参的类型,然后通过反射的思想,进行遍历对象里面的类型,如果是String类型的话,就trim操作重新赋值进去。
- 问题1:如果入参本身就是String类型,就需要进行修改String类型里面的char[]value这个数组,不然无法设置进去。
- 缺点:就是在使用反射的时候,如果对象里面还有对象,里面的对象的里面还有String类型的话,按理来说是要进行trim的,这样就是要进行递归操作,进行trim,对性能的代价很大。
2.重写DataBinder
- Databinder 类型是spring mvc 里面进行入参绑定的类,里面有一个方法叫做getTarget()这个方法,是得到目标类型的,我们在工程进行覆写这个类的getTarget()方法,在通过tomcat加载类的顺序不同,让加载器优先加载我们的类,从而达到trim的操作。
- 缺点:改动比较大,改了只有相当如每个参数都会走这个方法,但是有一些String是需要空格进行的,这样就造成了风险比较大。
3.StringTrimmerEditor + 重写ObjectMapper
- 以上的方法都是有风险或者不足,其实spring mvc 提供了很多的扩展点。我们通过注册的方式就行。
MyStringTrimmerEditor
@ControllerAdvice public class MyStringTrimmerEditor implements WebBindingInitializer { @InitBinder public void initBinder(WebDataBinder webDataBinder, WebRequest webRequest) { webDataBinder.registerCustomEditor(String.class,new StringTrimmerEditor(true)); } }
- 上面就是将spring的StringTrimmerEditor进行属性的绑定,StringTrimmerEditor是spring 实现的将String类型的值进行trim的editor类,但是默认为不添加的,但是我们现在可以添加,这样完成60%了。
- 剩下40%
- StringTrimmerEditor可以进行处理的是原始的HttpServletRequest里面的getParameter方法,但是如果为Body的内容,已流的形式进行转化的就不行了,最典型就是json格式。这个里面spring 默认的实现是MappingJackson2XmlHttp-MessageConverter进行实现的,而进行转化的是Jackson这个json转化的工具类型,我们只要实现自己的objectMapper来进行处理String的时候trim就行了。
@Component("customObjectMapper")
public class CustomObjectMapper extends ObjectMapper {
public CustomObjectMapper() {
CustomSerializerFactory factory = new CustomSerializerFactory();
factory.addGenericMapping(Date.class, new JsonSerializer<Date>() {
@Override
public void serialize(Date value, JsonGenerator jsonGenerator,
SerializerProvider provider) throws IOException, JsonProcessingException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
jsonGenerator.writeString(sdf.format(value));
}
});
this.setSerializerFactory(factory);
}
}
将这个进行注册到MappingJackson2XmlHttpMessageConverter类的objectMapper属性中就行。
测试
- 测试是最重要的,使用的是mock controller 来进行实现的。
/**
* Created by 黄建辉 on 2016/11/30.
*/
@RestController
@RequestMapping("/demo")
public class DemoController {
@RequestMapping(value="/getGetData",method = RequestMethod.GET)
public AttachAppQueryRequest returnData(AttachAppQueryRequest demo){
return demo;
}
@RequestMapping(value="/getPostData",method = RequestMethod.POST)
public AttachAppQueryRequest returnPostData(AttachAppQueryRequest demo){
return demo;
}
@RequestMapping(value="/getJsonData",method = RequestMethod.POST)
public AttachAppQueryRequest returnJsonData(@RequestBody AttachAppQueryRequest demo){
return demo;
}
@RequestMapping(value="/getStringData",method = RequestMethod.POST)
public String returnJsonData(String name){
return name;
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class StudentServiceImplTest {
protected MockMvc mockMvc;
@Autowired
protected WebApplicationContext wac;
@Before()
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); //初始化MockMvc对象
}
@Test
public void returnGetData() throws Exception {
String responseString = mockMvc.perform(
get("/demo/getGetData")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.param("moduleCode"," root ")
.param("dataCode"," code ")
.param("actionCode","11")
.param("actionType","12312")
).andExpect(status().isOk()) //返回的状态是200
.andDo(print()) //打印出请求和相应的内容
.andReturn().getResponse().getContentAsString(); //将相应的数据转换为字符串
AttachAppQueryRequest request = JSON.parseObject(responseString,AttachAppQueryRequest.class);
Assert.assertEquals("root",request.getModuleCode());
Assert.assertEquals("code",request.getDataCode());
}
@Test
public void returnPostData() throws Exception {
String responseString = mockMvc.perform(
post("/demo/getPostData")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.param("moduleCode"," root ")
.param("dataCode"," code ")
.param("actionCode","11")
.param("actionType","12312")
).andExpect(status().isOk()) //返回的状态是200
.andDo(print()) //打印出请求和相应的内容
.andReturn().getResponse().getContentAsString(); //将相应的数据转换为字符串
AttachAppQueryRequest request = JSON.parseObject(responseString,AttachAppQueryRequest.class);
Assert.assertEquals("root",request.getModuleCode());
Assert.assertEquals("code",request.getDataCode());
}
@Test
public void returnJsonData() throws Exception {
AttachAppQueryRequest request = new AttachAppQueryRequest();
request.setActionCode(1L);
request.setModuleCode(" code ");
request.setActionType(1);
request.setDataCode(" dataCode ");
String str = JSON.toJSONString(request);
String responseString = mockMvc.perform(
post("/demo/getJsonData")
.contentType(MediaType.APPLICATION_JSON)
.content(str)
).andExpect(status().isOk()) //返回的状态是200
.andDo(print()) //打印出请求和相应的内容
.andReturn().getResponse().getContentAsString(); //将相应的数据转换为字符串
request = JSON.parseObject(responseString,AttachAppQueryRequest.class);
Assert.assertEquals("code",request.getModuleCode());
Assert.assertEquals("dataCode",request.getDataCode());
}
@Test
public void returnStringData() throws Exception {
String responseString = mockMvc.perform(
post("/demo/getStringData")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.param("name"," root ")
).andExpect(status().isOk()) //返回的状态是200
.andDo(print()) //打印出请求和相应的内容
.andReturn().getResponse().getContentAsString(); //将相应的数据转换为字符串
Assert.assertEquals("root",responseString);
}
}