Spring 3: Select value to enum value mapping - spring

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) {
...
}

Related

java.lang.NullPointerException: null on a list that existed in database

So here's my code
Controller
#GetMapping("/faskes/tambah")
public String addFaskesForm(Model model){
List<VaksinModel> listVaksin = vaksinService.getVaksinList();
model.addAttribute("faskes", new FaskesModel());
model.addAttribute("listVaksin", listVaksin);
return "form-add-faskes";
}
HTML
<select name="vaksin" >
<option th:each="vaksin : ${listVaksin}"
th:value="${vaksin.idVaksin}"
th:text="${vaksin.jenisVaksin}">
</option>
</select>
The listVaksin is found to be null. Can someone point out my mistake? thank you so much in advance.

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

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

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"

Spring Thymeleaf th:selected on EnumList with multiple selection

I have this enum
enum Types{
A, B
}
I have a form class
public class MyForm {
private Types[] types;
//getter setters
}
here is my form with select
<form th:action="${#httpServletRequest.requestURI}" th:object="${myForm}" method="POST" id="form">
<select name="types" multiple="" id="testSelect"
th:each="type : ${T(com.test.Types).values()}"
th:value="${type}"
th:text="${type}"
th:selected="*{types != null AND #arrays.contains(types, type)}"
>
</select>
</form>
here is the error i am getting.
Property or field 'type' cannot be found on object of type 'com.test.MyForm' - maybe not public or not valid?
First, I believe you have a typo, it should be type != and not types !=. Also, you are using * in your selected, instead of $. Also, I believe you are using #list.contains() of Thymeleaf in a way that shouldn't work. You should use the whole function, just like this #list.contains(types, type). One last thing, the selected, value and text tags should should go in the option element, not the select. In the end your code should look like the following one.
<select name="types" multiple="" id="testSelect">
<option th:each="type : ${T(com.test.Types).values()}"
th:value="${type}" th:text="${type}"
th:selected="${types != null AND #arrays.contains(types, type)}">
</option>
</select>
One last thing, I am not sure where did the variable types came from, I am assuming you initialized it somewhere.
The best would be to change your form backing bean to have some collection of your enumerations, instead of array such as:
public class MyForm {
private List<Types> types = new ArrayList<Types>();
//getter setters
}
Then before you render the form, you can just fill this array with types, which you want to be preselected in the controller just by adding them to the list.
Then should be able to simply skip th:selected logic...
<select th:field="*{types}" multiple="multiple" id="testSelect">
<option th:each="type : ${T(com.test.Types).values()}"
th:value="${type}" th:text="${type}">
</option>
</select>
Thymeleaf will do the magic for you ;-)

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.

Resources