For debugging purposes I would like to list all model attributes available to my thymeleaf template while it is rendering.
Something like:
<table>
<tr th:each="model : ${*}">
<td th:text="${model}"></td>
</tr>
</table>
But obviously that's nonsense, and I get a well-deserved error.
(org.springframework.expression.spel.SpelParseException: EL1070E:(pos 0): Problem parsing left operand)
Is there a way of outputting such debug information? I'd settle even for some logging output.
Or, does Thymeleaf provide something similar to Struts 2's struts.devMode where it added a debug section at the bottom of the page listing all available properties?
Try this:
<table>
<tr th:each="var : ${#vars}">
<td th:text="${var.key}"></td>
<td th:text="${var.value}"></td>
</tr>
</table>
The accepted answer does not seem to work for Thymeleaf 3; here's an update. Please note that I'm using Spring; this might not work for non-Spring apps.
<table>
<tr th:each="var : ${#vars.getVariableNames()}">
<td th:text="${var}"></td>
<td th:text="${#vars.getVariable(var)}"></td>
</tr>
<!--
Adding these manually because they are considered special.
see https://github.com/thymeleaf/thymeleaf/blob/thymeleaf-3.0.3.RELEASE/src/main/java/org/thymeleaf/context/WebEngineContext.java#L199
-->
<tr>
<td>param</td>
<td th:text="${#vars.getVariable('param')}"></td>
</tr>
<tr>
<td>session</td>
<td th:text="${#vars.getVariable('session')}"></td>
</tr>
<tr>
<td>application</td>
<td th:text="${#vars.getVariable('application')}"></td>
</tr>
</table>
That said, what I've done is created a standalone Bean that makes things a bit prettier and dumps to logs instead of to HTML:
#Component
public class ThymeleafDumper {
private Logger log = LoggerFactory.getLogger(ThymeleafDumper.class);
public void dumpToLog(WebEngineContext ctx) {
log.debug("Thymeleaf context: {}", formatThisUpNicely(ctx));
}
// ... etc
}
Where formatThisUpNicely can use ctx.getVariableNames(), put the results into a SortedMap, export to json, whatever. Don't forget those three 'special' variables!
Then expose an instance of it as a #ModelAttribute in a Controller or a ControllerAdvice:
#ControllerAdvice
public class SomeControllerAdvice {
#Autowired
private ThymeleafDumper thymeleafDumper;
#ModelAttribute("dumper")
public ThymeleafDumper dumper() {
return this.thymeleafDumper;
}
}
Then in my template run:
<div th:text="${dumper.dumpToLog(#vars)}"/>
these are all the logging available configurations :
log4j.logger.org.thymeleaf=DEBUG
log4j.logger.org.thymeleaf.TemplateEngine.CONFIG=DEBUG
log4j.logger.org.thymeleaf.TemplateEngine.TIMER=DEBUG
log4j.logger.org.thymeleaf.TemplateEngine.cache.TEMPLATE_CACHE=DEBUG
log4j.logger.org.thymeleaf.TemplateEngine.cache.FRAGMENT_CACHE=DEBUG
log4j.logger.org.thymeleaf.TemplateEngine.cache.MESSAGE_CACHE=DEBUG
log4j.logger.org.thymeleaf.TemplateEngine.cache.EXPRESSION_CACHE=DEBUG
these will log all the thymeleaf actions. I hope it is helpful.
Thymeleaf 3.0:
To put it short, try the following:
<table>
<tr th:each="var : ${param.keySet()}">
<td th:text="${var}"></td>
<td th:text="${param.get(var)}"></td>
</tr>
</table>
When a #Controller returns some value stored in a Spring Model, the values are actually stored as request parameters, which is accessible using:
request.getParameter("paramName");
Thymeleaf provides a similar functionality: "Web context namespaces for request/session attributes", the syntax is as stated.
The Thymeleaf built-in ${param} kewords returns an WebRequestParamsVariablesMap extends VariablesMap<String,String[]> object,
whose keySet() method returns a String[], which contains those variable names within a httprequest.
Related
I have added some Http session variables in a Java class inside a loop, and each session variable contains a unique identifier as part of it's name.
I want to be able to read these variables from a loop on a Thymeleaf template, using the identifier which was set for each. Is this possible? And if so what syntax should I use to insert the id to the name of my session variable in the Thymeleaf template?
The name of each Http session variable is "Sid"+unique_id, as below.
<tr th:each="item : ${items}">
<td th:text="${item.id}"></td>
<td th:text="${item.name}"></td>
<td th:if="${item.expired != null
and session.Sid${item.id} == 'available'}">
</tr>
You can do this using preprocessing.
<tr th:each="item : ${items}">
<td th:text="${item.id}"></td>
<td th:text="${item.name}"></td>
<td th:if="${item.expired != null and session.Sid__${item.id}__ == 'available'}">??<td>
</tr>
(It works, but in general I wouldn't recommend this kind of structure. I think you should be using a map, or some other data structure built for pulling out data like this. Then you could do something like: session.sids[item.id] or session.sids.get(item.id))
I have part of the controller:
#RequestMapping(value = "1", method = RequestMethod.GET)
public String greeting(#RequestParam(value="1", required = false, defaultValue = "1") int id, Model model){
List<Question> survey = surveyDAO.getSurveyById(id);
model.addAttribute("survey", survey);
return "showSurvey";
}
where I try to addAttribute List<Question> to be passed on to thymeleaf page. But on the thymeleaf side I only get the "cannot resolve" error.
Part of the .html in showSurvey.html
<div class="col-sm-12">
<table class="table table-hover">
<tr th:each="survey: ${survey}">
<td th:text="${survey">1</td>
<!-- <td>Title ...</td>-->
</tr>
</table>
</div>
Packaging with mvn package and then running the jar starts up the application, and it works, but crashes when trying to resolve "survey" on showSurvey.html so SurveyDAO.GetSurveyById(id); actually comes back properly.
So how should I go about passing the list and then showing proper values out of it? It has two int and String for all that matters.
You are missing a right "}" - I have just tested this, and it works fine:
<table>
<tr th:each="survey : ${survey}">
<td th:text="${survey}">1</td>
</tr>
</table>
Just a typo.
Like I said in the comments your code doesn't look right.
Fix your code like so:
<div class="col-sm-12">
<table class="table table-hover">
<tr th:each="survey: ${survey}">
<td th:text="${survey.id}">1</td> // id is a property of the Question class
</tr>
</table>
</div>
im new to thymeleaf and Spring - im doing some small project to my school class and i have a problem with html link. I had troubles with it for 2hours now and im editing my code in 10 diffrent ways so please answer how to do it properly. Below its my html template (i tried using here th:href with two diffrent ways:
<table>
<th>Name</th>
<th>Date</th>
<th>See</th>
<th>Edit</th>
<a th:each=" i : ${workouts}" varStatus="status">
<tr>
<td><a th:text="${i.getName()}"/></td>
<td><a th:text="${i.getDate()}"/></td>
<td>See</td>
<td>See</td> </tr>
</a>
</table>
And here its my Controller:
#Controller
public class SeeWorkoutController {
#RequestMapping(value = "/seeWorkoutPage/{id}", method=RequestMethod.GET, params="id")
public String test2(#PathVariable("id")Long id, Model model) {
System.out.println(id);
return "workoutsPage";
}
but it's now working properly. Please help.
Check the documentation for Thymeleaf Link URLs. In particular this example:
<!-- Will produce '/gtvg/order/3/details' (plus rewriting) -->
view
I think you're almost there with your second example, but it should read
th:href="#{/seeWorkoutPage/{workoutId}(workoutId=${i.getId()})}"
Note how you specify the {workoutId} parameter, then give it's value between the brackets afterwards.
Try:
<span th:each="workout: ${workouts}">
<td><a th:text="${workout.name}"/></td>
<td><a th:text="${#dates.format(workout.date,'MMM d, yyyy')}</td>
<!-- add other stuff when you have the above working -->
</span>
You don't need the get() syntax (and it can throw an exception in some containers). Also, it looks like you're nesting anchor (<a>) tags too.
I am working on servlet and jsp project. I am passing an object from servlet to JSP. And currently I am iterating that object and showing them in a table -
Below is my code in jsp -
<TABLE id="tableSMS" BORDER="1" CELLPADDING="3" CELLSPACING="1" style="text-align: center;">
<TR style="color:#ffffff;background-color:#787878;">
<TH>Hash Name</TH>
<TH>Database Name</TH>
<TH>Version</TH>
</TR>
<c:forEach var="i" begin="0" end="${reportCount.getHash().size() - 1}">
<TR>
<TD>
${reportCount.getHash().get(i)}
</TD>
<TD>
${reportCount.getDatabaseName().get(i)}
</TD>
<TD>
${reportCount.getVersion().get(i)}
</TD>
</TR>
</c:forEach>
And above code is working fine and I am able to show the data properly. Now what I need to do is -
${reportCount.getDatabaseName().get(i)} will return database name as oracle or mysql only. Now I need to calculate what is the percentage of oracle database. I will get the total number of records from ${reportCount.getHash().size(). So if total number of records is 10 and oracle database is present 5 times, then the percentage should be 50%.
Now I am not sure how would I calculate the above percentage using that object? And after calculating that percentage, I need to show the result in a new table which is shown below -
<table>
<tr>
<th style="background-color: #E8E8E6;"><b>Oracle Database</b></th>
</tr>
<tr>
<!-- I would like to show the percentage in this row -->
<td>%</td>
</tr>
</table>
I am thinking I should iterate the reportCount object again in the above new table and extract the percentage here but not sure how would I do that? Can anyone provide an example?
UPDATE:-
Here is my bean code -
public class Response {
private List<String> hash = new LinkedList<String>();
private List<String> databaseName = new LinkedList<String>();
private List<String> version = new LinkedList<String>();
// getters and setters here
}
There are three things as following:
Add the functions taglib:
<%# taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
Add reportsCounts variable to requestScope instead of session if not required on any other page & use as following:
<c:set var="oracleDBCount" value="0" scope="page" />
<c:forEach var="reportCount"
items="${requestScope.reportCounts.databaseName}" varStatus="loop">
<TR>
<TD>${requestScope.reportCounts.hash[loop.index]}</TD>
<TD>${reportCount}
<c:if test="${reportCount == 'ORACLE'}">
<c:set var="oracleDBCount" value="${oracleDBCount + 1}" scope="page"/>
</c:if>
</TD>
<TD>${requestScope.reportCounts.version[loop.index]}</TD>
</TR>
</c:forEach>
Now display percentage as:
${(oracleDBCount / fn:length(requestScope.reportCounts))*100}%
Based on my experience, doing number-crunching on a JSP page can make it unreadable very quickly. Also you may encounter additional requirements in the future such as:
Text matching (Are you guaranteed that the value is always "oracle"? Or can it become "ORACLE" or "Oracle"?
What if there are zero reports? Then you will need an if-condition to prevent division by zero.
If your client says "We have more report servers like MS, Postgres...can you show the percentage of those?"
Is it possible to do the computation inside the servlet while you are making the reportCount object?
Then you can pass the value inside a session attribute
request.getSession(true).setAttribute("oracleReports", "50%")
and then in the JSP output something like
<c:out value="${sessionScope.oracleReports}"/>
Use JavaScript for doing the operation, Here is the code
Read the comments to understand the code.
Add an id to the so that i can read the inner content using
javascript. Appended id with the index so that each raw gets different
id's
<c:forEach var="i" begin="0" end="${reportCount.getHash().size() - 1}">
<TD id="databaseName<c:out value='${i}' />">
${reportCount.getDatabaseName().get(i)}
</TD>
Add Id to the so that i can set values to the raw using
JavaScript
<tr>
<td id="oraclePercentage">%</td>
<td id="mySQLPercentage">%</td>
</tr>
call the javascript function to set the values to the raw, as we don't
have any button to trigger we open a raw and add the JavaScript call
from the JSP so that the script is triggered every time the page loads
the raw.
<TR><TD><Script>setPercentage('${reportCount.getHash().size() - 1}');</script><TD><TR>
what to do is defined here
<Script>
function setPercentage(var index){
for(var i=0; i<index;i++){
var documentType=document.getElementById("databaseName"+i).innerHTML;
var oracleCount=0;
var mySQLCount=0;
if(vardocumentType=='Oracle')
oracleCount+=(Number)1;
else if(vardocumentType=='MySQL')
mySQLCount+=(Number)1;
document.getElementById("oraclePercentage").innerHTML=(oracleCount/index)*100;
document.getElementById("mySQLPercentage").innerHTML=(mySQLCount/index)*100;
}
</script>
I don't know if the titles says what i'm looking for.
Basically i got a table that shows current logged-in sessions. I'd like to be able to change their status and log them out. This is the JSTL code:
<div id="users_table_div">
<table id="box-table" style="width: 690px">
<thead>
<tr>
<th>IP</th>
<th>USER NAME</th>
<th>LAST ACTIVITY</th>
<th>LOGIN STATUS</th>
</tr>
</thead>
<tbody>
<c:forEach var="userDetail" items="${userSessionData}">
<tr>
<td><c:out value="${userDetail.ip}"/></td>
<td><c:out value="${userDetail.username}"/></td>
<td><c:out value="${userDetail.lastActivity}"/></td>
<td><img src="images/sign-out.png" /></td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
Currently i've set a javascript function in the sessionId, but there might be another way to log out a selected user by its sessionId using spring security MVC.
So from the controller, i get different session data from all the users.
IP, Username, LastActivity and their SessionId (to log them out)
Is there a nice way to manage this?
This has been already resolved.
Just in case other is under the same issue:
I just made another #RequestMapping in the Controller with the sessionId passed from the view as the following:
<a href="<c:url value='/endsession?sessionId=${userDetail.sessionId}' />">
Then in the Controller the code was very simple:
#RequestMapping(value="/endsession", method = RequestMethod.GET)
public String endSession(String sessionId, Principal principal) {
logger.info("Removing sessionID = " + sessionId);
sessionRegistry.getSessionInformation(sessionId).expireNow();
return "activeusers";
}
And taraam :D
Hope it helps to others as well.