Я оцениваю Thymeleaf и Flying Saucer для создания PDF-файлов из шаблонов, и у меня возникла проблема с применением css к моему шаблону Thymeleaf. Я уже читал соответствующие вопросы и ответы здесь, здесь и здесь; но ни одно из предложенных решений не устранило мою проблему.
Вот так выглядит моя папка с ресурсами:
Поэтому я использую каталоги по умолчанию, которые будет искать Spring. А вот так заголовок выглядит в моем 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>
Если я встроу свой css в template.html, тогда сгенерированный файл pdf будет оформлен правильно (поэтому не должно быть проблем с тем, как я генерирую pdf). Однако, когда я пытаюсь установить ссылку на файл css, как показано выше, сгенерированный PDF-файл не оформлен (поэтому CSS не применяется).
Наконец, я могу получить доступ к своему файлу css на http://localhost:8080/css/style.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?






Синтаксис выглядит нормально, поэтому проблема не в синтаксисе.
Также вы не можете использовать синтаксис @{...} без интерфейса IWebContext, поэтому вы получаете это исключение.
У меня была аналогичная проблема - мой CSS не был применен к моей странице шаблона.
Моя проблема заключалась в том, что файл css был в формате css sass
.table
margin: 0 0 40px 0
когда я конвертирую его в обычный формат css, например
.table {
margin: 0 0 40px 0;
}
это сработало
У меня были те же проблемы, и я также пытался использовать преобразователь шаблонов тимелеафа для генерации PDF. Я провел много исследований по тимелеафу и фреймворку Spring, я попробовал WebContext, я попробовал HttpServletRequest, я попробовал некоторые интеграционные решения Spring Thymeleaf, которые тоже не работали. Поэтому я думаю, что это не синтаксическая ошибка, и в итоге я использую абсолютный путь вместо относительного. URL для справки
Вот причина моего предположения, допустим, наши ресурсы обслуживаются на localhost:8080/myapp/css/style.css. И относительный путь к запросу ресурса действительно зависит от контекста, к которому он относится.
Для eaxmple обычная модель тимелеафа Veiw, которая возвращается в виде HTML-страниц в браузере для клиента, поэтому контекстом в этом случае будет имя хоста запроса, порт и контекст приложения (например: localhost: 8080 / myapp). И относительный путь будет основан на этом. Поэтому, если относительный путь /css/style.css, контекст + относительный путь будет localhost:8080/myapp/css/style.css
В отличие от веб-контекста, в нашем случае офлайн-шаблон находится на серверной части, поэтому я предполагаю, что контекстом будет контекст запуска сервера, которым будет путь к локальному серверу + контекст приложения (например: 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);
}
Получите базовый URL-адрес из HttpServletRequest, вы можете ввести его в метод или автоматически подключить в своем классе обслуживания или получить из RequestContextHolder. Я пишу это в своем классе обслуживания:
private static String getCurrentBaseUrl() {
ServletRequestAttributes sra = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest req = sra.getRequest();
return req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + req.getContextPath();
}
Это то место, где я использую шаблонизатор в своем классе:
Context context = new Context();
context.setVariable("variales", variables);
context.setVariable("baseUrl", getCurrentBaseUrl());
String content = springTemplateEngine.process("myTemplate",context);
В моем шаблоне я использую абсолютный URL-адрес css следующим образом:
<link type = "stylesheet" th:src = "@{|${baseUrl}/css/style.css|}" />
Спасибо за ответ. Я мог бы заставить его работать и с абсолютным путем, хотя я не очень люблю использовать абсолютные пути. Одно замечание: я использовал th:href = "@{|${baseUrl}/css/style.css|}" в шаблоне, и мне не нужно было реализовывать addResourceHandlers.
Думаю, мы в такой же ситуации, мне тоже не нравится абсолютный путь. Но насколько я знаю, это единственный способ заставить его работать у меня. Что касается обработчика ресурсов, я просто хочу убедиться, что статический контент должен обслуживаться в Интернете. Это не так уж и плохо, потому что базовый URL полностью зависит от реального запроса пользователя, поэтому он по-прежнему гибкий. Если вы можете найти решение для относительного пути, пожалуйста, дайте мне знать. Спасибо
Я решил эту проблему, изменив структуру пути в href. У меня была та же структура каталогов, что и у вас (файлы HTML находятся в документах шаблонов, файлы css находятся в статических документах).
<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-странице.
Я также считаю, что синтаксис в порядке, как и структура ресурсов. Встраивание css тоже работает, поэтому я не думаю, что есть проблема с генерацией pdf. Вот почему я озадачен, не понимаю, в чем может быть проблема.