I am having some serious issues with my Spring 4 / Thymeleaf setup. This is the error message:
Error resolving template "public/bootstrap/js/bootstrap.min", template might not exist or might not be accessible by any of the configured Template Resolvers
For some reason, Spring or Thymeleaf is treating css and js as if they are not static and trying to process them as if they were a request. I have 3 template resolvers:
#Bean()
public TemplateResolver templateResolver() {
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
resolver.setPrefix("/WEB-INF/templates/");
resolver.setSuffix(".html");
resolver.setTemplateMode("HTML5");
resolver.setCacheable(false);
resolver.setOrder(0);
return resolver;
}
#Bean()
public TemplateResolver publicTemplateResolver() {
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
resolver.setPrefix("/WEB-INF/templates/default/");
resolver.setSuffix(".html");
resolver.setTemplateMode("HTML5");
resolver.setCacheable(false);
resolver.setOrder(1);
return resolver;
}
#Bean()
public TemplateResolver customPublicTemplateResolver() {
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
resolver.setPrefix("/WEB-INF/templates/custom/");
resolver.setSuffix(".html");
resolver.setTemplateMode("HTML5");
resolver.setCacheable(false);
resolver.setOrder(2);
return resolver;
}
The pages are being served, the only issue is that the css and js is not. I am getting an error for each and every css and js that is included in the .html file. I literally moved a test css file to every possible directory trying to access it, but I am out of ideas at this point. Please let me know what I am doing wrong and if I need to further configure something.
EDIT 03/31/2015
src/main/webapp/templates/default/page99.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Insert title here</title>
<link rel="stylesheet" type="text/css" media="all" href="resources/css/main.css"/>
</head>
<body>
<h1 th:text="${content.title}"> PAGE 99 (/templates/default/page99.html)</h1>
<p th:text="${content.body}">This is dummy content</p>
</body>
</html>
The css is a simple file that only sets the background color, just so I can see it working.
when you reference items on your server you should use the thymeleaf # method for this in the corresponding thymeleaf attributes.
Like:
<link th:href="#{/css/style.css}" href="style.css" rel="stylesheet" type="text/css"/>
This generates correct URLs for you.
The css is in my case in src/main/resources/static/css/style.css
Related
I'm trying to generate a pdf contains Chinese UTF-8 characters via flying saucer and thymeleaf. But the generated pdf just ignore all the Chinese characters (latin is fine). Here is the Thymeleaf configuration
#Configuration
public class ThymeleafConfig {
#Bean
public ClassLoaderTemplateResolver fileTemplateResolver(){
ClassLoaderTemplateResolver fileTemplateResolver = new ClassLoaderTemplateResolver();
fileTemplateResolver.setPrefix("templates/");
fileTemplateResolver.setTemplateMode("HTML");
fileTemplateResolver.setSuffix(".html");
fileTemplateResolver.setCharacterEncoding("UTF-8");
fileTemplateResolver.setOrder(1);
return fileTemplateResolver;
}
#Bean
public SpringTemplateEngine templateEngine(){
SpringTemplateEngine springTemplateEngine = new SpringTemplateEngine();
springTemplateEngine.setEnableSpringELCompiler(true);
springTemplateEngine.setTemplateResolver(fileTemplateResolver());
return springTemplateEngine;
}
#Bean
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
resolver.setCharacterEncoding("UTF-8");
return resolver;
}
}
As you can see, I've set the character encoding to UTF-8 for both template resolver and view resolver.
And the PDF Util for generating pdfs
public class PDFUtil {
#Autowired
private TemplateEngine templateEngine;
public String createPdf(String templatename, String fileName, String modelName, Object model) throws IOException, DocumentException {
String fileNameUrl = "";
Context ctx = new Context();
ctx.setVariable(modelName, model);
String processedHtml = templateEngine.process(templatename, ctx);
FileOutputStream outputStream = null;
try {
final File outputFile = File.createTempFile(fileName, ".pdf");
outputStream = new FileOutputStream(outputFile);
ITextRenderer renderer = new ITextRenderer();
ITextFontResolver resolver = renderer.getFontResolver();
final ClassPathResource fonts = new ClassPathResource("fonts/PingFangSCRegular.ttf");
String test = fonts.getFilename();
resolver.addFont(fonts.getPath(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
renderer.setDocumentFromString(processedHtml);
renderer.layout();
renderer.createPDF(outputStream, false);
renderer.finishPDF();
FileSystemResource resource = new FileSystemResource(outputFile);
fileNameUrl = resource.getURL().toString();
}
finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) { }
}
}
return fileNameUrl;
}
}
Here I've added the Chinese font to the resolver.
And this is the template html head
<head th:fragment="html_head">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Title</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://unpkg.com/jsbarcode#latest/dist/JsBarcode.all.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/fontawesome.min.css" />
<style type="text/css">
#font-face {
font-family: 'PingFang SC Regular';
src: url('/fonts/PingFangSCRegular.ttf');
-fs-pdf-font-embed: embed;
-fs-pdf-font-encoding: Identity-H;
}
</style>
</head>
So I tried to declare that the charset is UTF-8 and the font family is PingFang SC Regular. But no surprise that does not work.
Here is the maven dependency I've added to my springboot project
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf</artifactId>
<version>9.1.22</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13.3</version>
</dependency>
<dependency>
<groupId>com.itextpdf.tool</groupId>
<artifactId>xmlworker</artifactId>
<version>5.5.13.3</version>
</dependency>
The html body I want to render
<body>
<div th:fragment="header(model)">
<div class="row">
<div class="col-4">
<img id="barcode" alt="111"/>
</div>
<div class="col-4">
<h3>啊啊啊啊啊啊aaa[[${model.title}]]</h3>
<p id="print-time">[[${model.printTime}]]</p>
</div>
</div>
</div>
</body>
And the rendered result
Can anyone figure out why the UTF-8 character does not show in the generated pdf? Any idea would be appreciate.
In your template, you declare the font-face, but you don't apply it to the content of the page.
You just have to declare that the font should be used:
body {font-family: 'PingFang SC Regular';}
Also, you don't need to use #font-face in the template, as you have added the font to the renderer (using resolver.addFont).
The following HTML should work fine:
<html>
<head>
<style>
body {font-family: 'PingFang SC Regular';}
</style>
</head>
<body>
<h3>啊啊啊啊啊啊</h3>
</body>
</html>
Spring boot: 2.3.3.RELEASE
Java: 11
I use webflux + RouterFunction + Thymeleaf and encounter the error "Could not resolve view with name 'index'".
index.html is under "resources/templates".
I put some source code looks important.
Are we not able to use Thymeleaf if we use "RouterFunction"?
Please feel free to put a comment if you need more detail.
######## handler ###########
#Component
public class ItemHandler {
public RouterFunction<ServerResponse> routes = route()
.path("/item", builder -> builder.GET("/", this::index))
.build();
public Mono<ServerResponse> index(ServerRequest request) {
Map<String, Object> attributes = new HashMap<>();
attributes.put("items", "Hello");
return ServerResponse.ok().contentType(MediaType.TEXT_HTML)
.render("index", attributes);
}
}
######## index.html ###########
<!DOCTYPE html>
<html lang="ja"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
</head>
<body>
<h1>FluxTest</h1>
</body>
</html>
######## entry point ###########
#SpringBootApplication
public class DemoWebfluxApplication {
public static void main(String[] args) {
SpringApplication.run(DemoWebfluxApplication.class, args);
}
}
The default property in charge of handling the location of static files is spring.resources.static-locations.
The default values are /META-INF/resources/, /resources/, /static/, /public/. You can either override the default values or put your index.html in one of these locations.
I want to put our templates folder in a remote host like aws-s3, currently
using a custom urlTemplateResolver and using the thymeleaf replace tag.
#Configuration
public class SpringTemplateConfiguration {
private final SpringResourceTemplateResolver springResourceTemplateResolver;
#Value("${spring.thymeleaf.cache}")
Boolean springThymeleafCache;
public SpringTemplateConfiguration(SpringResourceTemplateResolver springResourceTemplateResolver) {
this.springResourceTemplateResolver = springResourceTemplateResolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
UrlTemplateResolver urlTemplateResolver = new UrlTemplateResolver();
urlTemplateResolver.setCacheable(springThymeleafCache); // explicit set cacheable, otherwise it will be always cached
templateEngine.addTemplateResolver(urlTemplateResolver);
templateEngine.addTemplateResolver(springResourceTemplateResolver);
return templateEngine;
}
}
and this is the thymeleaf template
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org" th:replace="~{${url} :: html}">
</html>
is there another way to just use the templates folder from the remote host and just return the view name from the controller ??
It is possible to use another external location but not remote location which doesn't solve our problem.
I want to have a quick test of how to use Thymeleaf and please see my two screenshots:
The home.html is under my templates/ directory, and it can be displayed correctly when I visit http://localhost:8090/. However, it failed to link to the two static files in the bottom of the home.html file:
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script src="js/home.js"></script>
<link href="css/home.css" rel="stylesheet" type="text/css"/>
Please see the error message:
I don't have specific thymeleaf configurations except the spring configurations:
## web
server.port=8090
## velocity
spring.velocity.allowRequestOverride=false
spring.velocity.allowSessionOverride=false
spring.velocity.cache=false
spring.velocity.checkTemplateLocation=true
spring.velocity.contentType=text/html
spring.velocity.toolbox-config-location=/WEB-INF/toolbox.xml
spring.velocity.exposeRequestAttributes=false
spring.velocity.exposeSessionAttributes=false
spring.velocity.exposeSpringMacroHelpers=false
spring.velocity.resourceLoaderPath=/WEB-INF/templates/
spring.velocity.suffix=.vm
spring.velocity.templateEncoding=UTF-8
spring.velocity.charset=UTF-8
spring.velocity.properties.input.encoding=UTF-8
spring.velocity.properties.output.encoding=UTF-8
spring.velocity.requestContextAttribute=rc
spring.mvc.favicon.enabled = false
logging.config=classpath:log4j2.xml
And my controller:
#RequestMapping("/")
public String welcome(Model model) {
LOGGER.info("Run Successfully");
return "home";
}
My main class:
#SpringBootApplication
#Import({WebConfigurer.class})
#ComponentScan("com.jdd.jnlu.qe")
#PropertySource({"classpath:boot.properties", "classpath:important.properties", "classpath:jss.properties",
"classpath:system.properties", "classpath:ump.properties"})
#EnableAutoConfiguration
public class JnluQEWebStart extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(JnluQEWebStart.class, args);
}
}
Since you're using Thymeleaf, try this:
<script th:src="#{/js/home.js}"></script>
<link th:href="#{/css/home.css}" rel="stylesheet" type="text/css"/>
Don't forget to register Thymeleaf in your page:
<html xmlns:th="http://www.thymeleaf.org">
I get this infamous error:
cannot be context relative (/) or page relative unless you implement
the IWebContext
I have a spring boot application (without the web module) that creates pdf files.
I am planning to use an HTML file as a template, but I could not link the css file nor the image properly due to these url issues.
Html :
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<title>Company Invoice</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" media="all"
href="./css/company.css" th:href="#{./css/company.css}"/>
</head>
<body>
<p th:utext="#{home.welcome}">Welcome !</p>
<img src="/images/gtvglogo.png" th:src="#{/images/gtvglogo.png}"/>
</body>
</html>
folder structure:
src/main/resources/templates/sample.html
src/main/resources/templates/css/sample.css
I googled a bit but I donT want to solve this via IWebContext.
Is there another way?
Thanks in advance.
org.thymeleaf.exceptions.TemplateProcessingException: Link base
"/a/relative/link" cannot be context
relative (/...) unless the context used for executing the engine
implements the org.thymeleaf.context.IWebContext interface (template:
"templates/a-template" - line 6, col 13)
1 at org.thymeleaf.linkbuilder.StandardLinkBuilder.computeContextPath
(StandardLinkBuilder.java:493)
...
The exception is thrown by the org.thymeleaf.linkbuilder.StandardLinkBuilder. By providing a different implementation of org.thymeleaf.linkbuilder.ILinkBuilder to the TemplateEngine we can avoid this expception
TemplateEngine templateEngine = new TemplateEngine();
templateEngine.setLinkBuilder(new ILinkBuilder() {
#Override
public String getName() {
return null;
}
#Override
public Integer getOrder() {
return null;
}
#Override
public String buildLink(IExpressionContext context, String base, Map<String, Object> parameters) {
return null;
}
});