前言
json又双叒叕返回乱码了!
乱码一般都是编码问题,比如一个字符串你好世界
, 用GBK
编码后, 再用UTF-8
解码, 就会出现乱码问题。
样例
1 2 3 4 5 6 7 8
| @Controller public class TestController{ @GetMapping("/test") @ResponseBody public String test() { return "你好世界"; } }
|
使用CharacterEncodingFilter过滤器(没用)
在 web.xml 中加入CharacterEncodingFilter
过滤器, 对request和response进行编码转换。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <filter> <filter-name>encoding</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceRequestEncoding</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>forceResponseEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encoding</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
|
源码很简单, 就是调用setCharacterEncoding
方法设置编码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class CharacterEncodingFilter extends OncePerRequestFilter { @Override protected void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String encoding = getEncoding(); if (encoding != null) { if (isForceRequestEncoding() || request.getCharacterEncoding() == null) { request.setCharacterEncoding(encoding); } if (isForceResponseEncoding()) { response.setCharacterEncoding(encoding); } } filterChain.doFilter(request, response); } }
|
CV大法重写StringHttpMessageConverter类
行吧, 自己解决不了, 上stackoverflow看看,
在使用<mvc:annotation-driven />
自动驱动的前提下,
发现@ResponseBody
返回值是String
类型的话。
会调用StringHttpMessageConverter
这个类进行转换。
1 2 3 4 5
| public class StringHttpMessageConverter extends AbstractHttpMessageConverter<String> { public static final Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1"); private volatile List<Charset> availableCharsets; private boolean writeAcceptCharset = true; }
|
默认是ISO-8859-1
编码, 而且是final
修饰的。这就意味这不能继承这个方法了。
那就用CV大法吧。
1 2 3 4 5
| public class StringHttpMessageConverter extends AbstractHttpMessageConverter<String> { public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); private volatile List<Charset> availableCharsets; private boolean writeAcceptCharset = true; }
|
并且在<mvc:annotation-driven />
内注入这个Bean
1 2 3 4 5
| <mvc:annotation-driven> <mvc:message-converters register-defaults="true"> <bean class="com.chuanliu.platform.activity.basic.converter.MyStringHttpMessageConverter"/> </mvc:message-converters> </mvc:annotation-driven>
|
使用produces属性完成
使用CV大法是很不好的习惯,
【解决spring-mvc @responseBody注解返回json 乱码问题】这篇文章提出可以使用produces属性完成
1 2 3 4 5 6 7 8
| @Controller public class TestController{ @GetMapping(value = "/test", produces="text/html;charset=UTF-8") @ResponseBody public String test() { return "你好世界"; } }
|
省了一大堆配置, 但还是要在每个@ResponseBody
方法使用CV大法, 写入produces="text/html;charset=UTF-8"
。
直接返回对象
【(二)Java 中文乱码学习 与Spring @ResponseBody中的乱码 - Spring @ResponseBody中的乱码】中提到
在使用<mvc:annotation-driven />
自动驱动的前提下,
如果直接返回String类型, 则会调用StringHttpMessageConverter
。
如果直接返回对象类型, 则会调用MappingJackson2HttpMessageConverter
。
在MappingJackson2HttpMessageConverter
的父类AbstractJackson2HttpMessageConverter
中。
可以看到使用了UTF-8
编码。
1 2 3
| public abstract class AbstractJackson2HttpMessageConverter extends AbstractGenericHttpMessageConverter<Object> { public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); }
|
参考资料