Spring Boot + Thymeleaf css is not applied to template

会有一股神秘感。 提交于 2020-04-30 10:54:52

问题


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?


回答1:


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|}" />
    



回答2:


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.




回答3:


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



来源:https://stackoverflow.com/questions/53203909/spring-boot-thymeleaf-css-is-not-applied-to-template

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!