How do I validate an attribute of type BigDecimal using Bean Validation annotation? - spring-boot

I'm just wanting to do a simple validation, if the html fields below are sent "null or empty" the user can't persist the data. How can I solve this problem?
below my code
HTML:
<div th:each="msgErrors : ${erros}" class="alert alert-danger alert-dismissible fade show" role="alert">
<span th:text="${msgErrors}"></span>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<form th:action="cadastrar" method="post" th:object="${fatura}">
<div class="row">
<div class="col-lg-4 col-sm-12">
<label for="cofins">COFINS:</label>
<input type="text" class="form-control" autocomplete="off" id="cofins" th:field="*{cofins}" placeholder="0,00 %">
</div>
<div class="col-lg-4 col-sm-12">
<label for="icms">ICMS:</label>
<input type="text" class="form-control" autocomplete="off" id="icms" th:field="*{icms}" placeholder="0,00 %">
</div>
</div>
<div class="row mt-4">
<button type="submit" class="btn btn-success mr-3"><i class="far fa-save"></i> SALVAR</button>
</div>
</form>
My Model Class:
#Entity
public class Fatura {
#NumberFormat(pattern = "#,###.##")
#Column(name = "cofins")
private BigDecimal cofins;
#NumberFormat(pattern = "#,###.##")
#Column(name = "icms")
private BigDecimal icms;
}
My Controller:
public ModelAndView cadastro(#Valid Fatura fatura, BindingResult br){
if(br.hasErrors()){
ModelAndView mv = new ModelAndView("cadastro/cadastro");
mv.addObject("fatura", fatura);
mv.addObject("listLojas", Lojas.values());
List<String> msg = new ArrayList<String>();
for(ObjectError objError : br.getAllErrors()){
msg.add(objError.getDefaultMessage());
}
mv.addObject("erros", msg);
return mv;
}
I need the user to not be allowed to send the fields without typing anything

There are two methods you can use,
NotNull bean validation
Constraint in your database for the fields as not nullable
For more info about bean validation check this.

Related

How to update a table row by passing data from a Bootstrap modal form

I'm fresh in web development and I'm facing some problems
I have an html page that displays a table. Each row contains data and an "edit" button.
What I want is the following:
I already could invoke the modal form and make it pop up with data corresponding to the row's data (through the button "edit") before I add this code to my form tag th:action="#{/countries/update/{id} (id =${countryToUpdate.id})}" and hence I get this following error:
org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'id' cannot be found on null
I know that the passed model attribute countryToUpdateis null
I'm asking if it's possible to pass a model attribute to a the bootstrap modal form
That's my html table:
<table class="table">
<tr>
<th>Id</th>
<th>Description</th>
<th>Capital</th>
<th>Code</th>
<th>Actions</th>
</tr>
<tr th:each="country:${countries}">
<td th:text="${country.id}"></td>
<td th:text="${country.description}"></td>
<td th:text="${country.capital}"></td>
<td th:text="${country.code}"></td>
<td>
<!--Edit button to invoke the bootstrap form-->
<div class="btn-group">
<a th:href="#{/countries/findById/{id} (id=${country.id})}" class="btn btn-primary editModalBtn" data-toggle="modal" data-target="#editModal">Edit</a>
</div>
</td>
</tr>
</table>
The bootstrap form:
<div class="modal fade" id="editModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">New message</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<!--the action attribute of the from indicates to where the form is gonna be submitted-->
<form th:action="#{/countries/update/{id} (id =${countryToUpdate.id})}" method="post" th:object="${countryToUpdate}">
<div class="form-group">
<label for="descriptionEdit" class="col-form-label">Description</label>
<!--name should correspond to the fields in the modal class-->
<input
type="text"
class="form-control"
id="descriptionEdit"
name="description"
>
</div>
<div class="form-group">
<label for="capitalEdit" class="col-form-label">Capital</label>
<input type="text"
class="form-control"
id="capitalEdit"
name="capital"
>
</div>
<div class="form-group">
<label for="codeEdit" class="col-form-label">Code</label>
<input type="text"
class="form-control"
id="codeEdit"
name="code"
>
</div>
<div class="form-group">
<label for="continentEdit" class="col-form-label">Continent</label>
<input type="text"
class="form-control"
id="continentEdit"
name="continent"
>
</div>
<div class="form-group">
<label for="nationalityEdit" class="col-form-label">Nationality</label>
<input type="text"
class="form-control"
id="nationalityEdit"
name="nationality"
>
</div>
<div class="modal-footer">
<!--submit type button should be within the form to execute the query-->
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Update</button>
</div>
</form>
</div>
</div>
</div>
</div>
My controller:
#GetMapping("countries")
public String findAll(Model model){
List<Country> listOfCountries = countryService.findAll();
model.addAttribute("countries", listOfCountries);
return "country";
}
#GetMapping("countries/findById/{id}")
#ResponseBody
public Country findById(#PathVariable int id, Model mod)
{
Country country = countryService.findById(id).get();
//I want to create a countryToUpdate attribute to use it in the modal form
mod.addAttribute("countryToUpdate", country);
return country;
}
#GetMapping("countries")
public String findAll(Model model){
List<Country> listOfCountries = countryService.findAll();
model.addAttribute("countries", listOfCountries);
return "country";
}
#PostMapping(value="countries/update/{id}")
public String update(#ModelAttribute("countryToUpdate") Country country, #PathVariable int id) {
//Get the country object from database through the passed id
Optional<Country> c = countryService.findById(id);
c.get().setDescription(country.getDescription());
c.get().setContinent(country.getContinent());
c.get().setCode(country.getCode());
c.get().setCapital(country.getCapital());
c.get().setNationality(country.getNationality());
System.out.println("this country description is " + country.getDescription());
countryService.save(c.get());
return "redirect:/countries";
}
Any help would be appreciated.

Spring MVC; error messages of validation form not being displayed

I have built a form for login. I've read about validations with spring mvc following a tutorial.
The form is blank & doesn't pass values, however it doesn't show any error messages.
This is my code for the controller:
#Controller
public class LoginController {
#RequestMapping("/login")
public ModelAndView login() {
return new ModelAndView("login", "user", new UserModel());
}
#RequestMapping("/submitLogin")
public ModelAndView submitLogin(#Valid UserModel user, BindingResult result) {
ModelAndView model = new ModelAndView();
model.addObject("user", user);
model.setViewName(result.hasErrors() ? "login" : "index");
return model;
}
}
This is my model:
#Data
public class UserModel {
#NotBlank(message = "The field login name is required")
private String login;
#NotBlank(message = "The field password is required")
private String password;
}
And this is my form:
<mvc:form modelAttribute="user" class="col s12" action="/submitLogin" method="POST">
<div class="container login-form">
<div class="row">
<div class="input-field col s12">
<mvc:input path="login" id="userName" type="text" class="validate" />
<mvc:label path="login" for="userName">Login name</mvc:label>
</div>
</div>
<div class="row">
<mvc:errors path="login" cssStyle="color: #ff0000;"/>
</div>
<div class="row">
<div class="input-field col s12">
<mvc:input path="password" id="password" type="password" class="validate" />
<mvc:label path="password" for="password">Password</mvc:label>
</div>
</div>
<div class="row">
<mvc:errors path="password" cssStyle="color: #ff0000;"/>
</div>
<div class="row">
<input type="submit" class="btn waves-effect waves-light pulse green" value="Entrar"/>
</div>
</div>
</mvc:form>
Did I miss any configuration on spring boot or annotation?

How to display error message from custom validation on thymeleaf page

Similar question is posted here-> Spring + Thymeleaf custom validation display but I could not figure out the solution so posting this new question.
I have a simple registration form having username,email, password and confirmPassword fields
<form action="#" th:action="#{/register}" th:object="${user}"
method=post>
<!--error detection start -->
<div class="alert alert-danger" th:if="${#fields.hasErrors('*')}">
<p th:each="err : ${#fields.errors('*')}" th:text="${err}"></p>
</div>
<!--error detection ends -->
<div class="form-group input-group">
<div class="input-group-prepend">
<span class="input-group-text"> <i class="fa fa-user"></i>
</span>
</div>
<input name="username" th:field="*{username}" class="form-control"
placeholder="User Name" type="text">
</div>
<div class="form-group input-group"
th:if="${#fields.hasErrors('username')}" th:errors="*{username}">Name
Error</div>
<!-- form-group// -->
<div class="form-group input-group">
<div class="input-group-prepend">
<span class="input-group-text"> <i class="fa fa-envelope"></i>
</span>
</div>
<input name="email" th:field="*{email}" class="form-control"
placeholder="Email address" type="email">
</div>
<div class="form-group input-group"
th:if="${#fields.hasErrors('email')}" th:errors="*{email}">Name
Error</div>
<div class="form-group input-group">
<div class="input-group-prepend">
<span class="input-group-text"> <i class="fa fa-lock"></i>
</span>
</div>
<input class="form-control" th:field="*{password}"
placeholder="Create password" type="password">
</div>
<!-- form-group// -->
<div class="form-group input-group">
<div class="input-group-prepend">
<span class="input-group-text"> <i class="fa fa-lock"></i>
</span>
</div>
<input class="form-control" th:field="*{confirmPassword}"
placeholder="Repeat password" type="password">
<p class="error-message"
th:each="error: ${#fields.errors('user.confirmPassword')}"
th:text="${error}">Validation error</p>
</div>
<!-- form-group// -->
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block">
Create Account</button>
</div>
<!-- form-group// -->
<p class="text-center">
Have an account? Log In
</p>
</form>
I added a custom validation which gets trigger when password and confirm password field do not match.
1.FieldsValueMatchValidator
public class FieldsValueMatchValidator implements ConstraintValidator<FieldsValueMatch, Object> {
private String field;
private String fieldMatch;
public void initialize(FieldsValueMatch constraintAnnotation) {
this.field = constraintAnnotation.field();
this.fieldMatch = constraintAnnotation.fieldMatch();
}
public boolean isValid(Object value, ConstraintValidatorContext context) {
Object fieldValue = new BeanWrapperImpl(value).getPropertyValue(field);
Object fieldMatchValue = new BeanWrapperImpl(value).getPropertyValue(fieldMatch);
if (fieldValue != null) {
return fieldValue.equals(fieldMatchValue);
} else {
return fieldMatchValue == null;
}
}
}
3.FieldsValueMatch
#Constraint(validatedBy = FieldsValueMatchValidator.class)
#Target({ ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
public #interface FieldsValueMatch {
String message() default "Fields values don't match!";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String field();
String fieldMatch();
#Target({ ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
#interface List {
FieldsValueMatch[] value();
}
}
4.User.java
#FieldsValueMatch(field = "password", fieldMatch = "confirmPassword", message = "Passwords do not match!")
#Entity
public class User implements UserDetails
{
#NotBlank
private String password;
#Transient
#NotBlank
private String confirmPassword;
//other getters and setters
}
5.Controller code
#PostMapping("/register")
public String saveNonJsonData(#Valid #ModelAttribute("user") User theUser, BindingResult errors) {
if (errors.hasErrors()) {
return "register";
}
else
{
//successlogic
}
Custom validator is working fine and i can see the error message on the page using following code on thymeleaf page
<!--error detection start -->
<div class="alert alert-danger" th:if="${#fields.hasErrors('*')}">
<p th:each="err : ${#fields.errors('*')}" th:text="${err}"></p>
</div>
<!--error detection ends -->
As mentioned here - Spring + Thymeleaf custom validation display the problem is custom validator returning an ObjectError for password field match validation and not a fieldError. Even though I tried solution provided I can't figure out how to get Thymeleaf to display my custom error.
UPDATE
Got one more answer here Displaying "Passwords don't match" custom annotation message and now i can see the error message using following code
<input class="form-control" th:field="*{confirmPassword}" placeholder="Repeat password" type="password">
<div class="form-group input-group" th:if="${#fields.hasErrors('global')}" th:errors="*{global}"></div>
My updated question if I have two more fields for example 'email' and 'confirmEmail' field then how this approach will work on thymeleaf page?

How tell the view an error has occured from controller? (Spring MVC)

How can I say trigger error/validation messages in the view from the controller in a better way? Currently, I do this by sending boolean attributes. For example, in creating a product, I have two possible errors. Invalid format of UPC of a product, or duplicate upc. I also have a validati
#RequestMapping("/createProduct")
public String createProduct(Model model, #RequestParam(value = "name") String name,
#RequestParam(value = "upc") String upc, #RequestParam(value = "category") String categoryName,
#RequestParam(value = "description") String description, #RequestParam(value = "price") BigDecimal price,
#RequestParam(value = "stock") int stock){
model.addAttribute("activeTab", 3);
if(Validator.invalidUpcFormat(upc)){
model.addAttribute("invalidFormat", true); //trigger for invalid format
return "management";
}
Category category = productService.getCategory(categoryName);
Product product = new Product(upc, category, name, description, price);
InventoryProduct inventoryProduct = new InventoryProduct(product, stock);
try {
managerService.add(inventoryProduct);
model.addAttribute("productCreated", true);
} catch (DuplicateProductException e) {
model.addAttribute("upc", upc);
model.addAttribute("duplicateProduct", true); // trigger for duplicate product
}
return "management";
}
And here is my view:
<div id="menu3"
class="tab-pane fade <c:if test="${activeTab == 3}">in active</c:if>">
<div class="container-fluid" style="padding: 2%;">
<div class="row">
<div class="col-md-12"
style="padding-left: 15%; padding-right: 15%;">
<c:if test="${productCreated}">
<div class="alert alert-success fade in">
<a href="#" class="close" data-dismiss="alert"
aria-label="close">×</a> <strong>Success!</strong>
Product has been created!
</div>
</c:if>
<c:if test="${duplicateProduct}">
<div class="alert alert-warning fade in">
<a href="#" class="close" data-dismiss="alert"
aria-label="close">×</a> <strong>Oh no!</strong>
Product with the UPC ${upc} already exists!
</div>
</c:if>
<c:if test="${invalidFormat}">
<div class="alert alert-warning fade in">
<a href="#" class="close" data-dismiss="alert"
aria-label="close">×</a> <strong>Oops!</strong>
Invalid UPC format!
</div>
</c:if>
<form
action="${pageContext.request.contextPath}/manager/createProduct"
method="post">
<div class="form-group">
<label for="Name">Name </label> <input type="text" name="name"
class="form-control" required />
</div>
<div class="form-group">
<label for="UPC">UPC </label> <input type="number" name="upc"
class="form-control" required />
</div>
<div class="form-group">
<div class="form-group">
<label for="category">Category</label> <select
class="form-control" name="category" required>
<option selected disabled value="">SELECT CATEGORY</option>
<c:forEach items="${categories}" var="item">
<option>${item.getName()}</option>
</c:forEach>
</select>
</div>
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea class="form-control" rows="5" name="description"></textarea>
</div>
<div class="form-group">
<label for="price">Price </label> <input type="number"
name="price" class="form-control" required />
</div>
<div class="form-group">
<label for="stock">Stock </label> <input type="number"
name="stock" class="form-control" required />
</div>
<button type="submit" class="btn btn-primary">Add
product</button>
</form>
</div>
</div>
</div>
</div>
Is there a better of doing this other than sending boolean triggers?
You could use Spring BindingResult. This is typical filled with the result of Binding and Validation results. But you can also add errors by hand.
But first you need to refactor your code, so that you use an single command/form-backing object instead of all the #Param values
public class CreateProductCommand {
private String name;
private String upc;
private String categoryName;
.... //other fields
public CreateProductCommand (){} //parameter less conturctor
Getter+Setter
}
Controller
#RequestMapping("/createProduct")
public ModelAndView createProduct(CreateProductCommand createProductCommand, BindingResult bindingResult) //Binding result must be the parameter direct next to the object that should been validated!!!
{
if (someustomValidationForUcpFail()) {
bindingResult.rejectValue("upc", //the field name of the invalid field
"error.Message.Key",
"Default Error Message");
}
if (bindingResult.hasErrors()) {
ModelMap model = new ModelMap();
model.add("createProductCommand", createProductCommand);
return new ModelAndView("createForm", model)
} else {
Product product = ...
return new ModelAndView("showProduct", "product", product)
}
}
jsp:
You need to use springs form and input tag:
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:springForm="http://www.springframework.org/tags/form"
version="2.0">
....
<springForm:form action="<c:url value="/manager/createProduct">" method="POST" modelAttribute="createProductCommand">
<springForm:input path="name"/> <form:errors path="name" />
<springForm:input path="ucp"/> <form:errors path="ucp" />
....
</springForm:form>
....

400 the request sent by the client was syntactically incorrect

I have gone through so many examples of this nature and proposed solutions from this site, but none of the solutions provided thereon apply to my problem. I believe that this error message, 400, shows up when the information sent to the controller is mulformed. I spent the last two days cross referrencing to another project I worked on in the past, which works, but I cannot pick up the problem.
#RequestMapping(value = {"/", "/home"}, method = RequestMethod.GET)
public String homePage(ModelMap model) {
model.addAttribute("user", getPrincipal());
Catalog catalog = catalogService.getCatalogByCategory(Catalog.CatalogCategory.ALL);
model.addAttribute("catalog", catalog);
return "welcome";
}
This sends the data to a JSTL Spring form on my JSP as follows:
<form:form method="POST" modelAttribute="catalog">
<form:hidden path="id"/>
<form:hidden path="name"/>
<form:hidden path="category"/>
<form:hidden path="orderItems"/>
<div id="products" class="row list-group">
<c:forEach var="orderItem" items="${catalog.orderItems}">
<div class="item col-xs-4 col-lg-4">
<div class="thumbnail">
<img class="group list-group-image" src="http://placehold.it/400x250/000/fff" alt=""/>
<div class="caption">
<h4 class="group inner list-group-item-heading">
${orderItem.name}</h4>
<p class="group inner list-group-item-text">
${orderItem.description}
</p>
<div class="row">
<div class="col-xs-12 col-md-6">
<p class="lead">
R ${orderItem.price}</p>
</div>
<div class="col-xs-12 col-md-6">
<label for="${orderItem.id}" class="btn btn-primary">Add to Cart <input
type="checkbox" id="${orderItem.id}" name="orderItem.addedToCart"
class="badgebox"><span class="badge">&check;</span></label>
</div>
</div>
</div>
</div>
</div>
</c:forEach>
</div>
<div class="row">
<div class="form-group">
<div class="col-sm-12 pull-right">
</div>
<div class="col-sm-2 pull-right">
<input type="submit"
class="btn btn-default btn-block btn-primary"
value="Next" name="action" formmethod="POST"
formaction="confirmList"/>
</div>
</div>
</div>
</form:form>`
At this point I submit the form to the following listener in my controller:
#RequestMapping(value = "/confirmList", method = RequestMethod.POST)
public String confirmList(#ModelAttribute Catalog catalog, #ModelAttribute String numberOfItemsAdded) {
List<OrderItem> selectedItems = new ArrayList<OrderItem>();
for (OrderItem orderItem : catalog.getOrderItems()) {
if (orderItem.isAddedToCart()) {
selectedItems.add(orderItem);
}
}
//model.addAttribute("numberOfItemsAdded", selectedItems.size());
return "welcome";
}
That's it, execution flow does NOT even reach back my controller. Exhausting bug because I really do not understand what I am doing wrong here. Thank you in advance
EDIT:
Catalog.java
#Entity
#Table(name="Catalogs")
public class Catalog{
private long id; //generated value using hibernate ...
private String name; //column annotated by #Column
private String category;// column also annotated by #Column
private List<OrderItem> orderItems;// one to many mapping
//getters and setters here
}
I tested your code and I got HTTP 400 too. The thing is that what browser sends does not match whith what the controller method confirmList expects:
This is the form data I saw in Chrome's network tab:
id:1
name:the catalog
category:category
orderItems:[com.eej.ssba2.model.test.catalog.OrderItem#82ea8a, com.eej.ssba2.model.test.catalog.OrderItem#f441ae, com.eej.ssba2.model.test.catalog.OrderItem#40a13, com.eej.ssba2.model.test.catalog.OrderItem#1316c95, com.eej.ssba2.model.test.catalog.OrderItem#1cfc05a, com.eej.ssba2.model.test.catalog.OrderItem#5d725c, com.eej.ssba2.model.test.catalog.OrderItem#ff32b9, com.eej.ssba2.model.test.catalog.OrderItem#5b49a4, com.eej.ssba2.model.test.catalog.OrderItem#13faf31, com.eej.ssba2.model.test.catalog.OrderItem#6d64d]
orderItem.addedToCart:on
orderItem.addedToCart:on
orderItem.addedToCart:on
orderItem.addedToCart:on
action:Next
But controller cannot understand this, as OrderItems shows a toString() of each OrderItem instance and the addedToCart is not binded to any orderItem of the orderItems list.
You must modify your jsp this way:
<form:form method="POST" modelAttribute="catalog">
<form:hidden path="id"/>
<form:hidden path="name"/>
<form:hidden path="category"/>
<!-- form:hidden path="orderItems"/-->
<div id="products" class="row list-group">
<c:forEach var="orderItem" items="${catalog.orderItems}" varStatus="status">
<div class="item col-xs-4 col-lg-4">
<div class="thumbnail">
<img class="group list-group-image" src="http://placehold.it/400x250/000/fff" alt=""/>
<div class="caption">
<h4 class="group inner list-group-item-heading">
${orderItem.name}</h4>
<form:hidden path="orderItems[${status.index}].name" />
<p class="group inner list-group-item-text">
${orderItem.description}
<form:hidden path="orderItems[${status.index}].description" />
</p>
<div class="row">
<div class="col-xs-12 col-md-6">
<p class="lead">
R ${orderItem.price}</p>
<form:hidden path="orderItems[${status.index}].price" />
</div>
<div class="col-xs-12 col-md-6">
<label for="${orderItem.id}" class="btn btn-primary">Add to Cart <input
type="checkbox" id="${orderItem.id}" name="catalog.orderItems[${status.index}].addedToCart"
class="badgebox"><span class="badge">&check;</span></label>
</div>
</div>
</div>
</div>
</div>
</c:forEach>
</div>
<div class="row">
<div class="form-group">
<div class="col-sm-12 pull-right">
</div>
<div class="col-sm-2 pull-right">
<input type="submit"
class="btn btn-default btn-block btn-primary"
value="Next" name="action" formmethod="POST"
formaction="confirmList"/>
</div>
</div>
</div>
</form:form>
If you do so, you could see the message changes in Chrome's network tab (or the browser you are using). This is the form data right now:
id:1
name:the catalog
category:category
orderItems[0].name:OrderItemName#0
orderItems[0].description:OrderItemDesc#0
orderItems[0].price:0.0
orderItems[1].name:OrderItemName#1
orderItems[1].description:OrderItemDesc#1
orderItems[1].price:0.43645913001303904
orderItems[2].name:OrderItemName#2
orderItems[2].description:OrderItemDesc#2
orderItems[2].price:1.7151992716801088
orderItems[3].name:OrderItemName#3
orderItems[3].description:OrderItemDesc#3
orderItems[3].price:1.303683806806788
orderItems[4].name:OrderItemName#4
orderItems[4].description:OrderItemDesc#4
orderItems[4].price:2.507039003743686
orderItems[5].name:OrderItemName#5
orderItems[5].description:OrderItemDesc#5
orderItems[5].price:3.173744751378154
orderItems[6].name:OrderItemName#6
orderItems[6].description:OrderItemDesc#6
orderItems[6].price:3.183771167856446
catalog.orderItems[6].addedToCart:on
orderItems[7].name:OrderItemName#7
orderItems[7].description:OrderItemDesc#7
orderItems[7].price:6.73370053587355
catalog.orderItems[7].addedToCart:on
orderItems[8].name:OrderItemName#8
orderItems[8].description:OrderItemDesc#8
orderItems[8].price:2.0266022634803216
orderItems[9].name:OrderItemName#9
orderItems[9].description:OrderItemDesc#9
orderItems[9].price:5.251986962977732
catalog.orderItems[9].addedToCart:on
action:Next
And you would see now it returns a HTTP 200 as the request in fact reaches your controller. Delete the #ModelAttribute in your controller method too, as you have been suggested to:
#RequestMapping(value = "/confirmList", method = RequestMethod.POST)
public String confirmList(Catalog catalog, String numberOfItemsAdded) {
List<OrderItem> selectedItems = new ArrayList<OrderItem>();
for (OrderItem orderItem : catalog.getOrderItems()) {
if (orderItem.isAddedToCart()) {
selectedItems.add(orderItem);
}
}
//model.addAttribute("numberOfItemsAdded", selectedItems.size());
return "catalog";
}
try this extra handle in your Controller and Check your Console,
#ExceptionHandler(MissingServletRequestParameterException.class)
public void handleMissingRequestParams(MissingServletRequestParameterException ex) {
System.out.println();
System.out.println("------------------------MissingServletRequestParameterException------------------------");
System.out.println(" Parameter name:- "+ex.getParameterName());
System.out.println(" Parameter Type:- "+ex.getParameterType());
System.out.println(" Cause:- "+ex.getCause());
System.out.println(" LocalizedMessage:- "+ex.getLocalizedMessage());
System.out.println(" Message:- "+ex.getMessage());
System.out.println(" RootCause:- "+ex.getRootCause());
System.out.println("-------------------------------********************-----------------------------");
}
Edit
#kholofelo Maloma I can't see the variable numberOfItemsAdded in your jsp
AND i never used #ModelAttribute String numberOfItemsAdded to String parameter plz check this in documentation, I think it is used along with Bean, plz confirm
rather use #RequestParam
Read Documentation Here
It clears me
Sorry for above handle,
Note however that reference data and all other model content is not available to web views when request processing results in an Exception since the exception could be raised at any time making the content of the model unreliable. For this reason #ExceptionHandler methods do not provide access to a Model argument.

Resources