0
votes

I can't access the .xhtml in a folder(views) under webapp but i can access it if i place them right under the webapp using requestMapping URL.

Can someone help me how to access the xhtml file in a folders under webapp using Spring MVC and spring boot, i'm also planning to embed the static resources like image and css files by creating the folder(css, images) under webapp.

Thanks.

Here is my code

project explorer

MyAutoConfiguration.java

@Configuration
@ConditionalOnClass(Some.class)
@EnableConfigurationProperties(SomeProperties.class)
@ComponentScan("com.boot.configurations")
@SpringBootApplication
public class MyAutoConfiguration {

    private static Log log = LogFactory.getLog(MyAutoConfiguration.class);


    @Bean
    public static ViewScope viewScope() {
        return new ViewScope();
    }

    /**
     * Allows the use of @Scope("view") on Spring @Component, @Service and @Controller
     * beans
     */
    @Bean
    public static CustomScopeConfigurer scopeConfigurer() {
        CustomScopeConfigurer configurer = new CustomScopeConfigurer();
        HashMap<String, Object> hashMap = new HashMap<String, Object>();
        hashMap.put("view", viewScope());
        configurer.setScopes(hashMap);
        return configurer;
    }

    /*
     * Below sets up the Faces Servlet for Spring Boot
     */
    @Bean
    public FacesServlet facesServlet() {
        return new FacesServlet();
    }

    /*This one replaces both the web.xml and the Spring configuration file! 
     * To add a servlet, you add a method to the main class 
     * (instead of configuring it in the obsolete web.xml)
     * */
    @Bean
    public ServletRegistrationBean facesServletRegistration() {
        ServletRegistrationBean registration = new ServletRegistrationBean(
                facesServlet(), "*.xhtml");
        registration.setName("FacesServlet");
        registration.addUrlMappings("/views/*","*.xhtml","/faces/*","*.jsf");
        registration.setLoadOnStartup(1);
        registration.setEnabled(true);
        registration.setOrder(1);
        return registration;
    }


    @Bean
    WebMvcConfigurer configurer () {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addResourceHandlers (ResourceHandlerRegistry registry) {
                ResourceHandlerRegistration resourceRegistration  = registry
                        .addResourceHandler("/pages/**")
                        .addResourceLocations("/resources/","classpath:/images/")  //Configuring Multiple Locations for a Resource
                        .setCachePeriod(3600);            //The resources served will be cached in the browser for 3600 seconds
                registry.addResourceHandler("resources/**").addResourceLocations("/resources/");
                registry.addResourceHandler("/css/**").addResourceLocations("/css/");
                registry.addResourceHandler("/img/**").addResourceLocations("/img/");
                registry.addResourceHandler("/js/**").addResourceLocations("/js/");
            }
        };
    }

    @Bean
    public ServletListenerRegistrationBean<ConfigureListener> jsfConfigureListener() {
        return new ServletListenerRegistrationBean<ConfigureListener>(
                new ConfigureListener());
    }

Initializer.java

@Configuration
public class Initializer implements ServletContextInitializer {

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
    servletContext.setInitParameter("primefaces.CLIENT_SIDE_VALIDATION", "true");
    servletContext.setInitParameter("javax.faces.PROJECT_STAGE", "Development");

}
}

SpringMVCService

@RestController
@Scope("request")
public class SpringMVCService {

    @Autowired(required=true)
    TestService testService;

    /**
     * Displays the message from the test service including information in the
     * session scope
     * 
     * This is a proof that calling the Spring MVC service is on the same
     * context as the JSF views(A problem I had before)
     */
    @RequestMapping("/greeting")
    public String greeting() {
        return testService.getMessage();
    }

    @RequestMapping("/welcome.html")
    public ModelAndView firstPage() {
        return new ModelAndView("test.xhtml");
    }

    @RequestMapping("/login.html")
    public ModelAndView loginPage() {
        String transferFunds = "hellooooooooo";
        return new ModelAndView("login.xhtml","transferFunds",transferFunds);
    }

    @RequestMapping("/home.jsp")
    public ModelAndView homePage() {
        String transferFunds = "hellooooooooo";
        return new ModelAndView("home.xhtml");
    }

    @RequestMapping("/loginUser.jsp")
    public ModelAndView loginUserPage() {
        return new ModelAndView("loginPage.xhtml");
    }

    @RequestMapping("/userAccount.html")
    public ModelAndView registerPage() {
        return new ModelAndView("useraccount.xhtml");
    }
}

Viewscope.java

public class ViewScope implements Scope {
    public Object get(String name, ObjectFactory<? extends Object> objectFactory) {
        Map<String, Object> viewMap = FacesContext.getCurrentInstance()
                .getViewRoot().getViewMap();
        Object obj;
        if (viewMap.containsKey(name)) {
            obj = viewMap.get(name);
        } else {
            Object object = objectFactory.getObject();
            viewMap.put(name, object);
            obj = object;
        }
        return obj;
    }

    public Object remove(String name) {
        return FacesContext.getCurrentInstance().getViewRoot().getViewMap()
                .remove(name);
    }

    public String getConversationId() {
        return null;
    }

    public void registerDestructionCallback(String name, Runnable callback) {
        // Not supported
    }

    public Object resolveContextualObject(String key) {
        return null;
    }
}

application.properties

logging.level.org.springframework: DEBUG
logging.level.com=TRACE

spring.mvc.view.prefix=/
#spring.mvc.view.suffix=.xhtml

# for context-param in web.xml
#https://jsflive.wordpress.com/2013/04/01/jsf22-config-resource-dir/
server.context_parameters.javax.faces.WEBAPP_RESOURCES_DIRECTORY=/WEB-INF/

# ADMIN (SpringApplicationAdminJmxAutoConfiguration)
spring.application.admin.enabled=true
spring.application.admin.jmx-name=org.springframework.boot:type=Admin,name=SpringApplication # JMX name of the application admin MBean.

Web.xml (src -> main -> webapp -> WEB-INF -> Web.xml)

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
        http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
        id="WebApp_ID" version="3.0">

<!--    TODO put session timeout? where does JSF view scope grab it's timeout from? -->

<!-- TODO How do I get rid of this web.xml because right now this is throwing a could
not find backup factory exception when not adding this entry(Even thought it's a 
different servlet name(It has a space)) -->
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    </servlet>

</web-app>

build.gradle

buildscript {
    repositories {
        maven { url "http://repo.spring.io/libs-release" }
        mavenLocal()
        mavenCentral()
        jcenter()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.8.RELEASE")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'

repositories {
    mavenLocal()
    mavenCentral()
    maven { url "http://repo.spring.io/libs-release" }
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")

    //compile group: "org.springframework.boot", name: "spring-boot-starter"
//compile group: "org.springframework", name: "spring-web", version: "4.0.2.RELEASE"

    compile group: "org.primefaces", name: "primefaces", version: "6.1"
    compile group: "com.sun.faces", name: "jsf-api", version: "2.2.7"
    compile group: "com.sun.faces", name: "jsf-impl", version: "2.2.7"
    compile group: 'javax.el', name: 'el-api', version: '2.2'
    compile "org.glassfish.web:el-impl:2.2"
    compile "org.springframework.boot:spring-boot-autoconfigure:1.5.8.RELEASE",
            "org.springframework.boot:spring-boot-configuration-processor:1.5.8.RELEASE",

    compile group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1.1'
    compile group: 'javax.servlet', name: 'jstl', version: '1.2'
    //compile group: 'javax.servlet', name: 'servlet-api', version: '2.5'
    compile group: 'javax.servlet.jsp', name: 'jsp-api', version: '2.1'
    compile group: 'org.glassfish', name: 'javax.faces', version: '2.2.8'
    compile group: 'javax.inject', name: 'javax.inject', version: '1'

    compile "org.apache.tomcat.embed:tomcat-embed-core:8.5.24"
    compile "org.apache.tomcat.embed:tomcat-embed-logging-juli:8.5.24"
    //compile "org.apache.tomcat.embed:tomcat-embed-jasper:8.5.24"
    compile group: "org.apache.tomcat.embed", name: "tomcat-embed-jasper", version: "8.5.24"

    //below dependency  dont got @RestController    but current version is 4.3.12.RELEASE which got @RestController 
    //compile group: 'org.springframework', name: 'spring-web', version: '3.0.4.RELEASE'

    testCompile("junit:junit")
}

task wrapper(type: Wrapper) {
    gradleVersion = '2.6'
}
1

1 Answers

0
votes

Remove /views/* from urlMappings of the FacesServlet. You don't need it as you have *.xhtml mapped and the folder mapping is removed from the path when the servlet is looking for the actual file.

@Bean
public ServletRegistrationBean facesServletRegistration() {
    ServletRegistrationBean registration = new ServletRegistrationBean(
            facesServlet(), "*.xhtml");
    registration.setName("FacesServlet");
    registration.addUrlMappings("*.xhtml", "/faces/*", "*.jsf");
    registration.setLoadOnStartup(1);
    registration.setEnabled(true);
    registration.setOrder(1);
    return registration;
}

In fact, you could do with only *.xhtml mapping and everything would be just fine.

You can now access your files using http://yourserver/yourapp/views/home.xhtml. With your current configuration, this URL would find home.xhtml only directly under your webapp directory.