Spring Boot UTF-8 encoding issue. I suspect it tries to encode ISO-8859-1 to UTF-8 - spring

I'd like to use UTF-8 character encoding but I read somewhere that the controller's default encoding's ISO-8859-1.
I'm using spring boot with velocity.
So what I did, I tried to add the following ones (one at a time) to the header (None of them worked.)
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
Plus added to the application.properties the following lines:
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true
spring.velocity.charset=UTF-8
spring.velocity.content-type=text/html
server.tomcat.uri-encoding = UTF-8
I even tried to add the following line to the controller:
#RequestMapping(value = "/", method = RequestMethod.GET, produces={"text/html; charset=UTF-8"})
Plus tried to add the following bean to the application class:
#Bean
public HttpMessageConverter<String> responseBodyConverter() {
HttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
return converter;
}
This's a sample text that I included in the velocity template:
A sötét lovag igazi főhőse azonban valahogy ezúttal mégsem a mostanság nőnemű családtagjait szállodaszobábkban riogató Christian Bale, azaz a denevérember lett - hanem az ellenfél.
And that's the output I get:
A sötét lovag igazi fÅhÅse azonban valahogy ezúttal mégsem a mostanság nÅnemű családtagjait szállodaszobábkban riogató Christian Bale, azaz a denevérember lett - hanem az ellenfél.
Edit:
This's the controller I'm using currently:
#RequestMapping(value = "/", method = RequestMethod.GET, produces={"text/html; charset=UTF-8"})
public String homepage(Map<String, Object> model) {
return "homepage";
}
And I have a homepage.vm file at templates. Which has a header partial that contains this line:
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">

Could be due to default Eclipse encoding?
Window -> Preferences -> General -> Workspace : Text file encoding

To resolve same problem, I have used VelocityConfigurer with the following bean definition:
<bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
<property name="resourceLoaderPath" value="/WEB-INF/pages/"/>
<property name="configLocation" value="/WEB-INF/velocity.properties"/>
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
<property name="cache" value="false"/>
<property name="prefix" value=""/>
<property name="suffix" value=".vm"/>
<property name="contentType" value="text/html; charset=UTF-8"/>
</bean>
Please note the contentType property set in viewResolver.
When first tried providing it via VelocityEngineFactoryBean, I have realised late that my properties file was ignored.
Also, in velocity.properties make sure you have:
input.encoding=utf-8
output.encoding=utf-8
I didn't need anything else in here for simple case.
In 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>
That was it, I had no use for "produces" attribute in controller, no http meta needed, no xml charset encoding specified in the template file and no messing with messageconverter.
EDIT:
I don't have a playground setup with Spring Boot so can't test the exact implementation for you right now. However, web.xml here only defines a filter which can also be achieved programatically with Spring Boot:
import org.springframework.stereotype.Component;
import javax.servlet.*;
import java.io.IOException;
#Component
public class MyFilter implements Filter {
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//action here
filterChain.doFilter(servletRequest, servletResponse);
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {}
#Override
public void destroy() {}
}
I believe Spring Boot scans the sources for #Component automatically, otherwise package with filter's implementation should be added to component scan.
As for ideas on what the filter should do within doFilter(), you could explore the source code of Spring's CharacterEncodingFilter: https://github.com/spring-projects/spring-framework/blob/v4.2.1.RELEASE/spring-web/src/main/java/org/springframework/web/filter/CharacterEncodingFilter.java
Note that the above filter already extends other classes (such as OncePerRequestFilter).
I suppose you could instead add a method returning the filter instance:
#Bean
public Filter getCharacterEncodingFilter() {
org.springframework.web.filter.CharacterEncodingFilter characterEncodingFilter = new org.springframework.web.filter.CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
return characterEncodingFilter;
}

Related

jersey 2.5 and Spring 2.5 integration not working

I am trying to integrate Jersey (Version 2.x) into our current project which use's Spring 2.5. I have followed all the steps mentioned in their Spring webapp integration sample, but can't seem to get the auto wiring to work when the Jersey bean is called.
My config/class files are given below,
WEB.XML FILE
<servlet>
<servlet-name>jersey</servlet-name>
<servlet-class>
org.glassfish.jersey.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.inrev.rest.XXXSpringIntegration</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
SPRING FILE
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<bean name="myresource" class="com.xxx.rest.MyResource" autowire="byName"></bean>
XXXSpringIntegration CLASS
public XXXSpringIntegration()
{
register(RequestContextFilter.class);
register(MyResource.class);
System.err.println("I am getting registered");
}
MyResource.class
#Path("myresource")
public class MyResource {
#Autowired
private IRAdminDAO adminDAO;
public MyResource()
{
System.err.println("Getting ready now");
}
/**
* Method handling HTTP GET requests. The returned object will be sent
* to the client as "text/plain" media type.
*
* #return String that will be returned as a text/plain response.
*/
#Path("/list")
#GET
#Produces("application/json")
public String list()
{
System.err.println("Adming DAO "+adminDAO);
return "Got it!";
}
public void setAdminDAO(IRAdminDAO adminDAO)
{
System.err.println("Adming dao being set "+adminDAO);
this.adminDAO = adminDAO;
}
}
Added configuration for adminDAO
<bean id="adminDAO" class="com.xxx.bm.dao.impl.IRAdminDAOImpl">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
I am sure that the auto wiring works when Spring get's initialised, as the Syserr in the setter get's called when the file get's initialised by spring. However, when I make the API call, the adminDAO is null.
http://bm.com:8080/bm/rest/myresource/list
What could be causing this, I have tried all other permutation combinations but somehow the autowiring doesn't seem to be working when we make the API call.
Regards
Jersey work's fine with Spring 2.5, it's just a few jar's which were not present in my build. I am not sure if they would come with the maven build, but are certainly not present in the .zip download.
Also, there is no exceptions suggesting the jar is missing. jersey-spring3-2.11.jar being the star.

Spring MVC XML result chunked, missing Content-length header

I have a bunch of web services that return some content, sometimes > 100kb.
Unfortunately for the bigger results, I get the partial response with Transfer-encoding: Chunked.
Is there any way to disable chunking?
That's my method:
#RequestMapping(value = "/form/{repository}/{objectId}", method = RequestMethod.GET, headers="()")
#ResponseBody
public FormHelper getFormConfig(HttpServletRequest req, HttpServletResponse resp, #PathVariable String repository,
#PathVariable("objectId") String objectId) throws Exception
And that's the Spring XML config:
<import resource="classpath*:context-aaa.xml" />
<mvc:annotation-driven />
<bean
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="useDefaultSuffixPattern" value="false" />
</bean>
I had the same issue with Jersey library so I rewrote the project into Spring MVC, but it's still there...
Thanks in advance for any help.
Mariusz
I was able to make that work by adding the filter below:
<filter>
<filter-name>bufferFilter</filter-name>
<filter-class>org.springframework.web.filter.ShallowEtagHeaderFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>bufferFilter</filter-name>
<url-pattern>/services/*</url-pattern>
</filter-mapping>
https://jira.spring.io/browse/SPR-11948

request mapping url pattern in spring mvc3

I am using spring mvc3 in my project,and I am confused with the request mapping pattern (the last slash in the url)
Take the following controller method for example:
#RequestMapping(value = "/{id}/edit", method = RequestMethod.GET)
public String edit(#PathVariable int id, Model model) {
model.addAttribute(postDao.query(id));
return "posts/edit";
}
It works when get the url "http://localhsot/app/posts/3/edit",however it can not the method if get the url "http://localhsot/app/posts/3/edit/".
I know I can set the request mapping value like this:
#RequestMapping(value = {"/{id}/edit","/{id}/edit/"})
But I wonder if there is any other solution? It seems that rails will ignore the last slash in the url.
UPDATE:
servlet-context.xml:
<mvc:annotation-driven />
<mvc:view-controller path="/" view-name="home" />
<context:component-scan base-package="com.king.controller" />
<mvc:resources mapping="/res/**" location="/res/" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
web.xml
<filter>
<filter-name>httpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>httpMethodFilter</filter-name>
<servlet-name>modelServlet</servlet-name>
</filter-mapping>
<servlet>
<servlet-name>modelServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>modelServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
I think you are trying to solve the wrong problem.
If you match a URL both with and without a trailing slash, you will get a bad rating from search engines because of duplicate content.
What I would do is to add a Filter that sends all requests without trailing slash a redirect with trailing slash (or vice-versa) using status code HttpServletResponse.SC_MOVED_PERMANENTLY
Here is a minimal implementation of such a filter:
public class CanonicalUrlFilter implements Filter {
#Override
public void init(final FilterConfig filterConfig) throws ServletException { }
#Override
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain filterChain) throws IOException, ServletException {
if (servletRequest instanceof HttpServletRequest) {
HttpServletRequest hsr = (HttpServletRequest) servletRequest;
if (hsr.getMethod().equals("GET") && !hsr.getRequestURI().endsWith("/") && (hsr.getQueryString() == null)) {
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
response.sendRedirect(hsr.getRequestURI() + "/");
return;
}
}
filterChain.doFilter(servletRequest, servletResponse);
}
#Override
public void destroy() { }
}

How to set content-type in Freemarker views when using Spring MVC?

I'm using Sping MVC with freemarker views. I set up a FreeMarkerViewResolver to resolve the views and it works so far but now I have encoding problems. All my views are HTML 5 pages in UTF-8 encoding and I also added a <meta charset="UTF-8" /> to the HTML page but characters are still printed in the wrong encoding. I checked the HTTP headers with curl and found this:
k#jules:~$ curl -I http://localhost:8080/testweb/test.view
HTTP/1.1 200 OK
Content-Type: */*;charset=ISO-8859-1
But when I request some non-existing resource (Which generates a Tomcat error) then I get this:
k#jules:~$ curl -I http://localhost:8080/testweb/nothere.html
HTTP/1.1 200 OK
Content-Type: text/html;charset=utf-8
So Tomcat itself returns the correct content-type but a Spring MVC Freemarker views don't.
For a JSP I can set the Content-Type in the JSP header but where can I set it for a freemarker template? I guess I have to do this somewhere in the Spring bean configuration but I can't find the right place.
The view resolver (should be in your dispatcher-servlet.xml) has a contentType property for that:
<bean id="viewResolver"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="prefix" value=""/>
<property name="suffix" value=".ftl"/>
<property name="contentType" value="text/html;charset=UTF-8"/>
</bean>
I have also experienced a problem with showing UTF-8 characters (special characters like æ. ø and å etc.), when using spring framework and freemarker template.
What i did was.
1. Ensure that your .ftl page is encoded with utf-8
This is an important thing to ensure, that a page not encoded with UTF-8 charset, could show the wrong numbers even though you have all the other requirements set. Check your IDE settings, to find out which default encoding it sets your files to. I think however today that both Eclipse and NetBeans set all files with UTF-8 encoding as standard. You must ensure that it is encoding UTF-8 with no BOM.
2. Include the Meta tag in your template file to set the charset
In your template (.ftl) file, which holds your <head> tag, set a <meta>, with the attribute charset="UTF-8". This is if you use HTML 5. If you use xhtml or HTML 4, your meta tag needs to look like this
HTML 5 <meta charset="UTF-8" />
HTML 4/XHTML <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
3. Make sure you set a Character Encoding Filter in your Deployment Descriptor File
You have to filter all incoming/outgoing requests through a character encoding filter. This filter is set in your deployment descriptor (web.xml / or the java equivalent WebApplicationInitializer).
WebApplicationInitializer (Java File)
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
registerCharacterEncodingFilter(servletContext);
}
/**
* Filter all incoming requests with character encoding UTF-8
* #param servletContext
*/
private void registerCharacterEncodingFilter(ServletContext servletContext) {
CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
encodingFilter.setEncoding("UTF-8");
encodingFilter.setForceEncoding(true);
FilterRegistration.Dynamic characterEncodingFilter = servletContext.addFilter("characterEncodingFilter", encodingFilter);
characterEncodingFilter.addMappingForUrlPatterns(null, false, "/*");
}
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>
4. Set the FreeMarker Character Encoding in configurer and view resolver
You also need to make all your FreeMarker files be standard encoded with UTF-8, this is done by setting their properties to UTF-8 in the FreeMarkerConfigurer and the FreeMarkerViewResolver. This is set in your spring application context file (I will only show the Java equivalent as it is the same in the XML file).
/**
* FreeMarker Configurer will help configure different settings of
* the FreeMarker template engine.
*
* #return an object of the FreeMarkerConfigurer class.
*/
#Bean
public FreeMarkerConfigurer freemarkerConfig() {
FreeMarkerConfigurer freeMarkerConfigurer = new FreeMarkerConfigurer();
freeMarkerConfigurer.setTemplateLoaderPath("/templates/");
freeMarkerConfigurer.setDefaultEncoding("UTF-8");
return freeMarkerConfigurer;
}
/**
* The View resolver to use when resolving FreeMarker views.
*
* #return the View Resolver Object used to resolve FreeMarker views.
*/
#Bean
public FreeMarkerViewResolver viewResolver() {
FreeMarkerViewResolver viewResolver = new FreeMarkerViewResolver();
viewResolver.setPrefix("");
viewResolver.setSuffix(".ftl");
viewResolver.setCache(false); //Set to true during production
viewResolver.setContentType("text/html;charset=UTF-8");
return viewResolver;
}
Hope this helps you out :)

Spring Web Flow and Url Rewrite Filter - cleaning URLs

I'm working on Spring MVC + Web Flow web application. I have mapped /home to MVC Controller and /test to Flow Controller. To remove /app from URLs i'm trying to use Url Rewrite Filter.
Mappings in MVC Controllers (#Controller) works good with that:
http://localhost:8080/spring/home -> render home view.
But when a request goes to WebFlow Controller something is wrong resulting in Error 404:
http://localhost:8080/spring/test -> redirect to http://localhost:8080/spring/app/test?execution=e1s1 -> page not found.
How to remove /app from URLs and got everything working ?
urlrewrite.xml:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.0//EN" "urlrewrite3.0.dtd">
<urlrewrite default-match-type="wildcard">
<!-- to remove /app -->
<rule>
<from>/**</from>
<to>/app/$1</to>
</rule>
<outbound-rule>
<from>/app/**</from>
<to>/$1</to>
</outbound-rule>
</urlrewrite>
Dispatcher servlet mapping:
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
<filter-mapping>
<filter-name>UrlRewriteFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Simple controller:
#Controller
public class MainController {
#RequestMapping(value={"/home", "/"})
public String index(Model model) {
return "index";
}
}
Some logs:
DEBUG [FlowHandlerMapping:108] : Mapping request with URI '/spring/app/test' to flow with id 'test'
DEBUG [FlowExecutorImpl:135] : Launching new execution of flow 'test' with input null
DEBUG [FlowDefinitionRegistryImpl:59] : Getting FlowDefinition with id 'test'
DEBUG [FlowExecutionImplFactory:78] : Creating new execution of 'test'
...
DEBUG [FlowExecutionImpl:417] : Assigned key e2s1
DEBUG [FlowHandlerAdapter:367] : Sending flow execution redirect to '/spring/app/test?execution=e2s1'
DEBUG [DispatcherServlet:824] : Null ModelAndView returned to DispatcherServlet with name 'spring': assuming HandlerAdapter completed request handling
DEBUG [DispatcherServlet:674] : Successfully completed request
DEBUG [DispatcherServlet:693] : DispatcherServlet with name 'spring' processing GET request for [/spring/app/app/test]
DEBUG [FlowHandlerMapping:114] : No flow mapping found for request with URI '/spring/app/app/test'
WARN [PageNotFound:947] : No mapping found for HTTP request with URI [/spring/app/app/test] in DispatcherServlet with name 'spring'
Temporarily i did it as here using customized FlowHandler. It works, but i think it must be a simpler solution...
package utils;
public class PrettyFlowUrlHandler extends DefaultFlowUrlHandler {
#Override
public String createFlowDefinitionUrl(String flowId, AttributeMap input, HttpServletRequest request) {
return cleanUrl(super.createFlowDefinitionUrl(flowId, input, request), request);
}
#Override
public String createFlowExecutionUrl(String flowId, String flowExecutionKey, HttpServletRequest request) {
return cleanUrl(super.createFlowExecutionUrl(flowId, flowExecutionKey, request), request);
}
protected String cleanUrl(String url, HttpServletRequest request) {
String pattern = request.getServletPath().substring(1) + "/";
return url.replaceFirst(pattern, "");
}
}
config:
<bean id="flowMappings" class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
<property name="flowRegistry" ref="flowRegistry"/>
<property name="flowUrlHandler">
<bean class="utils.PrettyFlowUrlHandler"/>
</property>
<property name="order" value="0" />
</bean>
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
<property name="flowExecutor" ref="flowExecutor"/>
<property name="flowUrlHandler">
<bean class="utils.PrettyFlowUrlHandler"/>
</property>
</bean>
Edit
Not working with custom flow handler like below:
#Component("test")
public class DataHandler extends AbstractFlowHandler {
#Override
public String handleExecutionOutcome(FlowExecutionOutcome outcome,
HttpServletRequest request, HttpServletResponse response) {
// ... checking outcome ...
return "/home"; // redirect to '404 page not found', because of rewrite to `/app/app/home`
}
}
Are you you trying to remove app from your url for eg
http://www.mydomain.com/app/home.html and change it to
http://www.mydomain.com/home.html
If yes then you should be configuring server.xml and your application should be deployed as ROOT instead of app in public_html/ or your tomcat directory.
This will work for you

Resources