java 如何在 spring 4 中覆盖 StringHttpMessageConverter DEFAULT_CHARSET 以使用 UTF8

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27606769/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 12:06:41  来源:igfitidea点击:

How to overwrite StringHttpMessageConverter DEFAULT_CHARSET to use UTF8 in spring 4

javaajaxspringspring-mvcutf-8

提问by masterdany88

I am trying to make spring @ResponseBody return always utf-8. But I can't do it for so long. Problem comes when I am returning simple text answer:

我试图让 spring @ResponseBody 始终返回 utf-8。但我做不到这么久。当我返回简单的文本答案时出现问题:

@RequestMapping(value="/test", method=RequestMethod.PUT)
@ResponseBody
public String ajaxTest() {
    return "Characters test: ?ó??????ń";
}

Each polish chars (?ó??????ń) goes to ?

每个波兰语字符 (?ó????????) 转到 ?

And in web page I am getting this string: Characters test: ?????????instead of Characters test: ?ó??????ń

在网页中我得到这个字符串: Characters test: ?????????而不是Characters test: ?ó??????ń

I don't know what I am missing.

我不知道我错过了什么。

I've added custome bean to public class WebAppConfig extends WebMvcConfigurerAdapter {}Which goes as follows:

我已经添加了custome bean,public class WebAppConfig extends WebMvcConfigurerAdapter {}如下所示:

@Bean
public HttpMessageConverter<String> responseBodyConverter() {
    StringHttpMessageConverter converter = new StringHttpMessageConverter();
    converter.setSupportedMediaTypes(Arrays.asList(new MediaType("text", "plain", Charset.forName("UTF-8"))));
    return converter;
}

Instruction taken from https://jira.spring.io/browse/SPR-9099

说明取自 https://jira.spring.io/browse/SPR-9099

But it doesn't work. I can see in firefox and chrome that returned value is in utf-8: enter image description here

但它不起作用。我可以在 Firefox 和 chrome 中看到返回值是 utf-8: 在此处输入图片说明



Spring version: 4.1.1.RELEASE

春季版本:4.1.1.RELEASE

Web app config class:

Web 应用程序配置类:

package com.derp.common.init;

import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

import javax.annotation.Resource;
import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

//import com.derp.common.wicketView.HomePage;

@Configuration
@ComponentScan("com.derp")
@EnableWebMvc
@EnableTransactionManagement
@PropertySource("classpath:application.properties")
public class WebAppConfig extends WebMvcConfigurerAdapter {

    private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";
    private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
    private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
    private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";

    private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
    private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
    private static final String PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO = "hibernate.hbm2ddl.auto";
    private static final String PROPERTY_NAME_HIBERNATE_CONNECTION_CHARSET = "hibernate.connection.CharSet";
    private static final String PROPERTY_NAME_HIBERNATE_CONNECTION_CHARACTERENCODING = "hibernate.connection.characterEncoding";
    private static final String PROPERTY_NAME_HIBERNATE_CONNECTION_USEUNICODE = "hibernate.connection.useUnicode";
    private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN_SERVICES = "services.entitymanager.packages.to.scan";
    private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN_COMMON = "common.entitymanager.packages.to.scan";
    private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN_CMS = "cms.entitymanager.packages.to.scan";
    private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN_PROCEDURE = "procedure.entitymanager.packages.to.scan";

    @Resource
    private Environment env;

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
        dataSource.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
        dataSource.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
        dataSource.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
        return dataSource;
    }

    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource());
        //sessionFactoryBean.setPackagesToScan(env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
        sessionFactoryBean.setPackagesToScan(new String[] {
                env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN_SERVICES),
                env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN_COMMON),
                env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN_CMS),
                env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN_PROCEDURE)
                });
        sessionFactoryBean.setHibernateProperties(hibProperties());
        return sessionFactoryBean;
    }

    private Properties hibProperties() {
        Properties properties = new Properties();
        properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
        properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
        properties.put(PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO));
        properties.put(PROPERTY_NAME_HIBERNATE_CONNECTION_CHARSET, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_CONNECTION_CHARSET));
        properties.put(PROPERTY_NAME_HIBERNATE_CONNECTION_CHARACTERENCODING, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_CONNECTION_CHARACTERENCODING));
        properties.put(PROPERTY_NAME_HIBERNATE_CONNECTION_USEUNICODE, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_CONNECTION_USEUNICODE));
        properties.put("jadira.usertype.autoRegisterUserTypes", "true");
        return properties;  
    }

    @Bean
    public HibernateTransactionManager transactionManager() {
        HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setSessionFactory(sessionFactory().getObject());
        return transactionManager;
    }


    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        // Simple strategy: only path extension is taken into account
        configurer.favorPathExtension(true).
            ignoreAcceptHeader(true).
            useJaf(false).
            defaultContentType(MediaType.TEXT_HTML).
            mediaType("html", MediaType.TEXT_HTML).
            mediaType("xml", MediaType.APPLICATION_XML).
            mediaType("json", MediaType.APPLICATION_JSON);
    }
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/img/**").addResourceLocations("/WEB-INF/img/*");
        registry.addResourceHandler("/css/**").addResourceLocations("/WEB-INF/css/*");
        registry.addResourceHandler("/js/**").addResourceLocations("/WEB-INF/js/*");
        registry.addResourceHandler("/lib/**").addResourceLocations("/WEB-INF/lib/*");
    }



    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        super.configureMessageConverters(converters);
        converters.add(responseBodyConverter());
    }
    @Bean
    public HttpMessageConverter<String> responseBodyConverter() {
        StringHttpMessageConverter converter = new StringHttpMessageConverter();
        converter.setSupportedMediaTypes(Arrays.asList(new MediaType("text", "plain", Charset.forName("UTF-8"))));
        return converter;
    }
}

Application initializer:

应用初始化器:

package com.derp.common.init;

import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic;

import org.springframework.http.MediaType;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.servlet.DispatcherServlet;

public class Initializer implements WebApplicationInitializer {


    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(WebAppConfig.class);
        ctx.register(ThymeleafConfig.class);
        servletContext.addListener(new ContextLoaderListener(ctx));

        ctx.setServletContext(servletContext);

        Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
        servlet.addMapping("/");
        servlet.setAsyncSupported(true);     
        servlet.setLoadOnStartup(1);
        // Allow to use Put and Delete method for REST architecture
        registerCharachterEncodingFilter(servletContext);
        registerHiddenFieldFilter(servletContext);
    }


    private void registerCharachterEncodingFilter(ServletContext aContext) {
        CharacterEncodingFilter cef = new CharacterEncodingFilter();
        cef.setForceEncoding(true);
        cef.setEncoding("UTF-8");
        aContext.addFilter("charachterEncodingFilter", cef).addMappingForUrlPatterns(null ,true, "/*");
    }
    private void registerHiddenFieldFilter(ServletContext aContext) {
        aContext.addFilter("hiddenHttpMethodFilter", new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null ,true, "/*"); 
    }

}

Java script/Jquery ajax call

Java 脚本/Jquery ajax 调用

  $('h1').click(function() {
      $.ajax({
          type: "PUT",
          url: "/derp/procedury/test",
          data: "none",
          success: function (response, status, xhr) {
              showNotifications(status, xhr.responseText);
          },
          error: function (response, status, xhr) {
              showNotifications('error', JSON.stringify(response));
              showNotifications('error', status);
              showNotifications('error', xhr);
          }
      });
  });

Please help.

请帮忙。

回答by Sotirios Delimanolis

Your Network tab seems to be showing

您的网络标签似乎正在显示

text/html;charset=UTF-8

which isn't what you configured it to be

这不是你配置的

converter.setSupportedMediaTypes(Arrays.asList(new MediaType("text", "plain", Charset.forName("UTF-8"))));

It seems your custom HttpMessageConverterbean isn't getting registered. Add this to your WebAppConfigclass

您的自定义HttpMessageConverterbean似乎未注册。将此添加到您的WebAppConfig课程中

@Override
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    super.configureMessageConverters(converters);
    converters.add(responseBodyConverter());
}

You should see your response contain

你应该看到你的回复包含

Content-Type:"text/plain;charset=UTF-8"

I can't explain why your browser's network tab would show UTF-8but wouldn't be able to parse or render it properly. It works fine for me.

我无法解释为什么您的浏览器的网络选项卡会显示UTF-8但无法正确解析或呈现它。这对我来说可以。

回答by Muel

The problem is that StringHttpMessageConverterdefaults to ISO-8859-1. You need either set the default to UTF-8 as shown here:

问题是StringHttpMessageConverter默认为 ISO-8859-1。您需要将默认值设置为 UTF-8,如下所示:

    @Bean
    public HttpMessageConverter<String> responseBodyConverter() {
        StringHttpMessageConverter converter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
        converter.setSupportedMediaTypes(Arrays.asList(new MediaType("text", "plain", Charset.forName("UTF-8"))));
        return converter;
    }

Or get the client to specify exactly what they want with the Acceptheader, ie: Accept: text/plain;charset="UTF-8".

或者让客户端使用Accept标头准确指定他们想要的内容,即:Accept: text/plain;charset="UTF-8"

回答by Zakaf

The problem as others have stated is that StringHttpMessageConverterdefaults to ISO-8859-1.

正如其他人所说,问题是StringHttpMessageConverter默认为 ISO-8859-1。

I just replaced the default charset of existing StringHttpMessageConverter to UTF-8

我只是将现有 StringHttpMessageConverter 的默认字符集替换为 UTF-8

@Configuration
@EnableWebMvc
public class SampleWebConfiguration implements WebMvcConfigurer {
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.stream()
            .filter(converter -> converter instanceof StringHttpMessageConverter)
            .forEach(converter -> ((StringHttpMessageConverter) converter).setDefaultCharset(StandardCharsets.UTF_8));
    }
}