SpringBoot RedirectAttributes does not show in thymeleaf - spring-boot

controller code:
#Controller
#RequestMapping("/admin")
#AllArgsConstructor
public class AdminController {
private AdminUserService adminUserService;
#PostMapping("/login")
public String login(#RequestParam String username, #RequestParam String password, #RequestParam String kaptcha, RedirectAttributes attributes, HttpSession session) {
String errorMsg;
if (StringUtils.isEmpty(kaptcha)) {
errorMsg = "kaptcha can't be empty";
attributes.addFlashAttribute("errorMsg", errorMsg);
return "redirect:admin/login";
}
if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
errorMsg = "username or password can't be empty";
attributes.addFlashAttribute("errorMsg", errorMsg);
return "redirect:admin/login";
}
String code = (String) session.getAttribute(Const.kapchaCode);
if (StringUtils.isEmpty(code) || !kaptcha.equals(code)) {
errorMsg = "invalid kaptcha code";
attributes.addFlashAttribute("errorMsg", errorMsg);
return "redirect:admin/login";
}
AdminUser login = adminUserService.login(username, password);
if (login == null) {
errorMsg = "invalid username password combination";
attributes.addFlashAttribute("errorMsg", errorMsg);
return "redirect:admin/login";
}
session.setAttribute("loginUser", login.getAlias());
session.setAttribute("loginUserId", login.getAdminUserId());
return "redirect:/admin/index";
}
template:
<div class="form-group">
<div th:if="${errorMsg}" class="alert alert-danger" th:text="${errorMsg}"></div>
</div>
errorMsg wouldn't show up when there is an error.
I have checked that errorMsg indeed get into RedirectAttributes, but it wouldn't display on the page;

Please set the value in redirected controller admin/login. Example
#RequestMapping(value = "admin/login", method = RequestMethod.GET)
public String OtherController(#ModelAttribute("errorMsg") String errorMsg, Model model) {
model.addAttribute("errorMsg", errorMsg);
return "login";//template name
}

Related

Spingboot Thymeleaf form passes null values into the controller

could someone help me figure out why it is passing null values instead of actual names? The form has a input textbox for last name and fistname but I would only get null values when I access "authorRequest.getLastName() or authorRequest.getFirstName().
Controller:
#Controller
public class AuthorController {
private BooktownService __authorService = BooktownServiceFactory.getInstance();
private Model mod;
private String msg = "";
first endpoint, return a collection of authors
#GetMapping("/booktown/list")
public List<Author> returnAuthors() {
return __authorService.getAuthors();
}
#GetMapping("/booktown/list")
public String returnAuthors(Model model) {
this.mod = model;
Author auth= new Author();
List<Author> auths = __authorService.getAuthors();
if(msg == ""){
msg = "Listing page for Authors";
}
mod.addAttribute("authors", auths);
mod.addAttribute("authorRequest", auth);
mod.addAttribute("msg",msg);
return "list_form";
}
// third endpoint, create an Author via POST
#PostMapping("/booktown/add")
public String createAuthor(#ModelAttribute("authorRequest") Author authorRequest) {
__authorService.createAuthor(authorRequest.getLastName(), authorRequest.getFirstName());
msg = "Added Author" + authorRequest.getFirstName() + " " + authorRequest.getLastName();
return "redirect:/booktown/list";
}
// Sixth endpoint: DELETE
#GetMapping("/booktown/delete")
public String deleteAuthor(#RequestParam Integer id) {
// returns a boolean
__authorService.deleteAuthor(id);
msg = "Deleted Author " + id;
System.out.println("deleted");
return "redirect:/booktown/list";
}
}
Html:
<form action="#" th:action="#{/booktown/add}" th:object="${authorRequest}" method="post">
<p>Last name: <input type="text" th:field="*{__lastName}" /></p>
<p>First name: <input type="text" th:field="*{__firstName}" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
Author.java:
package com.booktown.booktownservice;
public class Author {
public Author(){}
public Author(int id, String lname, String fname) {
__id = id;
__lastName = lname;
__firstName = fname;
}
public int getAuthorID() {
return __id;
}
public String getLastName() {
return __lastName;
}
public String getFirstName() {
return __firstName;
}
public int get__id() {
return __id;
}
public String get__lastName() {
return __lastName;
}
public String get__firstName() {
return __firstName;
}
private int __id;
private String __lastName;
private String __firstName;
}

Non bean property throwing Bean property is not readable or has an invalid getter method

So my issue is a bit different from others. The error that it is throwing is not a field name but rather the input in a form. I've never encountered this error before
Error. The contents of '' is what I key for password
org.springframework.beans.NotReadablePropertyException: Invalid
property 'Yijian#123' of bean class [com.Alex.UserPackage.User]: Bean
property 'Yijian#123' is not readable or has an invalid getter method:
Does the return type of the getter match the parameter type of the
setter? at
org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:622)
~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE] at
org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:612)
~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE] at
org.springframework.validation.AbstractPropertyBindingResult.getActualFieldValue(AbstractPropertyBindingResult.java:104)
~[spring-context-5.2.7.RELEASE.jar:5.2.7.RELEASE]
Entity class
#Entity
#ValidPassword
public class User {
#Pattern(regexp="[a-zA-Z]+", message = "Enter letters only!")
private String firstName;
#Pattern(regexp="[a-zA-Z]+", message = "Enter letters only!")
private String lastName;
private String password;
private String matchingPassword;
private String passportNumber;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getMatchingPassword() {
return matchingPassword;
}
public void setMatchingPassword(String matchingPassword) {
this.matchingPassword = matchingPassword;
}
}
#ValidPassword custom annotation. The error started to occur after I used the getters for password and matchingPassword
private String message;
#Override
public boolean isValid(User user, ConstraintValidatorContext context) {
String password = user.getPassword();
String matchingPassword = user.getMatchingPassword();
if (password== null || matchingPassword == null) {
return false;
}
System.out.println("PASSWORDS: " + password + matchingPassword);
boolean flag = Pattern.matches("^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!#$%^&*-]).{8,}$", password);
boolean flag1 = password.equals(matchingPassword);
if ( !flag1 ) {
message = "Passwords do not match!";
}
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(message)
.addPropertyNode(password).addConstraintViolation();
return flag && flag1;
}
//Show default message if no special message is set
#Override
public void initialize(ValidPassword validPassword) {
message = validPassword.message();
}
Form password portion
<div class = "row">
<div class="col-sm-6 form-group">
<label>Password : </label> <Input type="password"
th:field="*{password}" th:required="required" class="form-control" />
<p th:if="${#fields.hasErrors('password')}"
th:errors="*{password}" class="alert alert-danger"></p>
</div>
You are passing the property value instead of the property name to addPropertyNode(password).
Replace the following:
context.buildConstraintViolationWithTemplate(message)
.addPropertyNode(password).addConstraintViolation();
with:
context.buildConstraintViolationWithTemplate(message)
.addPropertyNode("password").addConstraintViolation();

Themeleaf and submit form POST

Mavens,
I am struggling to invoke a controller from Themeleaf.
My themeleaf code looks like:
<form action="#" th:action="#{/order}" modelAttribute="order" th:object="${order}" method="POST">
<div class="div">
<h5>Amount</h5>
<input type="text" class="input" th:field="*{amountValue}">
</div>
<input type="submit" class="btn" value="Process Payment">
</form>
My Controller Code is:
#RequestMapping(value = "/order", method = RequestMethod.POST)
public ModelAndView processOrder(#ModelAttribute Order order) {
ModelAndView modelAndView = new ModelAndView();
String accessToken = token();
String paymentURL = null;
if (accessToken != null) {
paymentURL = placeOrder(accessToken, order);
if (paymentURL != null) {
modelAndView.addObject("orderReferenceNumber", paymentURL.substring(paymentURL.indexOf("=") + 1));
modelAndView.addObject("paymentURL", paymentURL + "&slim=true");
modelAndView.setViewName("paymentProcess");
return modelAndView;
}
}
return modelAndView;
}
My Get method is
#RequestMapping(value = "/index", method = RequestMethod.POST)
public ModelAndView doLogin(#RequestParam(value = "username", required = true) String username,
#RequestParam(value = "password", required = true) String password) {
ModelAndView modelAndView = new ModelAndView();
if (username != null && password != null) {
if (username.equalsIgnoreCase("one") && password.equalsIgnoreCase("one")) {
modelAndView.addObject("order", new Order());
modelAndView.setViewName("index");
return modelAndView;
}
}
modelAndView.setViewName("welcome");
return modelAndView;
}
Error on click of the button
Error resolving template [order], template might not exist or might not be accessible by any of the configured Template Resolvers
org.thymeleaf.exceptions.TemplateInputException: Error resolving template [order], template might not exist or might not be accessible by any of the configured Template Resolvers
What am i doing wrong ?
The issue comes from how you populate your ModelAndView instance. Only when your two if clauses are matched, you set the name of the view with modelAndView.setViewName("paymentProcess");. That means for some executions (not matching your both conditionals), you don't set the name of the view at all and Spring MVC doesn't know which view to render and return to the user.
To fix this, make sure you always set a default/fallabck view to return in case the if conditions are both not true. Your code might override this view name but you have at least for each case a view to fallback on:
#RequestMapping(value = "/order", method = RequestMethod.POST)
public ModelAndView processOrder(#ModelAttribute Order order) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("yourDefaultViewName"); // this is the important line
String accessToken = token();
String paymentURL = null;
if (accessToken != null) {
paymentURL = placeOrder(accessToken, order);
if (paymentURL != null) {
modelAndView.addObject("orderReferenceNumber", paymentURL.substring(paymentURL.indexOf("=") + 1));
modelAndView.addObject("paymentURL", paymentURL + "&slim=true");
modelAndView.setViewName("paymentProcess");
return modelAndView;
}
}
return modelAndView;
}

Spring MVC -- flash attributes not displaying in Thymeleaf

I've confirmed that i'm packing the RedirectAttributes with a BusinessAuth object with non-empty strings. What am I doing wrong?
AdminController:
#RequestMapping(path = BASE_URI + "/auth/business")
public String generateBusinessKeys(RedirectAttributes redirectAttributes) {
String keyBusiness = ControllerUtil.getNewAuthKey();
String keyMobile = ControllerUtil.getNewAuthKey();
BusinessAuth auth = new BusinessAuth(keyBusiness, keyMobile);
businessAuthService.save(auth);
redirectAttributes.addFlashAttribute("businessAuth", auth);
return "/admin/home";
}
HTML:
<p th:if="${businessAuth} != null" th:text="admin: "></p>
<p th:if="${businessAuth} != null" th:text="${businessAuth.keyAdmin}"></p> <br />
<p th:if="${businessAuth} != null" th:text="mobile: "></p> <br />
<p th:if="${businessAuth} != null" th:text="${businessAuth.keyMobile}"></p> <br />
BusinessAuth:
#Entity
public class BusinessAuth extends BaseEntity {
private String keyMobile;
private String keyAdmin;
public BusinessAuth() {}
public BusinessAuth(String keyMobile, String keyAdmin) {
this.keyMobile = keyMobile;
this.keyAdmin = keyAdmin;
}
public String getKeyMobile() {
return keyMobile;
}
public String getKeyAdmin() {
return keyAdmin;
}
}
Setting the attribute on a ModelMap did the trick.

getting null values in spring MVC controller

i am new in spring. and i am developing login application in spring mvc . while setting the values in LoginForm its is showing "null". please help me. want to get out of it!!
Any help will be appriciated.
My controller is:
#Controller
#RequestMapping("loginform.html")
public class LoginController extends MainController {
private String password;
private LoginDAO loginDAO;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#RequestMapping(method = RequestMethod.GET)
public String showForm(Map model) {
LoginForm loginForm = new LoginForm();
model.put("loginForm", loginForm);
return "loginform";
}
#RequestMapping(method = RequestMethod.POST)
public String processForm(#Valid LoginForm loginForm, BindingResult result,
Map model) {
//String userName = "Admin";
//String password = "root";
if (result.hasErrors()) {
return "loginform";
}
try {
loginForm.setUserName(userName);
loginForm.setPassword(password);
loginDAO = new LoginDAOImpl();
LoginForm tempLoginForm = loginDAO.validateUser(loginForm);
if (tempLoginForm == null) {
return "loginsuccess";
}
} catch (Exception e) {
}
model.put("loginForm", loginForm);
return "loginerror";
}
}
You must not set the username and password in the process form method, you must read it form the form object.
String userName = login form.getUserName();

Resources