现象
mvc-dispatch-servlet.xml中的配置:
测试接口controller,返回值类型为String:
其中入参queryNewsListReqVo的属性包括:
测试请求以及响应:
此时的Header:
当设置返回对象为Object时:
请求以及响应:
此时的Header:
Controller返回String时中文乱码,返回Object时中文正常,造成此问题的原因是:
当设置返回值为String类型时,Response的content-type被SpringMVC自动设置为
text/plain;charset=ISO-8859-1
当返回值类型为Object时,返回值会被json格式化,并使用UTF-8编码
application/json;charset=UTF-8
以上这些都是spring的默认设置
如果我们希望当返回值为string类型时也进行json格式化就需要在RequestMappingHandlerAdapter中设置Convert类:
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
原因分析
现在回过头看我们的配置:
可以看出配置的本意确实是想要配置返回值的转换类,但是从上面的实验结果看出,并没有生效。
原因是:
通过查看AnnotationDrivenBeanDefinitionParser的源码:
源码在org.springframework.web.servlet.config包中
在<mvc:annotation-driver/>的解析器AnnotationDrivenBeanDefinitionParser中已经进行了这个bean的初始化并注入到了容器中。
在</mvc:annotation-driver>之后自定义的RequestMappingHandlerMapping和RequestMappingHandlerAdapter这两个bean并没有被注入到spring的容器中,因此,上述配置并未生效。
当我们修改配置,在annotation-driven中配置converter类:
此配置的含义就是在解析<mvc:annotation-dirven/>配置并加载RequestMappingHandlerAdapter的时候设置对应的Converter类
再次请求返回值string类型的接口时:
返回值为中文时不再乱码
Header中的content-type也正确:
结论:
我们当前配置:
红框中的内容完全没有任何作用,如果希望配置返回值json化,可以改为如下配置:
引申内容:
从上述的分析中,可以看出在spring的xml中配置的bean,靠前配置的会优先加载,靠后加载的相同的bean不会被注入容器。
如果我们颠倒原有的配置方式,将<mvc:annotation-driver/>配置在后面的时候,也是可以达到返回值json化的目的,但是此时的造成其他问题。因为通过上面解析类的源码可以看到在加载RequestMappingHandlerAdapter的时候除了加载converter类之外,还加载了其他类:
其中的bindingDef的一个作用就是解析请求vo上的注解的:
当配置如下时:
请求返回值为String的接口正常:
但是当请求带有注解属性的参数时:
返回了400错误,如果打印了spring日志的话,也可以看到spring已经给出提示:
10:24:51,255 [ WARN] [org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver] :186 - Handler execution resulted in exception: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'queryNewsListReqVo' on field 'beginTime': rejected value [2019-05-05 10:10:10]; codes [typeMismatch.queryNewsListReqVo.beginTime,typeMismatch.beginTime,typeMismatch.java.util.Date,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [queryNewsListReqVo.beginTime,beginTime]; arguments []; default message [beginTime]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date' for property 'beginTime'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [java.util.Date] for property 'beginTime': no matching editors or conversion strategy found]