Tomcat considers the entire request to be ISO-8859-1
by default "factory".
The direct and specific solution for tomcat is to change the server configuration ( server.xml
):
<Server port="8105" shutdown="SHUTDOWN">
...
<Service name="Catalina">
<Connector port="8180" URIEncoding="UTF-8" />
<Engine name="Catalina" defaultHost="localhost">
<Host name="localhost" appBase="webapps" />
</Engine>
</Service>
....
</Server>
However, I do not consider this an ideal solution because when you need to deploy deploy from your application in a third-party environment you probably will not have access to this change.
A solution that can be implemented in the application itself divides (at least) into: encoding in the body of requests, parameters, and headers.
To solve the problem for data in the request body, I usually add a filter to the application in web.xml
which forces the encoding to be of a certain type. In a project where I use Spring, the following excerpt solves the problem:
<filter>
<filter-name>encoding-filter</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>encoding-filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
If you do not use Spring, you can use the apache library code and place the class in your own project.
For data in headers or parameters, we can encapsulate HttpServletRequest
through a filter. I did the implementation below, but I do not have an application on hand to test, so any problem give me a feedback :
public class ParametersEncodingFilter implements Filter {
private String charset = "UTF-8";
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String charsetParam = filterConfig.getInitParameter("charset");
if (charsetParam != null && !charsetParam.isEmpty()) {
this.charset = charsetParam;
}
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(new FilteredRequest(charset, request), response);
}
@Override
public void destroy() {
//nothing to clean up
}
final private static class FilteredRequest extends HttpServletRequestWrapper {
public FilteredRequest(String charset, ServletRequest request) {
super((HttpServletRequest)request);
//convert encoding params
Map<String, String[]> originalParams = super.getParameterMap();
for(Object key : originalParams.keySet()) {
String[] entry = originalParams.get(key);
for (int i = 0; i < entry.length; i++) {
try {
entry[i] = new String(entry[i].getBytes("ISO-8859-1"), charset);
} catch (UnsupportedEncodingException e) {
return; //if can't convert one, it cannot convert any of them
}
}
}
}
}
}
Note: This implementation considers that the filter has a parameter with the desired encoding, as in the Spring filter configuration above.
And one last comment: If it is possible to encode URL parameters, for example N%C3%A3o%2Bpermitido
instead of Não+Permitido
, it might solve the parameter-specific problem without additional implementations.