62

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;
}   
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
ysnky
  • 621
  • 1
  • 5
  • 3
  • 1
    See http://stackoverflow.com/questions/3616359/who-sets-response-content-type-in-spring-mvc-responsebody/3617594#3617594 – axtavt Apr 13 '11 at 12:49
  • possible duplicate of [Spring MVC response encoding issue](http://stackoverflow.com/questions/6638284/spring-mvc-response-encoding-issue) – kamaci Aug 01 '12 at 12:04
  • 1
    Can you accept the answer if it is already working for you? – Jugal Shah Dec 11 '13 at 03:42
  • response.setContentType(contentType); you don't need to write such code using frameworks, especially Spring. produces = "text/plain;charset=UTF-8" is your choice – Yura Apr 04 '16 at 16:07

13 Answers13

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

Michael Kohne
  • 11,888
  • 3
  • 47
  • 79
Charlie Wu
  • 7,657
  • 5
  • 33
  • 40
  • 1
    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. – rwitzel Mar 19 '15 at 17:40
  • For me, it works, I was looking so long for solution. Thank you. – Marko Mar 22 '15 at 14:58
  • 1
    @rwitzel Maybe you need this too: response.setCharacterEncoding("UTF-8"); I have filter for that. – Marko Mar 22 '15 at 15:00
  • 2
    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." – vijayakumar gopalakrishnan Mar 27 '16 at 12:23
  • the site is no longer hosted. I've added solution 1 to this blog post https://monsterbrain.github.io/2019/04/01/spring-mvc-ajax-utf-8-problem/ – Monster Brain Apr 01 '19 at 08:44
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>
aki
  • 1,731
  • 2
  • 19
  • 24
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");
}
rwitzel
  • 1,694
  • 17
  • 21
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.

Xobotun
  • 1,121
  • 1
  • 18
  • 29
  • 1
    It's deprecated since 5.2 see [docs.spring.io](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/MediaType.html) – Valerij Dobler Feb 27 '21 at 22:45
  • 1
    @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. :D – Xobotun Mar 25 '21 at 16:42
  • 1
    I had the same problems with an rest service, that's how I got here in the first place. – Valerij Dobler Mar 26 '21 at 07:52
4

You need add charset in the RequestMapping annotation:

@RequestMapping(path = "/account",  produces = "application/json;charset=UTF-8")
Neuron
  • 5,141
  • 5
  • 38
  • 59
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();
    }
}
Paul Cuddihy
  • 477
  • 6
  • 12
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.

Community
  • 1
  • 1
Trung
  • 1,012
  • 13
  • 26
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.

miguel.angel
  • 49
  • 1
  • 8
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.

Yura_dan
  • 29
  • 2
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

gil.fernandes
  • 12,978
  • 5
  • 63
  • 76
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/

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
EACUAMBA
  • 461
  • 4
  • 8
0

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.

Devabc
  • 4,782
  • 5
  • 27
  • 40