21
votes

I cannot get spring mvc to resolve .html view files.

I have the following view folder structure:

WEB-INF
      `-views
            |- home.jsp
            `- home.html

I have a simple hello world controller method that just prints a message and returns the view name "home". I have a home.jsp file, but would like to use the home.html instead.

<!-- Working servlet mapping --> 
<servlet-mapping>
    <servlet-name>spaceShips</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

<!-- working servlet context -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 
    <beans:property name="prefix" value="WEB-INF/views/" />
    <beans:property name="suffix" value=".jsp" /> 
</beans:bean>

When I hit spaceships/home the controller prints the hello world message and I see the home.jsp view without a problem.

The problem is when I change the suffix to .html.

After changing the suffix and navigating to /home, the controller prints the message however I see a 404 error in the browser and the following in the console: WARNING: No mapping found for HTTP request with URI [/spaceships/WEB-INF/views/home.html]

To clarify:

<!-- not working with .html -->
<servlet-mapping>
    <servlet-name>spaceShips</servlet-name>
    <!-- I have tried /* here as well without success -->
    <url-pattern>/</url-pattern>
</servlet-mapping>

<!-- not working with .html-->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 
    <beans:property name="prefix" value="WEB-INF/views/" />
    <beans:property name="suffix" value=".html" /> 
</beans:bean>

I have checked in the exploded war folder and can confirm that both home files are present.

Has anyone encountered something like this before?

Last chunk of console message:

INFO: Server startup in 5256 ms
Hello, World!
Jul 27, 2014 12:52:01 PM org.springframework.web.servlet.DispatcherServlet noHandlerFound
WARNING: No mapping found for HTTP request with URI [/spaceships/WEB-INF/views/home.html] in DispatcherServlet with name 'spaceShips'

Thanks for reading.

=========== SOLUTION ============

The following (ugly) configuration solved the issue. There are probably ways to clean this up, but if you are experiencing the same problem you may be able to piece together a solution from this.

Folder structure:

 WEB-INF
       `-static
              |-html
                    `-home.html
              |-css
              `-img

Controller method:

 @RequestMapping(value = "/home")
 public String goHome() { 
      System.out.println("lolololololol");
      return "static/html/home";
 }

Spring config:

 <resources mapping="/static/**" location="/WEB-INF/static/" />

 <beans:bean
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
      <beans:property name="prefix" value="" />
      <beans:property name="suffix" value=".html" />
 </beans:bean>
4
In your controller, the @Path may have to have .html extension.Wand Maker
I have the same problem but instead of 404 error I am getting 405. The problem according to what I understand is that resources handling accepts only GET requests so when I redirect to index.html after posting a form with POST request and redirect to index.html if user is registered !Adelin
Thank you for posting the solution. Other topics lacks the right combination of resources mapping and InternalResourceViewResolver.Oleg Kurbatov
try to use <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity</artifactId> <version>1.7</version> </dependency>Ali mohammadi

4 Answers

10
votes

Check this out for mapping html files in Spring mvc (Details step is given in Answer):

Which spring view resolver plays nice with angularjs?

In simple:

In order to use static resource(html,css,img,js) in spring, use a directory structure that looks like the following:

src/
   package/
   LayoutController.java
WebContent/
   WEB-INF/
    static/
      html/
       layout.html
      images/
       image.jpg
      css/
       test.css
      js/
       main.js
     web.xml
    springmvc-servlet.xml


@Controller 
public class LayoutController {

 @RequestMapping("/staticPage") 
public String getIndexPage() { 
return "layout.htm"; 

} }




<!-- in spring config file -->
 <mvc:resources mapping="/static/**" location="/WEB-INF/static/" />

layout.html

<h1>Page with image</h1>
<img src="/static/img/image.jpg"/>
3
votes

This is because normally *.jsp style uri patterns are handled by the servlet container and in this specific instance *.html is not being handled by the container and instead the path is being delegated to Spring MVC which does not know how to render these extensions.

As an example, if you are using tomcat, you would see these entries under conf/web.xml file:

<servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>*.jsp</url-pattern>
    <url-pattern>*.jspx</url-pattern>
</servlet-mapping>

i.e jsp servlet handles *.jsp, *.jspx extension.

So given this, a potential fix will be to add .html to be added to be handled by jsp servlet, as in this link:

Using .html files as JSPs

or even better ,leave the extension as .jsp and use .html as a controller pattern instead?

0
votes
I was also facing the same issue and tried various solutions to load the AngularJS html file using Spring configuration. After applying below steps it got resolved.

Step-1 in server's web.xml commemt these two lines

<!--     <mime-mapping>
        <extension>htm</extension>
        <mime-type>text/html</mime-type>
    </mime-mapping>--> 
<!--     <mime-mapping>
        <extension>html</extension>
        <mime-type>text/html</mime-type>
    </mime-mapping>
 -->

Step-2 enter following code in application's web xml

  <servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>*.htm</url-pattern>
</servlet-mapping>


Step-3

create a static controller class 

@Controller 
public class StatisController {
     @RequestMapping("/landingPage") 
    public String getIndexPage() { 
    return "CompanyInfo"; 

    }

}
Step-4 in the Spring configuration file change the suffix to .htm
        <property name="suffix">
            <value>.htm</value>
        </property>

Step-5
Rename page as .htm file and store it in WEB-INF and build/start the server 

localhost:8080/.../landingPage
-1
votes
//Finally a working solution both html and jsp view together 
------------------------------------------------------------------------

public class ChainableInternalResourceViewResolver extends InternalResourceViewResolver {

    private static Log logger = LogFactory.getLogger(ChainableInternalResourceViewResolver.class);

    /**
     * 
     */
    protected AbstractUrlBasedView buildView(String viewName) throws Exception {
        logger.entering("buildView");
        String url = getPrefix() + viewName + getSuffix();
        InputStream stream = getServletContext().getResourceAsStream(url);
        if (stream == null) {
            logger.log(Log.DEBUG,"-----!!!------resource not found-------!!!-----"+getPrefix() + viewName + getSuffix());
            return new NonExistentView();
        } else {
            logger.log(Log.DEBUG,"----***-------resource found-------***-----"+getPrefix() + viewName + getSuffix());
            stream.close();
        }
        return super.buildView(viewName);
    }

    /**
     * 
     * @author 
     *
     */
    private static class NonExistentView extends AbstractUrlBasedView {

        //private static Log logger = LogFactory.getLogger(NonExistentView.class);

        protected boolean isUrlRequired() {
            //logger.entering("isUrlRequired");
            return false;
        }

        public boolean checkResource(Locale locale) throws Exception {
            //logger.entering("checkResource");
            return false;
        }

        protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
                HttpServletResponse response) throws Exception {
            //logger.entering("renderMergedOutputModel");
            // Purposely empty, it should never get called
        }
    }
}

----------------------------------------------------------------------------
@EnableWebMvc
@Configuration
@ComponentScan({ "com.*" })
public class ApplicationConfig extends WebMvcConfigurerAdapter {

    //Be careful while changing here
    private static final String VIEW_DIR_HTML = "/WEB-INF/static/";
    private static final String VIEW_EXTN_HTML = ".html";

    private static final String VIEW_DIR_JSP = "/WEB-INF/";
    private static final String VIEW_EXTN_JSP = ".jsp";

    private static final String RESOURCE_URL_PATTERN_1 = "/resources/**";
    private static final String RESOURCE_URL_PATTERN_2 = "/WEB-INF/static/**";
    private static final String RESOURCE_PATH_1 = "/resources/";
    private static final String RESOURCE_PATH_2 = "/WEB-INF/static/";

    private static Logger logger = LoggerFactory.getLogger(ApplicationConfig.class);

    /**
     * 
     * @return
     */
    @Bean
    public ViewResolver htmlViewResolver() {
        logger.info(" htmlViewResolver method ");
        InternalResourceViewResolver viewResolver= new ChainableInternalResourceViewResolver();
        viewResolver.setPrefix(VIEW_DIR_HTML);
        viewResolver.setSuffix(VIEW_EXTN_HTML);
        viewResolver.setOrder(0);
        return viewResolver;
    }

    @Bean
    public ViewResolver jspViewResolver() {
        logger.info(" jspViewResolver method ");
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix(VIEW_DIR_JSP);
        viewResolver.setSuffix(VIEW_EXTN_JSP);
        viewResolver.setOrder(1);
        return viewResolver;
    }

--------------------------------------------------------------------------------
return "pages/login"; // for login.html resides inside /WEB-INF/static/pages/login.html

return "jsp/login"; // for login.jsp resides inside /WEB-INF/jsp/login.jsp