Проблема кодирования UTF-8 в Spring MVC

Я бин Spring MVC, и я хотел бы вернуть турецкий символ, установив кодировку UTF-8. но хотя моя строка "şŞğĞİıçÇöÖüÜ", она возвращается как "??????çÇöÖüÜ". а также, когда я смотрю на страницу ответа, которая является страницей Internet Explorer, кодировка - это западноевропейский iso, а не UTF-8.

Вот код:

    @RequestMapping(method=RequestMethod.GET,value="/GetMyList")
public @ResponseBody String getMyList(HttpServletRequest request, HttpServletResponse response) throws CryptoException{
    String contentType= "text/html;charset=UTF-8";
    response.setContentType(contentType);
    try {
        request.setCharacterEncoding("utf-8");
    } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    response.setCharacterEncoding("utf-8");     
    String str="şŞğĞİıçÇöÖüÜ";
    return str;
}   

13 ответов

Я понял это, вы можете добавить к отображению запроса производит = "text/plain;charset=UTF-8"

@RequestMapping(value = "/rest/create/document", produces = "text/plain;charset=UTF-8")
@ResponseBody
public void create(Document document, HttpServletRespone respone) throws UnsupportedEncodingException {

    Document newDocument = DocumentService.create(Document);

    return jsonSerializer.serialize(newDocument);
}

см. этот пост в блоге для более подробной информации о решении

В контексте xml сервлет-диспетчера вы должны добавить свойство "<property name="contentType" value="text/html;charset=UTF-8" />" на ваш взгляд bean Resolver. мы используем freemarker для просмотров.

это выглядит примерно так:

<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
       ...
       <property name="contentType" value="text/html;charset=UTF-8" />
       ...
</bean>

Конвертируйте строку JSON в UTF-8 самостоятельно.

@RequestMapping(value = "/example.json", method = RequestMethod.GET)
@ResponseBody
public byte[] example() throws Exception {

    return "{ 'text': 'äöüß' } ".getBytes("UTF-8");
}

В Spring 5 или, может быть, в более ранних версиях есть MediaType класс. В нем уже есть правильная строка, если вы хотите следовать DRY:

public static final String APPLICATION_JSON_UTF8_VALUE = "application/json;charset=UTF-8";

Поэтому я использую этот набор аннотаций, связанных с контроллером:

@RestController
@RequestMapping(value = "my/api/url", produces = APPLICATION_JSON_UTF8_VALUE)
public class MyController {
    // ... Methods here
}

В документации он помечен как устаревший, но я столкнулся с этой проблемой, и я думаю, что это лучше, чем копировать вышеупомянутую строку для каждого метода / контроллера во всем вашем приложении.

Вам нужно добавить кодировку в аннотацию RequestMapping:

@RequestMapping(path = "/account",  produces = "application/json;charset=UTF-8")

вот и все.

Я обнаружил, что "@RequestMapping производит =" и другие изменения конфигурации мне не помогли. К тому времени, как вы выполните функцию resp.getWriter(), будет уже слишком поздно устанавливать кодировку для писателя.

Добавление заголовка в HttpServletResponse работает.

@RequestMapping(value="/test", method=RequestMethod.POST)
public void test(HttpServletResponse resp) {
    try {
        resp.addHeader("content-type", "application/json; charset=utf-8");
        PrintWriter w = resp.getWriter();
        w.write("{\"name\" : \"μr μicron\"}");
        w.flush();
        w.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Есть несколько похожих вопросов: проблема с кодировкой ответов Spring MVC, Custom HttpMessageConverter с @ResponseBody для выполнения задач Json.

Тем не менее, мое простое решение:

@RequestMapping(method=RequestMethod.GET,value="/GetMyList")
public ModelAndView getMyList(){
  String test = "čćžđš";
  ...
  ModelAndView mav = new ModelAndView("html_utf8");
  mav.addObject("responseBody", test);
}

и представление html_utf8.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>${responseBody}

Никаких дополнительных классов и настроек.
И Вы также можете создать другое представление (например, json_utf8) для другого типа контента.

Если вы используете весеннюю загрузку, просто добавьте эти свойства в файл application.properties:

      server.servlet.encoding.charset=UTF-8
server.servlet.encoding.force=true

Когда вы пытаетесь отправить специальные символы, такие как è,à,ù и т. Д., Возможно, вы видите на своей странице Jsp Post много символов, таких как "£", "Ä" или "Æ". Чтобы решить эту проблему в 99% случаев, вы можете переместить в своем файле web.xml этот фрагмент кода в начало файла:

   <filter>
        <filter-name>encodingFilter</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>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

Полный пример см. Здесь: https://lentux-informatica.com/spring-mvc-utf-8-encoding-problem-solved/

Если вы используете Spring Boot (протестировано с версией 3.0.4), то UTF-8 по умолчанию будет работать как для запросов, так и для ответов HTTP POST.

Если вы вручную добавили Spring MVC, вам необходимо настроить две вещи:

  1. CharacterEncodingFilter : фильтр сервлетов Spring Web, который позволяет:

укажите кодировку символов для запросов . Это полезно, поскольку современные браузеры обычно не устанавливают кодировку символов, даже если она указана на странице или форме HTML.

  1. StringHttpMessageConverter: Spring HttpMessageConverter, который позволяет изменять поле HTTP-заголовка ответа. Без этого заголовок обычно будет вместо UTF-8.

Как установить FeatureEncodingFilter?

Это зависит от конфигурации вашего веб-приложения. Вам следует изучить, как вообще можно установить фильтр сервлетов. ДляCharacterEncodingFilterвам нужно будет установитьencodingпараметр дляutf-8иforceEncodingкtrue.

Например, если вы используете для настройки фильтров сервлетов, вы можете использовать что-то вроде этого в своем:

          <filter>
        <filter-name>characterEncodingFilter</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>forceEncoding</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>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>

Если это не работает (то есть ваш контроллер MVC не получает параметры запроса в формате UTF-8), вам необходимо переместитьcharacterEncodingFilterвыше вweb.xml, чтобы он вызывался раньше других фильтров.

Как установить StringHttpMessageConverter?

Изменить/добавить свойWebMvcConfigurerчто-то вроде этого:

      import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.nio.charset.StandardCharsets;
import java.util.List;

public class MyCustomWebMvcConfigurer implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(0, new StringHttpMessageConverter(StandardCharsets.UTF_8));
    }
}

Оно используетStandardCharsets.ISO_8859_1по умолчанию, но приведенный выше код изменит его на UTF-8. Вы можете проверить, работает ли это, проверивContent-Typeзаголовок в ответах HTTP. Который теперь должен показатьtext/html;charset=UTF-8вместоtext/html;charset=ISO-8859-1.

Если вы используете Spring MVC версии 5, вы можете установить кодировку, также используя @GetMapping аннотаций. Вот пример, который устанавливает тип контента в JSON, а также тип кодировки в UTF-8:

@GetMapping(value="/rest/events", produces = "application/json; charset=UTF-8")

Больше информации об аннотации @GetMapping здесь:

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/GetMapping.html

Я решил эту проблему, выведя полученный тип возврата в первый метод GET requestMethod. Важной частью здесь является

produces="application/json;charset=UTF-8

Поэтому каждый, кто использует /account/**, Spring будет возвращать application/json;charset=UTF-8 тип контента.

@Controller
@Scope("session") 
@RequestMapping(value={"/account"}, method = RequestMethod.GET,produces="application/json;charset=UTF-8")
public class AccountController {

   protected final Log logger = LogFactory.getLog(getClass());

   ....//More parameters and method here...

   @RequestMapping(value={"/getLast"}, method = RequestMethod.GET)
   public @ResponseBody String getUltimo(HttpServletResponse response) throws JsonGenerationException, JsonMappingException, IOException{

      ObjectWriter writer = new ObjectMapper().writer().withDefaultPrettyPrinter();
      try {
        Account account = accountDao.getLast();
        return writer.writeValueAsString(account);
      }
      catch (Exception e) {
        return errorHandler(e, response, writer);
      }
}

Таким образом, вам не нужно настраивать каждый метод в вашем контроллере, вы можете сделать это для всего класса. Если вам нужен больший контроль над конкретным методом, вам просто нужно определить тип содержимого возвращаемого продукта.

Также добавьте в свои бобы:

   <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="messageConverters">
        <array>
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <constructor-arg index="0" name="defaultCharset" value="UTF-8"/>
                <property name="supportedMediaTypes">
                    <list>
                        <value>text/plain;charset=UTF-8</value>
                        <value>text/html;charset=UTF-8</value>
                        <value>application/json;charset=UTF-8</value>
                        <value>application/x-www-form-urlencoded;charset=UTF-8</value>
                    </list>
                </property>
        </bean></bean>

Для @ExceptionHandler:

enter code<bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver">
    <property name="messageConverters">
        <array>
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <constructor-arg index="0" name="defaultCharset" value="UTF-8"/>
                <property name="supportedMediaTypes">
                    <list>
                        <value>text/plain;charset=UTF-8</value>
                        <value>text/html;charset=UTF-8</value>
                        <value>application/json;charset=UTF-8</value>
                        <value>application/x-www-form-urlencoded;charset=UTF-8</value>
                    </list>
                </property>
            </bean>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <value>text/plain;charset=UTF-8</value>
                        <value>text/html;charset=UTF-8</value>
                        <value>application/json;charset=UTF-8</value>
                        <value>application/x-www-form-urlencoded;charset=UTF-8</value>
                    </list>
                </property>
            </bean>
        </array>
    </property>
</bean>

Если вы используете <mvc:annotation-driven/> это должно быть после бобов.

Другие вопросы по тегам