SpringMVC注解之@ResponseBody

本文介绍了SpringMVC中使用@ResponseBody注解时遇到的中文乱码问题,特别是当返回类型为String时。文章揭示了SpringMVC如何使用不同的HttpMessageConverter处理不同类型的数据,如List、Map和String,并且提供了通过修改springmvc-servlet.xml配置解决StringHttpMessageConverter字符集问题的方法,以及另一种调整messageConverters配置的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SpringMVC注解之@ResponseBody

原文写于 2013-04-18 https://github.com/kuitos/kuitos.github.io/issues/3

web项目中会大量用到ajax请求实现前后台交互,以前处理后台返回给前台的集合数据的方式是这样的:

@RequestMapping("loadConfigUsers")
public void loadConfigUsers(String domain, HttpServletResponse response) {
    response.setCharacterEncoding("UTF-8");
    response.setContentType("text/html;charset=utf-8");
    List<Map<String, Object>> list = userConfigService.loadConfigUsers(domain);
    PrintWriter out = null;
    try {
        out = response.getWriter();
        out.print(JackSonMapper.toJsonString(list));
    } catch (IOException e) {
        logger.error("I/O出错", e);
    } finally {
        try {
            out.close();
        } catch (Exception e) {
            logger.error("关闭流出错", e);
        }
    }
}

也就是使用jackson将List

@ResponseBody
@RequestMapping("loadConfigUsers")
public List<Map<String,String>> loadConfigUsers(String domain, HttpServletResponse response) {
    return userConfigService.loadConfigUsers(domain);
}

前台接收到的即为json格式数组,如[{“a”:”b”},{“c”,”d”}]。SpringMVC底层会使用jackson将带有@ResponseBody的方法体的返回值转成标准的json格式。
想返回Map

@ResponseBody
@RequestMapping("loadConfigUsers")
public Map<String,String> loadConfigUsers(String domain, HttpServletResponse response) {
    return userConfigService.loadConfigUsers(domain);
}

返回的json格式为 {“a”:”b”,”c”:”d”}。
也可以直接向前台返回String

@ResponseBody
@RequestMapping("loadConfigUsers")
public String loadConfigUsers(String domain, HttpServletResponse response) {
    return "success";
}

前台接收到的为 “success”。
但是在实际开发中碰到一个问题,返回List,Map,即前台接收到的为json格式字符串的时候中文字符都正常,但是直接返回String却会出现中文乱码问题。google一下发现SpringMVC是这样实现的。
SpringMVC对于注有@ResponseBody注解的方法返回值有自己的一系列转换器,当发现返回值为List,Map等集合类型时SpringMVC使用的是MappingJacksonHttpMessageConverter转换器,改转换器字符集设置的为UTF-8,附部分代码

public class MappingJacksonHttpMessageConverter extends AbstractHttpMessageConverter<Object> {
    // 设置默认字符集
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
    private ObjectMapper objectMapper = new ObjectMapper();
    private boolean prefixJson = false;
    /**
     * Construct a new {@code BindingJacksonHttpMessageConverter}.
     */
    public MappingJacksonHttpMessageConverter() {
        super(new MediaType("application", "json", DEFAULT_CHARSET));
    }
}

而对于返回值为String时使用的转换器则为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());
    }
}

可以发现,两个转换器用的字符集竟然不一样,这个实在是难以理解,为毛用于处理同一个注解的两个转换器要用两种字符集??
经过一番google及测试,发现了有一种方式是可以解决StringHttpMessageConverter字符集的问题,即修改我们的springmvc-servlet.xml,在前加上这样一段配置

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <value>text/plain;charset=UTF-8</value>
                    </list>
                </property>
            </bean>
            <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
        </list>
    </property>
</bean>

<mvc:annotation-driven />

即设置StringHttpMessageConverter可支持的媒体类型仅只有”text/plain;charset=UTF-8”一种。
另外还有一种是配置AnnotationMethodHandlerAdapter的messageConverters,即

<bean class="org.springframework.web.servlet.mvc.method.annotation.AnnotationMethodHandlerAdapter">       
    <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                    <property name="supportedMediaTypes">
                        <list>
                            <value>text/plain;charset=UTF-8</value>
                        </list>
                    </property>
                </bean>
                <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
            </list>
     </property>
</bean>

这种方式是将spring所有的messageConverters改为两种StringHttpMessageConverter、MappingJacksonHttpMessageConverter
使用这种配置就不能再用mvc:annotation-driven了,官方文档是这样写的。也就是说它会覆盖之前的配置

The above registers a RequestMappingHandlerMapping, a RequestMappingHandlerAdapter, and an ExceptionHandlerExceptionResolver (among others) in support of processing requests with annotated controller methods using annotations such as @RequestMapping , @ExceptionHandler, and others
This is the complete list of HttpMessageConverters set up by mvc:annotation-driven:
ByteArrayHttpMessageConverter converts byte arrays.
StringHttpMessageConverter converts strings.
ResourceHttpMessageConverter converts to/from org.springframework.core.io.Resource for all media types.
SourceHttpMessageConverter converts to/from a javax.xml.transform.Source.
FormHttpMessageConverter converts form data to/from a MultiValueMap

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值