I am trying to use Thymeleaf template engine for generating Emails in my Spring Web Application.
I have followed the documentation on their website, but I keep getting a SaxParseException no matter how simple my HTML5 template is.
I am using a HTML 5 template as shown below.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title th:remove="all">Account confirmation HTML email</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<h3 th:utext="#{mail.template.confirmation.greeting(${user.firstName}, ${user.lastName})}"></h3>
<p th:utext="#{mail.template.confirmation.introduction(${createdDate})}">
</p>
</body>
</html>
My Spring config.
#Bean
public ClassLoaderTemplateResolver emailTemplateResolver() {
ClassLoaderTemplateResolver cltr = new ClassLoaderTemplateResolver();
cltr.setPrefix("/dk/rfit/orderit/web/mail/");
cltr.setSuffix(".html");
cltr.setTemplateMode("HTML5");
cltr.setCharacterEncoding("UTF-8");
cltr.setOrder(3);
cltr.setCacheable(true);
return cltr;
}
#Bean
public TemplateEngine mailTemplateEngine() {
SpringTemplateEngine ste = new SpringTemplateEngine();
ste.setTemplateResolver(emailTemplateResolver());
return ste;
}
StackTrace..
2013-01-31 08:01:33,431 [org.thymeleaf.TemplateEngine] [http-bio-8080-exec-10] (TemplateEngine.java:829) INFO org.thymeleaf.TemplateEngine - [THYMELEAF] INITIALIZING TEMPLATE ENGINE
2013-01-31 08:01:33,496 [org.thymeleaf.templateresolver.AbstractTemplateResolver] [http-bio-8080-exec-10] (AbstractTemplateResolver.java:99) INFO org.thymeleaf.templateresolver.AbstractTemplateResolver - [THYMELEAF] INITIALIZING TEMPLATE RESOLVER: org.thymeleaf.templateresolver.ClassLoaderTemplateResolver
2013-01-31 08:01:33,496 [org.thymeleaf.templateresolver.AbstractTemplateResolver] [http-bio-8080-exec-10] (AbstractTemplateResolver.java:110) INFO org.thymeleaf.templateresolver.AbstractTemplateResolver - [THYMELEAF] TEMPLATE RESOLVER INITIALIZED OK
2013-01-31 08:01:33,498 [org.thymeleaf.messageresolver.AbstractMessageResolver] [http-bio-8080-exec-10] (AbstractMessageResolver.java:72) INFO org.thymeleaf.messageresolver.AbstractMessageResolver - [THYMELEAF] INITIALIZING MESSAGE RESOLVER: org.thymeleaf.spring3.messageresolver.SpringMessageResolver
2013-01-31 08:01:33,499 [org.thymeleaf.messageresolver.AbstractMessageResolver] [http-bio-8080-exec-10] (AbstractMessageResolver.java:78) INFO org.thymeleaf.messageresolver.AbstractMessageResolver - [THYMELEAF] MESSAGE RESOLVER INITIALIZED OK
2013-01-31 08:01:33,506 [org.thymeleaf.TemplateEngine.CONFIG] [http-bio-8080-exec-10] (ConfigurationPrinterHelper.java:130) INFO org.thymeleaf.TemplateEngine.CONFIG - [THYMELEAF] TEMPLATE ENGINE CONFIGURATION:
[THYMELEAF] * Cache Factory implementation: org.thymeleaf.cache.StandardCacheManager
[THYMELEAF] * Template modes:
[THYMELEAF] * LEGACYHTML5
[THYMELEAF] * VALIDXHTML
[THYMELEAF] * HTML5
[THYMELEAF] * XHTML
[THYMELEAF] * XML
[THYMELEAF] * VALIDXML
[THYMELEAF] * Template resolvers (in order):
[THYMELEAF] * [3] org.thymeleaf.templateresolver.ClassLoaderTemplateResolver
[THYMELEAF] * Message resolvers (in order):
[THYMELEAF] * org.thymeleaf.spring3.messageresolver.SpringMessageResolver
[THYMELEAF] * Dialect: org.thymeleaf.spring3.dialect.SpringStandardDialect
[THYMELEAF] * Prefix: "th"
[THYMELEAF] TEMPLATE ENGINE CONFIGURED OK
2013-01-31 08:01:33,507 [org.thymeleaf.TemplateEngine] [http-bio-8080-exec-10] (TemplateEngine.java:842) INFO org.thymeleaf.TemplateEngine - [THYMELEAF] TEMPLATE ENGINE INITIALIZED
2013-01-31 08:09:52,146 [org.thymeleaf.TemplateEngine] [http-bio-8080-exec-10] (TemplateEngine.java:1173) ERROR org.thymeleaf.TemplateEngine - [THYMELEAF][http-bio-8080-exec-10] Exception processing template "account-confirmation": Exception parsing document
2013-01-31 08:09:52,149 [dk.rfit.orderit.web.controller.AccountController] [http-bio-8080- exec-10] (AccountController.java:213) ERROR dk.rfit.orderit.web.controller.AccountController org.thymeleaf.templateparser.xmlsax.AbstractNonValidatingSAXTemplateParser.parseTemplateUsingP ool(AbstractNonValidatingSAXTemplateParser.java:167) org.thymeleaf.templateparser.xmlsax.AbstractNonValidatingSAXTemplateParser.parseTemplate(Abstr actNonValidatingSAXTemplateParser.java:115)
at org.thymeleaf.TemplateRepository.getTemplate(TemplateRepository.java:276)
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1192)
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1148)
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1095)
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1008)
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:982)
dk.rfit.orderit.web.service.EmailServiceThymeLeafImpl$1.prepare(EmailServiceThymeLeafImpl.java:65)
at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:352)
... 73 more
Caused by: org.xml.sax.SAXException: Scanner State 24 not Recognized
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1245 )
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:5 22)
at javax.xml.parsers.SAXParser.parse(SAXParser.java:395)
at org.thymeleaf.templateparser.xmlsax.AbstractNonValidatingSAXTemplateParser.doParse(AbstractNon ValidatingSAXTemplateParser.java:208)
at org.thymeleaf.templateparser.xmlsax.AbstractNonValidatingSAXTemplateParser.parseTemplateUsingP ool(AbstractNonValidatingSAXTemplateParser.java:132)
... 82 more
Hope that somebody can tell me what to do to solve this problem..
In addition to Vel's answer: if you need to insert invalid XHTML via utext, which could be perfectly fine for HTML5 (like unclosed <br> tags), you need to use template mode LEGACYHTML5:
cltr.setTemplateMode("LEGACYHTML5");
This error is usually raised by the parser when the parsed markup is not well-formed XML.
The html5 template file becomes not a valid html file after parsing. This means some end-tag (/>)or something extra tag which does not meet the validation of XHTML.
Another option is to specify property in application.properties:
spring.thymeleaf.mode=LEGACYHTML5
Having nekohtml dependency in your project, e.g. in a pom.xml
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
</dependency>
is mandatory.
Related
I have 2 ftl files ( helloworld2.ftl and helloworld4.ftl ). I am trying to understand the variables sharing between ftl files. In helloworld4.ftl i have declared SharedVar and i am trying to access that varible in included file ie helloworld2.ftl. Am able to access. But at the end one set of extra error message im getting. why is it so?
I have used global instead of assign still same behaviour.
Contents of them follows
helloworld2.ftl :
<html>
<head>
<title>new file
</head>
<body>
<h1>${sharedVar}</h1>
</body>
</html>
helloworld4.ftl
<#assign sharedVar="sharedVar">
**********************
<#include "t2">
**********************
${sharedVar}*
ftl loading part,
Map<String, String> m = new HashMap<>();
m.put("t2", readFile("E://workspace//example//src//main//resources//templates//helloworld2.ftl"));
m.put("t4", readFile("E://workspace//example//src//main//resources//templates//helloworld4.ftl"));
for (Map.Entry<String, String> n : m.entrySet()) {
stringLoader.putTemplate(n.getKey(), n.getValue());
}
Output follows,
**********************
<html>
<head>
<title>new file
</head>
<body>
<h1>sharedVar</h1>
</body>
</html>
**********************
sharedVar*Aug 07, 2022 3:08:56 PM freemarker.log._JULLoggerFactory$JULLogger error
SEVERE: Error executing FreeMarker template
FreeMarker template error:
The following has evaluated to null or missing:
==> sharedVar [in template "t2" at line 7, column 17]
I'm using the Mustache engine and I have this controller method:
#Controller
public class BetController {
#GetMapping("/bet")
public String show (Model model/*, #RequestParam long id*/){
//Bet bet = this.service.get(id);
return "bet_page"; //returns directly the template
}
}
Which it should return a view with a template called "bet_page":
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Apuestas</title>
</head>
<body>
<h1>Tus apuestas</h1>
<div id="navbar"></div>
<h2>Apuestas realizadas</h2>
{{bets}}
<h2>Próximos partidos</h2>
{{games}}
<div id="match"></div>
<script src="/static/assets/js/jquery.min.js"></script>
<script src="/static/assets/js/navbar.js"></script>
</body>
</html>
However, looks like Spring can't see the template, and IntelliJ throws this warning:
[![image showing warning: cannot resolve MVC view][1]][1]
I look into internet some solutions and none of these helped me to solve the problem.
By the way, here's the configuration that I use and the directory structure:
spring.mustache.suffix="html"
spring.mustache.prefix=classpath:/templates/
#ACCESS INFO
spring.datasource.url=jdbc:mysql://localhost/quidditch\
?useUnicode=true\
&useJDBCCompliantTimezoneShift=true\
&useLegacyDatetimeCode=false\
&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
#DATABASE PROPERTIES
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto= create-drop
[![Directory structure of my project][2]][2]
Any guesses?
EDIT: Looks like something from SQL is affecting in loading the templates (I'm using MySQL with JPA an JDBC)
[1]: https://i.stack.imgur.com/c3fFm.png
[2]: https://i.stack.imgur.com/vzmMv.png
I am using Jersey with Spring Boot 1.2.5. I have a Jersey controller (annotated with #Produces(MediaType.APPLICATION_JSON)) which works fine and returns JSON as long as I return an ok response such as
return Response.ok(dto).build();
but whenever I try to return a custom error status such as
return Response.status(Status.CONFLICT).build();
it gets turned into a 404 such as
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Error 404 Not Found</title>
</head>
<body>
<h2>HTTP ERROR 404</h2>
<p>Problem accessing /error. Reason:
<pre> Not Found</pre>
</p>
<hr>
<i>
<small>Powered by Jetty://</small>
</i>
<hr/>
</body>
</html>
Any ideas what's going on here?
Jersey expects the response to contain an entity. If I return an empty map together with my error code, the error gets passed onto the browser with an empty JSON object.
return Response.status(Status.CONFLICT).entity(new HashMap<>()).build();
If you have any better solutions, please feel free to comment.
We're using JTwig templating engine in our Spring webapp. It's great tool and has really nice features, but we have hit a wall with unicode content encoding using UTF-8.
First of all, ViewResolver is configured in Java with:
#Bean
public ViewResolver viewResolver() {
JtwigViewResolver view = new JtwigViewResolver()
view.setPrefix("/WEB-INF/templates/");
view.setSuffix(".twig");
return view;
}
then we have Spring MVC controller adding some text to model and passing it to view:
#RequestMapping(value = "/unicode", produces = "text/html;charset=UTF-8")
public String testUnicode(ModelMap model) {
model.addAttribute("text", "tête de bou 간편한 설치 및 사용");
return "testPage";
}
where it's finally rendered:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
</head>
<body>
<h1>tête de bouton -- 간편한 설치 및 사용</h1>
From model: {{ text }}
</body>
</html>
but the output is actually:
tête de bouton -- 간편한 설�? 및 사용
From model: t?te de bou ??? ?? ? ??
Unicode text hardcoded in template i almost right, but the one from model is totally screwed. Any ideas?
Jtwig uses Java's default charset when rendering. This violates Twig compatibility, as Twig defaults to UTF-8.
I wrote a patch for the issue which was released in 3.1.0.
You can do the following:
1) view.setEncoding("UTF-8");
2) view.setContentType("text/html; charset=UTF-8");
The second
I have a little problem with my app in Spring MVC. I want to edit users data in my app. So I have edit controller which has listWorkers, redirectWorker and editWorker method.
#RequestMapping("/print")
public String listWorkers(Model model)
{
model.addAttribute("workerList", workerService.getAllWorkers());
return "print";
}
#RequestMapping("/edit")
public String redirectWorker(HttpServletRequest request)
{
String parameter = request.getParameter("workers");
String path = "redirect:/edit/" + parameter;
return path;
}
#RequestMapping("/edit/{worker}")
public String editWorker(#PathVariable("worker")
String login, Model model)
{
model.addAttribute("worker", workerService.getWorker(login));
return "edition";
}
I have a problem with resources and images folders. When I'm using for example, print method everything is good but when I try to use editWorker method my logo and css files are not loading. I have a request mapping for this folders in servlet-context file:
<resources mapping="/resources/**" location="/resources/" />
<resources mapping="/images/**" location="/images/" />
When I'm using print method I have URL like this:
http://localhost:8080/WWP/print
and I can see image and style.
But when I'm using edit method on my specific user I have URL like this:
http://localhost:8080/WWP/edit/caro
And in this way I can't see image and style. I have a warn:
WARN : org.springframework.web.servlet.PageNotFound - No mapping found for HTTP request with URI [/WWP/edit/resources/images/logo.png] in DispatcherServlet with name 'appServlet'
WARN : org.springframework.web.servlet.PageNotFound - No mapping found for HTTP request with URI [/WWP/edit/resources/styles/menu.css] in DispatcherServlet with name 'appServlet'
I have images and styles catalogues in resource folder which is directly in webapp folder (cause I'm using maven). It works earlier, but when I have something like /*/* it doesn't work. I suppose that something is wrong with resurces mapping in my servlet-context file.
I' m loading my css and image file like this:
<img src="resources/images/logo.png">
<link rel="stylesheet" href="resources/styles/menu.css" type="text/css"></link>
Thanks in advance for your help.
Don't use relative paths. Use absolute paths instead:
<img src="<c:url value='/resources/images/logo.png'/>">
<link rel="stylesheet" href="<c:url value='/resources/styles/menu.css'/>" type="text/css"></link>
The JSTL <c:url> tag makes sure the context path is prepended to the absolute path passed as argument in the value attribute, so if your webapp is deployed to http://localhost:8080/WWP, the generated HTML code will be
<img src="/WWP/resources/images/logo.png">
<link rel="stylesheet" href="/WWP/resources/styles/menu.css" type="text/css"></link>
The <c:url> tag should also be used for every other URL: anchor hrefs, form actions, etc.