Changed form value does not display on return. Is there a binding problem between Thymeleaf and Spring Boot? - spring-boot

See this thymeleaf snippet in the form:
<form id="onlineRegistrationForm" action="#"
th:action="#{/__${someId}__/registration}" th:object="${onlineRegistrationForm}"
method="post" novalidate class="needs-custom-validation">
...
<div class="form-group">
<label th:for="__${personInstance}__.city" th:text="#{label.city}">city</label>
<input type="text" class="form-control basicAutoComplete"
th:id="__${personInstance}__.city"
aria-describedby="cityHelp" autocomplete="off"
th:placeholder="#{label.city.ph}"
th:field="*{__${personInstance}__.city}"
th:attr="data-noresults-text='__#{search.nf}__'"
th:attrappend="data-url='/__${someId}__/city/like'"
th:errorclass="is-invalid">
<small id="cityHelp" class="form-text text-muted"
th:unless="${#fields.hasErrors('__${personInstance}__.city')}"
th:text="#{label.city.tt}">city</small>
<small id="cityError" class="invalid-feedback"
th:if="${#fields.hasErrors('__${personInstance}__.city')}"
th:errors="*{__${personInstance}__.city}">Errors</small>
</div>
Consider this POST - from a thymeleaf page:
#PostMapping(value = "/{someId}/apply")
public String submitRegistration(#Valid #ModelAttribute(name = "onlineRegistrationForm") OnlineRegistrationForm onlineRegistrationForm,
BindingResult bindingResult,
#PathVariable String someId,
Model model,
RedirectAttributes redirectAttributes)
throws OnlineRegistrationRuntimeException {
...
validateOnlineRegistration(s, onlineRegistrationForm, bindingResult);
...
if (bindingResult.hasErrors()) {
bindingResult.addError(new ObjectError("onlineRegistrationForm", messageSource.getMessage("error.message", new Object[]{""}, LocaleContextHolder.getLocale())));
return "apply";
}
...
Within validateOnlineRegistration, I change some field, say city - because I determined it thru the postal code.
I tracked down this change until into the response message. It's there.
I mean, having the BindingResult directly after the #Valid#Modelattribute,
spring gives me control in the #Controller, so why the heck is the change not displayed on the result page?

Related

Passing parameter from get to post method

I'm building an feature for a webste where a user can reset his password. He receives an email with a generated token in the url. When this link is clicked, the user is sent to the /reset page. The Get method for that page is the following:
#RequestMapping(value = "/reset", method = RequestMethod.GET)
public ModelAndView displayResetPasswordPage(ModelAndView modelAndView, #ModelAttribute User user, #RequestParam("token") String token) {
User u = userService.findByResetToken(token);
if (u == null) {
modelAndView.setViewName("error/404");
return modelAndView;
} else {
modelAndView.addObject("token", token);
modelAndView.setViewName("resetPassword");
return modelAndView;
}
}
This works fine, if the token in the url is changed, the user is sent to an error page. Now I want to pass this "token" parameter to the post method:
#RequestMapping(value = "/reset", method = RequestMethod.POST)
public ModelAndView setNewPassword(ModelAndView modelAndView, #RequestParam Map<String, String> requestParams, #ModelAttribute User user, BindingResult bindingResult, RedirectAttributes redir) {
System.out.println("token: " + requestParams.get("token"));
User u = userService.findByResetToken(requestParams.get("token"));
// User u = userService.findByEmail(user.getEmail());
if (u != null) {
User updatedUser = userService.updateUserPassword(user);
modelAndView.addObject("User",updatedUser);
modelAndView.setViewName("redirect:login");
return modelAndView;
} else {
modelAndView.setViewName("resetPassword");
}
return modelAndView;
}
This always returns the resetPassword view, since the requestparams.get("token") always returns an empty string. Am I not using the correct method to get the param value?
The reset password view:
<div class="wrapper">
<form class="form-signin" th:action="#{/reset}" method="post" th:object="${user}">
<h2 class="form-signin-heading">Reset wachtwoord</h2>
<input type="hidden" name="token" th:value="*{resetToken}"/>
<div class="form-group">
<input type="password" th:field="*{encryptedPassword}" id="password" class="form-control input-lg"
placeholder="Password" tabindex="3"/>
<div class="form-group">
<input type="password" th:field="*{matchingPassword}" id="password_confirmation"
class="form-control input-lg" placeholder="Confirm Password" tabindex="4"/>
</div>
<div class="row">
<div class="col-xs-6 col-sm-6 col-md-6">
<input type="submit" class="btn btn-secondary" value="Registreer"/>
</div>
</div>
</form>
This can be done by employing the Flash Scope that will allow your token to survive a redirect. You can do that by:
Making the first controller method accessing the second one via a redirect
Using RedirectAttributes on your first controller method and explicitly adding your token into the RedirectAttributes as a Flash Attribute
Take a look at the documentation about RedirectAttributes.

Insert jsp form to database using spring boot

I'm a beginner in spring boot I start with creating a contact form that send data to data base. this is the form:
<form:form method="POST" id="contactform" modelAttribute="message">
<div class="form">
<div class="six columns noleftmargin">
<label name="name">Name</label>
<form:input path="name" type="text" class="smoothborder" placeholder="Your name *"/>
</div>
<div class="six columns">
<label name="email">E-mail address</label>
<form:input path="email" type="text" class="smoothborder" placeholder="Your e-mail address *"/>
</div>
<label name="comment">Message</label>
<form:textarea path="comment" class="smoothborder ctextarea" rows="14" placeholder="Message, feedback, comments *"></form:textarea>
<input type="submit" id="submit" class="readmore" value="Submit"/>
</div>
</form:form>
And this is my conact controller:
#Autowired
private MessageRepository messageRepository ;
#RequestMapping(value= "/newmessage", method = RequestMethod.GET)
public String newMessage(ModelMap model) {
Message message = new Message();
model.addAttribute("message", message);
return ("/contact");
}
#RequestMapping(value="/newmessage",method=RequestMethod.POST)
public String saveMessage( Message message, BindingResult result, ModelMap model)
{
if (result.hasErrors()) {
return "/contact";
}
messageRepository.save(message);
model.addAttribute("success", "Message " + message.getName() + " "+ message.getEmail() + " "+ message.getComment()+ " registered successfully");
//return "success";
return "/homepage";
Folder Structure
You need to set the action of the form. If you want to hit /newmessage while submitting form, then you need to change as following :
<form:form method="POST" id="contactform" action="/newmessage" modelAttribute="message">
<!-- The elements of the form -->
</form:form>
Also, you need to add the modelAttribute to your controller method. And you should return only the name of the jsp page. If your page name is homepage.jsp then you should only return homepage from your controller method. Of course, homepage.jsp file needs to be in WEB-INF folder.
#RequestMapping(value="/newmessage",method=RequestMethod.POST)
public String saveMessage(#ModelAttribute("message") Message message, BindingResult result, ModelMap model) {
// Rest of the code
return "homepage";
}

Spring Boot ModelAndView - cannot update value to Model

I am trying to create a form with 3 fields within the class LoginForm: usuario, senha, msgLogin.
I receive the fields usuário and senha from the input boxes and then I try to redirect to the same page with the same fields plus the field MsgLogin. But I've not been able to update the msgLogin field and I don't understand why.
These are the code:
HTML:
<form id="frmLogin" class="form col-md-12" action="#" th:action="#{/login}" th:object="${loginForm}" method="post">
<div class="form-group">
<label for="usuario" class="col-md-1">Usuário: </label>
<input type="text" id="usuario" placeholder="Email" th:field="*{usuario}"/>
</div>
<div class="form-group">
<label for="senha" class="col-md-1">Senha: </label>
<input type="password" id="senha" placeholder="senha" th:field="*{senha}"/>
</div>
<div class="row">
<button id="entrar">Entrar</button>
</div>
<div class="row">
<div id="msgLogin"></div>
<p th:text="${loginForm.msgLogin}" />
</div>
</form>
The Controller:
#RequestMapping("/")
public String init(#ModelAttribute LoginForm loginForm) {
Logger.getAnonymousLogger().info("Tela Inicial.");
return "home";
}
#PostMapping("/login")
public ModelAndView entrar(LoginForm loginForm) throws IOException {
Logger.getAnonymousLogger().info("Entrando no Internet Banking.");
service.login(usuario, senha);
ModelMap model = new ModelMap();
loginForm.setMsgLogin("I want to update that value!");
model.addAttribute("loginForm", loginForm);
return new ModelAndView("redirect:/", model);
}
Class using Lombok:
#Getter
#Setter
public class LoginForm {
private String usuario;
private String senha;
private String msgLogin;
}
A redirect send a 302 HTTP status back to the browser to resubmit using a new url, so it resubmits the same two fields to the new url. There's no expectation of payload data in the 302 response.
In your Controller, change the last line in your entrar method to: return new ModelAndView("/login", model);

how to get form values to controller in spring mvc

I am trying to get form values from jsp to controller in spring mvc, but i am not able to get form data.
This is my DTO (bean)
public class LoginDTO implements Serializable {
private Long id;
private String username;
private String password;
// setter and getter methods
}
and my Jsp
<form class="form-signin" action="test" method="get" modelAttribute="userFormData">
<input type="text" class="form-control"
placeholder="Email" required autofocus>
<input type="password" class="form-control"
placeholder="Password" required>
<input class="btn btn-md btn-success btn-block"
type="submit" value="Signin">
</form>
and my controller
#RequestMapping(value = "/test", method = RequestMethod.GET)
public String checkLogin(#ModelAttribute("userFormData") LoginDTO formData, BindingResult
result) {
System.out.println("Controller...");
System.out.println("=====> " + formData.getUsername());
System.out.println("=====> " + formData.getPassword());
}
Add names to the controls on your JSP pages.
<input type="text" name="username" ...>
<input type="password" name="password" ...>
To let spring understand which form control value should go to which property of the LoginDTO
we can also use the springframework has given us a form tags.so that we can also use that but in that case you have to define your the input path same as the member varibale given in your class.
like this
<form:form method="post" modelAttribute="userFormData">
<form:input path="username" />
<form:input path="password" />
Then in the controller you can write like this as you have written
public String checkLogin(#ModelAttribute("userFormData") LoginDTO formData, BindingResult
result)
In case you want to get the result on other jsp page as well as on console then do:
public String checkLogin(#ModelAttribute("userFormData") LoginDTO formData, BindingResult
result , Model model){
System.out.println("=====> " + formData.getUsername()); //this outputs username on console
System.out.println("=====> " + formData.getPassword()); //this outputs password on console
model.addAttribute("LoginDTO ", LoginDTO );
return "success"; //this is the return page where the username and password will be rendered as view
}

Spring MVC: #RequestParam validation

In my register form i'm using Bean Validator (JSR-303) for validate User object, and need to validate separately password confirmation, because it is not a member of User. I have a problem to assign error message for confirm field. How to do that ?
View:
<form:form modelAttribute="user" method="post" action="register.html">
<div class="fcell">
<div class="clabel"><spring:message code="label.password"/></div>
<div class="cdata"><form:password path="password"/></div>
<div class="cmsgs"><form:errors path="password" /></div>
</div>
<div class="fcell">
<div class="clabel"><spring:message code="label.confirm"/></div>
<div class="cdata"><input type="password" name="confirm"/></div>
<div class="cmsgs"></div>
</div>
</form:form>
Controller:
#RequestMapping("/register.html")
public String register(#RequestParam("confirm") String confirm, #ModelAttribute("user") #Valid User user, BindingResult result) {
if(!DigestUtils.sha256Hex(confirm).equals(user.getPassword())) {
/* Invalid property 'confirm' ... */
result.rejectValue("confirm", "text.passwords_not_equal");
}
return "register";
}
In this case confirmation can be considered a part of model object, like this:
public class RegistrationForm {
#Valid
private User user;
private String confirm;
...
}
...
public String register(#ModelAttribute("user") #Valid RegistrationForm user,
BindingResult result) { ... }
...
<div class="cdata">
<form:password path="confirm"/></div>
<div class="cmsgs"><form:errors path="confirm" />
</div>
...

Resources