Validation messages don't show in Thymeleaf - kotlin - spring boot - spring-boot

I return the template of a form with this controller suspend method:
#GetMapping("/checkout/customer")
suspend fun checkoutCustomerView(model: Model): String {
model["cart"] = shoppingCartService.getShoppingCartWithItems()
model["checkout"] = checkoutService.getCheckout()
return "checkout/checkoutCustomer"
}
I post form data with:
#PostMapping("/checkout/customer")
suspend fun updateCustomerData(
request: ServerHttpRequest,
response: ServerHttpResponse,
model: Model,
#Valid #ModelAttribute customerData: CheckoutCustomerData,
bindingResult: BindingResult
): String {
if (bindingResult.hasErrors()) {
model["cart"] = shoppingCartService.getShoppingCartWithItems()
model["checkout"] = checkoutService.getCheckout()
return "checkout/checkoutCustomer"
}
model["checkout"] = checkoutWizardCookieService.updateCustomerData(customerData, request, response)
return "redirect:/checkout/shipping"
}
the binding gets populated when there's an error, I can see it in debug mode.
Data is:
data class CheckoutCustomerData(
#field:NotBlank
val firstName: String?,
)
and html file is:
<form id="customer-form" th:action="#{/checkout/customer}" th:object="${checkout}"
method="post">
<div class="mb-3 d-flex flex-row">
<input type="text" class="form-control me-3" th:field="*{firstName}" placeholder="First Name">
<p th:if="${#fields.hasErrors('firstName')}"
th:errorclass="invalid-feedback"
th:errors="*{firstName}" >The first name is mandatory</p>
</div>
</form>
when I submit the form without a value for the field "firstName", I should expect some error showing under the input field, which doesn't happen, because the form is considered valid, so #fields.hasErrors() returns false.
I am not sure what I am doing wrong.
I am using Spring Boot Webflux with kotlin and coroutines. Is there some extra configuration due to the reactive nature of the project, maybe?
Thanks
Is

Related

Missing request attribute 'projektId' of type String | Thymleaf Form with just a String

I'm working on a Projekt where you can add workers to projects with their ids.I am using springboot, thymeleaf and a database means you give a project and a worker Id and the programm adds the worker to the project.workerlist. The Problem ist that I get this error:
Required request parameter 'projektId' for method parameter type String is not present
My HTML Form looks like this
<form action="#" th:action="#{neuenMitarbeiterzuProjektHinzufuegen}" method="post">
Projekt ID: <input type="text" th:value="*{projektId}" required/><br>
Mitarbeiter ID: <input type="text" th:value="*{mitarbeiterId}" required/><br>
<br>
<input type="submit" value="Mitarbeiter hinzufügen"/>
<input type="reset" value="Clear"/>
</form>
My Post Route Handler Method looks like this
#PostMapping(value="/neuenMitarbeiterzuProjektHinzufuegen")
public String neuenMitarbeiterzuProjektHinzufuegen(#RequestAttribute(value = "projektId") String projektID, #RequestAttribute(value = "mitarbeiterId") String mitarbeiterID,Model m)
{
Optional<Projekt> projekt = projektRepository.findById(Long.parseLong(projektID));
projektRepository.findById(Long.parseLong(projektID)).get().mitarbeiterHinzufuegen(mitarbeiterRepository.findById(Long.parseLong(mitarbeiterID)).get());
return "redirect:Projekte";
}
Looking at your code example I think you should be using #RequestParam not #RequestAttribute. Param is for things posted from the user (web) side and attribute you can set on the server side.
This blog has some explanation on the difference of #RequestAttribute https://www.logicbig.com/tutorials/spring-framework/spring-web-mvc/request-attribute.html

Problem while posting data in spring boot Rest Api- org.springframework.web.bind.MethodArgumentNotValidException

I am new to spring boot rest api.
I have create a category Rest controller using which i am posting data to my backend mysql database.
I also added spring-jpa and hibernate in my project and its working fine.
When I am posting data using Bootstrap form and JqueryAjax, i am gettting org.springframework.web.bind.MethodArgumentNotValidException in intellij console and 400 in browser console when i am hitting submit button in my form.
my rest cotroller code
private CategoryRepository categoryRepository;
//#GetMapping("/Categories")
#RequestMapping(value="/Categories", method=RequestMethod.GET)
public Page<Category> getAllCategories(Pageable pageable) {
return categoryRepository.findAll(pageable);
}
//#PostMapping("/Categories")
#RequestMapping(value="/Categories", method=RequestMethod.POST)
public Category createCategory( #Valid #RequestBody Category Category) {
return categoryRepository.save(Category);
}
my js-ajax file
$(document).ready(
function() {
// SUBMIT FORM
$("#Cateform").submit(function(event) {
// Prevent the form from submitting via the browser.
event.preventDefault();
ajaxPost();
});
function ajaxPost() {
// PREPARE FORM DATA
var formData = {
CategoryId : $("#CatId").val(),
CategoryName : $("#CatName").val(),
CategoryDescription : $("#Catdesc").val()
}
// DO POST
$.ajax({
type : "POST",
contentType : "application/json",
url : "http://localhost:8080/Categories",
data : JSON.stringify(formData),
dataType : 'json',
success : function(result) {
if (result.status == "success") {
$("#postResultDiv").html(
"" + result.data.CategoryName
+ result.data.CategoryDescription
+ "Post Successfully! <br>"
+ "---> Congrats !!" + "</p>");
} else {
$("#postResultDiv").html("<strong>Error</strong>");
}
console.log(result);
},
error : function(e) {
alert("Error!")
console.log("ERROR: ", e);
}
});
}
})
My Bootstrap form
<form id="Cateform">
<div class="form-group">
<input type="hidden" class="form-control" id="CatId" placeholder="Enter Book Id" name="CategoryId">
</div>
<div class="form-group">
<label for="CatName">Category Name:</label>
<input type="text" class="form-control" id="CatName" name="CategoryName">
</div>
<div class="form-group">
<label for="Catdesc">Category Desc:</label>
<input type="text" class="form-control" id="Catdesc" name="CategoryDescription">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
my category model
#Entity
#Table(name = "Categories")
public class Category extends AuditingModel {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer categoryId;
public String CategoryName;
#NotNull
#Size(max = 250)
public String Description;
//gettter and setters
}
The good thing is that...i am able to post data using swagger-UI and PostMan but i dont know what is happeing when i am posting data using form and getting method argument not valid exception for the my description field of category model.
i have set this field as notnull in model but why its giving error from posting the data from UI and not from Swagger-UI and Postman.
below is the exxact error i get in intellij console when i am hitting submit in form
**
Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public edu.ait.shoppingCart.Dto.Category edu.ait.shoppingCart.Controllers.CategoryController.createCategory(edu.ait.shoppingCart.Dto.Category): [Field error in object 'category' on field 'Description': rejected value [null]; codes [NotNull.category.Description,NotNull.Description,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [category.Description,Description]; arguments []; default message [Description]]; default message [must not be null]] ]
**
browser error
Please note that the problem is variable name miss match. The ajax call sends the CategoryDescription while the entity expects Description also note the case sensitive C on categoryId. Ajax call sends a capital C while the entity was declared with a small letter c

modelAttribute in mustache Templates (Spring-Boot App) / binding form data

I'm working on a Spring-Boot app which handles form data. My question is, if there is a possibility to bind the form data in case of validation errors for example.
My case:
form.mustache:
<form action="/form/basisdata" method="post" name="basisdata">
<label for="contactName">Kontakt / Ansprechpartner*:</label>
<input type="text" name="contactName"/>
<label for="emailAddress">E-Mail-Adresse*:</label>
<input type="text" name="emailAddress"/>
<input type="hidden" name="_csrf" value="{{_csrf.token}}" />
<button class="a-button" type="submit">Weiter</button>
</form
Controller method:
#PostMapping("/basisdata")
public ModelAndView setFormBasisdata(#Valid #ModelAttribute("basisdata") Basisdata basisdata, BindingResult bindingResult, Map<String, Object> model) {
if (bindingResult.hasErrors()) {
List<Error> errorList = getErrors(bindingResult);
model.put("errors" , errorList);
model.put("basisdata", basisdata);
return new ModelAndView("formBasisdata", model);
}
return new ModelAndView("formNextStep", model);
}
In case of validation errors we're returning correctly to the same form page and shows the list of errors. But the form stays empty. I would prefer it, if the form is prefilled with the values that were entered before.
Is returning ModelAndView in that case the wrong option?
In jsp templates using spring forms there is an attribute in the form, that specifies the model (modelAttribute) in thymeleaf it's th:object. Is there something that I need to change / add in my mustache template?

Spring Boot error while submitting form

I'm trying to add a table to the database via a form. The entity being created is called Album and it has 2 fields, Artist and Genre. Each of these two are separate entities. These 2 fields are annotated with #ManyToOne
#ManyToOne
private Artist artist;
#ManyToOne
private Genre genre;
When I submit the form, this is the error im getting:
There was an unexpected error (type=Internal Server Error, status=500).
Error during execution of processor 'org.thymeleaf.spring4.processor.attr.SpringOptionFieldAttrProcessor' (album/add:52)
The following code is part of my controller:
#RequestMapping({"/add", "/add/"})
public String adminAlbumAdd(Model model) {
model.addAttribute("album", new Album());
model.addAttribute("artists", artistService.list());
model.addAttribute("genres", genreService.list());
return "album/add";
}
#RequestMapping( value = "/save", method = RequestMethod.POST )
public String save(#Valid Album album, BindingResult bindingResult, Model model) {
if(bindingResult.hasErrors()) {
model.addAttribute("artists", artistService.list());
model.addAttribute("genres", genreService.list());
return "album/add";
} else {
Album savedAlbum = albumService.save(album);
return "redirect:/album/view/" + savedAlbum.getAlbumId();
}
}
And the following code is part of the thymeleaf template:
<div th:class="form-group" th:classappend="${#fields.hasErrors('artist')}? 'has-error'">
<label class="col-sm-2 control-label">Artist <span class="required">*</span></label>
<div class="col-md-10">
<select class="form-control" th:field="*{artist}">
<option value="">Select Artist</option>
<option th:each="artist : ${artists}" th:value="${artist.artistId}" th:text="${artist.artistFirstName + ' ' + artist.artistFirstName}">Artists</option>
</select>
<span th:if="${#fields.hasErrors('artist')}" th:errors="*{artist}" th:class="help-block">Artist Errors</span>
</div>
</div>
<div th:class="form-group" th:classappend="${#fields.hasErrors('genre')}? 'has-error'">
<label class="col-sm-2 control-label">Genre <span class="required">*</span></label>
<div class="col-md-10">
<select class="form-control" th:field="*{genre}">
<option value="">Select Genre</option>
<option th:each="genre : ${genres}" th:value="${genre.genreName}" th:text="${genre.genreName}">Genres</option>
</select>
<span th:if="${#fields.hasErrors('genre')}" th:errors="*{genre}" th:class="help-block">Genre Errors</span>
</div>
</div>
What is causing this error ?
The issue turned out to be related to the repository. I was extending CrudRepository, but the id was of type int. Once i changed that, it worked.
Firstly, you might consider using same mapping for GET/POST requests as a standard like:
#GetMapping("/new")
...
#PostMapping("/new")
Also #Valid Album album parameter should be annotated as #ModelAttribute.
You should not add model attributes if binding result has errors. (Actually, you should not add any model attribute for a POST method.)
You should not create that savedAlbum object with albumService.save().
That method should be void.
I will advise against posting directly to your database object. You should rather create a DTO class, say AlbumDto, that will map the classes like so:
public class AlbumDto {
...
private long genreId;
private long artistId;
// Getters & Setters
}
You can then convert it to your Album object, lookup the corresponding Genre and Artist in your controller, set them on the Album object and then save.

Why this Spring MVC controller method can't handle this POST Request (Content type 'application/x-www-form-urlencoded' not supported)

I am working on a Spring MVC application and I have the following problem.
Into a FreeMarker view (but is not so important that the view is made using FreeMarker) I have this form:
<form id="reg-form" name="reg-form" action="<#spring.url '/iscrizioneStep2' />" method="post">
<fieldset>
<div class="form-group">
<label for="cf">Codice fiscale:</label>
<input type="text" id="cf" name="codiceFiscale" class="form-control input-mm" placeholder="Inserisci il tuo codice fiscale" data-validation="[NOTEMPTY, NOSPACE, L==16, CF]" data-validation-label="codice fiscale" aria-required="true" tabindex="10">
</div>
<div class="form-group">
<div class="g-recaptcha" data-sitekey="6LcOfhcTAAAAAE3D2hsa3UcyTQ0PI4upcZ759FDa" tabindex="20"></div>
</div>
<button type="submit" class="btn btn-block submit-btn" aria-label="prosegui la registrazione" tabindex="30">Passaggio 2</button>
</fieldset>
</form>
As you can see the form is submittet to this action: action="<#spring.url '/iscrizioneStep2' />" performing a POST request.
This generate a POST request toward this URL (I see it using FireBug):
http://localhost:8080/iam-ssum-public/iscrizioneStep2?codiceFiscale=AAAAAAAAAAAAAAAA&g-recaptcha-response=
So I think that it should send the input field having name="codiceFiscale" into the POST request.
Then I have this controller method:
#RequestMapping(value = "/iscrizioneStep2", method = RequestMethod.POST)
public String iscrizioneStep2(#RequestBody(required = true) IscrizioneStep1Form iscrizioneStep1Form, Model model)
throws APIException {
/*
* Verifica se l'utenza è attivata per il codice fiscale
*/
String codiceFiscale = iscrizioneStep1Form.getCodiceFiscale();
..............................................................
..............................................................
..............................................................
return "myView";
}
So the data sended in the post request should be putted inside the IscrizioneStep1Form iscrizioneStep1Form parameter, that is:
public class IscrizioneStep1Form {
/**
* Codice fiscale
*/
private String codiceFiscale;
public String getCodiceFiscale() {
return codiceFiscale;
}
public void setCodiceFiscale(String codiceFiscale) {
this.codiceFiscale = codiceFiscale;
}
}
But the problem is that this HTTP POST request is not handled by the iscrizioneStep2() method. When I submit the form don't enter into this method and into the Eclipse console I obtain the following error message:
11:55:43,949 WARN [org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver] (http-localhost/127.0.0.1:8080-6) Handler execution resulted in exception: Content type 'application/x-www-form-urlencoded' not supported
Why? What am I missing? How can I fix this issue?
Try to add heders param to your RequestMapping annotation:
#RequestMapping(value = "/iscrizioneStep2", method = RequestMethod.POST,
headers = "content-type=application/x-www-form-urlencoded")
Try to remove #RequestBody(required = true) from your request method.
Here Spring Mvc Rest Webservice jstl form submittion HTTP Status 415 Content type 'application/x-www-form-urlencoded' not supported has the same problem.
There is no built-in converter that knows how to convert content of the type 'application/x-www-form-urlencoded to IscrizioneStep1Form. Simply omit #RequestBody. Form data is automatically mapped to objects.
The problem is that when we use application/x-www-form-urlencoded, Spring doesn't understand it as a RequestBody. So, if we want to use this
we must remove the #RequestBody annotation.
Then try the following:
#RequestMapping(value = "/iscrizioneStep2", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public String iscrizioneStep2(IscrizioneStep1Form iscrizioneStep1Form, Model model) throws APIException {
//method body where
}
Note that removed the annotation #RequestBody
answer: Http Post request with content type application/x-www-form-urlencoded not working in Spring

Resources