Hello I'm new in Thymeleaf and encountered a problem that might be trivial, but thymeleaf don't behave like it supposed to be. Just a little help will be much appreciated
I don't use spring boot for the matters of learning. Additionally, I am also pretty new to Spring. Might miss one or two things.
I have simple index.html like this
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Index 2</title>
</head>
<body>
<div th:replace="~{fragments/fragment1 :: fr1}"></div>
</body>
</html>
and fragment1.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
</head>
<body>
<div th:fragment="fr1"><h1>HERE IS FRAGMENTS 1</h1></div>
</body>
</html>
Supposedly it does resolve the template, but the result doesn't change at all.
here is what i get from the browser page source
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Index 2</title>
</head>
<body>
<div th:replace="~{fragments/fragment1 :: fr1}"></div>
</body>
</html>
and yes it exactly the same as raw index.html.
So I figured it might have something to do with the configuration, but it just looks fine for me. In my other learning project, it just works fine with the exactly same configuration.
Here is the configuration
/* package and imports */
#Configuration
#EnableWebMvc
#ComponentScan("com.eshop")
public class WebConfig extends WebMvcConfigurerAdapter {
private static final String UTF8 = "UTF-8";
private static final String VIEWS = "/WEB-INF/templates/";
private static final String RESOURCES_LOCATION = "/resources/";
private static final String RESOURCES_HANDLER = RESOURCES_LOCATION + "**";
//Thymeleaf Configuration
#Bean
public ITemplateResolver templateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setPrefix(VIEWS);
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCacheable(false);
return resolver;
}
#Bean
public SpringTemplateEngine templateEngine(){
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
templateEngine.setDialect(new SpringSecurityDialect());
return templateEngine;
}
#Bean
public ViewResolver viewResolver(){
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setCharacterEncoding(UTF8);
return viewResolver;
}
// tells DispatcherServlet to give static resources and not handle the resources itself
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
// handle various resources like javascript and css
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler( RESOURCES_HANDLER ).addResourceLocations( RESOURCES_LOCATION );
}
}
pom.xml
<!-- thymeleaf -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring4</artifactId>
<version>3.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
<version>3.0.0.RELEASE</version>
</dependency>
here is the project tree
webapp
|__resources
|__WEB-INF
|__i18n
|__templates
|__fragments
|__fragment1.html
|__index.html
What do I miss here and how can I fix this?
Try calling the th:replace without ~{}
<div th:replace="fragments/fragment1 :: fr1"></div>
Also make sure you have separate html file named fragment1.html
This Layouts tutorial should help you get going.
Related
I am getting a very strange error in that sometimes there is no problem and the CSS and JS files are fetched correctly but then all of sudden, it throws error that the mapping can't be found.
I suspect this is some kind of cache problem because closing the application and running a different application and then again running this application resolves that error.
My mapControl.java looks like this:
#Controller
public class MapControl {
#Autowired
TrafficAndRoutingService trs;
#GetMapping(value="/")
public String read(Model model)
{
model.addAttribute("pt",new UrlTransformer());
model.addAttribute("bbox",trs.getBoundingBox());
return "index";
}
#RequestMapping(value="/routing",method=RequestMethod.GET)
public String load(#ModelAttribute("pt") UrlTransformer pt, BindingResult errors, Model model)
{
UrlContainer rp=pt.convert();
RoutePath res=trs.getPath(rp);
model.addAttribute("route",res);
model.addAttribute("bbox",res.getBounds());
return "index";
}
#ResponseBody
#RequestMapping(value = "/routing",method=RequestMethod.GET,produces="application/json")
public RoutePath fetchJSONResponse(#ModelAttribute("pt") UrlTransformer pt, BindingResult errors, Model model)
{
UrlContainer rp=pt.convert();
RoutePath res=trs.getPath(rp);
return res;
}
#RequestMapping(value = "/traffic", method = RequestMethod.GET, produces = "application/json")
#ResponseBody
public TrafficData show()
{
return trs.getAll();
}
}
My WebConfig.java looks like this:
#Configuration
#EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.parameterName("mediaType").
defaultContentType(MediaType.ALL).
mediaType("json", MediaType.APPLICATION_JSON);
}
}
And my index.html (header part) looks like this:
<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org">
<head>
<meta charset='utf-8'>
<title>N.S</title>
<!-- Loading all relevant scripts and stylesheets -->
<!-- Loading relevant leaflet scripts and stylesheets -->
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.7.1/dist/leaflet.css"
integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
crossorigin=""/>
<script src="https://unpkg.com/leaflet#1.7.1/dist/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin=""> </script>
<!-- Loading relevant mapbox scripts and stylesheets for geocoding -->
<link href="https://api.mapbox.com/mapbox-gl-js/v2.4.0/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v2.4.0/mapbox-gl.js"></script>
<script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v4.7.2/mapbox-gl-geocoder.min.js"></script>
<link rel="stylesheet" href="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v4.7.2/mapbox-gl-geocoder.css" type="text/css">
<!-- Loading relevant jquery libraries and bootstrap libraries for toggle mode -->
<link rel = "stylesheet" href = "https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity = "sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin = "anonymous">
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity = "sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin = "anonymous"></script>
<script src = "https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity = "sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin = "anonymous"></script>
<!-- Loading stylesheet for webpage -->
<link rel="stylesheet" th:href="#{/static/css/styles.css}">
<!-- Loading scripts for canva5 used in traffic display -->
<script th:src="#{static/js/leaflet_canvas_layer.js}"></script>
<script th:src="#{static/js/leaflet_tileloader_mixin.js}"></script>
<!-- Loading scripts traffic display (fetch and display) -->
<script th:src="#{static/js/traffic_disp/traffic_layer.js}"></script>
<script th:src="#{static/js/traffic_disp/traffic_fetch.js}"></script>
<!-- Loading script for converting string to title case-->
<script th:src="#{static/js/text_style/title_case.js}"></script>
</head>
Could anyone help me understand what I could have done wrong to get this error intermittently? And also how to resolve it.
In my Spring boot API, I need to send an email using Thymeleaf.Therefore, I chose this tutorial.However, when adding ThymeleafConfig.java, STS throws the following error.
The import org.thymeleaf.templatemode.StandardTemplateModeHandlers
cannot be resolved
As stated in this answer, I changed the dependencies as follows.But it didn't solve the problem.
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
</dependency>
ThymeleafConfig.java
import java.nio.charset.StandardCharsets;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//following import is not resolved
import org.thymeleaf.templatemode.StandardTemplateModeHandlers;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
#Configuration
public class ThymeleafConfig {
#Bean
public ClassLoaderTemplateResolver htmlTemplateResolver(){
ClassLoaderTemplateResolver emailTemplateResolver = new ClassLoaderTemplateResolver();
emailTemplateResolver.setPrefix("/templates/");
emailTemplateResolver.setSuffix(".html");
emailTemplateResolver.setTemplateMode(StandardTemplateModeHandlers.HTML5.getTemplateModeName());
emailTemplateResolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
return emailTemplateResolver;
}
}
Use TemplateMode instead of StandardTemplateModeHandlers
import org.thymeleaf.templatemode.TemplateMode;
#Bean
public SpringResourceTemplateResolver htmlTemplateResolver(){
SpringResourceTemplateResolver emailTemplateResolver = new SpringResourceTemplateResolver();
emailTemplateResolver.setPrefix("classpath:/templates/");
emailTemplateResolver.setSuffix(".html");
emailTemplateResolver.setTemplateMode(TemplateMode.HTML);
emailTemplateResolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
return emailTemplateResolver;
}
In HTML template, use th:text
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>hello</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="${name}">
</body>
</html>
When you are processing your template , use thymeleaf's TemplateEngine
import org.thymeleaf.TemplateEngine;
#Autowired
private TemplateEngine templateEngine;
Context context = new Context();
context.setVariables(mail.getModel());
String html = templateEngine.process("email-template", context);
I'm trying to build a little hello world WebApp prototype with Spring 4 without any xml file configuration.
Than I use tomcat 7 and here is my pom:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
Than I have this configuration class:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "it.spring4.configuration")
public class HelloWorldConfiguration {
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new
InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
and the web initializer class:
public class HelloWorldInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { HelloWorldConfiguration.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
The controller:
#Controller
#RequestMapping("/")
public class HelloWorldController {
#RequestMapping(value = "/hello", method = RequestMethod.GET)
public String sayHello(ModelMap model) {
model.addAttribute("greeting", "Hello World from Spring 4 MVC");
return "welcome";
}
#RequestMapping(value = "/helloagain", method = RequestMethod.GET)
public String sayHelloAgain(ModelMap model) {
model.addAttribute("greeting", "Hello World Again, from Spring 4 MVC");
return "welcome";
}
}
and under WEB-INF the folder views that contains welcome.jsp:
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>HelloWorld page</title>
</head>
<body>
Greeting : ${greeting}
</body>
</html>
This is an example found here and doesn't work. I tried other similar examples but noone works.. can you explain me were I'm wrong?
Sorry the error is:
HTTP Status 404 – Not Found
Type Status Report
Message /Spring4FullAnnotation/
Description The origin server did not find a current representation for the
target resource or is not willing to disclose that one exists.
Damn.. I don't dowload the example I just copy the code in my eclipse... I don't have a maven project, I use maven just for resolving the dependencies (I create a Dynamic Web Project after that Configure -> Convert to maven project), than I normally run it on server. I have many project built as described above with Spring4 that are perfectly working.
I don't know why I can't launch this. The code is simple and the functioning can't depends of maven configuration..
Thank you
The code is working fine for the following URL
http://localhost:8080/Spring4MVCHelloWorldNoXMLDemo-1.0.0/
Please check your URL
I have been looking at all of the resources available on how to include an html file into another html file using Thymeleaf's th:insert. I am wondering if anyone could tell me what I am doing wrong as I feel like this html looks exactly like the examples I have seen.
My index.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.thymeleaf.org ">
<head>
<title>Default Page</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<div th:insert="templates/Navbar :: navbar"> </div>
</body>
</html>
My Navbar.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.thymeleaf.org ">
<head>
<meta charset="UTF-8"/>
<title>NavigationBar</title>
<link rel="stylesheet" type="text/css" media="all" href="../../css/NavBar.css" th:href="#{/css/NavBar.css}" />
</head>
<body>
<div>
<div th:fragment="navbar" class="navbar">
<div class="navbar-inner">
<a th:href="#{/}" href="/home"> Home</a>
<a th:href="#{/}" href="/help">Help</a>
</div>
</div>
</div>
</body>
</html>
Also, here is my project's resource hierarchy via screen shot
If I put the code between the into the index.html and link the css file, the navbar shows up and works. So, I am not sure why the insert is not working. Here is my configuration file which has been edited based on examples below:
#Configuration
public class WebPageControllerConfig {
private SpringTemplateEngine templateEngine;
private ServletContextTemplateResolver templateResolver;
#Value("${WebController.startHour}")
public String startHour;
#Value("${WebController.endHour}")
public String endHour;
#Value("${WebController.numOfSkus}")
public int numOfSkus;
#Value("${WebController.skusToQuery}")
public File skusToQuery;
#Bean
public ClassLoaderTemplateResolver webPageTemplateResolver(){
ClassLoaderTemplateResolver webPageTemplateResolver = new ClassLoaderTemplateResolver();
webPageTemplateResolver.setPrefix("templates/");
webPageTemplateResolver.setSuffix(".html");
webPageTemplateResolver.setTemplateMode("HTML5");
webPageTemplateResolver.setCharacterEncoding(CharEncoding.UTF_8);
webPageTemplateResolver.setOrder(1);
return webPageTemplateResolver;
}
/* Old way of trying to configure
#Bean
public MessageSource messageSource() {...}
#Bean
public ServletContextTemplateResolver setTemplateResolver(){...}
#Bean
public SpringTemplateEngine setTemplateEngine() {...}
#Bean
public ViewResolver viewResolver() {...}
End of old configuration */
public String getStartHour() {return startHour;}
public String getendHour() {return endHour;}
public Object getnumOfSkus() {return numOfSkus;}
public File getSkusToQuery(){return skusToQuery;}
}
Change to
th:insert="templates/Navbar :: navbar"
and
th:fragment="navbar"
Configuration example:
import org.apache.commons.lang3.CharEncoding;
import org.springframework.context.annotation.*;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
#Configuration
public class ThymeleafConfiguration {
#Bean
#Description("Thymeleaf template resolver serving HTML 5 emails")
public ClassLoaderTemplateResolver emailTemplateResolver() {
ClassLoaderTemplateResolver emailTemplateResolver = new ClassLoaderTemplateResolver();
emailTemplateResolver.setPrefix("root folder where all thymeleaf files/");
emailTemplateResolver.setSuffix(".html");
emailTemplateResolver.setTemplateMode("HTML5");
emailTemplateResolver.setCharacterEncoding(CharEncoding.UTF_8);
emailTemplateResolver.setOrder(1);
return emailTemplateResolver;
}
}
Try with:
th:replace="/navbar::navbar"
or
th:insert="/navbar::navbar"
It works for me. No need to specify "template/navbar".
I am trying to use layouts/templates with Thymeleaf but I'm getting the following exception.
Exception processing template "user/index": Error resolving template "/layouts/default.html", template might not exist or might not be accessible by any of the configured Template Resolvers
Here is my ThymeleafConfig.java
#Configuration
public class ThymeleafConfig {
#Bean
public ServletContextTemplateResolver templateResolver() {
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".html");
resolver.setTemplateMode("HTML5");
resolver.setOrder(1);
return resolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(templateResolver());
engine.addDialect(new LayoutDialect());
engine.addDialect(new SpringSecurityDialect());
engine.addDialect(new SpringStandardDialect());
return engine;
}
#Bean
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
return resolver;
}
}
I have the following folder structure
webapp/
..WEB-INF/
....views/
......layouts/
........default.html
......user
........index.html
Here is my default.html which is my main layout.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Default</title>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<header>
This is a header from default.html
</header>
<section layout:fragment="content">
<p>Content should go here!</p>
</section>
<footer>
Footer from default
<p layout:fragment="custom-footer">Custom footer here!</p>
</footer>
<!-- scripts -->
<script src="https://code.jquery.com/jquery-2.1.3.min.js" />
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
</body>
</html>
Here is the index.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorator="layouts/default.html">
<head>
<title>Users</title>
</head>
<body>
<section layout:fragment="content">
<p>This is a paragraph from content page 1</p>
</section>
<footer>
<p layout:fragment="custom-footer">This is some footer content from content page 1</p>
</footer>
</body>
</html>
They are in different folders but the pathing should work unless I'm just missing something really silly.
I found my issue. If you specify the suffix in your Thymeleaf config you do not need the .html extension.
#Bean
public ServletContextTemplateResolver templateResolver() {
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".html"); // here
resolver.setTemplateMode("HTML5");
resolver.setOrder(1);
return resolver;
}
It should be:
layout:decorator="layouts/default"
Instead of:
layout:decorator="layouts/default.html"
I'm guessing it was effectively looking for layouts/default.html.html which would be a problem.
I solved this issue by having following code:
#Configuration
public class ThymeleafConfig{
#Bean
public SpringTemplateEngine springTemplateEngine()
{
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(htmlTemplateResolver());
return templateEngine;
}
#Bean
public SpringResourceTemplateResolver htmlTemplateResolver()
{
SpringResourceTemplateResolver emailTemplateResolver = new SpringResourceTemplateResolver();
emailTemplateResolver.setPrefix("classpath:/templates/");
emailTemplateResolver.setSuffix(".html");
emailTemplateResolver.setTemplateMode(StandardTemplateModeHandlers.HTML5.getTemplateModeName());
emailTemplateResolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
return emailTemplateResolver;
}
}
The trick was to add: emailTemplateResolver.setPrefix("classpath:/templates/");
You should not give the extension.And you have to provide correct path like this
layout:decorator="../layouts/default"