Spring Boot + Thymeleaf css 不适用于模板 [英] Spring Boot + Thymeleaf css is not applied to template

查看:56
本文介绍了Spring Boot + Thymeleaf css 不适用于模板的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在评估 Thymeleaf 和 Flying Saucer 以从模板生成 pdf,我在将 css 应用到我的 Thymeleaf 模板时遇到了问题.我已经阅读了相关问题&答案

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

<title>Spring Boot 和 Thymeleaf 示例</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}"/>

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

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

为了完整性,这就是我生成 pdf 的方式:

private final SpringTemplateEngine templateEngine;私人最终日志日志;@自动连线公共 PdfGenerator(SpringTemplateEngine 模板引擎){this.templateEngine = templateEngine;日志 = LogFactory.getLog(getClass());}公共无效生成(HttpServletRequest servletRequest,HttpServletResponse servletResponse,ServletContext servletContext){//用 Thymeleaf 解析 pdf 模板语言环境 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);//用飞碟创建pdf试试 (OutputStream outputStream = new FileOutputStream("generated.pdf")) {ITextRenderer 渲染器 = new ITextRenderer();renderer.setDocumentFromString(html);渲染器.layout();renderer.createPDF(outputStream);} catch (IOException | DocumentException e) {log.error("生成pdf时出错", e);}}

我使用 WebContext 而不是 Context 因为我在使用 Context 时遇到以下错误:

org.thymeleaf.exceptions.TemplateProcessingException:链接基/css/style.css"不能是上下文相关的(/...),除非用于执行引擎的上下文实现了 org.thymeleaf.context.IWebContext 接口

我在这里遗漏了什么,为什么我的 style.css 没有应用于 template.html?

解决方案

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

这是我假设的原因,假设我们的资源在 localhost:8080/myapp/css/style.css 上提供.请求资源的相对路径实际上取决于它相对于什么上下文.例如,一个普通的百里香叶模型 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,这是没有意义的.为了使用静态资源,我必须传递它的绝对路径.

我开始使用:

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

这是我的代码:

1.配置资源处理程序:

@Overridepublic void addResourceHandlers(最终ResourceHandlerRegistry注册表){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("变量", 变量);context.setVariable("baseUrl", getCurrentBaseUrl());String content = springTemplateEngine.process("myTemplate",context);

  3. 在我的模板中,我使用这样的绝对 css url:

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

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

这篇关于Spring Boot + Thymeleaf css 不适用于模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆