Announcement Announcement Module
Collapse
No announcement yet.
UTF-8 encoding in Spring MVC Portlet Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • UTF-8 encoding in Spring MVC Portlet

    We are writing a jsr-168 portlet using spring-webmvc-portlet-2.5.5 however we are encountering character encoding problems when displaying any special characters. For instance the character displays as é. If we deploy a second app with the same jsp but use getPortletContext().getRequestDispatcher("/path/file.jsp") instead of spring's org.springframework.web.portlet.DispatcherPortlet, it displays correctly. Also, if we use spring-webmvc-2.5.5 outside of the portal environment, it also displays correctly. All of our pages have character encoding set to UTF-8 and we have also tried using the org.springframework.web.filter.CharacterEncodingFi lter to force encoding to UTF-8. The text still displays incorrectly. Any idea why this is happening and how we can fix it?

    I should also point out that with debug turned on the DispatcherPortlet still indicates that it is setting the response to IS-8859-1 even with the filter supposedly forcing everything to UTF-8:
    DEBUG [org.springframework.web.portlet.DispatcherPortlet. render:1088] - Setting portlet response content type to view-determined type [text/html;charset=ISO-8859-1]

    Our web.xml is as follows:

    <web-app>

    <display-name>MyApp</display-name>

    <!-- CONTEXT PARAMS -->

    <context-param>
    <param-name>log4jConfigLocation</param-name>
    <param-value>/WEB-INF/classes/log4j.xml</param-value>
    <description>Location of the Log4j configuration file</description>
    </context-param>

    <context-param>
    <param-name>log4jRefreshInterval</param-name>
    <param-value>60000</param-value>
    <description>Milliseconds between checks to refresh log4j configuration, 60000 = 1 minute</description>
    </context-param>

    <context-param>
    <param-name>log4jExposeWebAppRoot</param-name>
    <param-value>false</param-value>
    <description>Should Log4j listener overwrite webAppRootKey? See Spring documentation for Log4j listener</description>
    </context-param>

    <context-param>
    <param-name>webAppRootKey</param-name>
    <param-value>MyApp.root</param-value>
    </context-param>

    <context-param>
    <param-name>contextPath</param-name>
    <param-value>MyApp</param-value>
    <description>The webapp name</description>
    </context-param>

    <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>WEB-INF/context/applicationContext.xml, WEB-INF/context/app/*-context.xml</param-value>
    <description>Comma-separated list of Spring context files to load to initialize the application</description>
    </context-param>

    <!-- I18N -->
    <context-param>
    <param-name>javax.servlet.jsp.jstl.fmt.localizationContex t</param-name>
    <param-value>MyAppResources</param-value>
    <description>Basename of the localized message bundles</description>
    </context-param>

    <context-param>
    <param-name>javax.servlet.jsp.jstl.fmt.fallbackLocale</param-name>
    <param-value>en_US</param-value>
    <description>Locale to use if Java Runtime does not support the web request's locale</description>
    </context-param>

    <!-- Force Char Encoding -->
    <filter>
    <filter-name>SetCharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEnco dingFilter</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>

    <!-- SECURITY FILTER TO PREVENT DIRECT ACCESS TO WEB-APP -->

    <filter>
    <filter-name>PortletApplicationSecurityFilter</filter-name>
    <filter-class>com.portal.PortletApplicationSecurityFilter</filter-class>
    </filter>

    <filter-mapping>
    <filter-name>SetCharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter-mapping>
    <filter-name>PortletApplicationSecurityFilter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>


    <!-- LOG4J CONFIG LISTENER -->

    <listener>
    <listener-class>org.springframework.web.util.Log4jConfigList ener</listener-class>
    </listener>

    <!-- PORTLET APPLICATION CONTEXT LISTENER -->

    <listener>
    <listener-class>com.portal.PortletApplicationServletContextL istener</listener-class>
    </listener>

    <!-- SPRING APPLICATION CONTEXT LISTENER -->

    <listener>
    <listener-class>org.springframework.web.context.ContextLoade rListener</listener-class>
    </listener>

    <!-- PORTLET COMMAND SERVLET -->

    <servlet>
    <servlet-name>PortletCommandServlet</servlet-name>
    <servlet-class>com.portal.portlet.jsrcontainer.PortletComma ndServlet</servlet-class>
    </servlet>

    <!-- VIEW RENDERER SERVLET -->

    <servlet>
    <servlet-name>ViewRendererServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.ViewRenderer Servlet</servlet-class>
    <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- SERVLET MAPPINGS -->

    <servlet-mapping>
    <servlet-name>PortletCommandServlet</servlet-name>
    <url-pattern>/portletCommand/*</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
    <servlet-name>ViewRendererServlet</servlet-name>
    <url-pattern>/WEB-INF/servlet/view</url-pattern>
    </servlet-mapping>

    <!-- SESSION CONFIG -->

    <session-config>
    <session-timeout>30</session-timeout>
    </session-config>

    <!-- TAGLIB -->

    <taglib>
    <taglib-uri>/spring</taglib-uri>
    <taglib-location>/WEB-INF/taglib/spring.tld</taglib-location>
    </taglib>

    <taglib>
    <taglib-uri>/portlet</taglib-uri>
    <taglib-location>/WEB-INF/taglib/portlet.tld</taglib-location>
    </taglib>

    </web-app>

    and a clip from our portlet.xml:

    <portlet>
    <description>MyPortlet</description>
    <portlet-name>MyPortlet</portlet-name>
    <display-name>MyPortlet</display-name>
    <portlet-class>org.springframework.web.portlet.DispatcherPo rtlet</portlet-class>
    <init-param>
    <name>contextConfigLocation</name>
    <value>/WEB-INF/context/portlet/viewService.xml</value>
    </init-param>
    <expiration-cache>0</expiration-cache>
    <supports>
    <mime-type>text/html</mime-type>
    <portlet-mode>view</portlet-mode>
    <portlet-mode>config</portlet-mode>
    </supports>
    <supported-locale>en</supported-locale>
    <supported-locale>es</supported-locale>
    <portlet-info>
    <title>MyPortlet</title>
    <short-title>MyPortlet</short-title>
    <keywords>basic, portlet</keywords>
    </portlet-info>
    </portlet>
    Last edited by jhughes; Nov 25th, 2008, 05:07 PM.

  • #2
    We found a solution to our problem... but it raises a question.

    If we add:
    <property name="contentType" value="text/html;charset=UTF-8" />
    to our view resolver definition, the character encoding works.

    So the question is why does the view resolver default to ISO-8859-1 instead of using the character encoding based on the <%@ page contentType="text/html;charset=UTF-8" isELIgnored="false" pageEncoding="UTF-8" %> at the top of the jsp?
    Last edited by jhughes; Nov 25th, 2008, 05:43 PM.

    Comment


    • #3
      Servlet filter do not get applied to portlet requests. That would (partially) explain why it works in a servlet context but not in a portlet context.

      If you remove the CharacterEncodingFilter, do you get the same behavior in a Servlet context? I assume the answer to this is yes.

      So, this does sound like the ViewResolver is not picking up the encoding properly. Which ViewResolver are you using and how is it configured?

      Comment


      • #4
        Looks like the DispatcherPortlet sets the content type BEFORE your jsp ever gets included - so no matter what your JSP has set this will be ignored. The DispatcherPortlet uses the default content type for the view if no content type is explicitly set on the view, this is "text/html;charset=ISO-8859-1".

        Your approach is probably the best way to overcome this, perhaps raising a jira would be appropriate.

        Comment


        • #5
          Dug into the code a bit more -- here is what is happening:

          The DispatcherPortlet will set the ContentType on the RenderResponse, but only if it was not already set prior to rendering. When it is time to render, it checks to see if any ContentType was already set. If not, it gets the ContentType string from the View object and uses that (this is the debug message that you are seeing).

          The eventual call to PortletRequestDispatcher.include would not generally set the ContentType on the RenderResponse. However, the spec (and many portlet containers) require that the ContentType be explicitly set. That is why the DispatcherPortlet does it. Regardless, I think the ContentType would still be getting set this way even if the include were doing it -- the View object sets the ContentType on the ServletResponse when it renders itself using the same ContentyType value that the DispatcherPortlet is already using.

          The problem here appears to be that the ContentType on the View object is never set in the case of JSP. It just uses the default value defined in AbstractView, which is ""text/html;charset=ISO-8859-1". It does this because the JSP will set the ContentType itself when used as part of a forward, but is ignored when used as part of an include. Since all Portlet requests are includes (there is no such thing as forward in the PortletRequestDispatcher), the JSP never sets the ContentType.

          So, after all that, you would either need a special View class that could parse the view definition to determine it's ContentType (yuck) or you need to continue with the solution you already have, which is to explicitly set the ContentType somewhere else. You can continue to do this with the ViewResolver as you have already done, or you could do it in your Controller by setting the ContentType on the RenderResponse there, or you could create a HandlerInterceptor that is analogous to the CharacterEncodingFilter.

          Sorry this isn't a "happy" answer, but at least it is a comprehensive one...

          Comment


          • #6
            Much along the lines of what John is saying, we use a interceptor (that gets added to the DefaultAnnotationHandlerMapping bean that we use)


            Code:
            public class CharEncodingInterceptor extends HandlerInterceptorAdapter {
            	
            	private String contentType;
            	
            	public void setContentType(String contentType) {
            		this.contentType = contentType;
            	}
            
            	@Override
            	public boolean preHandleRender(RenderRequest request, RenderResponse response, Object handler) throws Exception {
            		response.setContentType(this.contentType);
            		return true;
            	}
            
            }

            Comment


            • #7
              We have just encountered this problem while re-platforming our portlets from Oracle Application Server 10g to WebLogic 11g (10.3). Both versions of our code use the same 2.0.8 version of the Spring framework.

              The view resolver <property name="contentType" value="text/html;charset=UTF-8" /> fix has worked for us - many thanks.

              I can see why we would need this setting on WebLogic, but I'm puzzled as to why we did not have the issue on Application Server 10g.

              Comment

              Working...
              X