1

I use thymeleaf and springboot to build a framework. And try to use the layout template of thymeleaf. The problem is when using the layout template by using ThymeleafLayoutInterceptor. The url for css and js could not be found any more.

The Codes and configuration are as below:

You can see the project layout through the link project view

public class ThymeleafLayoutInterceptor extends HandlerInterceptorAdapter {

private static final String DEFAULT_LAYOUT = "layouts/default";

private static final String DEFAULT_VIEW_ATTRIBUTE_NAME = "view";

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    if (modelAndView == null || !modelAndView.hasView()) {
        return;
    }
    String originalViewName = modelAndView.getViewName();
    if (isRedirectOrForward(originalViewName)) {
        return;
    }
    modelAndView.setViewName(DEFAULT_LAYOUT);
    modelAndView.addObject(DEFAULT_VIEW_ATTRIBUTE_NAME,originalViewName);
}

private boolean isRedirectOrForward(String viewName) {
    return viewName.startsWith("redirect:") || viewName.startsWith("forward:");
}

}

@Configuration

public class WebMvcConfig extends WebMvcConfigurationSupport {

@Override
protected void addInterceptors(InterceptorRegistry registry) {
    super.addInterceptors(registry);
    registry.addInterceptor(new ThymeleafLayoutInterceptor());
}

@Bean
public ServletContextTemplateResolver templateResolver(){
    ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
    resolver.setPrefix("/templates/views/");
    resolver.setSuffix(".html");
    resolver.setTemplateMode("HTML5");
    resolver.setOrder(1);
    return resolver;
}

@Bean
public SpringTemplateEngine templateEngine(){
    Set<IDialect> dialects = new HashSet<>();
    dialects.add(new LayoutDialect());
    SpringTemplateEngine engine = new SpringTemplateEngine();
    engine.setTemplateResolver(templateResolver());
    engine.setAdditionalDialects(dialects);
    return engine;
}

@Bean
public ThymeleafViewResolver thymeleafViewResolver(){
    ThymeleafViewResolver resolver = new ThymeleafViewResolver();
    resolver.setTemplateEngine(templateEngine());
    resolver.setViewNames(new String[]{"*","springBootMvc/js/*","springBootMvc/css/*"});
    return resolver;
}

}

default.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">

<head>
    <link th:href="@{/dataTable/media/css/jquery.dataTables.css}" rel="stylesheet" type="text/css"/>
    <link href="css/boot.css" rel="stylesheet" type="text/css"/>
    <link th:href="@{/bootstrap/css/bootstrap.min.css}" rel="stylesheet" type="text/css"/>

    <script th:src="@{/dataTable/media/js/jquery.js}" type="text/javascript" charset="utf8"/>
    <script th:src="@{/dataTable/media/js/jquery.dataTables.js}" type="text/javascript" charset="utf8"></script>
    <script th:src="@{/bootstrap/js/bootstrap.min.js}" type="text/javascript" charset="utf8"/>
    <script th:src="@{/js/boot.js}" type="text/javascript" charset="utf8"/>
</head>
<body>
<div th:raplace="fragments/header :: header">
    Header1
</div>
<div th:replace="${view} :: content">
    Content
</div>
<div th:replace="fragments/footer :: footer">
    Footer
</div>
</body>
</html>

.html

application.yaml

server:
  context-path: /springBootMvc
  port: 8082

spring:
  profiles:
    active: test
  messages:
    basename: i18n
  devtools:
    restart:
      exclude: static/**
      additional-paths: src/main/
  thymeleaf:
    prefix: /templates/views/
    suffix: .html

Then a problem happened, I couldn't get the url of *.js and *.css. The error stack is as below:

2016-07-07 09:22:08.427  WARN 9572 --- [nio-8082-exec-2] o.s.web.servlet.PageNotFound             : No mapping found for HTTP request with URI [/springBootMvc/css/boot.css] in DispatcherServlet with name 'dispatcherServlet'
2016-07-07 09:22:08.452  WARN 9572 --- [nio-8082-exec-4] o.s.web.servlet.PageNotFound             : No mapping found for HTTP request with URI [/springBootMvc/dataTable/media/js/jquery.js] in DispatcherServlet with name 'dispatcherServlet'
2016-07-07 09:22:08.454  WARN 9572 --- [nio-8082-exec-5] o.s.web.servlet.PageNotFound             : No mapping found for HTTP request with URI [/springBootMvc/dataTable/media/css/jquery.dataTables.css] in DispatcherServlet with name 'dispatcherServlet'
2016-07-07 09:22:08.457  WARN 9572 --- [nio-8082-exec-6] o.s.web.servlet.PageNotFound             : No mapping found for HTTP request with URI [/springBootMvc/bootstrap/css/bootstrap.min.css] in DispatcherServlet with name 'dispatcherServlet'
2016-07-07 09:22:08.461  WARN 9572 --- [nio-8082-exec-7] o.s.web.servlet.PageNotFound             : No mapping found for HTTP request with URI [/springBootMvc/dataTable/media/js/jquery.dataTables.js] in DispatcherServlet with name 'dispatcherServlet'
2016-07-07 09:22:08.475  WARN 9572 --- [nio-8082-exec-3] o.s.web.servlet.PageNotFound             : No mapping found for HTTP request with URI [/springBootMvc/bootstrap/js/bootstrap.min.js] in DispatcherServlet with name 'dispatcherServlet'
2016-07-07 09:22:08.740  WARN 9572 --- [nio-8082-exec-8] o.s.web.servlet.PageNotFound             : No mapping found for HTTP request with URI [/springBootMvc/js/boot.js] in DispatcherServlet with name 'dispatcherServlet'
2016-07-07 09:22:08.745 ERROR 9572 --- [nio-8082-exec-2] o.a.c.c.C.[Tomcat].[localhost]           : Exception Processing ErrorPage[errorCode=0, location=/error]

If I remove the class WebMvcConfig, those *.css and *.js could be found. But the layout template doesn't work any more. screen with js, css but no header and footer

3 Answers 3

17

In the class that extends WebMvcConfigurerAdapter, I was using @EnableWebMvc annotation, regarding to same layout example.

I removed this annotation, layout works the same, and css is loaded.

I hope this helps.

Sign up to request clarification or add additional context in comments.

2 Comments

Yes! exactly this was my situation, it works, but why?
Same here. But why?
0

At last, I solved it by reading a lot of source codes. And I found that there missing a SimpleUrlHandlerMapping in our configuration. And I configure it in code. It might be a little complex. If someone has a simpler way, welcome to contact with me!

@Bean
    public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
        SimpleUrlHandlerMapping simpleUrlHandlerMapping = new SimpleUrlHandlerMapping();
        Map<String, Object> map = new LinkedHashMap<>();
        ResourceHttpRequestHandler resourceHttpRequestHandler = new ResourceHttpRequestHandler();
        List<Resource> locations = new ArrayList<>();
        locations.add(new ServletContextResource(getServletContext(), "/"));
        locations.add(new ClassPathResource("META-INF/resources"));
        locations.add(new ClassPathResource("resources/"));
        locations.add(new ClassPathResource("static/"));
        locations.add(new ClassPathResource("public/"));
        resourceHttpRequestHandler.setLocations(locations);
        resourceHttpRequestHandler.setApplicationContext(getApplicationContext());

        List<ResourceResolver> resourceResolvers = new ArrayList<>();
        PathResourceResolver resourceResolver = new PathResourceResolver();
        resourceResolver.setAllowedLocations(new ServletContextResource(getServletContext(), "/"), new ClassPathResource("META-INF/resources"), new ClassPathResource("resources/"), new ClassPathResource("static/"), new ClassPathResource("public/"));
        resourceResolvers.add(resourceResolver);

        resourceHttpRequestHandler.setResourceResolvers(resourceResolvers);
        map.put("/**", resourceHttpRequestHandler);
        simpleUrlHandlerMapping.setUrlMap(map);
        ResourceUrlProvider resourceUrlProvider = new ResourceUrlProvider();
        Map<String, ResourceHttpRequestHandler> handlerMap = new LinkedHashMap<>();
        handlerMap.put("/**", resourceHttpRequestHandler);
        resourceUrlProvider.setHandlerMap(handlerMap);
        ResourceUrlProviderExposingInterceptor interceptor = new ResourceUrlProviderExposingInterceptor(resourceUrlProvider);
        simpleUrlHandlerMapping.setInterceptors(new Object[]{interceptor});
        return simpleUrlHandlerMapping;
    }

Comments

0

by default spring boot resources should be placed in "src/main/resources", for example js and css files should be placed in /static folder "src/main/resources/static/css" the same applies for template folder, there is almost no need for any configuration if you dont need anything special. Try to run your application and check the logging, spring logs all mapping there and you can check what s the default mappings.

When I will come to home, I'll attach my project hierarchy.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.