How do I use dynamic content in thymeleaf fragments? - spring-mvc

I have a spring project set up with thymeleaf and thymeleaf-layout-dialect.
In this project I have a controller
#Controller
public class HomeController {
#RequestMapping(value="/", method = RequestMethod.GET)
public String showHome(Model model){
return "home";
}
#RequestMapping(value="/info", method = RequestMethod.GET)
public String showInfo(Model model){
return "info";
}
}
I also have a layout
...
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<body>
<div layout:fragment="header">
dummy header
</div>
<div layout:fragment="content">
dummy contents
</div>
</body>
</html>
and two views: home.html and info.html which have different unique contents
<!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"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorator="layout">
<body>
<div layout:fragment="content">
unique contents
</div>
</body>
</html>
and a header
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<body>
<div layout:fragment="header">
username is ${username}
</div>
</body>
</html>
I'd like to print the username in the header without passing it as an attribute on the model in the controller methods. So, Can I run some custom java code before the header is included to find out the username regardless of what controller method is beeing used? What options do I have?

If you would use Spring Security in combination with the Thymeleaf Spring Security module, you can do the following:
<span class="user-info">
<small>Welcome,</small>
<span sec:authentication="principal">Username</span>
</span>
If you don't want to use Spring Security, you can write a custom dialect/processor which inserts the username for you.

Related

Unable to display value which is returned from Spring controller

I'm trying to display like ${mesg}, it's not displaying the content, which is coming from the Spring controller. I have tried many ways, but no luck.
<html>
<head> <meta charset="ISO-8859-1">
<title>HOME</title>
</head>
<body>
<div align="center"> ${mesg} </div>
</body>
</html>
#RequestMapping(value="/savefile",method=RequestMethod.POST)
public String getStatus(#PathParam("pwd") String Pwd,ModelMap map){
System.out.println(":::pwd::"+Pwd);
map.addAttribute("mesg", "Welcome to mBOK");
return "Success";
}

how to access variables in thymeleaf templates using spring mvc

How can I access the variables I add to model in Spring MVC inside the thymeleaf templates? I have the following controller code:
#Controller
public class ThymeLeafController {
#GetMapping("/thyme")
public void thymeleaf(ModelAndView modelAndView) {
modelAndView.addObject("var1", "var1");
modelAndView.addObject(Arrays.asList("var2", "var3", "var4"));
modelAndView.getModel().put("var5", "var5");
modelAndView.getModelMap().addAttribute("var6", "var6");
modelAndView.getModelMap().addAttribute(Arrays.asList("var7", "var8", "var9"));
modelAndView.setViewName("thymeleaf");
}
}
How can I access the variables var1, var5, var6, etc. inside thymeleaf templates?
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title>Thymeleaf</title>
</head>
<body>
<div th:if="#{var1}"></div>
</body>
</html>
Behavior:
Accessing the attributes depends upon where they were added. If the attributes were added to the ModelAndView object, they must be accessed throught "${modelAndView.model.xxxx}" where xxxx is the attribute name. If the attributes were added to Model object, they are accessible using just the attribute name itself "${attributeName}". See example below.
Controller:
#GetMapping("/thyme")
public void thymeleaf(ModelAndView modelAndView, Model model) {
modelAndView.addObject("var1", "var1");
modelAndView.addObject(Arrays.asList("var2", "var3", "var4"));
modelAndView.getModel().put("var5", "var5");
modelAndView.getModelMap().addAttribute("var6", "var6");
modelAndView.getModelMap().addAttribute(Arrays.asList("var7", "var8", "var9"));
model.addAttribute("attribute1", "attributeValue1");
}
Template:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Thymeleaf</title>
</head>
<body>
<div th:text="${attribute1}"></div>
<div th:text="${modelAndView.model}"></div>
<div th:text="${modelAndView.model.var1}"></div>
</body>
</html>
Output:
attributeValue1
{var1=var1, stringList=[var7, var8, var9], var5=var5, var6=var6}
var1

How to pass a map in thymeleaf (spring 4)

I want to pass a map from a properties file using the thymeleaf template engine.
Exception:
org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'title' cannot be found on object of type 'java.lang.String' - maybe not public?
provider.html:
<!DOCTYPE>
<html th:include="receiver :: receiver(#{site})"></html>
receiver.html:
<!DOCTYPE HTML>
<html th:fragment="receiver(map)">
<head>
<title th:text="${map.title}">title</title>
</head>
<body th:text="${map.body}">
body
</body>
</html>
messages.properties:
site.title = Any title
site.body = Any body
Controller:
#Controller
public class StartController {
#RequestMapping(value = "/", method = RequestMethod.GET)
public String start(Model model) {
return "provider";
}
}
It simply like in Java. Key and value of the Map
<div th:each="userEnrty: ${userMap}">
<p th:text="${userEntry.key}">No Id!</p>
<p th:text="${userEntry.value}">No Name!</p>
</div>
So I figured out that property-files are processed as Map. So 'site' wasn't a map at all.
My solution now is to pass the name of the variable-prefi and get the keys by thymeleaf preprocessing.
provider.html:
<!DOCTYPE>
<html th:include="receiver :: receiver('site')"></html>
receiver.html:
<!DOCTYPE HTML>
<html th:fragment="receiver(mapname)">
<head>
<title th:text="#{__${mapname}__.title}">title</title>
</head>
<body th:text="#{__${mapname}__.body}">
body
</body>
</html>
messages.properties
site.title = Any title
site.body = Any body

Include fragments in themeleaf layout based on condition using Spring Boot

I am very newbie to Thymeleaf template engine, but i have working with other template engine like blade.
I want to include fragment based on condition like i have different menus for different users for example admin, manager, super user, user etc. I have keep these menus in headers and each header is in different fragment file like adminheader, defaultheader, userheader.html.
Now i want to check what whether user is logined or not. If not logined than display layout with defaultheader or if logined, than check user is admin or not. If user is admin than display page with adminheader otherwise display page page with userheader.
Efforts:
Till now page is opening with the default header and i have design layout file like below code,
layout.html
<!DOCTYPE html>
<html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head layout:include="layouts/fragments/head :: headFragment">
</head>
<body>
<div class="container-fluid">
<header id="header" class="row navbar-fixed-top" layout:include="layouts/fragments/header :: headerFragment" >
</header>
<section class="row margin-top-120">
<div class="container-fluid">
<section id="main-content" class="col-lg-12" layout:fragment="content">
</section>
</div>
</section>
<footer id="footer" class="row">
<div class="container-fluid" layout:include = "layouts/fragments/footer :: footerFragment">
</div>
</footer>
</div>
</body>
</html>
I have included headerFragment in this layout file and working fine. Now don't know how to include other header fragment based on condition.
**Updated**
Controller
#Controller
public class IndexController {
private static final Logger logger = LoggerFactory.getLogger(IndexController.class);
#RequestMapping("/")
public String index(){
return "index";
}
#RequestMapping(value="/login", method=RequestMethod.GET)
public String login(User user) {
logger.info("Hello Get Login");
return "login";
}
#RequestMapping(value="/validateLogin", method=RequestMethod.POST)
public String validateLogin(#Valid #ModelAttribute("user") User user, BindingResult bindingResult) {
logger.info(user.toString());
if (bindingResult.hasErrors()) {
logger.info(bindingResult.toString());
return "login";
}
return "redirect:/";
}
#RequestMapping("/logout")
public String logout(){
return "index";
}
....
}
Please suggest me the solution.
Thanks.
You can use expressions for the include of different fragments on a condition. There is an example in the docs of thymeleaf.
In templatename :: domselector, both templatename and domselector can be fully-featured expressions. In the below example we want to include different fragments depending on a condition. If the authenticated user is an Admin, we will show a different footer than for a regular user:
<div th:replace="fragments/footer :: ${#authentication.principal.isAdmin()} ? 'footer-admin' : 'footer'">
© 2013 The Static Templates
</div>
Thanks #Patrick for your answer. But i have found the solution own.
I don't know whether it is good or not. Please tell.
layout.html
<!DOCTYPE html>
<html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head layout:include="layouts/fragments/head :: headFragment"></head>
<body>
<div class="container-fluid">
((${session.containsKey('user')}) ?
<header id="header" class="row navbar-fixed-top" layout:include="layouts/fragments/admin-Header :: headerFragment">
</header> :
<header id="header" class="row navbar-fixed-top" layout:include="layouts/fragments/default-Header :: headerFragment">
</header>)
<section class="row margin-top-120">
<div class="container-fluid">
<section id="main-content" class="col-lg-12" layout:fragment="content">
</section>
</div>
</section>
<footer id="footer" class="row">
<div class="container-fluid" layout:include = "layouts/fragments/footer :: footerFragment">
</div>
</footer>
</div>
</body>
</html>

Newly added jap page requested resource is not available

I have an existing MVC application that uses the following Dispatcher:
<servlet-mapping>
<servlet-name>SpringDispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
What I did was under the WEB-INF/views directory add a menu.jsp file to be the new startup jsp.
/SpringMvcJdbcTemplate/WEB-INF/views/menu.jsp
New menu.jsp:
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<div align="center">
<h1>Main Menu</h1>
<h3>List Contacts</h3>
</div>
</body>
</html>
Now what I did is change the initial "/" RequestMapping controller method to look like the following:
#RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView menu(ModelAndView model){
model.setViewName("menu");
return model;
}
Now I feel that everything should work but when I run the application I receive the following page errors:
HTTP Status 404 - /SpringMvcJdbcTemplate/WEB-INF/views/menu.jsp
type Status report
message /SpringMvcJdbcTemplate/WEB-INF/views/menu.jsp
description The requested resource is not available
I am not sure what I am doing wrong. Can anyone help?
I was doing something dumb. I misspelled "menu" as "meun". Renamed and now all is better.

Resources