How to not redirect page when authentication fail - JSP & Spring MVC - spring

I have a JSP form as below,
<form method="post" id="loginForm" action="<c:url value='/login'/>">
<fieldset>
<label class="block clearfix">
<span class="block">
<input type="text" class="form-control"
placeholder='Username'
name="username"
required="required"
maxlength="50"/>
<i class="icon-user"></i>
</span>
</label>
<label class="block clearfix">
<span class="block">
<input type="password" class="form-control"
placeholder='Password'
required="required"
name="password" maxlength="50"/>
</span>
</label>
<div>
<c:if test="${userNameRequired == true}">
<br/>
<div class="alert alert-block alert-danger">
<button class="close" data-dismiss="alert" type="button">
<i class="icon-remove"></i>
</button>
<strong>
<i class="icon-remove"></i>
Error!
</strong>
Please enter your Email.
</div>
<c:remove var="userNameRequired" scope="session"/>
</c:if>
<c:if test="${passwordRequired == true}">
<br/>
<div class="alert alert-block alert-danger">
<button class="close" data-dismiss="alert" type="button">
<i class="icon-remove"></i>
</button>
<strong>
<i class="icon-remove"></i>
Error!
</strong>
Please enter your Password.
</div>
<c:remove var="passwordRequired" scope="session"/>
</c:if>
<c:if test="${invalidCredentials == true}">
<br/>
<div class="alert alert-block alert-danger">
<button class="close" data-dismiss="alert" type="button">
<i class="icon-remove"></i>
</button>
<strong>
<i class="icon-remove"></i>
Error!
</strong>
Invalid Credentials.
</div>
<c:remove var="invalidCredentials" scope="session"/>
</c:if>
<c:if test="${userNotExists == true}">
<br/>
<div class="alert alert-block alert-danger">
<button class="close" data-dismiss="alert" type="button">
<i class="icon-remove"></i>
</button>
<strong>
<i class="icon-remove"></i>
Error!
</strong>
Invalid Credentials.
</div>
<c:remove var="userNotExists" scope="session"/>
</c:if>
</div>
<div class="clearfix">
<button type="submit"
class="btn btn-block btn-primary"
value='Login'>
</button>
</div>
</fieldset>
</form>
When authentication fails, it should show a message as invalid credentials or respective message on the same page, but it is redirecting to a new page as below,
There are no redirects added in my authenticate method which is triggered when login is clicked. Below is the code,
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) {
String userName = obtainUsername(request);
String password = obtainPassword(request);
if (userName == null || userName.isEmpty()) {
request.getSession().setAttribute("userNameRequired", true);
throw new BadCredentialsException("Email field should not be empty.");
}
if (password == null || password.isEmpty()) {
request.getSession().setAttribute("passwordRequired", true);
throw new BadCredentialsException("Password field should not be empty.");
}
UsernamePasswordAuth authRequest = new UsernamePasswordAuth (
userName, password);
setDetails(request, authRequest);
try{
return this.getAuthenticationManager().authenticate(authRequest);
}catch(BadCredentialsException ex){
request.getSession().setAttribute("invalidCredentials", true);
throw new ex;
}
}
I'm new to JSP's and Spring MVC so hard time debugging & understanding. Any help is much appreciated.
Thank you.

It looks like you created a subclass of AbstractAuthenticationProcessingFilter which has a method setAuthenticationFailureHandler to set field failureHandler value. so you should create a implementation of AuthenticationFailureHandler and invoke method setAuthenticationFailureHandler
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
//write the authentication failure message to response
response.getWriter().write(exception.getMessage());
}
}
authFilter.setAuthenticationFailureHandler(new MyAuthenticationFailureHandler());
authFilter is subclass of AbstractAuthenticationProcessingFilter

Let me see if i understand.
When you click the submit button, it redirects always even if the credentials are incorrect?
It is gonna redirect you everytime you click the button because it is submitting you to the "action="<c:url value='/login'/>" attribute you wrote in "<form>" tag.
Buttons inside a form always sends you to the action location.
To avoid this, i recommend you to use ajax to request and listen the response without redirecting or reloading the page.
Or you can redirect back to the form explicitly in your validation side when the credentials are wrong.
I hope i were helpful.

Related

pass object from HTML template back to the controller

I have the following HTML block. I want to pass the object "jobDTO" back to the contoller "/deleteJob" method. Whatever I do I am getting null object.
<th:block th:if="${jobDTO != null}" th:each="jobDTO: ${allJobDTOs.get(jobGroup)}">
<div id="accordion2" style="margin-bottom: 3px;">
<div class="card" id="headingOne">
<div class="card-header" style="padding: 0">
<h5 class="mb-0">
<button class="btn btn-link" data-toggle="collapse" th:attr="data-target='#accordion2_'+${jobDTO.identity.name}"
aria-expanded="true" aria-controls="collapseChild" >
<p class="font-weight-bold custom-p identity-black" > Job Identity </p>
<p class="custom-p" style="padding-left: 52px;" th:text="${jobDTO.identity.group} +' , ' + ${jobDTO.identity.name}"></p>
</button>
</h5>
</div>
<div th:id="'accordion2_'+${jobDTO.identity.name}" class="collapse" aria-labelledby="headingOne" data-parent="#accordion2">
<div class="card-body">
<dl class="row">
<dt class="col-lg-3">Trigger List</dt>
<dd class="col-sm-9">
<th:block th:each="trigger: ${jobDTO.triggers}">
<p><b>nextFireTime</b> <span th:text="${trigger.nextFireTime}"> </span></p>
<hr>
</th:block>
</dd>
</dl>
<!-- important part.. how to pass the jobDTO object back to the controller -->
<form id="form2" action="#" th:action="#{/deleteJob}" th:object="${jobDTO}" th:method="post">
<input type="text" th:value="*{identity.name}" th:field="*{identity.name}" hidden/>
<button type="submit" value="Submit" class="btn btn-danger btn-sm" >Delete Job</button>
</form>
</div>
</div>
</div>
</div>
</th:block>
my controller relevant parts are:
#GetMapping(value = "/deleteJob")
public String deleteJobPage(Model model) {
model.addAttribute("jobDTO", new ScheduleJobDTO());
//Returns the Home page with the prepared model attributes
return "Home";
}
// =================
#PostMapping("/deleteJob")
public String deleteJob(#ModelAttribute final ScheduleJobDTO jobDTOReturn, BindingResult bindingResult, Model model) {
// I want to receive the jobDTO object here
schedulerService.deleteJobFromGroup(jobDTOReturn.getIdentity().getGroup(),
jobDTOReturn.getIdentity().getName());
return "redirect:/";
}
what I am missing here?
I think there is an error in your input tag, try this :
<input type="text" th:value="${jobDTO.identity.name}" th:field="*{identity.name}" hidden/>

How can I fix the CSRF related issues when it is enabled using Spring Boot with Spring Security?

I have a spring boot application. I am using Spring Security. I am facing two issues when CSRF is enabled. Please find the below issues, code and screenshots. How can I fix this?
Whenever the server is restarted, the login always fails the first time. It gives 404 error. But it is successful the second time.
I am using customAuthenticationFailureHandler in case if login is
failed, I am setting the error message in session and redirecting it
to login jsp to display it. It was working fine before CSRF was
enabled. Now, it looks like the value stored in session is destroyed
Security configuration
#Override
protected void configure(HttpSecurity http) throws Exception {
//http.csrf().disable();
http
.authorizeRequests()
.antMatchers("/ui/static/assets/**").permitAll()
.antMatchers("/register", "/forgotPassword").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/LoginPage")
.loginProcessingUrl("/authenticate")
.permitAll()
.defaultSuccessUrl("/addDocument")
.failureHandler(customAuthenticationFailureHandler)
.and().exceptionHandling().accessDeniedPage("/Access_Denied")
.and().logout().permitAll().invalidateHttpSession(true);
}
CustomAuthenticationFailureHandler
#Component
public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {
#Override
public void onAuthenticationFailure(
HttpServletRequest request,
HttpServletResponse response,
AuthenticationException exception)
throws IOException, ServletException {
String errMsg=exception.getMessage();;
request.getSession().setAttribute("loginErrorMessage", errMsg);
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.sendRedirect(request.getContextPath()+"/login?error");
}
}
Login.jsp
<c:set var="params" value="${requestScope['javax.servlet.forward.query_string']}"/>
<div class="account-content">
<c:if test="${params eq 'error' && loginErrorMessage ne null}">
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<strong>${loginErrorMessage}</strong>
</div>
</c:if>
<form action="${pageContext.servletContext.contextPath}/authenticate" class="form-horizontal" method="post" id="formLogin" data-parsley-validate="">
<sec:csrfInput />
<div class="form-group m-b-25">
<div class="col-12">
<label for="emailaddress">Email address<span class="text-danger">*</span></label>
<input class="form-control input-lg" type="email" name="username" id="username" placeholder="Enter your email" data-parsley-required="true">
</div>
</div>
<div class="form-group m-b-25">
<div class="col-12">
Forgot your password?
<label for="password">Password<span class="text-danger">*</span></label>
<input class="form-control input-lg" type="password" id="pwd" name="password" placeholder="Enter your password" data-parsley-required="true">
</div>
</div>
<div class="form-group account-btn text-center m-t-10">
<div class="col-12">
<button class="btn w-lg btn-rounded btn-lg btn-primary waves-effect waves-light"
id="signInBtn" type="submit" value="Next" >Sign In
<i class="fas fa-spinner fa-spin" id="loadingBtn" style="display:none;"></i></button>
</div>
</div>
</form>
<div class="clearfix"></div>
</div>

Forbidden Error when login in SpringBoot app

I have a basic SpringBoot app. using Spring Initializer, JPA, embedded Tomcat, Thymeleaf template engine, and package as an executable JAR file.
This is my config file:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(publicMatchers()).permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").defaultSuccessUrl("/menu/config")
.failureUrl("/login?error").permitAll()
.and()
.logout().permitAll();
}
my Thymeleaf template:
<form id="loginForm" th:action="#{/login}" method="post">
<div class="row">
<div class="col-md-6 col-md-offset-3 text-center">
<div th:if="${param.error}" class="alert alert-danger alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">x</span>
</button>
<p th:text="#{login.error.message}" />
</div>
<div th:if="${param.logout}" class="alert alert-success alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">x</span>
</button>
<p th:text="#{login.logout.success}" />
</div>
</div>
</div>
<div class="input_label"><i class="fa fa-user"></i><input type="text" id="usernameId" name="username" th:attr="placeholder=#{login.user.placeholder}" value="peris" /></div>
<div class="input_label"><i class="fa fa-key"></i><input type="password" name="password" value="peris"/></div>
<input type="submit" value="LOGIN" />
</form>
and my Login controller:
#Controller
public class LoginController {
public static final Logger LOG = LoggerFactory.getLogger(LoginController.class);
/** The login view name */
public static final String LOGIN_VIEW_NAME = "login/login";
#RequestMapping(value={ "/", "/login", "/elCor/login"}, method = {RequestMethod.GET})
public String login() {
LOG.info(serverContextPath + "/" + LOGIN_VIEW_NAME);
return serverContextPath + "/" + LOGIN_VIEW_NAME;
}
}
Evefything is OK using the browser, but when I use the mobile, I log in, I go back using the browser button, then I try to log in again but I have this error:
2018-06-28 08:56 [http-nio-5678-exec-2] ERROR c.t.w.c.AppErrorController - getErrorAttributes(request, true) --> {timestamp=Thu Jun 28 08:56:48 CEST 2018, status=403, error=Forbidden, message=Forbidden, path=/elCor/login}
I found the same problem in the computer browser but just once, and I can't not reproduce the problem.. I am trying to guess it
Try adding csrf tokens for login request.
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>

Form submit with a file in Spring mvc + bootstrap

Its a two part question.
I am trying to submit a pop up form with a file and textarea. I am not able to receive file in my controller code.
Part 1 - How do I receive the file at the controller.
Part 2 - Once I submit the form, how do I close the popup and remain on the same page so that URL does not change.
Popup code-
<form name="eperform">
<div class="modal fade" id="export" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">
<span class="glyphicon glyphicon-remove" aria-hidden="true" style="padding-top: 10px;"></span>
</button>
<h4 class="modal-title custom_align" id="Heading">Provide ID's here:</h4>
</div>
<div class="form-group">
<div>
<fieldset style="margin-left: 10px;">
<legend style="font-size: medium;">File Upload</legend>
<input id="fileUpload" name="fileUpload" type="file" style="margin-left: 20px"/>
</fieldset>
</div>
<br/>
<div>
<fieldset style="margin-left: 10px;">
<legend style="font-size: medium;">Ids</legend>
<label for="envIds"></label>
<textarea class="form-control noresize" rows="4" style="width:98% " name="ids" id="ids" value="">
</textarea>
<input type="hidden" id="server" name="server" value="${server}">
<input type="hidden" id="port" name="port" value="${port}">
<input type="hidden" id="queuename1" name='queuename1' value="">
<input type="hidden" id="environment" name="environment" value="${environment}">
</fieldset>
</div>
</div>
<div class="modal-footer ">
<button type="button" class="btn btn-success" id="eid"
onclick="exportObjects(document.getElementById('ids').value,document.getElementById('queuename1').value,'${port}','${server}','${environment}',document.getElementById('fileUpload').value)">
<span class="glyphicon glyphicon-ok-sign"></span>Export
</button>
<button type="button" class="btn btn-default" data-dismiss="modal">
<span class="glyphicon glyphicon-remove"></span> Cancel
</button>
</div>
</div>
</div>
</div>
</form>
Javascript code-
function exportObjects(ids, queueName, port, server, environment, fileUpload) {
var strHREF = "/exportObjects?ids=" + ids
+ "&queueName=" + queueName + "&port=" + port + "&server="
+ server + "&environment=" + environment +"&fileUpload=" + fileUpload;
document.eperform.action = strHREF;
document.eperform.submit();
}
Controller code-
#RequestMapping(value="/exportObjects", method = RequestMethod.GET)
public ModelAndView exportObjects(HttpServletRequest request) throws Exception{
String server =request.getParameter("server");
String port =request.getParameter("port");
String environment = request.getParameter("environment");
String type =request.getParameter("queueName");
String ids = request.getParameter("ids");
CommonsMultipartFile file = (CommonsMultipartFile) request.getAttribute("fileUpload");
if(file != null && file.getSize() != 0){
String path=request.getServletContext().getRealPath("/");
String filename=file.getOriginalFilename();
System.out.println(path+" "+filename);
try{
InputStream in = file.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder out = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
out.append(line);
}
System.out.println(out.toString());
}catch(Exception e){System.out.println(e);}
}
// Perform action on ids and file data
ModelAndView model = new ModelAndView();
// I do not know what to do here.
return model;
}
It seems that you are not familiar with web developement,I recommend you take some time to review the java web development knowledge.
Below are the answer for your two questions:
If you want to upload a file to the server,you must add enctype="multipart/form-data" to your form
<form name="eperform" enctype="multipart/form-data">
<div>
<fieldset style="margin-left: 10px;">
<legend style="font-size: medium;">File Upload</legend>
<input id="fileUpload" name="fileUpload" type="file" style="margin-left: 20px"/>
</fieldset>
</div>
</form>
If you want to stay on the same page,you should using an asynchronous method to submit your action,and Ajax is your best choice.You need to submit your request and in the success callback method close the popup dialog.
$.ajax({
url:"exportObjects",
type:"post",
data:{
queueName:queueName,
port:port,
server:server,
environment:environment
},
success:function(data){
//if the request submit success,invoke 'close' method to close the dialog
$("#dialog_div").dialog("close");
}
});
In your springmvc code,you should not use ModelAndView because it will forward to a new page,you need to return an original string,like the code listed below,after that you can use MultipartFile to get your upload file:
#RequestMapping(value="eperform",method=RequestMethod.POST)
#ResponseBody
public String updateNodeRelation(#RequestParam(value="fileUpload")
MultipartFile file,HttpServletRequest request) {
System.out.println(file.getOriginalFilename());
return "success";
}
UPDATED
If you want to submit a file and then stay on the same page,then you need to use iframe and not use Ajax,as below:
<!-- using iframe to stay on the same page-->
<form id="eperform"name="eperform" action="exportObjects" enctype="multipart/form-data"
target="hidden_frame">
<div>
<fieldset style="margin-left: 10px;">
<legend style="font-size: medium;">File Upload</legend>
<input id="fileUpload" name="fileUpload" type="file"
style="margin-left: 20px"/>
</fieldset>
</div>
<iframe id="hidden_frame" name="hidden_frame"
style="display:none"/>
<button type="button" onclick="submitFile()">Submit</button>
</form>
And using the below Javascript code to submit the form and close popup dialog**
function submitFile(){
$("#eperform").submit();
$("#dialog_div").dialog("close");
}

how to turn this spring boot thyme-leaf code into Ajax

I Have a comment and post system and I want To turn it into ajax without using thymeleaf fragmentation. How to do it i cannot figure out I do not want to refresh the page each time i make a post or comment .
Controller :
#Controller
public class DashboardController {
private Post post;
private User user;
#Autowired
private PostRepository postRepository;
#Autowired
private UserRepository userRepository;
#Autowired
CommentRepository commentRepository;
#RequestMapping(value = "/dashboard", method = RequestMethod.GET)
public String returnPosts(Model model) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String currentPrincipalName = authentication.getName(); //holding login user details
model.addAttribute("firstName", userRepository.findByEmail(currentPrincipalName).getFirstName());
model.addAttribute("newPost", new Post());
model.addAttribute("newComment", new Comment());
model.addAttribute("posts", postRepository.findAllByOrderByDateDesc());
model.addAttribute("comments", commentRepository.findAll());
return "main";
}
#RequestMapping(value = "/dashboard/posts", method = RequestMethod.POST)
public String addPost(Model model, #ModelAttribute Post post, #ModelAttribute User user) {
model.addAttribute("newPost", post);
creatPost(post);
System.out.println(post.getId());
return "redirect:/dashboard";
}
#RequestMapping(value = "/dashboard/comments", method = RequestMethod.POST)
public String addComment( Model model, #ModelAttribute Comment comment,
#ModelAttribute User user) {
model.addAttribute("newComment", comment);
// model.addAttribute("posts", post);
creatComment(comment.getPostId(), comment);
System.out.println(comment.toString());
//System.out.println(post.getId());
// System.out.println(comment.getPostId());
return "redirect:/dashboard";
}
private Comment creatComment(String id, Comment comment) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String currentPrincipalName = authentication.getName();
comment.setDate(new Date());
comment.setAuthor(userRepository.findByEmail(currentPrincipalName).getFirstName()
+ " " + userRepository.findByEmail(currentPrincipalName).getLastName());
comment.setPostId(id);
return commentRepository.save(comment);
}
private Post creatPost(Post post) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String currentPrincipalName = authentication.getName(); //holding login user details
post.setAuthor(userRepository.findByEmail(currentPrincipalName).getFirstName()
+ " " + userRepository.findByEmail(currentPrincipalName).getLastName());
post.setDate(new Date());
return postRepository.save(post);
}
}
Thymeleaf forms :
<div id="content" class="yellow col-xs-12">
<form class="col-xs-12" role="form" action="/dashboard/posts"
th:action="#{/dashboard/posts}" th:object="${newPost}" method="post">
<div class="form-group col-xs-12">
<textarea class="form col-xs-6" rows="2" id="full" placeholder="share anything....."
th:field="*{content}" style="font-size: 20px;" required="required"></textarea>
<div class="menu1 col-xs-12">
<hr/>
<ul class="text-center col-xs-12">
<a href="#">
<li>
<button type="submit" class="sendpost btn btn-success">Send</button>
</li>
<li class="xs-12 "><i class="fa fa-flash fa-lg"></i>Tasks</li>
<li class="xs-12"><i class="fa fa-paperclip fa-lg"></i>files</li>
<li class="xs-12"><i class="fa fa-calendar fa-lg"></i> calendar</li>
<li class="xs-12"><i class="fa fa-search fa-lg"></i>stying</li>
</a>
</ul>
</div>
</div>
</form>
<div>
<div th:each="post : ${posts}" style="border:2px solid #CCCCCC ; margin-bottom: 50px" id="post-div"
class="post-group col-xs-12">
<div class="imag col-xs-2">
<!--<input type="hidden" th:field="*{post.id}" disabled="disabled"/>-->
<img style="width: 50px;" src="images/1.png" class="img-circle img-responsive" alt=""/>
</div>
<div class=" col-xs-10">
<h4 style="line-height: .4;"><p class="name" th:text="*{post.author}">
</p>
<small style="color: #337ab7" th:text="*{post.date}"></small>
</h4>
<br/>
<p style="font-size: 20px" id="post-p" class="desc" th:text="*{post.content}"></p><br/>
<div class="footer ignore-zoom">
<a class="comment" onclick="showDiv1()"><i class="aa fa fa-comment"></i>
<span class="lin">0</span></a>
<a onclick="showDiv2()" href="#">
<i id="like" class="aa fa fa-heart active"></i>
<span style="display:none;" id="like-1" class="lin">1</span></a>
<a class="aa dropdown-toggle" data-toggle="dropdown" href="#" aria-expanded="false"><i
class="fa fa-pencil"></i> </a>
</div>
<div th:each="comment : ${comments}" id="my-comment">
<div th:if="${post.id == comment.postId}">
<hr/>
<br/>
<img class="img-circle img-responsive" src="images/1.png"
style="margin-right:5%; width: 50px; display: inline-flex; color:#080602;"/>
<div style="line-height:.8">
<label th:text="*{comment.author}"> </label><br/>
<small th:text="*{comment.date}" style=" color: #337ab7 ; margin-left:16%;">time of
comment
</small>
</div>
<br/>
<p style="font-size: 16px;" id="-comment" th:text="*{comment.comment}"></p>
<div class="footer footer1 ignore-zoom">
<a onclick="showDiv4()" href="#">
<i id="like1" class="aa fa fa-heart active"></i>
<span style="display:none;" id="like-2" class="lin">1</span></a>
<a class="aa dropdown-toggle" data-toggle="dropdown" href="#" aria-expanded="false"><i
class="fa fa-pencil"></i> </a>
</div>
</div>
</div>
<form role="form" action="/dashboard/comments"
th:action="#{/dashboard/comments}" th:object="${newComment}" method="post">
<input type="hidden" name="postId" th:value="${post.id}"/>
<div id="comment-div" class="form-group col-xs-12">
<textarea th:field="*{comment}" class="form col-xs-6" rows="2" id="full2"
placeholder="Your Comment....." required="required"></textarea>
<div class="menu1 col-xs-12">
<hr/>
<ul class="text-center col-xs-12">
<a href="#">
<li onclick="showDiv()">
<button type="submit" class="btn btn-info">Send</button>
</li>
<li class="xs-12 "><i class="fa fa-flash fa-lg"></i></li>
<li class="xs-12"><i class="fa fa-paperclip fa-lg"></i></li>
<li class="xs-12"><i class="fa fa-calendar fa-lg"></i></li>
<li class="xs-12"><i class="fa fa-search fa-lg"></i></li>
</a>
</ul>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
You can have a look at the tutorial http://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#ajax-fragments
And the content is as below:
Ajax fragments
WebFlow allows the specification of fragments to be rendered via AJAX with tags, like this:
<view-state id="detail" view="bookingDetail">
<transition on="updateData">
<render fragments="hoteldata"/>
</transition>
</view-state>
These fragments (hoteldata, in this case) can be a comma-separated list of fragments specified at the markup with th:fragment :
<div id="data" th:fragment="hoteldata">
This is a content to be changed
</div>
Always remember that the specified fragments must have an id attribute, so that the Spring JavaScript libraries running on the browser are capable of substituting the markup.
tags can also be specified using DOM selectors:
<view-state id="detail" view="bookingDetail">
<transition on="updateData">
<render fragments="[//div[#id='data']]"/>
</transition>
</view-state>
...and this will mean no th:fragment is needed:
<div id="data">
This is a content to be changed
</div>
As for the code that triggers the updateData transition, it looks like:
<script type="text/javascript" th:src="#{/resources/dojo/dojo.js}"></script>
<script type="text/javascript" th:src="#{/resources/spring/Spring.js}"></script>
<script type="text/javascript" th:src="#{/resources/spring/Spring-Dojo.js}"></script>
...
<form id="triggerform" method="post" action="">
<input type="submit" id="doUpdate" name="_eventId_updateData" value="Update now!" />
</form>
<script type="text/javascript">
Spring.addDecoration(
new Spring.AjaxEventDecoration({formId:'triggerform',elementId:'doUpdate',event:'onclick'}));
</script>

Resources