【问题标题】:Spring Boot + Thymeleaf css is not applied to templateSpring Boot + Thymeleaf css 不适用于模板
【发布时间】:2019-04-11 17:39:04
【问题描述】:

我正在评估从模板生成 pdf 的 Thymeleaf 和 Flying Saucer,但在将 css 应用于我的 Thymeleaf 模板时遇到了问题。我已经阅读了相关问答hereherehere;但建议的解决方案都没有解决我的问题。

这是我的资源文件夹的样子:

所以我使用的是 Spring 将查找的默认目录。这就是我的 template.html 中 head 标签的样子:

<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>

如果我在template.html 中内联我的 css,那么生成的 pdf 文件的样式将正确(因此我生成 pdf 的方式应该没有问题)。但是,当我尝试链接到如上所示的 css 文件时,生成的 pdf 未设置样式(因此未应用 css)。

最后,我可以通过 http://localhost:8080/css/style.css 访问我的 css 文件,因此 Spring 提供静态内容似乎没有问题。

为了完整起见,这就是我生成 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);
    }
}

我使用WebContext 而不是Context,因为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

我在这里缺少什么,为什么我的style.css 不适用于template.html

【问题讨论】:

    标签: css spring-boot thymeleaf


    【解决方案1】:

    语法看起来不错,所以问题不在于语法。

    此外,如果没有 IWebContext 接口,您也不能使用 @{...} 语法,因此您会遇到此异常。

    【讨论】:

    • 我也觉得语法不错,资源结构也不错。内联 css 也可以,所以我认为 pdf 生成没有问题。这就是为什么我很困惑,我看不出问题出在哪里。
    【解决方案2】:

    我遇到了类似的问题 - 我的 css 没有应用于我的模板页面。

    我的问题是 css 文件是 css sass 格式

    .table
       margin: 0 0 40px 0
    

    当我将其转换为普通的 css 格式时,例如

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

    成功了

    【讨论】:

      【解决方案3】:

      我遇到了同样的问题,我也尝试使用 thymeleaf 模板解析器生成 pdf。我对 thymeleaf 和 spring 框架做了很多研究,我尝试了 WebContext,我尝试了 HttpServletRequest,我尝试了一些 Spring Thymeleaf 集成解决方案,它也不起作用。所以我认为这不是语法错误,我最终使用绝对路径而不是相对路径。 Url for reference

      这是我假设的原因,假设我们的资源在localhost:8080/myapp/css/style.css 上提供服务。请求资源的相对路径实际上取决于它相对于什么上下文。 例如,一个普通的 thymeleaf 模型 Veiw,它在客户端的浏览器上以 html 页面的形式返回,因此这种情况下的上下文将是请求主机名、端口和应用程序上下文(例如:localhost:8080/myapp)。相对路径将基于此。所以如果相对路径是/css/style.css,那么上下文+相对路径就会是localhost:8080/myapp/css/style.css

      与 web 上下文不同,在我们的例子中,离线模板位于服务器后端,所以我假设的上下文是服务器运行上下文,即本地服务器路径 + appcontext(例如:D:/myServer/apps/myapp ),相对路径 /css/style.css 将是 D:/myServer/apps/myapp/css/style.css,这是没有意义的。为了使用静态资源,我必须传递它的绝对路径。

      我开始使用了:

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

      它工作正常,但是如果有多个主机名或服务器在代理上运行,那么这将是一个硬编码的解决方案。最好知道用户请求的真实基本 url 是什么。所以我们无法真正摆脱 HttpSevletRequest。

      这是我的代码:

      1.Config 资源处理程序:

      @Override
      public void addResourceHandlers(final ResourceHandlerRegistry registry) {
          registry.addResourceHandler("/css/**")
          .addResourceLocations("classpath:/css/")
                  .setCachePeriod(31556926);
      }
      
      1. 从 HttpServletRequest 获取基本 url,您可以将其注入方法中或在服务类中自动装配,或者从 RequestContextHolder 中获取。我在我的服务类中写了这个:

        private static String getCurrentBaseUrl() {
        ServletRequestAttributes sra = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest req = sra.getRequest();
        return req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + req.getContextPath();
        } 
        
      2. 这是我在课堂上使用模板引擎的地方:

            Context context = new Context();
            context.setVariable("variales", variables);
            context.setVariable("baseUrl", getCurrentBaseUrl());
            String content = springTemplateEngine.process("myTemplate",context);
        
      3. 在我的模板中,我使用这样的绝对 css url:

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

      【讨论】:

      • 感谢您的回答。我也可以让它与绝对路径一起工作,尽管我不太喜欢使用绝对路径。不过有一点:我在模板中使用了th:href="@{|${baseUrl}/css/style.css|}",不需要实现addResourceHandlers
      • 猜我们处于同样的情况,我也不喜欢绝对路径。但据我所知,这是让它对我有用的唯一方法。对于资源处理程序,我只想确保必须在 Web 上提供静态内容。不过这还不错,因为基本 url 完全取决于真实的用户请求,所以它仍然很灵活。如果您能找到相对路径解决方案,请告诉我。谢谢
      【解决方案4】:

      我通过改变href中的路径结构解决了这个问题。我的目录结构和你一样(html 文件在模板 doc 中,css 文件在静态 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>
      

      它可能会帮助您将 css 应用于您的 html 页面。

      【讨论】:

        【解决方案5】:

        我找到了一个懒人的方法来解决这个问题。它的工作原理非常简单。 “插入”片段只是简单 HTML 文档正文中的 CSS 样式标记。我把它放在我的目标文件的 HEAD 中,就在我应该放置 LINK REL 标签的地方:

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

        【讨论】:

        • 正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center
        猜你喜欢
        • 2020-08-15
        • 2021-01-17
        • 2016-01-26
        • 2016-10-26
        • 2020-03-14
        • 2017-03-08
        • 1970-01-01
        • 2019-10-31
        • 2017-05-26
        相关资源
        最近更新 更多