本来是使用的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----
哈哈 结果显而易见。