In Spring boot and thymeleaf dropdown select option, I have = the server responded with a status of 404 () thymeleaf select option + oneTomany form - spring-boot

I am new to thymeleaf and stuck with this error :404 when I save the new record of the table "Pret" (add). In the class form, I can selecte the title of the "Livre" and the name of the "Lecteur". And then my addPret.html is desinged as.
<form th:action="#{SavePret}" method="post"
th:object="${pretFormulaire}">
<select th:field="*{livre}">
<option th:each="livre:${listLivres}"
th:value="${livre}"
th:text="${livre.titre}">
</option>
</select>
<select th:field="*{lecteur}">
<option th:each="lecteur:${listLecteurs}"
th:value="${lecteur}" th:text="${lecteur.nom}">
</option>
</select>
<button type="submit" >Save</button>
</form>
And here the controller first method signature :
#RequestMapping(value = "/form", method = RequestMethod.GET)
public String formPret(Model model) {
Pret pretFormulaire=new Pret();
model.addAttribute("pretFormulaire", pretFormulaire);
List<Lecteur> listLecteurs=lecteurRepository.findAll();
List<Livre> listLivres=livreRepository.findAll();
model.addAttribute("listLecteurs", listLecteurs);
model.addAttribute("listLivres", listLivres);
return "Form";
}
The controller method of savePret is like this :
#PostMapping(value = "/savePret")
public String savePret2(#Valid #ModelAttribute("pret")
Pret pret, BindingResult bindingResult,
Long livre_id, Long lecteur_id){
Livre livre=livreRepository.findOne(livre_id);
Lecteur lecteur=lecteurRepository.findOne(lecteur_id);
livre.setNbFoisPret(livre.getNbFoisPret()+1);
livre.setDisponible(livre.getDisponible()+"Non");
pret.setLecteur(lecteur);
pret.setLivre(livre);
pret.setDatePret(new Date());
pretRepository.save(pret);
return "redirect:Index";
}
Could anyone please help?

<form th:action="#{SavePret}" method="post"
should be
<form th:action="#{/savePret}" method="post"

Related

How to use HttpServletRequest and HttpServletResponse in Thymeleaf?

When I click in A tag, it doesn't respond or return anything. I'm using Thymeleaf 5 and spring boot 2.
When I change href to "${'/?sortByPrice='+'ASC'}", it still has same result.
Please, help me.
<div class="sort-price">
<select name="">
<option value="" selected="selected">sort</option>
<option value=""><a th:href="${'/?sortByPrice='+ASC}">ASC</a></option>
<option value=""><a th:href="${'/?sortByPrice='+DESC}">DESC</a></option>
</select>
</div>
#GetMapping(value = "")
public String home(
Model model,
#Valid #ModelAttribute("productname")ProductVM productName,
#RequestParam(name = "page", required = false, defaultValue = "0") Integer page,
#RequestParam(name = "size", required = false, defaultValue = "10") Integer size,
#RequestParam(name = "sortByPrice", required = false) String sort,
HttpServletResponse response,
HttpServletRequest request,
final Principal principal)
{
this.checkCookie(response,request,principal);
HomeVM homeVM = new HomeVM();
// sort price of the product in home page
Sort sort1 = by(Sort.Direction.DESC, "id");
if(sort != null) {
if (sort.equals("ASC"))
sort1 = by(Sort.Direction.ASC,"price");
else
sort1 = by(Sort.Direction.DESC,"price");
}
// product getter setter
model.addAttribute("vm",homeVM);
model.addAttribute("page",productPage);
return "/home";
}
<a> in select option doesnt work. One approach is to have a <form> tag and your filters inside that:
<form method="GET" action="">
<select name="sortByPrice">
<option value="">Select</option>
<option value="ASC">ASC</option>
<option value="DESC">DESC</option>
</select>
<button type="submit">Sort</button>
</form>
In this way when you click on Sort form will be submitted to the URL present in the browser with the params present in the form

Form with a select (drop-down) doesn't show error code

I have a form that contains a select to list all teachers by id in the system but it is not working properly.
Here is the code part of the form
and the corresponding path controller requests
I'm Using Thymeleaf and Spring Boot, so 'pr' corresponds a name for a variable of a repository of teachers.
<form th:action="#{/professor/updateProfessor/}" method="post" th:object="${professor}">
<div class= "form-group">
<label th:for = "id">Id</label>
<select th:field="*{id}">
<option
th:value = "${id}"
th:text = "${professor.id}">
</option>
</select>
</div>
<input type = "submit" value = "Add Professor">Save</button>
</form>
#GetMapping(value = {"/selecionaProfessor"})
#ResponseBody
public ModelAndView professorSelecao(){
ModelAndView atualizaProfessor = new ModelAndView("/atualizaProfessor");
atualizaProfessor.addObject("Add Professor");
return atualizaProfessor;
}
#PostMapping(value = {"/selecionaProfessor"})
#ResponseBody
public ModelAndView selecaoProfessor(){
ModelAndView pagSucesso = new ModelAndView("/pagSucesso");
pagSucesso.addObject(pr.findAll());
return pagSucesso;
}
From your controller, send a list of professors as per following to your view. Here you are associating the list of professors to the "professorList" :
model.addAttribute("professorList", pr.findAll());
And then to access above "professorList" in your thymeleaf do (similar to) this :
<option th:each="professor: ${professorList}" th:value="${professor}"> </option>
Not a full code but i hope you got the idea to get started.
For a full example, take a look here and here.
First of all what is not working? because I see a lot of things that may not work maybe because I don't see the all code or I am guessing some things, let's see
When you enter to your controller using
localhost:8080/professor/selecionaProfessor
are you expecting to use the form you put right? (the next code)
<form th:action="#{/professor/updateProfessor/}" method="post" th:object="${professor}">
<div class= "form-group">
<label th:for = "id">Id</label>
<select th:field="*{id}">
<option
th:value = "${id}"
th:text = "${professor.id}">
</option>
</select>
</div>
<input type = "submit" value = "Add Professor">Save</button>
</form>
because if that's correct you have a problem in your method:
#GetMapping(value = {"/selecionaProfessor"})
#ResponseBody
public ModelAndView professorSelecao(){
ModelAndView atualizaProfessor = new ModelAndView("/atualizaProfessor");
atualizaProfessor.addObject("Add Professor");
return atualizaProfessor;
}
you will get an error saying:
Neither BindingResult nor plain target object for bean name 'professor' available as request attribute
So you're missing to add the Key professor and a List so change:
atualizaProfessor.addObject("Add Professor");
with something like:
atualizaProfessor.addObject("professor", someListOfProfessorHereFromTheService (List<Professor>));
and it should work if your profesor object have the attributes you have on your form.
Now let's suppose that that worked before and the error wasn't that.
When you enter to your form if you see here:
form th:action="#{/professor/updateProfessor/}"
you're using updateProfessor I don't see that on your controller you have
#PostMapping(value = {"/selecionaProfessor"})
So I think that you should change the url mapping inside the html page or the controller and use the same as error 1, map the object using a key and value and iterate the list into the html as I showed in the 1st error
Hope it helps

How to send String[] from Thymeleaf multiple select form to Controller

I have a template with a form:
<h2>Favorite States</h2>
<form action="#" th:action="#{/states}" name="states" method="post">
<select class="js-example-basic-multiple" multiple="multiple" style="width: 60%">
<option th:each="state: ${states}" th:utext="${state.name}"></option>
</select>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
I want to get a String[] back from this form, for example if user selected NY, CA, MA states, I want to get String[] selectedStates = {"NY", "CA", "MA"}; in my post map Controller. How can I do that?
I have tried
#GetMapping(path="/states")
public #ResponseBody String statesList (#RequestParam String[] name) {
}
But it says required parameter is not received.
Thank you!
You can convert the javascript array to JSON using below code.
JSON.stringify(array);
And in controller, accept it as String parameter and then convert it back to array using Jackson library as below:
ObjectMapper mapper = new ObjectMapper();
String [] array = mapper.readValue(jsonString, String[].class):
You can wrap it and pass as a model attribute

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.

Spring 3: Select value to enum value mapping

I have a very simple scenario to handle. An enum is created to represent a set of options for select control. The select control needs to have a prompt mapped to '-' as the prompt value. The corresponding enum does not have this dash. When page is submitted with select control still sitting at the prompt, exception is thrown. How do you handle such cases?
Page:
<select id="filterUserAccessLevel" name="filterUserAccessLevel">
<option value="-">Select Value</option>
<option value="DEPOSITOR">Depositor</option>
<option value="READER">Reader</option>
<option value="AUTHOR">Author</option>
<option value="EDITOR">Editor</option>
<option value="ADMINISTRATOR">Administrator</option>
</select>
<input type="submit" name="resetFilter" value="<spring:message code="common.filterResetButtonLabel" />" />
UserAccessLevel enum:
public enum UserAccessLevel {
DEPOSITOR("DEPOSITOR"),
READER("READER"),
AUTHOR("AUTHOR"),
EDITOR("EDITOR"),
ADMINISTRATOR("ADMINISTRATOR");
private String code;
private UserAccessLevel(String code) {
this.code=code;
}
public String getCode() {
return this.code;
}
}
Controller:
#RequestMapping(value="/userIndex/", method=RequestMethod.POST, params="resetFilter")
public void resetFilter(#ModelAttribute("userIndexBean") UserIndexBean bean, Model model) {
System.out.println("resetFilter()");
bean.resetFilterSection();
loadBean(1, bean, model);
}
Exception:
Field error in object 'userIndexBean' on field 'filterUserAccessLevel': rejected value [-];
Why is necessary an option mapped to "-"? Can't it be just an empty String?
In this case, I think that the simplest solution is:
<option value="">Select Value</option>
.
#RequestMapping("userIndex")
public void resetFilter(#RequestParam(required = false) UserAccessLevel filterUserAccessLevel) {
...
}

Resources