Friday, July 10, 2020

JSON Web Token (JWT) Use Case: Secure Information Exchange Between Two Parties

Today our topic of discussion is related to JSON Web Token (JWT). There are mainly two use cases where one can use JWT:
  1. For authentication purposes 
  2. For secure information exchange between two parties 
Out of these two use cases, we would be discussing the second use case today. Although it's not the most usable or most common scenario for using JWT, it offer's a great way for interaction between 3rd party applications/clients and the target application where the target application doesn't want to persist any user-related data corresponding to 3rd party clients in their end. If you are thinking, how come then target application would identify or authenticate the 3rd party clients then you are on the right track, we would be touching this in a while. Please stay with me for a little longer. Apart from this, We would also provide some practical industry standard use-cases of JWT and explain a generic JWT flow using sequence diagram.

1. The Job


Let's discuss the problem statement first.
A third-party application would like to interact with the target application either for
- accessing some protected resource of the target application
- executing some business logic in the target application
For performing these operations, the third-party application must be authenticated & authorized first. Now we will see the traditional way & JWT way as the solution of this problem statement.

2. The Traditional Way 


In the traditional client-server model, the client requests an access-restricted resource (protected resource) on the server by authenticating with the server using the resource owner's credentials.  In order to provide third-party applications access to restricted resources, the resource owner shares its credentials with the third party i.e. the target application's owner create a user in their system for the third-party application. But this creates several problems like:
  • Session Management
  • Performance: Need to make multiple databases calls for authentication every time we log out or our session expires. Also, increase network round-trip time. 
  • Compromise of any third-party application results in compromise of the end user's password and all of the data protected by that password.
The burning question is "How can we avoid these problems then"?  The answer is by using a token-based authentication system. JWT allows the server to verify the information contained in the JWT without necessarily storing state on the server.

3. The JWT Way 


We would be giving a glimpse of use case 1 i.e. using JWT for improving the authentication process and then move on to use case 2 i.e. using JWT for transmitting information securely between the service provider and the client so that we all have a clear understanding about the use cases of JWT.

3.1 For authentication purposes 

After the initial successful authentication (either by using username and password or by other means if using OAuth), the authorization server would generate the JWT and pass it to the client. Now client would use this token in every request while accessing protected resources until the token expires.
It means one will need to authenticate only in two cases:
  • first time to get the token and
  • when token expires
The service provider only cares about the token and it's validity. If the received token is valid then access is granted to the client.

3.2 For secure information exchange between two parties 

Now when we say secure exchange information could happen between two parties then it's important to understand the reason behind it. It raises a very crucial question.
Q1: Is it really a secure and trusted way for information exchange?
The answer would be Yes. One could use JWT for secure information exchange because one could verify the validity of JWT
  • whether the JWT is well-formed or not 
  • whether the signature is matched or not 
  • whether the standard claims in the JWT are as per the agreement or not
Accessibility of secured resources or information exchange between two parties is allowed only if it has passed the validity checks of JWT. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.

4. Real World Use Case 


Let's talk about the real world use case of JWT.

Usecase 1: There is requirement that some of the RESTful services that are being developed by the enterprise would be used by 3rd parties, that means they have to be available outside of the enterprise network. Now the enterprise need to protect such services against unauthorized access and JWT is a good candidate for this scenario.

Usecase 2: Securing the APIs to makes system less vulnerable to any unauthorized access of our data and any kind of attack on the system.

Usecase 3: A partner 3rd party enterprise would like to securely exchange information like It would like to create accounts for their user, would like to fire fulfillment service or would like to access any protected resources. In this case, 3rd party enterprise could be granted JWT by the target enterprise by using Client Credential grant type workflow. Now the 3rd party app could send the JWT, typically in the Authorization header using the Bearer schema and then make a required service calls.

5. JWT Flow: Sequence Diagram


To make everything clear, here the sequence diagram for the JWT workflow which is self explanatory. Here,
- Client is the 3rd part App,
- Application is the Target Application
- Admin is the internal app of the Target Application


6. Conclusion


JWT provides the stateless authentication mechanism as the user state is never saved in the server memory. The server's protected routes will check for a valid JWT in the Authorization header, and if there is, the user will be allowed as JWTs are self-contained, all the necessary information is there, reducing the need of going back and forward to the database.Also one could easily fully rely on data APIs that are stateless for information exchange.

Hoping that this articles would help you understand different usecases where JWT could be used and in what kind of usecases enterprises are using JWT. Happy Learning!!:-)

Wednesday, October 16, 2019

Axios In Action

We all know that Axios is a promise-based HTTP client for the browser and node.js. Although I have used Axios extensively while making GET, POST request calls and multiple concurrent requests call from the front end, I have never used Axios in conjunction with node.js. Today we would be discussing how to use Axios for making any kind of calls from the front end and some other Axios related important stuff.

1. Introduction


Similar to traditional AJAX call, one could easily make Axios calls without much hustle from the front end. One needs to include below JS library in order to work it properly:
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
Today we would be touching on below items:
  • How to make Axios GET / POST calls?
  • How to make multiple concurrent requests calls?
  • How to handle the dependent request calls using Axios?
  • Understanding the response to a request
  • How to handle errors that occurred while making Axios calls?

2. GET Request


Performing a GET request:
// Make a request for a user with a given ID
axios.get('/getAssignment?id=12345')
  .then(function (response) { // handle success
    console.log(response);
  })
  .catch(function (error) {  // handle error
    console.log(error);
  })
  .finally(function () {  // always executed
   ...
  });
Optionally the above request could also be done as
axios.get('/getAssignment', {
    params: {
      id: 12345
    }
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  })
  .then(function () {
    // always executed
  });  

3. POST Request


Performing a POST request:
axios.post('/saveAssignment', {
   'assignmentData' : assignmentData // an array containing: label,type,availableon,dueon etc
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
Obviously, @RequestMapping i.e. /saveAssignment would call one of our Controller's methods. Worried about how this data would be available in Controller layers? Don't worry? We got you covered here. Just look at the below code snippet:
@RequestMapping(value = "/saveAssignment", headers = "Content-Type=application/json", method = RequestMethod.POST)
@PreAuthorize("isAuthenticated()")
public ResponseEntity<String> saveAssignment(Model model, @RequestBody Map<String, String[]> assignmentDataMap) {

 String[] assignmentData = assignmentDataMap.get("assignmentData");
 ...
} 

4. Multiple concurrent requests


Performing multiple concurrent requests:
function findAssignmentById(assignmentId) {
 return axios.get("/getAssignment?id=" + assignmentId);
}

function findAllAssignmentUser(assignmentId) {
 return axios.get("/getAssignmentUsers?assignmentid=" + assignmentId);
}

axios.all([findAssignmentById(), findAllAssignmentUser()])
  .then(axios.spread(function (assignmentData, userData) {
    // Both requests are now complete
 var assignment = assignmentData.data;
 var users = userData.data;
  }));
Tips: Never use this, when the requests are dependent anyhow.

5. Multiple requests but dependent somehow


It may happen that depending upon the return value from one Axios call, one may require to make another Axios call conditionally. In those cases, one could follow the below approach.
var assignmentId1 = 1234;
axios.get("/getAssignmentUser?id="+assignmentId1).then(function(response) {    
 var assignmentUserFlag = response.data.size() > 0;
 if(assignmentUserFlag){
  axios.get("/getAssignment?id="+assignmentId1).then(function(response) { 
  
  }).catch(function (error) {
   ...
  });
 } else {
   ....
 }
}).catch(function (error) {
 ...
});

6. Understanding the response to a request 


The response to a request contains the following information:
{
  // `data` is the response that was provided by the server
  data: {},
 
  // `status` is the HTTP status code from the server response
  status: 200,
 
  // `statusText` is the HTTP status message from the server response
  statusText: 'OK',
 
  // `headers` the headers that the server responded with
  // All header names are lower cased
  headers: {},
 
  // `config` is the config that was provided to `axios` for the request
  config: {},
 
  // `request` is the request that generated this response
  // It is the last ClientRequest instance in node.js (in redirects)
  // and an XMLHttpRequest instance the browser
  request: {}
}
When using then, one will receive the response as follows:
axios.get('/getAssignment?id=12345')
  .then(function (response) {
    console.log(response.data);
    console.log(response.status);
    console.log(response.statusText);
    console.log(response.headers);
    console.log(response.config);
 });

7. Handling Errors


You must be thinking about why there is a separate section for this. From the start of this article, we have maintained that inside catch block i.e. ".catch(function (error) { ..}" we would handle the error, End of the Story right? But wait there is still more left to it. 
axios.get('/getAssignment?id=12345')
  .catch(function (error) {
    if (error.response) {
      // The request was made and the server responded with a status code
      // that falls out of the range of 2xx
      console.log(error.response.data);
      console.log(error.response.status);
      console.log(error.response.headers);
    } else if (error.request) {
      // The request was made but no response was received
      // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
      // http.ClientRequest in node.js
      console.log(error.request);
    } else {
      // Something happened in setting up the request that triggered an Error
      console.log('Error', error.message);
    }
    console.log(error.config);
  });
Point to ponder: Before starting I would like to highlight that the above code snippet is taken from the official website. It's regarding "else if (error.request) {..}" block. It states that "The request was made but no response was received" obviously from the server. Now one open question to you - In Microservice Architecture, suppose service A is calling service B which is down (we have manually stopped it) then no doubt it would enter in catch block but where would the control go, if, else if or last else block? 
According to me, it should go inside else if block as the server is down(service B) but we have made the request properly. But to my surprise, it entered inside if block. But how can that happen when the server was down? How the server can respond? Just for information, in JS, we are getting Internal Server Error(500 status code) whereas in STS console, 404. If you have the answer to the above question or any logical explanation then please share in the comment section.

8. Conclusion


I hope that now you know how to use Axios. It would surely help you while doing development work using Axios. Happy Learning !! ☺

Friday, October 11, 2019

Download data in CSV format using JavaScript

Today we would be discussing Export to CSV functionality using JavaScript. You might be wondering that there are many 3rd party libraries to generate the CSV file using JavaScript/jQuery then why am I reinventing the wheel? Why don't use the already existing solution? Bear with me, I would not only explain why but also describe how to download data in CSV format using JavaScript?

1. Introduction 


It's the very common use-case that we already have some data on the browser (HTML pages) and we would like to provide the option to users to download these data in CSV format using jQuery / JavaScript. That's why there are many 3rd party libraries in the market to generate the CSV file using jQuery but from the HTML table as the source. Just lookout for a solution that facilitates us to generate the CSV file using jQuery / JavaScript if the current HTML structure representing the data on the page is not in the tabular format. This is where our solution comes in the picture which is very simple and handy. One might argue that it is possible to create a temporary table from the complicated HTML structure on the fly in order to use the 3rd party libraries. But again it depends upon the complexity and we won't be discussing that here. 

2. Browser Compatability 


Tested this utility in below version of the browser and it's working as expected:
  • Google Chrome Version 77.0.3865.90 (64-bit)
  • Firefox Quantum Version 69.0(64-bit)
  • IE 11 Version 11.0.9600.19467

3. Why & Implementation


Now again we would reiterate one which situation and why one should use this Export to CSV utility developed using JavaScript and then directly jump on the implementation.

3.1 Why? 

  • Preferred to use if the current HTML structure is not in tabular format and very complicated  but one could use it even if HTML structure is in tabular format 
  • Handling boundary usecases: Currently if data values have comma then also it properly handles it. 
  • Simple to use
  • Don't have to load any 3rd part library 

3.2 Implementation 


One needs to just create the multi-dimensional data array from the HTML page containing the data using jQuery / JavaScript and then we are good to go. Here for the demo purpose, we have created the multi-dimensional data array manually inside JavaScript. 
<html>
<head>
<title>Download CSV</title>
<script>
// prepare the data from the HTML page using jQuery/JavaScript.
// Demo purpose, we are manually preparing the data
var data = [
   ['Anshul', 'programmer','Gamer'],
   ['Rahul', 'Computer Science Engineer','Traveller'],
   ['Rajnikant', 'Hero','Sky Ga,zing']
];


function downloadCSV() {
    var csv = 'Name,Job,Passion\n';
 
 data.forEach(function(row) {
        var row1 = []; 
        row.forEach(function(item) { // handling commna in data values
        if(item.indexOf(',') == -1) { // not having comma 
    row1.push(item);
  } else {
    item = "\"" + item + "\"";
    row1.push(item);
  }
     });
 console.log("row1:" + row1)
 csv += row1.join(',');
 csv += "\n";
     });
 
 if (navigator.msSaveBlob) { //IE
  var csvURL =  null;
  var csvData = new Blob([csv], {type: 'text/csv;charset=utf-8;'});
                csvURL = navigator.msSaveBlob(csvData, 'download-reports.csv');
 } else { // Firefox,Chrome
         console.log(csv);
  //var hiddenElement = document.createElement('a');
                var hiddenElement = document.getElementById('dummyDownload'); //For Firefox 
  hiddenElement.href = 'data:text/csv;charset=utf-8,' + encodeURI(csv);
  hiddenElement.target = '_blank';
  hiddenElement.download = 'download-reports.csv';
  hiddenElement.click();
    }  
}
</script>
</head>
<body>
<a id=dummyDownload hidden></a> 
<button onclick="downloadCSV()">Download CSV</button> 
</body>
</html>

4. Downloaded CSV File


For reference, showing the downloaded CSV file in both the notepad++ & by Open Office(Separated by option: Comma). See the last row in which, intentionally I have put a comma in one of the data values but our utility properly handles it. 


5. Conclusion


Now you know how to integrate Download CSV functionality in your application which is pretty simple.  Let me know in the comments if it's working for you or not. Happy Learning!! ☺

How to add jQuery datetimepicker in the page?

Today we would be looking at the jQuery datetimepicker implementation. It improves the User Experience. One needs to make a few things in mind for datetimepicker integration like
  • Adding the required HTML code snippet in the page for selecting the date & time i.e. adding input element of type text  
  • Respective JS & CSS libraries(datetimepicker and jQuery related) should be included in the page
  • Activating the datetimepicker using jQuery or JavaScript 
After configuring the datetimepicker, it would look like below:


Implementation:


<html>
<head>
<title>Datetimepicker Demo</title>
<!–– Respective JS & CSS libraries(datetimepicker and jQuery related) should be included in the page ––>
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery-datetimepicker/2.5.20/jquery.datetimepicker.min.css" rel="stylesheet"/> 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery-datetimepicker/2.5.20/jquery.datetimepicker.full.min.js"></script>
<script>
$(document).ready(function () {
   // Activating the datetimepicker using jQuery or JavaScript 
   $('#datetimepicker1').datetimepicker(); //default    
   $('#datetimepicker2').datetimepicker({ //customized
      format:'d/m/Y H:i',
      minDate:0,
      formatTime:"h:i a",
      step:10,
      // if one would like to take user selected input from datetimepicker and atomatically round off to nearest integral of 10 minutes
      onChangeDateTime:function(dp,$input){
      //27/10/2019 12:01 -> dateTime[0] = date, dateTime[1] = time
 var dateTime = $input.val().split(" "); 
 var time = dateTime[1].split(":");
 var hour = time[0];
 var minutes = time[1];
 var datetimestring;
    
 if(minutes > 0 && minutes < 10) {
         datetimestring = dateTime[0] + ' ' + hour + ':' + 10;
         $input.val(datetimestring);
  }
    ...
  } // end of onChangeDateTime function
   });
   
});
</script>
</head>
<body>
<!–– Adding the required HTML code snippet in the page for selecting the date & time i.e. adding input element of type text  ––>
Default Datetimepicker:
<input type="text" id="datetimepicker1" placeholder="select date time">
Customized Datetimepicker:
<input type="text" id="datetimepicker2" placeholder="select date time">
</body>
</html>

Hoping that it would help you. Happy Learning!! ☺

Thursday, October 10, 2019

th:block tag in Thymeleaf

While designing and developing a Thymeleaf template, have you ever faced a problem of adding unnecessary HTML tag just for holding any conditional statements or an iterative statement which you won't prefer to use if you design the same page statically? Let me give you an example: using <div> blocks inside <table> for iteration purpose only, it might work but it would add an unnecessary empty HTML tag. Don't worry Thymeleaf has a solution for this type of use case. One could use Thymeleaf's provided Synthetic th:block tag. Today we would be discussing th:block tag with some example.

1. th:block tag


  • It's an element processor included in the Standard Dialects. Don't confuse this with an attribute as it is not an attribute. 
  • It is a mere attribute container that allows template developers to specify whichever attributes they want. Thymeleaf will execute these attributes and then simply make the block disappear without a trace.

2. th:block tag Implementation Examples


There are many instances where one could use th:block tag while designing the Thymeleaf templates. It would make our Thymeleaf templates more readable and helps in avoiding unnecessary empty HTML tags which are added after processing of Thymeleaf's attributes if we don't use th: block. I would be sharing the use cases where I have used it:
  • when creating iterated tables that require more than one <tr> for each element
    Disclaimer: This example reference is taken from here. I haven't used it.
    <table>
      <th:block th:each="user : ${users}">
        <tr>
            <td th:text="${user.login}"></td>
            <td th:text="${user.name}"></td>
        </tr>
        <tr>
            <td colspan="2" th:text="${user.address}"></td>
        </tr>
      </th:block>
    </table>
    
  • when creating the ordered / unordered list of items
    <ul>
       <th:block th:each="node : ${bookModel.getOrderedSubTopics()}">
         <li th:if="${node eq 'activity'}">
     <input th:id="${node.nodeId}" type="checkbox" th:value="${node.nodeId}">
      <span th:utext="${node.label}">Topic Name</span>    
          </li>
          <li th:if="${node eq 'reading'}">
       <span th:utext="${node.label}">Topic Name</span>    
          </li>
       </th:block>
    </ul>
    
  • when creating a select box when dropdown items are selected or unselected conditionally
     <select>
       <option value="0"></option>
       <th:block th:each="tag : ${tags}">
         <option th:text="${tag.label}" th:if="${itemTags.contains(tag)}" th:value="${tag.tagTypeLabel}" selected>name</option>
         <option th:text="${tag.label}" th:if="not ${itemTags.contains(tag)}" th:value="${tag.tagTypeLabel}">name</option>
        </th:block>
    </select>

3. Conclusion


th:block tag is a very useful tool that could be used while designing and development of Thymeleaf templates. Template developers don't have to unnecessarily complicate their template/page by adding an HTML tag for holding Thymeleaf's attributes if they don't want that HTML tag after execution in their HTML structure.  Hoping that it would help you. Happy Learning!! ☺

How to access Spring beans in Thymeleaf registered at the Spring Application Context?

Thymeleaf allows accessing beans registered at the Spring Application Context in the standard way defined by Spring EL i.e. by using the @beanName syntax, for example:
<div th:text="${@urService.getSomething()}">...</div> 
This could be useful if one wants to expose some utility methods from Java end to Thymeleaf templates.

Disclaimer:
Till now I haven't used this feature in any of my projects but when I came to know about this feature. I thought why not test it whether it really works or not.
For testing purposes, I have added a @Component annotation (org.springframework.stereotype.Component;) in one of my Spring Boot Utility Class and added a test method i.e. getMessage() which simply returns a String. The idea is to make this bean available in the Spring Application Context. After that, I have tried accessing it using the above syntax and it worked.
For reference,
## test Method
public String getMessage() {
   return "pura game hai";
}
## accessing it in Thymeleaf template 
<div th:text="${@utility.getMessage()}">...</div> 
This is fairly easy and might be useful in some scenarios. Happy Learning!! ☺

Wednesday, October 9, 2019

Web context objects: #httpServletRequest & #httpSession in Thymeleaf

Recently while working on a web application developed using Spring Boot & Thymeleaf, I came to know that Thymeleaf provides direct access to #httpServletRequest & #httpSession objects inside a web environment. These objects are also known as Web context objects. Today we would be discussing these objects and their usages with examples.
  • #httpServletRequest: It provides direct access to the javax.servlet.http.HttpServletRequest object associated with the current request.
    ## Usages
    ${#httpServletRequest.getParameter('foo')}
    ${#httpServletRequest.getAttribute('foo')}
    ${#httpServletRequest.getContextPath()}
    ${#httpServletRequest.getRequestName()}
    
    ## use case while using Script Inlining Feature of Thymeleaf
    <script th:inline="javascript" type="text/javascript">
    /*<![CDATA[*/
        ...
        var assignmentId = /*[[${#httpServletRequest.getParameter('assignmentid')}]]*/ 0;
    
    /*]]>*/
    </script>
    
    ## another example 
    <a th:if="${#httpServletRequest.getParameter('assignmentid') != null} and ${#httpServletRequest.requestURI eq '/studentassignment'}" 
       th:href="@{${#httpServletRequest.requestURI}(isbn=${bookModel.isbn},assignmentid=${#httpServletRequest.getParameter('assignmentid')})}"   
       th:text="${'Test Link'}">Test Link</a>
    
  • #httpSession: It provides direct access to the javax.servlet.http.HttpSession object associated with the current request.
    ## Usages
    ${#httpSession.getAttribute('foo')}
    ${#httpSession.id}
    ${#httpSession.lastAccessedTime}
Hoping that it might be useful for you guys. Happy Learning!! ☺

Different Expression Utility Objects in Thymeleaf With Examples

I bet every one of you must have performed one of the below tasks while development irrespective of the programming language you use for development:
  • Created a Utility class or 
  • Added utility methods in the existing Utility class or 
  • Used already written, existing Utility class methods for performing any common job 
You all would agree that knowing the available Utility classes in any language makes the developer's life easy. Therefore today we would be looking at various utility objects provided by Thymeleaf that help developers in performing common tasks in Thymeleaf expression like performing date formatting, performing numeric operations, performing String-related operation, etc. These utility objects are also known as Expression Utility Objects.

Expression Utility Objects


Below is the list of utility objects:
  • #dates: utility methods for java.util.Date objects: formatting, component extraction, etc.
    ## See javadoc API for class org.thymeleaf.expression.Dates
    <span th:if="${assignment.availableOn > #dates.createNow()}">
    <span th:text="${#dates.format(patient.currentDate, 'dd-MMM-yyyy')}">10-09-2019</span>
    
  • #calendars: analogous to #dates, but for java.util.Calendar objects.
  • #numbers: utility methods for formatting numeric objects.
    ## See javadoc API for class org.thymeleaf.expression.Numbers
    ## format decimal number by setting minimum integer digits and exact decimal digits
    <p th:with="num=${1.23345}" th:text="${#numbers.formatDecimal(num,2,3)}">01.233</p>
    <div th:text="${#numbers.formatDecimal(totalScore*0.1*100/totalMaxScore,0,0)}+'%'">
     80%</div>
    
  • #strings: utility methods for String objects: contains, startsWith, prepending/appending, etc.
    Example:
    ## See javadoc API for class org.thymeleaf.expression.Strings
    <span th:with="firstName=${#strings.substring(userModel.username,0,#strings.indexOf(userModel.username,' '))},
            lastName=${#strings.substring(userModel.username,#strings.indexOf(userModel.username,' ') + 1,#strings.length(userModel.username))},
            username=${ lastName + ', ' + firstName}" 
          th:data-username="${#strings.contains(userModel.username,' ') ? username : userModel.username}" 
          th:text="${username}"></span> 
    
  • #objects: utility methods for objects in general.
  • #bools: utility methods for boolean evaluation.
  • #arrays: utility methods for arrays.
  • #lists: utility methods for lists.
    ## See javadoc API for class org.thymeleaf.expression.Lists
    ## topicToFirstReadingTypeSubTopicMap is model attribute
    <select th:name="assetTopics" th:multiple="multiple">
     <option th:each="row : ${topicToFirstReadingTypeSubTopicMap}" 
             th:text="${row.key.label}" th:value="${row.value.nodeId}"  
             th:selected="${#lists.contains(objIdListForAsset, row.value.nodeId)}">Topic
     </option>
    </select> 
    ## assets is model attribute
    <div th:if="${not #lists.isEmpty(assets)}">...</div>
    
  • #sets: utility methods for sets.
  • #maps: utility methods for maps.
  • #aggregates: utility methods for creating aggregates on arrays or collections.
    ## See javadoc API for class org.thymeleaf.expression.Aggregates
    ## initially created a list of elements statically for demo and then used utilities
    <p th:with="array=${ {1,2,3} }" th:text="${#aggregates.sum(array)}">6</p>
    <p th:with="array=${ {1,2,3} }" th:text="${#aggregates.avg(array)}">2</p>
    
  • #messages: utility methods for obtaining externalized messages inside variables expressions, in the same way as they would be obtained using #{…} syntax.
  • #ids: utility methods for dealing with id attributes that might be repeated (for example, as a result of an iteration).
  • #execInfo: information about the template being processed.
  • #uris: methods for escaping parts of URLs/URIs.
  • #conversions: methods for executing the configured conversion service (if any).
Hoping that, these expression utility objects and given examples would help you while development. Happy Learning!! ☺