I am trying to submit a form using post request and first validate inputs.
However when I make bad inputs (for example all empty) instead of showing error I get bad request (400).
For showing error I am using th:if
and th:errors
tags in HTML.
If I submit all valid inputs, there is no problem.
Controller class:
@Controller @RequestMapping(path = "/order") public class PurchaseController { @GetMapping(path = "/new") public String newOrder(Model model) { model.addAttribute("Purchase", new Purchase()); return "neworder"; } @PostMapping(path = "/new") public String createPurchase(@Valid @ModelAttribute(name = "Purchase") Purchase purchase) { int purchaseId = 0; try { purchaseId = PurchaseManager.insertPurchase(purchase); } catch (SQLException e) { return "purchaseerror"; } if (purchaseId == 0) return "purchaseerror"; return "redirect:/order/success?id=" + purchaseId; } @GetMapping(path = "/success") public String successPurchase(@RequestParam(required = true, name = "id") int id, Model model) { model.addAttribute("id", id); return "ordersuccess"; } }
HTML form:
<form th:action="@{new}" th:object="${Purchase}" method="post"> <table> <tr> <td>First name:</td> <td><input type="text" th:field="*{firstName}" /></td> <td th:if="${#fields.hasErrors('firstName')}" th:errors="*{firstName}">Must be filled</td> <td>Last name:</td> <td><input type="text" th:field="*{lastName}" /></td> <td th:if="${#fields.hasErrors('lastName')}" th:errors="*{lastName}">Must be filled</td> </tr> <tr> <td>Adresa:</td> <td><input type="text" th:field="*{address}" /></td> <td th:if="${#fields.hasErrors('address')}" th:errors="*{address}">Must be filled</td> </tr> <tr> <td>ico:</td> <td><input type="text" th:field="*{ico}" /></td> <td th:if="${#fields.hasErrors('ico')}" th:errors="*{ico}">Must be filled</td> <td>dic:</td> <td><input type="text" th:field="*{dic}" /></td> <td th:if="${#fields.hasErrors('dic')}" th:errors="*{dic}">Must be filled</td> </tr> <tr> <td>Email:</td> <td><input type="text" th:field="*{email}" /></td> <td th:if="${#fields.hasErrors('email')}" th:errors="*{email}">Must be filled</td> <td>phone:</td> <td><input type="text" th:field="*{phone}" /></td> <td th:if="${#fields.hasErrors('phone')}" th:errors="*{phone}">Must be filled</td> </tr> </table> <input type="submit" value="Submit"/> </form>
Model class (Purchase)
public class Purchase { private int id; @NotBlank @Size(max = 50) private String firstName; @NotBlank @Size(max = 50) private String lastName; @NotBlank @Size(max = 50) private String ico; @NotBlank @Size(max = 50) private String dic; @NotBlank @Size(max = 400) private String address; @NotBlank @Size(max = 50) private String email; @NotBlank @Size(max = 50) private String phone; private LocalDateTime creationDate; ... getters and setters, constructors
How to make showing error using thymeleaf work?
EDIT: I managed to make it work by adding BindingResult parameter to my post method in Controller class and checking if there are any errors. If yes, i return same page the form is on (/new mapping), which is “neworder”.
return “purchaseerror”; might created a bit of confusion.
@PostMapping(path = "/new") public String createPurchase(@Valid @ModelAttribute(name = "Purchase") Purchase purchase, BindingResult result) { if (result.hasErrors()) { return "neworder"; } int purchaseId = 0; try { purchaseId = PurchaseManager.insertPurchase(purchase); } catch (SQLException e) { return "redirect:/purchaseerror"; } if (purchaseId == 0) return "redirect:/purchaseerror"; return "redirect:/order/success?id=" + purchaseId; }
Advertisement
Answer
I think your problem could be resolved if you use Model
as your 2nd parameter in the createPurchase
method. Then inside your method you could do something like the following to add messages:
@PostMapping("/add") public String addUser(@Valid User user, BindingResult result, Model model) { if (result.hasErrors()) { return "errors/addUser"; } repository.save(user); model.addAttribute("users", repository.findAll()); //this is what you could do. return "errors/home"; }
which would kind of result your method as following (please do amend it your discretion — I am only writing for demonstrative purposes):
@PostMapping(path = "/new") public String createPurchase(@Valid @ModelAttribute(name = "Purchase") Purchase purchase, Model model) { int purchaseId = 0; try { purchaseId = PurchaseManager.insertPurchase(purchase); } catch (SQLException e) { // todo: don't return right away. Add `model.addAttribute` first. return "purchaseerror"; } if (purchaseId == 0) { // todo: don't return right away. Add `model.addAttribute` first. return "purchaseerror"; } return "redirect:/order/success?id=" + purchaseId; }
The added values in the modelAttribute would then be picked by your Thymeleaf implementation from where you could pick the errors (as you would have populated it) and simply base logic upon that.
You can follow example from here for a better understanding. Just remember that you need to add into the Model
before you can lay out logic in your thymeleaf based upon that.
I hope my answer resolves your queries. If not, apologies.