Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot Not Serving Static Content with Thymeleaf

I have the following thymeleaf html page:

<head th:fragment="header">

    <meta charset="utf-8" />
    <link rel="stylesheet" href="../../css/main.css" th:href="@{/css/main.css}" />
    <title th:text="#{device.page.title}">Title</title>
</head>

<body>
<div>
    <h1 th:text="#{device.table.caption}"></h1>
    <hr class="fineline"/>
    Select devices using the checkboxes, you can update the client version or add client commands.
    <form action="#" th:action="@{/devices/modify}" th:object="${deviceCommand}" method="post">
    <table border="0" cellpadding="0" cellspacing="0" class="touchTable">
        <!--<thead> -->
            <tr>
                <td scope="col" th:text="#{device.check.label}">Select</td>
                <td width="300" scope="col"><span th:text="#{device.id.label}"></span>&nbsp;(<span th:text="#{device.retailer.name.label}"></span>)</td>
                <td scope="col" th:text="#{device.current.label}">Curr Version</td>
                <td scope="col" th:text="#{device.next.label}">Next Version</td>
                <td scope="col" th:text="#{device.commands.label}">Commands</td>
            </tr>
        <!--</thead>-->
        <!--<tbody> -->
            <tr th:each="d : ${devices}">
                <td><input type="checkbox" th:field="*{deviceModificationIds}" th:value="${d.id}"/></td>
                <td><span th:text="${d.id}"></span>&nbsp;(<span th:text="${d.retailerName}"></span>)</td>
                <td th:text="${d.currentClientVersion}">Washington</td>
                <td th:text="${d.nextClientVersion}">gwash</td>
                <td th:text="${d.commands}">gwash</td>
            </tr>
            <tr>
                <td colspan="2"></td>
                <td><span th:text="#{device.change.version.label}"></span><br/><input type="text" th:field="*{newVersion}"/></td>
                <td><span th:text="#{device.add.command.label}"></span><br/><input type="text" th:field="*{newCommand}"/></td>
                <td><br/><button type="submit" th:text="#{device.modify.action.button}">Action</button></td>
            </tr>
        <!--</tbody>  -->
    </table>
    </form>


</div>
</body>

The problem is with the css stylesheet. Basically spring doesn't seem to be able to find it, despit me placing the file in /resources/static/css/main.css

It returns the error (in the logs):

o.s.web.servlet.PageNotFound - No mapping found for HTTP request with URI [/css/main.css] in DispatcherServlet with name 'dispatcherServlet'

Now the doco all says that Spring Boot should automatically serve things in /resources/static

Here is my WebConfig:

@Configuration
@ComponentScan("com.txxxxcorp.txxxxpoint.resource")
@EnableWebMvc
public class WebConfig {

    @Bean
    MultipartConfigElement multipartConfigElement() {
        MultiPartConfigFactory factory = new MultiPartConfigFactory();
        factory.setMaxFileSize("4096KB");
        factory.setMaxRequestSize("4096KB");
        return factory.createMultipartConfig();
    }

    @Bean  
    public ViewResolver viewResolver() {
        ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
        templateResolver.setTemplateMode("XHTML");
        templateResolver.setPrefix("templates/");
        templateResolver.setSuffix(".html");

        SpringTemplateEngine engine = new SpringTemplateEngine();
        engine.setTemplateResolver(templateResolver);

        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setTemplateEngine(engine);

        String[] excludedViews = new String[]{
            "/resources/static/**"};
        viewResolver.setExcludedViewNames(excludedViews);

        return viewResolver;
    }

    @Bean
    public EmbeddedServletContainerCustomizer servletContainerCustomizer() {
        return new EmbeddedServletContainerCustomizer() {
            @Override
            public void customize(ConfigurableEmbeddedServletContainer servletContainer) {
                ((TomcatEmbeddedServletContainerFactory) servletContainer).addConnectorCustomizers(
                        new TomcatConnectorCustomizer() {
                            @Override
                            public void customize(Connector connector) {
                                AbstractHttp11Protocol httpProtocol = (AbstractHttp11Protocol) connector.getProtocolHandler();
                                httpProtocol.setCompression("on");
                                httpProtocol.setCompressionMinSize(256);
                                String mimeTypes = httpProtocol.getCompressableMimeTypes();
                                String mimeTypesWithJson = mimeTypes + "," + MediaType.APPLICATION_JSON_VALUE;
                                httpProtocol.setCompressableMimeTypes(mimeTypesWithJson);
                            }
                        }
                );
            }
        };
    }

    @Bean
    public ResourceBundleMessageSource messageSource() {
        ResourceBundleMessageSource source = new ResourceBundleMessageSource();
        source.setBasename("messages");
        return source;
    }

For some reason, the editor does not let me insert the spring security config without complaining that its not properly formatted (IntelliJ, Maven and Spring Boot disagree with this, since it compiles and works), rest assured that I have allowed the /css/main.css path to go through

Does anyone know why I cannot resolve the css file?

like image 458
Michael Coxon Avatar asked Sep 04 '14 04:09

Michael Coxon


2 Answers

The fact that you have used @EnableWebMvc turns off Spring Boot's MVC autoconfiguration (and therefor the static resource handling).

To enable the static resource handling the best solution is to remove @EnableWebMvc and let Spring Boot do what it does best - auto-configuration.

After the change you should do some regression testing to make sure nothing else broke

like image 53
geoand Avatar answered Sep 23 '22 20:09

geoand


@geoand's Answer is correct ,your application's static resource is turn off as you use the @enablWebMvc . so any css file you used here been parsed by thyemeleaf ,you need to declare the class to inheritted the WebMvcAutoConfigurationAdapter and override the addResourceHandlers method, the code could be like below :

 @Configuration
    @ComponentScan("com.txxxxcorp.txxxxpoint.resource")
    @EnableWebMvc
    public class WebConfig extends WebMvcConfigurerAdapter {

 @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        String[] STATIC_RESOURCE = {"/","classpath:/","classpath:/META-INF/resources/", "classpath:/META-INF/resources/webjars/",
                "classpath:/resources/", "classpath:/static/", "classpath:/public/"};

        if (!registry.hasMappingForPattern("/**")) {
            registry.addResourceHandler("/**").addResourceLocations(STATIC_RESOURCE);
        }
    }

.......................
}
like image 33
Alter Hu Avatar answered Sep 25 '22 20:09

Alter Hu