Spring mvc - POST request with #ModelAttribute cause unnecessary sql queries - spring

I have a form with three select inputs, which are added from the db in the view. Everything is OK and the user can select for every select. The problem is that when I submit the form, the #ModelAttribute generates the same queries as the GET request (when these three selects are added into the view) and in the same, the select fields are empty after the POST.
#GetMapping("/road-assistance")
public String viewPage(Model model, Locale locale) {
model.addAttribute("roadAssistanceDto", roadAssistanceService.createRoadAssistanceDto(locale, null));
return "admin/roadassistance/view";
}
#PostMapping("/road-assistance")
public String createRoadAssistance(Model model, Locale locale,
final #Valid #ModelAttribute("roadAssistanceDto") RoadAssistanceDto roadAssistanceDto,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return "redirect:/";
}
return "admin/roadassistance/view";
}
Why the #PostMapping generates the same queries and in the same time, I don't have the info in the view/model?
the view -
<div class="row card-pagging">
<div class="col-sm-2 mt-3 offset-sm-2">
<label data-th-text="#{control.panel.roadassistance.country}"
class="control-label"
for="country">Country</label>
<select id="country" data-th-field="*{country}" class="form-control">
<option data-th-each="countryList : ${roadAssistanceDto.countryList}"
data-th-value="${countryList.id}"
data-th-text="${countryList.countryI18n[#locale].name}"></option>
</select>
</div>
<div class="col-sm-3 mt-3">
<label data-th-text="#{control.panel.roadassistance.region}" class="control-label"
for="region">Region</label>
<select data-th-field="*{region}" id="region" class="form-control">
<option value='' data-th-text="#{control.panel.roadassistance.chooseregion}"></option>
<option data-th-each="reg : ${roadAssistanceDto.regionList}" data-th-value="${reg.id}"
data-th-text="${reg.regionI18n[#locale].name}"></option>
</select>
</div>
<div class="col-sm-3 mt-3">
<label data-th-text="#{control.panel.roadassistance.city}" class="control-label"
for="region">City</label>
<select data-th-field="*{city}" id="city" class="form-control">
<option value="" data-th-text="#{control.panel.roadassistance.chooseregion}"></option>
<option data-th-each="city : ${roadAssistanceDto.cityList}" data-th-value="${city.id}"
data-th-text="${city.cityI18n[#locale].name}"></option>
</select>
</div>
</div>
And the RoadAssistanceDto -
public class RoadAssistanceDto implements Serializable {
private Long id;
private Country country;
private Region region;
private City city;
private List<Country> countryList;
private List<Region> regionList;
private List<City> cityList;
/* GETTERS AND SETTERS /*
}
Hm... I think that I notice the problem.. there is something workng when I'm binding the fields in the thymeleaf... but anyway, why is generating these queries?

Related

Binding the select option list

I am currently unsure on how should I be doing this. When the method = RequestMethod.POST, how should I bind the select picker to my object.
This is part of my form
<form th:action="#{/incidentDetail/update}" method="post" id="incidentDetailForm">
<div class="form-row">
<div class="form-group col-md-6">
<label for="location">Name</label> <input class="form-control"
type="text" name="ioName" id="ioName" th:value="${incident.ioName}" />
</div>
<div class="form-group col-md-3">
<label for="location" class="cols-sm-2 control-label">Preparation
By</label><span class="bg-danger pull-right"></span>
<div class="cols-sm-10">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-reorder fa"
aria-hidden="true"></i></span> <select class="form-control selectpicker"
th:object="${incident}" th:field="*{incidentPreparationBy}"
id="incidentPreparationBy" name="incidentPreparationBy"
roleId="incidentPreparationBy">
<option th:each="user: ${userList}" th:value="${incident.incidentPreparationBy}"
th:text="${user.name}"></option>
</select>
</div>
</div>
</div>
</form>
My controller
#RequestMapping(value = "/update", method = RequestMethod.POST)
public String registerIncidentPost(#ModelAttribute("incident") Incident incident, HttpServletRequest request)
throws Exception {
incidentService.save(incident);
return "redirect:/incidentDetail?id=" + incident.getId();
}
Part of Incident Entity
#ManyToOne
#JoinColumn(name = "user_id_preparation_by")
private User incidentPreparationBy;
You can acces the select by adding:
#RequestParam("incidentPreparationBy") String option as a method argument
to your controller method.
This way the string "option" will contain the selected value.
Like this:
#RequestMapping(value = "/update", method = RequestMethod.POST)
public String registerIncidentPost(#ModelAttribute("incident") Incident incident,
#RequestParam("incidentPreparationBy") String option, HttpServletRequest request)
throws Exception {
String incidentPrepartionBy = option; //incidentPrepartionBy will give you the selected value now.
incidentService.save(incident);
return "redirect:/incidentDetail?id=" + incident.getId();
}

Spring How to update database entites from dropdown lists thymeleaf

So I need to update the entities in my table with the selected values from dropdown lists from thymeleaf.
What I want to do is update the movie column based on the selections from dropdown list. But I have more than one dropdown list for each WeekMovie entity.
I cant figure out how to update them all.
My WeekMovies Class
#Entity
public class WeekMovies {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#ManyToOne
#JoinColumn(name="movie_id")
private Movie movie;
#ManyToOne
#JoinColumn(name="saloon_id")
private Saloon saloon;
//getter setters.
My Controller
#RequestMapping(value = "/update",method= RequestMethod.GET)
public String updateweekmovies(Model model){
List<WeekMovies> weekMoviesList = weekMovieService.findAll();
List<Movie> movieList= movieService.findAll();
model.addAttribute("weekMovieList",weekMoviesList);
model.addAttribute("movieList",movieList);
return "updateweekmovies";
}
#RequestMapping(value = "/update",method= RequestMethod.POST)
public String updateweekPost(Model model){
return "updateweekmovies";
}
My Thymeleaf
div class="container">
<div class="row">
<form class="form-horizontal" th:action="#{/week/update}" method="post"
enctype="multipart/form-data">
<fieldset>
<legend class="center-block">
Update Book Information<span style="font-size: small"> * is a
required field</span>
</legend>
<!-- category -->
<div class="form-group">
<label class="col-md-2 control-label" for="weekmovie">*
Category</label>
<div class="col-md-8">
<li th:each="weekmovie:${weekMovieList}">
<select th:value="${weekmovie.movie}" id="weekmovie" name="weekmovie" class="form-control">
<option value="" selected="selected" disabled="disabled">Please
select an option...</option>
<option th:each="movie:${movieList}" th:value="${movie.id}" th:text="${movie.title}"> </option>
</select>
</li>
</div>
</div>
<div class="form-group">
<div class="col-md-2"></div>
<div class="col-md-8">
<button type="submit" class="btn btn-success">Update Movie</button>
</div>
</div>
</fieldset>
</form>
</div>

How to assign entity to another entity in a form using ThymeLeaf?

I am working on MVC Java project and am using Spring Boot with ThymeLeaf. The issue I have is, that when creating a Task, I want to select and save a User, that will be assign to the task. I managed to do the selection correctly, but am unable to save the selected user. It always saves without the User assigned.
Here is my Task entity class:
#Entity
public class Task extends BaseEntity {
private String name;
private String description;
private Date dateOfCreation;
#DateTimeFormat(pattern = "yyyy-MM-dd")
private Date dueDate;
#ManyToOne
private User assignee;
public Task() {
this.dateOfCreation = new Date(System.currentTimeMillis());
}
}
My User entity is as follows:
#Entity
public class User extends BaseEntity {
private String username;
private String password;
#OneToMany(mappedBy = "assignee")
private List<Task> assignedTasks;
}
Where BaseEntity contains
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Version
private Integer version;
My controller function, that is responsible for my taskform.html is:
#RequestMapping("/new")
public String newTask(Model model){
model.addAttribute("task", new Task());
model.addAttribute("users", userService.getAllUsers());
return "task/taskform";
}
And my taskform.html looks like this:
<form class="form-horizontal" th:object="${task}" th:action="#{/task}" method="post">
<input type="hidden" th:field="*{id}"/>
<input type="hidden" th:field="*{version}"/>
<div class="form-group">
<label class="col-sm-2 control-label">Name:</label>
<div class="col-sm-10">
<input type="text" class="form-control" th:field="*{name}"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Description:</label>
<div class="col-sm-10">
<input type="text" class="form-control" th:field="*{description}"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Description:</label>
<div class="col-sm-10">
<input type="date" th:value="*{dueDate}" th:field="*{dueDate}" id="dueDate" />
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Select user:</label>
<div class="col-sm-10">
<select class="form-control">
<option th:field="*{assignee}" th:each="assignee : ${users}" th:value="${assignee}" th:text="${assignee.username}">
</option>
</select>
</div>
</div>
<div class="row">
<button type="submit" class="btn btn-default">Submit</button>
</div>
I am trying to pass the object from users list as the value, but it does not work Any idea, how to do it?
Showing the users works as expected:
Working frontend
Null is being assigned to assignee column, where the user should be assigned.
Null in H2 Database
EDIT
Here is my POST method from Task Controller:
#RequestMapping(method = RequestMethod.POST)
public String saveOrUpdate(Task task){
taskService.persistTask(task);
return "redirect:/task/list";
}

Spring Nested object is getting null while submitting form

I am trying to post data with thymeleaf, command model has two nested objects, one is fetching data, while another is fetching null. I am confused, what is going on behind the scene, though using the same concept and code.
Please notice, I am getting data for People Object in logs, but not for Project Object, though using the same code. Please help.
Form Snippet.
<form th:fragment="form" method="post" th:object="${expense}" th:action="#{/createexpense}">
<input type="hidden" th:field="*{expenseId}" />
<div class="form-group">
<label class="col-md-4 control-label" for="textarea">Expense Description</label>
<div class="col-md-4">
<textarea class="form-control" id="textarea" th:field="*{description}" name="textarea">Expense Description</textarea>
</div>
</div>
<div class="form-group">
<label class="col-md-4 control-label" for="textinput">Amount</label>
<div class="col-md-4">
<input id="textinput" name="textinput" type="text" placeholder="Enter Amount" th:field="*{amount}" class="form-control input-md">
</div>
</div>
<div class="form-group">
<label class="col-md-4 control-label" for="textinput">Project</label>
<div class="col-md-4">
<select class="form-control" id="sel1" th:field="*{project}">
<option th:each="project: ${projects}" th:value="${{project.projectId}}" th:text="${project.name}">1</option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-md-4 control-label" for="textinput">People</label>
<div class="col-md-4">
<select class="form-control" id="sel1" th:field="*{people}" >
<option th:each="people: ${peoples}" th:value="${people.id}" th:text="${people.name}">1</option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-md-4 control-label" for="textinput">Expense Type</label>
<div class="col-md-4">
<select class="form-control" id="sel1" th:field="*{expenseType}">
<option th:each="exp: ${expenseTypes}" th:value="${exp}" th:text="${exp}">1</option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-md-4 control-label" for="textinput">Create
Expense</label>
<div class="col-md-4">
<input type="submit" class="btn btn- danger" value="Submit"/
</div>
</div>
Model Bean Class
#Data
#JsonIgnoreProperties(value = {"createdAt", "updatedAt"},
allowGetters = true)
#Entity
public class Expense {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long expenseId;
#Lob
private String description;
#OneToOne
#Cascade(CascadeType.ALL)
private People people;
private Double amount;
#Temporal(TemporalType.TIMESTAMP)
#CreatedDate
private Date createdAt;
#Temporal(TemporalType.TIMESTAMP)
#LastModifiedDate
private Date updatedAt;
#ManyToOne
#Cascade(CascadeType.ALL)
private Project project;
#Enumerated(EnumType.STRING)
private ExpenseType expenseType;
public Expense(String description, Double expense) {
this.description = description;
this.amount = expense;
}
public Expense() {
}
public void setCreatedAt(Date createdAt) {
this.createdAt = new Date();
}
public Date getUpdatedAt() {
return updatedAt;
}
#PreUpdate
public void setUpdatedAt() {
this.updatedAt = new Date();
}
}
Controller Snippet
#PostMapping(path="/createexpense")
public Expense addExpense(#ModelAttribute("expense") Expense expense ,BindingResult result){
log.debug(expense.toString());
expense.setPeople(peopleService.getPeople(expense.getPeople().getId()));
expense.setProject(flatProjectService.getFlatProjectById(expense.getProject().getProjectId()));
return expenseService.createExpense(expense);
}
#GetMapping(path="/createexpense")
public ModelAndView addExpense(ModelAndView modal){
//adding projects list and people list in expense view
modal.addObject("projects", flatProjectService.getAllProjects());
modal.addObject("peoples", peopleService.getAllPeoples());
modal.setViewName("createexpense");
modal.addObject("expense", new Expense());
modal.addObject("expenseTypes", ExpenseType.values());
return modal;
}
Error Logs
2018-07-22 18:22:44.010 DEBUG 25500 --- [nio-8080-exec-5] c.d.b.controller.HomeController : Expense(expenseId=null, description=hello, people=People(id=2, name=Avinash, peopleType=null, phoneNo=9504974665, address=Beside Maa Clinic, expense=[], createdDate=2009-06-01 13:45:30.0, updatedDate=2009-06-01 13:45:30.0), amount=5000.0, createdAt=null, updatedAt=null, project=null, expenseType=PAID)
2018-07-22 18:22:44.090 ERROR 25500 --- [nio-8080-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException: null
Looking at your HTML logic. I suspect issue is in Project Loop
You are defining th:field="*{project}"
but using as pro in option
Ideally it should be like this
<div class="form-group">
<label class="col-md-4 control-label" for="textinput">Project</label>
<div class="col-md-4">
<select class="form-control" id="sel1" th:field="*{project}">
<option th:each="project: ${projects}" th:value="${project.projectId}"
th:text="${pro.name}">1</option>
</select>
</div>
</div>

Form Select and Thymeleaf

I'm porting my app to Thymeleaf and i'm having problems in creating form select from List of Objects.
I have this form
<form th:with="reservationUrl=(${price != null} ? '/book/confirm' : '/book/new')"
th:action="#{${reservationUrl}}" method="POST"
class="form-signin" th:object="${reservation}"
id="form-signin">
<div class="form-group row">
<label class="col-sm-2 col-form-label" for="plate"
th:text="#{reservation.plate }">Targa</label>
<div class="col-sm-4 input-group">
<select th:type="*{plate}" class="form-control">
<option th:each="p : ${plates}"
th:value="${p.plateId}" th:text="${p.plateNumber}">Opzione</option>
</select>
</div>
// rest of the form
From the controller I have a List<Plate> plates and my Reservation has a Plate field, so it's a really basic select association (which worked with plain JSP)
I'm getting this exception
Exception evaluating SpringEL expression: "p.plateId" (reservation:67)] with root cause
Property or field 'plateId' cannot be found on object of type 'org.thymeleaf.util.EvaluationUtil$MapEntry' - maybe not public?
This is Plate
#Entity
public class Plate {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long plateId;
private String plateNumber;
private String plateName;
#ManyToOne
#JoinColumn(name="userId")
#JsonBackReference(value="plates-user-reference")
private User user;
private boolean favourite;
#JsonIgnore
private boolean enabled;
//standard getters and setters
EXAMPLE
<div class="form-group">
<label for="location">Pick a location:</label>
<select class="form-control" th:value="${appointment.location}" name="location" id="location"
>
<option disabled="disabled" selected="selected" > -- select the location --</option>
<option>Boston</option>
<option>New York</option>
<option>Chicago</option>
<option>San Francisco</option>
</select>
</div>
if you want to try a drop-down menu then yu can follow this way.

Resources