Issue
I have a spring MVC web application and using JSPs to create my web pages. The problem is that when I directly submit a form the encoding is "application/x-www-form-urlencoded". When I submit the same data from the same form via an AJAX-Request the encoding is "application/x-www-form-urlencoded; charset=UTF-8".
I need the utf8 encoded characters typed in be a user in my controller. For example: A user types "äöüß" my controller gets "äöüÃ". When I send the data via an AJAX-Request I get "äöüß" which is correct.
What am I doing wrong? This is a simple form submit via http-post. It can't be impossible to do this utf8 encoded.
My application is running on a tomcat 8.5.11 with Spring 5.0.1. The web pages are all in HTML5 and I use the JSTL 1.2.5 in a servlet 3.1 environment. The JSON mapping and serialization is done by fasterxml 2.9.2
The configuration is completely Java-based.
My WebAppInitializer (a.k.a. web.xml)
...
@Override
protected Filter[] getServletFilters() {
return new Filter[] { new HiddenHttpMethodFilter(),
new CharacterEncodingFilter("UTF-8", true, true) };
}
In my servlet config I explicitly set a charset for the StringHttpMessageConverter.
...
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
converters.add(new ResourceHttpMessageConverter());
converters.add(new MappingJackson2HttpMessageConverter());
}
The Webpage looks like
<%@page contentType="text/html;charset=UTF-8"%>
<%@page pageEncoding="UTF-8"%>
<%@page session="true" %>
<%@page trimDirectiveWhitespaces="true" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<!DOCTYPE html>
<html lang="de">
...
<meta charset="UTF-8"/>
...
<form id="createArticleForm" action="<c:url value='/article/save' />" method="post">
<input type="hidden" name="utf8" value="✓" />
...
<input type="text" name="name" required="required" />
...
</form>
As you can see I also tried the utf8 hacks with a hidden field. But nothing works. Even if I set the form attributes accept-charset="UTF-8" and/or encoding="application/x-www-form-urlencoded; charset=UTF-8" nothing changes.
Edit1 I checked the HTTP Request Header sent from the browser to the server. And I found out that all parameters are correct. So I assume a spring configuration problem.
Solution
I found the solution myself. The problem lies in the initialiation of the characterEncodingFilter.
In a web.xml you do the following:
<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>
Since with Spring 5 Java-based Annotation Configuration is favored, according to the documentation you can do the following in your WebApplicationInitializer which is much simpler than the code above:
@Override
protected Filter[] getServletFilters() {
return new Filter[] { new HiddenHttpMethodFilter(),
new CharacterEncodingFilter("UTF-8", true, true) };
}
BUT this is NOT working properly with every HttpRequest coming in!!!
The solution is to not use the provided convenient way to automatically map the filter to the servlet.
Instead you must:
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
FilterRegistration.Dynamic filterRegistration = servletContext.addFilter("characterEncodingFilter", new CharacterEncodingFilter("UTF-8", true, true));
filterRegistration.addMappingForUrlPatterns(null, false, "/*");
filterRegistration = servletContext.addFilter("hiddenHttpMethodFilter", new HiddenHttpMethodFilter() );
filterRegistration.addMappingForUrlPatterns(null, false, "/*");
super.onStartup(servletContext);
}
And here you have your filter mapping back in sight and this works perfect!
Answered By - M46
Answer Checked By - Marie Seifert (JavaFixing Admin)