I have a rest api returns a Json value as a Output of the service call.
eg:- https://localhost:8080/getEmployees/loadAll
this returns following json values
eg:-
{
"employees":[
{"firstName":"John", "lastName":"Doe"},
{"firstName":"Anna", "lastName":"Smith"},
{"firstName":"Peter", "lastName":"Jones"}
]
}
I need to load the following json values to my thymeleaf table.
In normal way returning values in controller using modal in spring can retun values as list like following.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Employee List</title>
</head>
<body>
<h1>Welcome</h1>
<br>
<h3>Employee List</h3>
<br />
<table border="1">
<tr>
<td>Employee First Name</td>
<td>Employee Last Name</td>
</tr>
<tr th:each="emp : ${empList}">
<td th:text="${emp.firstName}">First Name</td>
<td th:text="${emp.name}">Last Name</td>
</tr>
</table>
</body>
</html>
is there a way to accomplish this using above json using thymeleaf?
You can do something like that using the following structure.
When you call the service
https://localhost:8080/getEmployees/loadAll
you will need to pass the employees data using model.addAttribute.
For instance, let's say you have the following method:
#RequestMapping(value="/getEmployees/loadAll")
String getAllEmployees(Model model) {
model.addAttribute("empList", <your service here that generates the data>);
return "pagenamehere";
}
The above method, will only be executed when you make a call using the following url: https://localhost:8080/getEmployees/loadAll
and it will add your empList data as an attribute. Then, the return string indicates the name of the page that will load. You will need to use your own page with the thymeleaf code.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Employee List</title>
</head>
<body>
<h1>Welcome</h1>
<br>
<h3>Employee List</h3>
<br />
<table border="1">
<tr>
<td>Employee First Name</td>
<td>Employee Last Name</td>
</tr>
<tr th:each="emp : ${empList}">
<td th:text="${emp.firstName}">First Name</td>
<td th:text="${emp.lastNname}">Last Name</td>
</tr>
</table>
</body>
</html>
Now, thymeleaf will be able to display the given data.
I think that you are a little confused. Thymeleaf templates are compiled on server side generating html code. Then, no thymeleaf code found on client side.
The json data got of the api response is generated on client side.
One way is use javascript to load the api response data into a html table.
Another way can you take is modify the controller that calls to the thymeleaf template to get the JSon value. If you store this response (on an object List named empList on your example) yo can add the object into the Controller response (Model or ModelAndView objects) as a template attribute.
Related
We have an Java application which reads information from DB and generates HTML table via Freemarker like this:
<#if marks?size != 0>
<div>
<p>
<b>Total rows with information about broken utm-marks for ${date} is: ${total}. Displayed in current report: ${displayed}</b>
</p>
<br/>
</div>
<table border="1" cellspacing="0" cellpadding="1">
<tr class="tableHeader" style = "background-color:#f8f5e4; text-align:center; font-weight: bold;">
<th>Report date</th>
<th>Account Login</th>
<th>View Id</th>
<th>Utm marks</th>
<th>Exception type</th>
<th>Exception message</th>
</tr>
<#list marks as mark>
<tr class="tableBody">
<td>${(mark.reportDate)!""}</td>
<td>${(mark.accountLogin)!""}</td>
<td>${(mark.accountViewId)!""}</td>
<td>${(mark.utmMarks)!""}</td>
<td>${(mark.exceptionType)!""}</td>
<td>${(mark.exceptionMessage)!""}</td>
</tr>
</#list>
</table>
<br/>
<#else>
<div>
<p>
<b>No information about broken utm marks for ${date}.</b>
</p>
</div>
</#if>
This generated table will be sent to configured email.
Is it possible to build this type of application with Apache NiFi (without and with ExecuteScript)? Read from DB - fine; send email - fine; but what about templates and html table?
create ./templates folder in nifi root folder
put there a template file test.ftlh with content:
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<h1>Welcome ${user}!</h1>
<p>Our latest product:
${latestProduct.name}!
</body>
</html>
use GenerateFlowFile to inject following json into flow file:
{
"user":"Big Joe",
"latestProduct": {
"name":"green mouse",
"url":"aaa/bbb/ccc"
}
}
use ExecuteGroovyScript to merge template with data
#Grab(group='org.freemarker', module='freemarker', version='2.3.31')
import freemarker.template.*
import groovy.json.*
class Const{
static Configuration cfg
}
//on processor start
static onStart(ProcessContext context){
Const.cfg = new Configuration(Configuration.VERSION_2_3_29)
Const.cfg.with{
setDirectoryForTemplateLoading(new File("./templates"))
setDefaultEncoding("UTF-8")
setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER)
setLogTemplateExceptions(false)
setWrapUncheckedExceptions(true)
setFallbackOnNullLoopVariable(false)
}
}
//flowfile process
def ff=session.get()
if(!ff)return
ff.write{InputStream rawIn, OutputStream rawOut->
//assume json in flowfile
def root = new JsonSlurper().parse(rawIn)
Template tpl = Const.cfg.getTemplate("test.ftlh")
rawOut.withWriter("UTF-8"){w-> tpl.process(root, w) }
}
REL_SUCCESS << ff
One way to do this without ExecuteScript (or similiar) would be:
put the HTML template-text in a NiFi process group variable
then use NiFi expression language function evaluateELString to substitute the flowfile attributes into the template.
This approach would have the advantage of being easy to maintain: the HTML template-text could be with the process group; there is no scripting code to maintain.
To illustrate this approach, suppose you put the HTML template-text into a process group variable, named email_template. Further, suppose a flowfile has the attributes set that are required by the HTML template (e.g., from a database). Then to get the realized email body, put the NiFi expression ${email_template:evaluateELString()} in the value for the Replacement Value property of the ReplaceText processor (which precedes the PutEmail processor).
In the illustration above, the variable,email_template could be set to:
<#if marks?size != 0>
<div>
<p>
<b>Total rows with information about broken utm-marks for ${date} is: ${total}. Displayed in current report: ${displayed}</b>
</p>
<br/>
</div>
<table border="1" cellspacing="0" cellpadding="1">
<tr class="tableHeader" style = "background-color:#f8f5e4; text-align:center; font-weight: bold;">
<th>Report date</th>
<th>Account Login</th>
<th>View Id</th>
<th>Utm marks</th>
<th>Exception type</th>
<th>Exception message</th>
</tr>
<#list marks as mark>
<tr class="tableBody">
<td>${mark.reportDate}</td>
<td>${mark.accountLogin}</td>
<td>${mark.accountViewId}</td>
<td>${mark.utmMarks}</td>
<td>${mark.exceptionType}</td>
<td>${mark.exceptionMessage}</td>
</tr>
</#list>
</table>
<br/>
<#else>
<div>
<p>
<b>No information about broken utm marks for ${date}.</b>
</p>
</div>
</#if>
...and ${email_template:evaluateELString()} would substitute the flowfile attribute values for date, total, displayed, mark.reportDate, etc.
I'm using spring boot and thymeleaf to create a form to collect the data from front-end and update the database at back-end. I'm having trouble to pass the object value by using ModelAttribute. I can almost guaranty my repository and my bean work fine because I have written Junit test case against it and I can see the update from DB. I tried to use th:field at the html page, but it doesn't give me any default value in the field, so I have to use th:value. The print out statements in the controller just keep return 0. It feels like (#ModelAttribute("city") CityBean city) just never pass any data into the variable city. I can't really tell where the problem is after hours of the debugging. I will attach my code here. Thank you very much for helping.
My bean:
public class CityBean {
int cityID;
int population;
String cityName;
String state;
My Repository/DAO:
public int updatePopulation(CityBean city) {
String sql = "UPDATE CITY SET population = ? WHERE cityID = ?";
Object[] args = {city.getPopulation(), city.getCityID()};
int[] types = {Types.VARCHAR, Types.INTEGER};
return jdbcTemplate.update(sql, args, types);
}
My controller:
#RequestMapping(value = "/action", method = RequestMethod.POST)
public String updatePopulation(#ModelAttribute("city") CityBean city) {
System.out.println("This is city ID " + city.getCityID());
System.out.println("This is city population " + city.getPopulation());
cityRepository.updatePopulation(city);
return "redirect:/cityInfo";
}
My Front-end HTML:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>CS6400 Fall 2020 Team 017 Project</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
</head>
<body>
<h1 style="text-align:center">City Population Update Form</h1>
<br>
<form action="#" th:action="#{/action}" th:object="${city}" method="post" modelAttribute="city">
>
<table class="table">
<thead>
<tr>
<th scope="col">City ID</th>
<th scope="col">City Name</th>
<th scope="col">State</th>
<th scope="col">Population</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
<tr >
<td><input type="text=" th:value="*{cityID}" readonly="readonly"></td>
<td><input type="text=" th:value="*{cityName}" readonly="readonly"></td>
<td><input type="text=" th:value="*{state}" readonly="readonly"></td>
<td><input type="text=" th:value="*{population}" ></td>
<td>
<button type="submit" class="btn btn-primary">Update Population</button>
</td>
</tr>
</tbody>
</table>
</form>
</body>
</html>
Problem solved, I added name="pramName" in the input tag then everything works fine.
I am using IntelliJ IDEA community Edition 2020.1.2 x64 and written a program using Spring DataJPA and Thymeleaf,there is no problem with my code and i am not getting error but when i am passing URL which i mapped in controller class i am unable to get desired result i.e the thymeleaf template which i have created is not displayed on browser.
I am posting the controller class,thymeleaf template and output which i am getting on browser to make you clear:-
controller class:
#RestController
#RequestMapping("/ecommerce")
public class EmployeeController {
#Autowired
private ProductService productService;
#GetMapping("/available")
public String ShowAllProducts(Model model)
{
model.addAttribute("listProducts",productService.getAllProducts());
return "availableProducts";
}
}
Thymeleaf template:-
<!DOCTYPE html>
<html xmlns:th="html://thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>AvailableProducts</title>
</head>
<body>
<div align="center">
<h1>Product List</h1>
<table>
<thead>
<tr>
<th>p_id</th>
<th>ProductName</th>
<th>Productcost</th>
<th>QuantityAvailable</th>
</tr>
</thead>
<tbody>
<tr th:each="product : ${listProducts}">
<td th:text="${product.productId}"></td>
<td th:text="${product.productName}"></td>
<td th:text="${product.productCost}"></td>
<td th:text="${product.quanityAvailable}"></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
Output on browser:-
Dependency added:-
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
application.properties:-
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/ecommerce
spring.datasource.username=root
spring.datasource.password=deep
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto= update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.thymeleaf.prefix=classpath*:/templates/
spring.thymeleaf.check-template-location=true
spring.thymeleaf.suffix=.html
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.content-type=text/html
spring.thymeleaf.mode=HTML5
At last when i am passing url http://hocalhost:8080/ecommerce/available what i am seeing in console is,hibernate is accessing the database every time.
Thanks in advance..
Please help i am stuck and don't know what i am doing wrong and not able to figure out on my own..
In your case seems like controller is just returning string "availableProducts" and its not resolving as thymleaf template. you can just return some dummy name("availableProductsTest") and you will see same(availableProductsTest) on the web page.
Did you referred to sample https://spring.io/guides/gs/serving-web-content/
Sample code is available here .. git clone https://github.com/spring-guides/gs-serving-web-content.git
if you just add your product class and modify the Greetings contoller like below then you can see its working!
#GetMapping("/greeting")
public String greeting(#RequestParam(name="name", required=false, defaultValue="World") String name, Model model) {
model.addAttribute("name", name);
List<Products> productList= new ArrayList<>();
Products product = new Products("productId","ProductName", "ProductCost", "ProductQtyAvlb");
productList.add(product);
model.addAttribute("listProducts",productList);
return "greeting";
}
Also modify greetings template as below
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="'Hello, ' + ${name} + '!'" />
<div align="center">
<h1>Product List</h1>
<table>
<thead>
<tr>
<th>p_id</th>
<th>ProductName</th>
<th>Productcost</th>
<th>QuantityAvailable</th>
</tr>
</thead>
<tbody>
<tr th:each="product : ${listProducts}">
<td th:text="${product.productId}"></td>
<td th:text="${product.productName}"></td>
<td th:text="${product.productCost}"></td>
<td th:text="${product.quanityAvailable}"></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
Hope this Helps! Happy Coding
Web reference: https://spring.io/guides/gs/serving-web-content/
Whenever you get Whitelabel Error Page you will have details about error listed on same page also same details can be seen in server logs or on console of the application.
For example if i use wrong template name in controller then i see below:
2020-07-28 22:35:51.031 ERROR 19572 --- [nio-8080-exec-1] org.thymeleaf.TemplateEngine : [THYMELEAF][http-nio-8080-exec-1] Exception processing template "greeting1": Error resolving template [greeting1], template might not exist or might not be accessible by any of the configured Template Resolvers
org.thymeleaf.exceptions.TemplateInputException: Error resolving template [greeting1], template might not exist or might not be accessible by any of the configured Template Resolvers
at org.thymeleaf.engine.TemplateManager.resolveTemplate(TemplateManager.java:869) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE]
at org.thymeleaf.engine.TemplateManager.parseAndProcess(TemplateManager.java:607) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE]
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1098) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE]
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1072) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE]
I am fetching some data with a Ajax request in my main JSP page.
Snippet of main.jsp
function gu(){
$.get('/admin/getAllUsers', {}, function(data) {
console.log(data); // see below
$("#allUsersData").html(data);
});
}
In my Spring controller I add all the users to a different JSP page.
Snippet of MainController.java
#RequestMapping(value = "/admin/getAllUsers", method = RequestMethod.GET)
public String getAllUsers(Model model){
List<User> users = userRepository.findAll();
System.out.println(users.size()); // output: 3
model.addAttribute("allUsers", users);
return "data/all-users";
}
Now in all-users.jsp I have a <c:forEach> which is supposed to load all users in a html table:
<table class="table">
<thead>
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Email</th>
<th>Date</th>
</tr>
</thead>
<tbody>
<c:if test="${not empty allUsers}">
<c:forEach items="${allUsers}" var="usr">
<tr>
<td>${usr.firstName}</td>
<td>${usr.lastName}</td>
<td>${usr.username}</td>
<td>${usr.creationDate}</td>
</tr>
</c:forEach>
</c:if>
</tbody>
</table>
However, when I add the html coming from the request to my main JSP page, an empty table is shown. When I log the result of the Ajax request I find that the user data is inserted in the all-users.jsp:
<c:if test="true">
<c:forEach items="[User{id=1, username='username1', firstName='John', lastName='Doe', roles=[Role{id=1, name='ROLE_USER'}], creationDate=2018-02-19T08:58:13.333}, User{id=2, username='username2', firstName='John2', lastName='Doe2', roles=[Role{id=3, name='ROLE_USER'}], creationDate=2018-02-19T08:58:13.471}]" var="usr">
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</c:forEach>
</c:if>
Why is it happening that the data is loaded into the data JSP page, but not shown when appending it to the main JSP page?
Can you check, maybe you haven't included the core tag library in your JSP file.
You will do this by inserting the following Line at the top of your file.
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
Howto integrate Jasper HTML Report in Spring View (Conceptional)
I would like to create a kind of dashboard in my Spring framework Application.
I have a view (jsp) and would like to include Jasper Report HTML/Pie Chart Image Output ( in my html sample) in a specific part of my produced HTML Page.
Is this possible to do ? If yes. Will the report be generated in the controller and sent to the view by ModelView ?
My View (dashboard.jsp) looks like this (sample):
<%#taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<body>
<h2>Key Figures</h2>
<table border=1 width=700>
<tbody>
<tr> <Navigation Items like Buttons and Tabs> </tr>
<tr height=200>
<td><c:forEach var="listValue" items="${lists}">
<li>${listValue}</li>
</c:forEach>
</td>
<td>Other Content from the Model</td>
</tr>
<tr height=200>
<td><My Pie Chart 1></td>
<td><My Pie Chart 2></td>
</tr>
</tbody>
</table>
</body>
</html>