发现问题
在Controller类方法上加@ResponseBody,直接返回字符串。结果乱码。
例如以下所看到的:
MockHttpServletResponse:
Status = 200
Error message = null
Headers = {Content-Type=[text/plain;charset=ISO-8859-1], Content-Length=[45]}
Content type = text/plain;charset=ISO-8859-1
Body = {
"Msg":"????
????
??????
?nameEntTypeCode?
?
"
}
用浏览器訪问也是乱码。
分析问题
1、分析日志
日志级别设为DEBUG,查看日志。节选例如以下:
(1)
<Method [handleRuleException] returned [{
"Msg":"调用时规则时未传入必要參数:“nameEntTypeCode”。
"
}]>
到这里还是对的。Handle调用完毕。获得了返回值。接下来归View了。
(2)
ModelAndViewMethodReturnValueHandler@12eae9c]
supports [class java.lang.String]>
web.method.annotation.ModelMethodProcessor@12c50a4]
supports [class java.lang.String]>
web.servlet.mvc.method.annotation.ViewMethodReturnValueHandler@56a5b]
supports [class java.lang.String]>
web.servlet.mvc.method.annotation.HttpEntityMethodProcessor@9463a0]
supports [class java.lang.String]>
web.method.annotation.ModelAttributeMethodProcessor@1aad6f4]
supports [class java.lang.String]>
web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor@1c45fa4]
supports [class java.lang.String]>
快找到元凶了。
accept.PathExtensionContentNegotiationStrategy$JafMediaTypeFactory]
Loading Java Activation Framework FileTypeMap from class path resource
[org/springframework/mail/javamail/mime.types] //默认支持的类型是从这里读取的
mvc.method.annotation.AbstractMessageConverterMethodProcessor<Written [{
"Msg":"调用时规则时未传入必要參数:“nameEntTypeCode”。"
}] as "text/plain;charset=ISO-8859-1" using [org.springframework.http.converter.StringHttpMessageConverter@1efa83c]>
找到元凶。他是如何作案的呢?
我猜。大概是StringHttpMessageConverter注入了AbstractMessageConverterMethodProcessor。
“text/plain;charset=ISO-8859-1”是StringHttpMessageConverter的属性。
2、尝试解决
(1)AbstractMessageConverterMethodProcessor是抽象类,在StringHttpMessageConverter上想办法。
(2)
假设org.springframework.http.converter.StringHttpMessageConverter是单例,能够自己配置一下看看
<bean id="stringHttpMessageConverter"
class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
</list>
</property>
</bean>
在<xxx>-servlet.xml中配置无效。
确认放在<mvc:annotation-driven>之前了。
(3)注入的姿势不正确,还是老实看看Spring源码吧
3、寻找注入口
(1)
RequestMappingHandlerAdapter构造函数中:
public RequestMappingHandlerAdapter() {
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
...
this.messageConverters.add(stringHttpMessageConverter);
}
直接这么new啊。太粗暴了。
这仅仅是默认行为,应该有覆盖办法的。
(2)
跟代码。跟到
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();
// Single-purpose return value types
handlers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.contentNegotiationManager));
// Annotation-based return value types
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager));
}
然后找到:
public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
this.messageConverters = messageConverters;
}
(3)
试试看:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
这就是老版本号的报错吧:
cvc-complex-type.2.1: 元素 'mvc:annotation-driven' 必须不含字符或元素信息项 [子级], 由于该类型的内容类型为空。
看mvc命名空间中xsd版本号。
好吧,就是这里:http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
(4)
修正,好了:
MockHttpServletResponse:
Status = 200
Error message = null
Headers = {Content-Type=[text/plain;charset=UTF-8], Content-Length=[79]}
Content type = text/plain;charset=UTF-8
Body = {
"Msg":"调用时规则时未传入必要參数:“nameEntTypeCode”。"
}
Forwarded URL = null
Redirected URL = null
Cookies = []
总结
1、遇到问题多看日志,多看代码。
2、Spring MVC注入口非常多,太爽了,但应该慎重使用,考虑影响范围。
3、HttpMessageConverter是神器,能够完毕传入參数和返回值的转换。通过自己定义Media Type可实现奇妙效果,有机会好好研究下。