本来是使用的Jackson来处理普通对象到json对象的转换工作 ,无奈在对象中的属性为空时Jackson默认是将为空的属性也转换,然后就报错。 而且当前场景无法使用Jackson自带的注解等方式排除null属性,于是乎我便痛下狠心,用json-lib自己转换直接返回json字符串。结果异常是没了,但是乱码又出现了。。。
根据之前的经验,我发现出现的乱码都是“???”一堆的问号,直觉告诉我又是ISO8859-1在作祟。于是乎,查了查源码,果然在 StringHttpMessageConverter中发现了端倪。
public class StringHttpMessageConverter extends AbstractHttpMessageConverter<String> {
public static final Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1");
private final List<Charset> availableCharsets;
private boolean writeAcceptCharset = true;
public StringHttpMessageConverter() {
super(new MediaType("text", "plain", DEFAULT_CHARSET), MediaType.ALL);
this.availableCharsets = new ArrayList<Charset>(Charset.availableCharsets().values());
}
/**
* Indicates whether the {@code Accept-Charset} should be written to any outgoing request.
* <p>Default is {@code true}.
*/
public void setWriteAcceptCharset(boolean writeAcceptCharset) {
this.writeAcceptCharset = writeAcceptCharset;
}
@Override
public boolean supports(Class<?> clazz) {
return String.class.equals(clazz);
}
@Override
protected String readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException {
MediaType contentType = inputMessage.getHeaders().getContentType();
Charset charset = contentType.getCharSet() != null ? contentType.getCharSet() : DEFAULT_CHARSET;
return FileCopyUtils.copyToString(new InputStreamReader(inputMessage.getBody(), charset));
}
@Override
protected Long getContentLength(String s, MediaType contentType) {
if (contentType != null && contentType.getCharSet() != null) {
Charset charset = contentType.getCharSet();
try {
return (long) s.getBytes(charset.name()).length;
}
catch (UnsupportedEncodingException ex) {
// should not occur
throw new InternalError(ex.getMessage());
}
}
else {
return null;
}
}
@Override
protected void writeInternal(String s, HttpOutputMessage outputMessage) throws IOException {
if (writeAcceptCharset) {
outputMessage.getHeaders().setAcceptCharset(getAcceptedCharsets());
}
MediaType contentType = outputMessage.getHeaders().getContentType();
Charset charset = contentType.getCharSet() != null ? contentType.getCharSet() : DEFAULT_CHARSET;
FileCopyUtils.copy(s, new OutputStreamWriter(outputMessage.getBody(), charset));
}
/**
* Return the list of supported {@link Charset}.
*
* <p>By default, returns {@link Charset#availableCharsets()}. Can be overridden in subclasses.
*
* @return the list of accepted charsets
*/
protected List<Charset> getAcceptedCharsets() {
return this.availableCharsets;
}
}
(⊙o⊙)… 也不知道 为啥SpringMVC的开发者将ISO-8859-1设置为默认编码格式。得亏 SpringMVC提供了配置方式来解决这个问题。开源的东西的优势立马就体现出来了。
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean class = "org.springframework.http.converter.StringHttpMessageConverter">
<property name = "supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
</list>
</property>
</bean>
</list>
</property>
</bean>
看了网上不少都说必须 将以上配置放在<context:component-scan/>前面 我就有点儿丈二和尚摸不到头脑了 这都是不沾边的东西 有嘛关系吗?
具体要说的话应该是跟<mvc:annotation-driven/>关系比较大 (如果你不使用这种注解方式 就更容易了) 需要我们将上面的配置放在<mvc:annotation-driven/>之前。下面是鄙人做的小测试。
/**
* @Author: Sonicery_D
* @Date: 2014-10-10
*/
public class ExtBeanFactoryProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
String[] beanNames = beanFactory.getBeanNamesForType(AnnotationMethodHandlerAdapter.class);
for(String name : beanNames){
System.out.println("---------------"+name+"-----start----");
AnnotationMethodHandlerAdapter adapter = (AnnotationMethodHandlerAdapter)beanFactory.getBean(name);
HttpMessageConverter<String>[] converters = (HttpMessageConverter<String>[])adapter.getMessageConverters();
for(HttpMessageConverter<String> converter : converters){
for(MediaType type :converter.getSupportedMediaTypes()){
if(type==null ||type.getCharSet() == null){
System.out.println("encoding:null");
}else{
System.out.println("encoding:"+type.getCharSet().name());
}
}
}
System.out.println("---------------"+name+"-----end----");
}
}
}
放在<mvc:annotation-driven/>之前:
---------------org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#0-----start----
encoding:UTF-8
---------------org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#0-----end----
---------------org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#1-----start----
- Hibernate Validator 4.1.0.Final
encoding:null
encoding:null
encoding:ISO-8859-1
encoding:null
encoding:null
encoding:null
encoding:null
encoding:null
encoding:null
encoding:null
encoding:null
encoding:null
encoding:null
encoding:UTF-8
---------------org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#1-----end----
---------------org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#2-----start----
encoding:null
encoding:null
encoding:ISO-8859-1
encoding:null
encoding:null
encoding:null
encoding:null
encoding:null
encoding:null
---------------org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#2-----end----
放在<mvc:annotation-driven/>之后
---------------org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#0-----start----
- Hibernate Validator 4.1.0.Final
encoding:null
encoding:null
encoding:ISO-8859-1
encoding:null
encoding:null
encoding:null
encoding:null
encoding:null
encoding:null
encoding:null
encoding:null
encoding:null
encoding:null
encoding:UTF-8
---------------org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#0-----end----
---------------org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#1-----start----
encoding:UTF-8
---------------org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#1-----end----
---------------org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#2-----start----
encoding:null
encoding:null
encoding:ISO-8859-1
encoding:null
encoding:null
encoding:null
encoding:null
encoding:null
encoding:null
---------------org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#2-----end----
哈哈 结果显而易见。