claudioivp
claudioivp

Reputation: 549

View using Spring/JSF don't load CSS

I’m trying to run the project below, but I get a “bug” on Internet Explorer 9 with Document Mode: IE9 Standards. It simply don’t load the css.

In Chrome, Firefox, IE 7 and IE8, IE 9 with IE8 Standards / IE7 Standards it runs ok.

What I could to do to fix this “bug”???

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <display-name>HibernateSpringJSFDispatcher</display-name>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/application-context.xml</param-value>
    </context-param>
    <context-param>
        <param-name>facelets.REFRESH_PERIOD</param-name>
        <param-value>2</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
        <param-value>.xhtml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.jsf</url-pattern>
    </servlet-mapping>
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/application-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

application-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mvc="http://www.springframework.org/schema/mvc"

       xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

    <context:component-scan base-package="br.gov.pr.maringa" />

    <import resource="classpath:persistence-context.xml"/>

    <!-- map all requests to /resources/** to the container default servlet (ie, don't let Spring handle them) -->

    <bean id="defaultServletHttpRequestHandler" class="org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler" />

    <bean id="simpleUrlHandlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="urlMap">
        <map>
            <entry key="/resources/**" value-ref="defaultServletHttpRequestHandler" />
            <entry key="/javax.faces.resource/**" value-ref="defaultServletHttpRequestHandler" />
        </map>
        </property>
    </bean>

    <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter" />

    <mvc:annotation-driven/>
    <bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="cache" value="false" />
        <property name="viewClass" value="org.springframework.faces.mvc.JsfView" />
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".xhtml" />
    </bean>

    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="loadTimeWeaver">
            <bean
                class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
        </property>
        <property name="persistenceUnitName" value="persistence-unit" />
    </bean>
</beans>

faces-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="2.0" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="       http://java.sun.com/xml/ns/javaee       http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">
    <application>
        <resource-handler>br.gov.pr.maringa.hibernatespringjsfdispatcher.CustomResourceHandler</resource-handler>
        <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
        <resource-bundle>
            <base-name>MessageResources</base-name>
            <var>messages</var>
        </resource-bundle>
    </application>
</faces-config>

CustomResourceHandler.java

package br.gov.pr.maringa.hibernatespringjsfdispatcher;

import javax.faces.application.Resource;
import javax.faces.application.ResourceHandler;
import javax.faces.application.ResourceHandlerWrapper;
import javax.faces.application.ResourceWrapper;
import javax.faces.context.FacesContext;

import com.sun.faces.util.Util;

/**
 * Custom JSF ResourceHandler.
 * 
 * This handler bridges between Spring MVC and JSF managed resources. The handler takes
 * care of the case when a JSF facelet is used as a view by a Spring MVC Controller and the
 * view uses components like h:outputScript and h:outputStylesheet by correctly pointing the 
 * resource URLs generated to the JSF resource handler.
 * 
 * The reason this custom handler wrapper is needed is because the JSF internal logic assumes
 * that the request URL for the current page/view is a JSF url. If it is a Spring MVC request, JSF
 * will create URLs that incorrectly includes the Spring controller context.
 * 
 * This handler will strip out the Spring context for the URL and add the ".jsf" suffix, so the
 * resource request will be routed to the FacesServlet with a correct resource context (assuming the
 * faces servlet is mapped to the *.jsf pattern). 
 * 
 *
 */
public class CustomResourceHandler extends ResourceHandlerWrapper {

    private ResourceHandler wrapped;

    public CustomResourceHandler(ResourceHandler wrapped) {
        this.wrapped = wrapped;
    }
    @Override
    public ResourceHandler getWrapped() {
        return this.wrapped;    
    }

    @Override
    public Resource createResource(String resourceName, String libraryName) {
        return new CustomResource(super.createResource(resourceName, libraryName));
    }
    @Override
    public Resource createResource(String resourceName, String libraryName,
            String contentType) {
        return new CustomResource(super.createResource(resourceName, libraryName, contentType));
    }

    private static class CustomResource extends ResourceWrapper {

        private Resource wrapped;

        private CustomResource(Resource wrapped) {
            this.wrapped = wrapped;
        }
        @Override
        public Resource getWrapped() {
            return this.wrapped;
        }
        @Override
        public String getRequestPath() {
            String path = super.getRequestPath();
            FacesContext context = FacesContext.getCurrentInstance();
            String facesServletMapping = Util.getFacesMapping(context);
            // if prefix-mapped, this is a resource that is requested from a faces page
            // rendered as a view to a Spring MVC controller.
            // facesServletMapping will, in fact, be the Spring mapping
            if (Util.isPrefixMapped(facesServletMapping)) {
                // remove the Spring mapping
                path = path.replaceFirst("(" + facesServletMapping + ")/", "/");
                // append .jsf to route this URL to the FacesServlet
                path = path.replace(wrapped.getResourceName(), wrapped.getResourceName() + ".jsf");
            }
            return path;
        }

    }
}

HelloWorldController.java

package br.gov.pr.maringa.hibernatespringjsfdispatcher.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import br.gov.pr.maringa.exception.InvalidEntityException;
import br.gov.pr.maringa.hibernatespringjsfdispatcher.model.HelloWorld;
import br.gov.pr.maringa.hibernatespringjsfdispatcher.model.Usuario;
import br.gov.pr.maringa.hibernatespringjsfdispatcher.model.UsuarioHome;

@Controller
public class HelloWorldController {

    @Autowired
    private HelloWorld helloWorld;
    @Autowired
    private UsuarioHome uh;

    @RequestMapping(value="/helloWorld", method=RequestMethod.GET)
    public void helloWorld() {
        helloWorld.setMessage("Hello World from Spring MVC to JSF");

        Usuario u = new Usuario();

        u.setUsuario("claudio");
        u.setSenha("1234");

        try {
            uh.save(u);
        } catch (InvalidEntityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    @RequestMapping(value="/helloWorld", method=RequestMethod.POST)
    public void helloWorldPost(@RequestParam String msg) {
        helloWorld.setMessage(msg);
    }
}

helloWorld.xhtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:p="http://primefaces.org/ui"  
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">
    <h:head>
        <title>Hello World</title>
    </h:head>
    <h:body>
        <p>${helloWorld.message}</p>
        <p:panel header="qualquercoisa">abc</p:panel>
        <p>Say something: </p>
        <form method="post">
            <input name="msg" type="text"></input>
            <input type="submit" ></input>
        </form>
        <p>This image is linked as a JSF resource</p>
        <h:graphicImage name="images/jsf.jpg" />
        <p>This image is directly linked</p>
        <img src="resources/images/spring.png"></img>
    </h:body>
</html>

References: http://papweb.wordpress.com/2011/07/29/spring-mvc-3-jsf-2-with-maven-2-and-tomcat/

Upvotes: 1

Views: 1403

Answers (1)

BalusC
BalusC

Reputation: 1108722

IE9 standards mode accepts only Content-Type: text/css for CSS resources. If another content type is returned, IE9 ignores the entire CSS resource altogether.

You need to make absolutely sure that your custom resource handler sets the proper content type header. I have no idea how Spring plays a role here and how exactly that custom resource handler makes sense in this construct, but by default the content type is been set based on the file extension. At least, you need to make sure that the Resource#getContentType() method of your CustomResource returns text/css.

Upvotes: 1

Related Questions