UTF-8 encoding problem in Spring MVC
Asked Answered
P

13

64

I' ve a Spring MVC bean and I would like to return turkish character by setting encoding UTF-8. but although my string is "şŞğĞİıçÇöÖüÜ" it returns as "??????çÇöÖüÜ". and also when I look at the response page, which is internet explorer page, encoding is western european iso, not UTF-8.

Here is the code:

    @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;
}   
Proper answered 13/4, 2011 at 12:38 Comment(4)
See #3616859Cabinet
possible duplicate of Spring MVC response encoding issueStradivarius
Can you accept the answer if it is already working for you?Harmonie
response.setContentType(contentType); you don't need to write such code using frameworks, especially Spring. produces = "text/plain;charset=UTF-8" is your choiceSeguidilla
S
79

I've figured it out, you can add to request mapping produces = "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);
}

see this blog post for more details on the solution

Slink answered 19/8, 2012 at 2:44 Comment(5)
Solution 1 of the linked blog post works for me, i.e. writing bytes to the outputstream. The other two solutions don't work for me.Montoya
For me, it works, I was looking so long for solution. Thank you.Crossexamine
@Montoya Maybe you need this too: response.setCharacterEncoding("UTF-8"); I have filter for that.Crossexamine
For me also , "Solution 1 of the linked blog post works for me, i.e. writing bytes to the output stream. The other two solutions don't work for me."Edva
the site is no longer hosted. I've added solution 1 to this blog post monsterbrain.github.io/2019/04/01/spring-mvc-ajax-utf-8-problemDelmardelmer
Z
27

in your dispatcher servlet context xml, you have to add a propertie "<property name="contentType" value="text/html;charset=UTF-8" />" on your viewResolver bean. we are using freemarker for views.

it looks something like this:

<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
       ...
       <property name="contentType" value="text/html;charset=UTF-8" />
       ...
</bean>
Zaslow answered 22/2, 2012 at 12:16 Comment(1)
Also fixed my issues with Thymeleaf. Thanks.Jerrelljerri
M
7

Convert the JSON string to UTF-8 on your own.

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

    return "{ 'text': 'äöüß' } ".getBytes("UTF-8");
}
Montoya answered 20/3, 2015 at 9:29 Comment(1)
Only solution that worked for me, using response.getOutputStream().write(jsonObject.toString().getBytes("UTF-8"));Mccaslin
L
5

In Spring 5, or maybe in earlier versions, there is MediaType class. It has already correct line, if you want to follow DRY:

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

So I use this set of controller-related annotations:

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

It is marked deprecated in the docs, but I've run into this issue and it is better than copy-pastying the aforementioned line on every method/controller throughout your application, I think.

Litigable answered 11/11, 2019 at 14:35 Comment(3)
It's deprecated since 5.2 see docs.spring.ioOssy
@Vala.D. Thanks for pointing this out. When I used this option, we were surely using som 5.0.* version, and were planning to move to 5.1.* branch, IIRC. Still, that's some arguable reason they decided to deprecate it, as we had the problem with encoding with some rest-like service. And unlike "modern browsers", those internal webservices tend to be legacy-ish sometimes. :DLitigable
I had the same problems with an rest service, that's how I got here in the first place.Ossy
J
4

You need add charset in the RequestMapping annotation:

@RequestMapping(path = "/account",  produces = "application/json;charset=UTF-8")
Jolynjolynn answered 4/6, 2020 at 12:38 Comment(0)
S
3

I found that "@RequestMapping produces=" and other configuration changes didn't help me. By the time you do resp.getWriter(), it is also too late to set the encoding on the writer.

Adding a header to the HttpServletResponse works.

@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();
    }
}
Staffordshire answered 24/9, 2020 at 13:50 Comment(0)
W
2

There are some similar questions: Spring MVC response encoding issue, Custom HttpMessageConverter with @ResponseBody to do Json things.

However, my simple solution:

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

and the view html_utf8.jsp

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

No additional classes and configuration.
And You can also create another view (for example json_utf8) for other content type.

Wulfila answered 17/7, 2011 at 17:14 Comment(0)
H
1

I've resolved this issue by inferring the produced return type into the first GET requestMethod. The important part here is the

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

So every one how use /account/**, Spring will return application/json;charset=UTF-8 content type.

@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);
      }
}

So, you do not have to set up for each method in your Controller, you can do it for the entire class. If you need more control over a specific method, you just only have to infer the produces return content type.

Hillary answered 22/8, 2016 at 20:41 Comment(0)
H
1

Also add to your beans :

   <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>

For @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>

If you use <mvc:annotation-driven/> it should be after beans.

Holmgren answered 7/10, 2016 at 9:6 Comment(0)
W
1

If you are using Spring MVC version 5 you can set the encoding also using the @GetMapping annotation. Here is an example which sets the content type to JSON and also the encoding type to UTF-8:

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

More information on the @GetMapping annotation here:

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

Winnie answered 10/6, 2018 at 20:19 Comment(0)
P
1

When you try to send special characters like è,à,ù, etc etc, may be you see in your Jsp Post page many characters like '£','Ä’ or ‘Æ’. To solve this problem in 99% of cases you may move in your web.xml this piece of code at the head of file:

   <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>

For complete example see here : https://lentux-informatica.com/spring-mvc-utf-8-encoding-problem-solved/

Parados answered 23/7, 2018 at 8:23 Comment(0)
F
1

If are using spring boot just add this properies to your applications.properties file:

server.servlet.encoding.charset=UTF-8
server.servlet.encoding.force=true
Flagellate answered 14/2, 2023 at 19:31 Comment(0)
N
1

If you are using Spring Boot (tested with 3.0.4), then UTF-8 will work out of the box by default for both HTTP POST requests and responses.

If you have manually added Spring MVC, then you'll need to configure two things:

  1. CharacterEncodingFilter: a Spring Web servlet filter that allows you to:

specify a character encoding for requests. This is useful because current browsers typically do not set a character encoding even if specified in the HTML page or form.

  1. StringHttpMessageConverter: a Spring HttpMessageConverter that allows you to change the response Content-Type HTTP header field. Without this, the Content-Type header will usually be text/html;charset=ISO-8859-1 instead of UTF-8.

How to set CharacterEncodingFilter?

It depends on your web app configuration. You should look into how you can set a Servlet Filter in general. For CharacterEncodingFilter you'll need to set the encoding param to utf-8 and the forceEncoding to true.

For example, if you are using web.xml to configure Servlet Filters, then you could use something like this in your web.xml:

    <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>

If this doesn't work (meaning, your MVC controller doesn't receive request parameters as UTF-8), then you need to move the characterEncodingFilter higher up in web.xml, so that it gets called before other filters.

How to set StringHttpMessageConverter?

Change/add your WebMvcConfigurer to something like this:

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));
    }
}

It uses StandardCharsets.ISO_8859_1 by default, but the code above will change it to UTF-8. You can verify if this is working, by checking the Content-Type header in the HTTP responses. Which should now show text/html;charset=UTF-8 instead of text/html;charset=ISO-8859-1.

Nye answered 16/3, 2023 at 22:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.