2
votes

I have a spring web application that loads the templates correctly, but does not load static assets like CSS and images. I have added my static resources within the src/main/resources/static directory, added thymeleaf annotations, added configurations and checked them against similar questions here on StackOverflow, but none of my CSS/image files are getting loaded:

Console Error

Refused to apply style from 'http://localhost:8080/login' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.

Directory Structure

Directory Structure

TemplateConfig.java

package com.valencra.recipes.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.thymeleaf.extras.springsecurity4.dialect.SpringSecurityDialect;
import org.thymeleaf.spring4.SpringTemplateEngine;
import org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring4.view.ThymeleafViewResolver;

@Configuration
public class TemplateConfig {
  @Bean
  public SpringResourceTemplateResolver templateResolver() {
    final SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
    templateResolver.setPrefix("classpath:/templates/");
    templateResolver.setSuffix(".html");
    templateResolver.setTemplateMode("LEGACYHTML5");
    return templateResolver;
  }

  @Bean
  public SpringTemplateEngine templateEngine() {
    final SpringTemplateEngine springTemplateEngine = new SpringTemplateEngine();
    springTemplateEngine.addTemplateResolver(templateResolver());
    springTemplateEngine.addDialect(new SpringSecurityDialect());
    return springTemplateEngine;
  }

  @Bean
  public ThymeleafViewResolver viewResolver() {
    final ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
    viewResolver.setTemplateEngine(templateEngine());
    viewResolver.setOrder(1);
    return viewResolver;
  }
}

layout.html

<!DOCTYPE html>
<html lang="en">

<head th:fragment="head">

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">

    <title>My Recipes</title>

    <link href='https://fonts.googleapis.com/css?family=Varela+Round' rel='stylesheet' type='text/css'>
    <link rel="stylesheet" th:href="@{/css/unsemantic-grid-responsive.css}">
    <link rel="stylesheet" th:href="@{/css/styles.css}">

</head>

<body>

    <nav th:fragment="nav">
        <a th:href="@{|/profile|}" th:text="${currentUser.name}">
            Chandra S.
        </a>
        &bull;
        <form th:action="@{/logout}" method="post" style="display: inline">
            logout
        </form>
    </nav>

    <div th:fragment="home">
        <div class="grid-100">
            <a th:href="@{|/|}">
                <h1>
                    <img th:src="@{/images/chefbot.svg}" height="60px">
                    <br>
                    My Recipes
                </h1>
            </a>
        </div>
    </div>

    <div th:fragment="favorite">
        <form th:action="@{|/recipes/${recipe.id}/favorite|}" method="post" style="display:inline">
            <button type="submit">
                <img th:src="${recipe.isFavorite(currentUser)} ? @{/images/favorited.svg} : @{/images/favorite.svg}" style="height: 15px;">
            </button>
        </form>
    </div>

</body>

</html>

login.html

<!doctype html>
<html lang="en">

<head th:replace="layout :: head"></head>

<body>

    <nav>
        <a th:href="@{/signup}">
            sign-up
        </a>
    </nav>

  <div class="grid-container">

    <div th:replace="layout :: home"></div>

    <div class="grid-100">
      <div class="recipes">

        <form th:action="@{|/login|}" method="post" th:object="${user}">
          <div class="prefix-20 grid-60 suffix-20">
            <p>
              <input placeholder="Username" th:field="*{username}"> </input>
            </p>
          </div> <div class="clear"></div>
          <div class="prefix-20 grid-60 suffix-20">
            <p>
              <input placeholder="Password" type="password" th:field="*{password}"> </input>
            </p>
          </div> <div class="clear"></div>
          <div class="prefix-20 grid-60 suffix-20">
            <p>
              <button>Login</button>
            </p>
          </div> <div class="clear"></div>
        </form>

      </div> <!-- recipes -->
    </div> <!-- grid-100 -->

  </div> <!-- grid-container -->

</body>

</html>
2
Please, add the error messageSergii Bishyr
Do you get any error? Open the Browser Inspection Tab. Do you see any 4xx or 5xx Errors?phisch
please see the updated questionRobert Valencia
So I tried adding type='text/html' (as suggested in stackoverflow.com/questions/48248832/…), and the error goes away, but none of the css get's loaded and they all have a status code of 302.Robert Valencia

2 Answers

4
votes

It looks like your CSS is served as HTML.

Since you put the Stylesheets in src/main/resources/static Spring should set up most things based on sensible defaults, including setting the correct content-type header.

I assume you are using Spring Security, since you showed a login form.

It could be that your resources are protected by Spring Security. Thus instead of your stylesheet you get a 30x redirect to the login page. This would explain why your browser complains about the text/html content type, which is wrong for css but the correct type for a login page.

Do you configure HttpSecurity somewhere in your project (most likely annotated with @EnableWebSecurity)?

If so, you need to allow anonymous access to your resources:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            .antMatchers("/css/**", "/images/**").permitAll()
            // rest of your code 

If you switch to the network tab in your browser console, you should be able to inspect the redirect to the login page.

0
votes

What helped in my case was answer from @phisch and the following code

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler(
            "/webjars/**",
            "/img/**",
            "/css/**",
            "/js/**")
            .addResourceLocations(
                    "classpath:/META-INF/resources/webjars/",
                    "classpath:/static/img/",
                    "classpath:/static/css/",
                    "classpath:/static/js/");
     }

}