简体   繁体   中英

Spring Boot + Thymeleaf css is not applied to template

I am evaluating Thymeleaf and Flying Saucer for pdf generation from templates, and I am having a problem with applying css to my Thymeleaf template. I already read the relevant questions & answers here , here , and here ; but none of the suggested solutions fixed my problem.

This is how my resources folder looks like:

在此处输入图片说明

So I am using the default directories that Spring will look for. And that's how the head tag looks like in my template.html :

<head>
    <title>Spring Boot and Thymeleaf Example</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <link rel="stylesheet" type="text/css" href="../static/css/style.css" th:href="@{/css/style.css}"/> 
</head>

If I inline my css in template.html then the generated pdf file will be styled properly (so there shouldn't be a problem with how I generate the pdf). However, when I try to link to the css file as shown above the generated pdf is not styled (so the css is not applied).

Lastly, I can access my css file at http://localhost:8080/css/style.css , so there doesn't seem to be a problem with Spring serving the static content.

For completeness, this is how I generate the pdf:

private final SpringTemplateEngine templateEngine;
private final Log log;

@Autowired
public PdfGenerator(SpringTemplateEngine templateEngine) {
    this.templateEngine = templateEngine;
    log = LogFactory.getLog(getClass());
}

public void generate(HttpServletRequest servletRequest, HttpServletResponse servletResponse, ServletContext servletContext) {
    // Parse the pdf template with Thymeleaf
    Locale locale = getLocale(servletRequest);
    WebContext context = new WebContext(servletRequest, servletResponse, servletContext, locale);
    context.setVariable("user", buildDummyUser());
    context.setVariable("discounts", buildDummyDiscounts());
    String html = templateEngine.process("template", context);

    // Create the pdf with Flying Saucer
    try (OutputStream outputStream = new FileOutputStream("generated.pdf")) {
        ITextRenderer renderer = new ITextRenderer();
        renderer.setDocumentFromString(html);
        renderer.layout();
        renderer.createPDF(outputStream);
    } catch (IOException | DocumentException e) {
        log.error("Error while generating pdf", e);
    }
}

I am using WebContext instead of Context because I was getting the following error with Context :

org.thymeleaf.exceptions.TemplateProcessingException: Link base "/css/style.css" cannot be context relative (/...) unless the context used for executing the engine implements the org.thymeleaf.context.IWebContext interface

What am I missing here, why is my style.css not applied to template.html ?

I had same problems and I was also trying to use thymeleaf template resolver for pdf generation. I did lots research on thymeleaf and spring framework, I tried WebContext, I tried HttpServletRequest, I tried some of Spring Thymeleaf integration solutions it was not working either. So I think it was not syntax error, and I finally end up with using absolute path instead of relative. Url for reference

Here the reason with my assumption, lets say our resources are served on localhost:8080/myapp/css/style.css . And the relative path to request resource is really ups to what context it relatives to. For eaxmple a normal thymeleaf model Veiw, which return as html pages on browser for client, so the context in that case would be the request hostname, port and application context(eg: localhost:8080/myapp). And relative path will be based on that. So if relative path is /css/style.css, context + relative path will result to be localhost:8080/myapp/css/style.css

Unlike web context, in our case, offline template is on server backend, so the context I assume would be the server running context, which would be the local server path + appcontext(eg: D:/myServer/apps/myapp), relative path /css/style.css on this would be D:/myServer/apps/myapp/css/style.css , this is not make sense. In order to use static resources, I have to pass it's absolute path.

I started use :

<link rel="stylesheet" type="text/css" th:href="@{http://localhost:8080/myapp/css/style.css}"/>

It's working fine but what if there are multiple host names or server is running on a proxy, then this is going to be a hard coded solution. It's better to know what is the real base url the user is requesting. So we can't really get rid off HttpSevletRequest.

Here is my code:

1.Config resource handler:

@Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/css/**")
    .addResourceLocations("classpath:/css/")
            .setCachePeriod(31556926);
}
  1. Get base url from HttpServletRequest, you can inject it in method or autowired in your service class, or get from RequestContextHolder. I write this in my Service class:

     private static String getCurrentBaseUrl() { ServletRequestAttributes sra = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes(); HttpServletRequest req = sra.getRequest(); return req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + req.getContextPath(); }
  2. This is the place I use template engine in my class:

     Context context = new Context(); context.setVariable("variales", variables); context.setVariable("baseUrl", getCurrentBaseUrl()); String content = springTemplateEngine.process("myTemplate",context);
  3. In my template, I use absolute css url like this:

     <link type="stylesheet" th:src="@{|${baseUrl}/css/style.css|}" />

Syntax looks fine so the problem is not with the syntax.

Also you cannot use @{...} syntax without an IWebContext interface so You are getting this exception.

I had a similar problem - my css was not applied to my template page.

My problem was that the css file was in css sass format

.table
   margin: 0 0 40px 0

when I convert it to the normal css format like

 .table {
  margin: 0 0 40px 0;
  }

it worked

I solved this problem by changing the path structure in href. I had the same directory structure as you (html files are in templates doc, css files are in static doc).

<head>
    <title>Spring Boot and Thymeleaf Example</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <link rel="stylesheet" type="text/css" href="/css/style.css"/> 
</head>

It might help you to apply css to your html page.

I found a lazy man's way of taking care of this. It works, with a very simple approach. The 'inserted' fragment is just a CSS style tag in the body of a simple HTML document. I place this in the HEAD of my target file, right where I would have put the LINK REL tag:

<th:block th:insert="std-reports/std-reports-css-fragment.html :: style"></th:block>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM