So actually I have an controller that show form to user. User get that form and for example if he enter a wrong data, for example amount field is just positive numbers but user insert -1 user will get error message on screen, but when user change that value and enter for example 3 for amount and submit form, user get 404 Whitelabel Error Page
.
So first URL is:
http://localhost:8080/api/transaction/expenseTransaction/4
, now, user enter -1 for amount and click submit, URL is http://localhost:8080/api/transaction/saveExpense/4
, so is there any way to stay on same page and allow user to save form after he insert properly data?
I have this controller to show form:
@GetMapping("/expenseTransaction/{id}")
public String expenseTransaction(@PathVariable(value = "id") long id, Transaction transaction, Model model) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserDetailsImpl user = (UserDetailsImpl) authentication.getPrincipal();
long userId = user.getId();
model.addAttribute("userId", userId);
model.addAttribute("transaction", transaction);
model.addAttribute("expenseCategories", ExpenseCategories.values());
return "expense_transaction";
}
This is the form:
<div >
<h3> Expense transaction</h3>
<div >
<div >
<div >
<form action="#"
th:action="@{/api/transaction/saveExpense/{walletId} (walletId=${id})}"
th:object="${transaction}" method="post">
<div >
<div >
<label for="amount" >Amount</label> <input
type="text" th:field="*{amount}" id="amount"
placeholder="amount"> <span
th:if="${#fields.hasErrors('amount')}" th:errors="*{amount}"
></span>
</div>
<div >
<label for="note" >Note</label> <input
type="text" th:field="*{note}" id="note"
placeholder="note"> <span
th:if="${#fields.hasErrors('note')}" th:errors="*{note}"
></span>
</div>
<div >
<label for="date" >Date</label> <input
type="date" th:field="*{date}"
id="date" placeholder="date"> <span
th:if="${#fields.hasErrors('date')}" th:errors="date"
></span>
</div>
<div >
<label for="date" >Category</label>
<select th:field="${transaction.expenseCategories}">
<option value="0">Select expense category</option>
<option
th:each="expenseCategories : ${expenseCategories}"
th:value="${expenseCategories}"
th:text="${expenseCategories.displayName}"
></option>
</select>
</div>
<div >
<input type="submit"
value="Update Student">
</div>
</div>
</form>
</div>
</div>
</div>
This is controller to save that form:
@PostMapping("/saveExpense/{walletId}")
public String saveExpense(@PathVariable(value = "walletId") long walletId,
@Valid Transaction transaction, BindingResult result, Model model) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserDetailsImpl user = (UserDetailsImpl) authentication.getPrincipal();
long userId = user.getId();
Wallet wallet = walletService.getWalletById(walletId);
boolean thereAreErrors = result.hasErrors();
if (thereAreErrors) {
transaction.setId(walletId);
model.addAttribute("expenseCategories", ExpenseCategories.values());
return "expense_transaction";
}
transaction.setWallet(wallet);
transactionService.saveExpense(transaction, walletId, userId);
return "redirect:/api/wallet/userWallet/balance/" userId;
}
CodePudding user response:
The problem is your code.
Your get method is defined with @GetMapping("/expenseTransaction/{id}")
and your POST method is defined with @PostMapping("/saveExpense/{walletId}")
.
The GET method will expose a variable named id
in your model and fill that with the value of the path variable.
Your POST method will expose a variable named walletId
in your model and fill that with the value of the path variable.
In your th:action
you expect the id
to be filled. Which is true for the GET not for the POST because the names are different.
Either fix your path variable names, or explicitly add id
to the model in the POST method with the value from walletId
.