Spring Boot, Thymeleaf Form Error - spring

I am trying to create a task creation page. There is a form where the user can enter the name, description and task status and save it. However, when I go to the page it shows me this error
There was an unexpected error (type=Internal Server Error, status=500).
Error during execution of processor 'org.thymeleaf.spring4.processor.attr.SpringInputGeneralFieldAttrProcessor' (index)
I also have a delete task in my program and that seems to work perfectly fine.
This is what my mainController looks like
#RequestMapping(value = "/save-task")
public String saveTask(#ModelAttribute("task") Task task, BindingResult bindingResult, Model model) {
task.setDateCreated(new Date());
taskService.save(task);
model.addAttribute("tasks", taskService.findAll());
model.addAttribute("task", new Task());
model.addAttribute("mode", "MODE_TASKS");
return "index";
}
#RequestMapping( value = "/delete-task")
public String deleteTask(#RequestParam (required = false) int id, Model model){
taskService.delete(id);
model.addAttribute("tasks", taskService.findAll());
model.addAttribute("mode", "MODE_TASKS");
return "index";
}
Here is the form
<div class="container text-center">
<h3>Manage Task</h3>
<hr/>
<form class="form-horizontal" method="POST" th:action="#{/save-task}" th:object="${task}">
<input type="hidden" name="id" th:field="*{id}"/>
<div class="form-group">
<label class="control-label col-md-3">Name</label>
<div class="col-md-7">
<input type="text" class="form-control" name="name" th:field="*{name}"/>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3">Description</label>
<div class="col-md-7">
<input type="text" class="form-control" name="description" th:field="*{description}"/>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3">Finished</label>
<div class="col-md-7">
<input type="radio" class="col-sm-1" th:name="finished" value="true"/>
<div class="col-sm-1">Yes</div>
<input type="radio" class="col-sm-1" th:name="finished" value="false"/>
<div class="col-sm-1">No</div>
</div>
<div class="form-group">
<input type="submit" class="btn btn-primary" value="Save"/>
</div>
</div>
</form>
</div>
</div>
Delete Task html
<tr th:each="task: ${tasks}">
<td th:text="${task.id}"></td>
<td th:text="${task.name}"></td>
<td th:text="${task.description}"></td>
<td th:text="${task.dateCreated}"></td>
<td th:text="${task.finished}"></td>
<td><a th:href="#{'delete-task?id=' + ${task.id}}"><span class="glyphicon glyphicon-trash"></span></a> </td>
</tr>
Here is a part of my Task entity
#Entity
#Table(name = "T_TASKS")
public class Task implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private int id;
#Column(name = "NAME")
private String name;
#Column(name = "DESCRIPTION")
private String description;
#Column(name = "DATE_CREATED")
#Temporal(TemporalType.TIMESTAMP)
private Date dateCreated;
#Column(name = "FINISHED")
private boolean finished;
Here is the error in the slack trace
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'task' available as request attribute

Change your controller mapping to accept GET and POST requests. You're getting the error because Spring can't bind a bean to the form. So add a bean when GET is called.
#GetMapping("/save-task")
public String addTask(Model model) {
Task task = new Task();
task.setDateCreated(new Date();
model.addAttribute("task", task);
return "save-task"; //or whatever the page is called
}
Then do your processing:
#PostMapping("/save-task")
public String saveTask(#ModelAttribute("task") Task task,
BindingResult bindingResult,
Model model) {
taskService.save(task);
model.addAttribute("mode", "MODE_TASKS");
return "index";
}
Your bean looks fine. I don't see that you use tasks in your HTML snippet, but that would go in the method mapped with #GetMapping if you're looking to just display all tasks.

Add the following to your controller class:
#ModelAttribute("task")
public Task newTaskObject() {
return new Task();
}
It will solve the binding problem. Also you need a post controller to handle the form submission.

Related

How to iterate and save 2 objects with thymeleaf?

I dont know how fix this error, i saw some articles about that but nothing works.
Error
Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errorsField error in object 'pupil' on field 'curse': rejected value [ModelCurse(id=2, name=PHP, division=2da, pupilList=[], teacherList=[])];
[Failed to convert property value of type 'java.lang.String' to required type 'com.example.administrator.administrator.model.ModelCurse' for property 'curse';
HTML
<form th:action="#{/pupilController/add}" th:object="${pupil}" method="post">
<div class="form-row">
<div class="form-group col-md-6">
<label>Name</label>
<input type="text" class="form-control" th:field="*{name}" placeholder="Name">
</div>
<div class="form-group col-md-6">
<label>Last Name</label>
<input type="text" class="form-control" th:field="*{lastName}" placeholder="Last Name">
</div>
<div class="form-group col-md-6">
<label>Age</label>
<input type="number" class="form-control" th:field="*{age}" placeholder="Age">
</div>
<div class="form-group col-md-6">
<label>Phone Number</label>
<input type="text" class="form-control" th:field="*{phoneNumber}" placeholder="Phone Number">
</div>
<div class="form-group col-md-6">
<select th:field="*{curse}" class="form-control">
<option th:each="curso : ${curses}"
th:value="${curso}"
th:text="${curso.name}"></option>
</select>
</div>
</div>
<input type="submit" name="btnInsert" class="btn btn-primary" value=AƱadir>
</form>
Controller
#GetMapping("/addPupil")
public ModelAndView login(Model model){
ModelAndView mav = new ModelAndView("addpupil");
List<ModelCurse> modelCurses = curseService.getAllCurses();
mav.addObject("pupil",new ModelPupil());
mav.addObject("curses",modelCurses);
return mav;
}
#PostMapping("/add")
public RedirectView addPupil(#ModelAttribute("pupil")ModelPupil modelPupil){
pupilService.addPupil(modelPupil);
return new RedirectView("/pupilController/pupilList");
}
DTO
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#ToString
public class ModelCurse {
private long id;
private String name;
private String division;
private List<ModelPupil> pupilList;
private List<ModelTeacher> teacherList;
}
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#ToString
public class ModelPupil {
private long id;
private String name;
private String lastName;
private int age;
private int phoneNumber;
private ModelCurse curse;
}
When we submit the form, the value of selected option is sent as Text or String in HTTP POST. So, if you are expecting that Spring would automatically convert that String value of curse to object of type ModelCurse, then your assumption is wrong. But Spring does provide us a way to do it using Java beans PropertyEditorSupport. Here you can extend this class, and provide your own implementation on how to convert that String to the required object.

Can not save object to MySQL DB using Java Spring Boot

I've got ENTITY Country with all getters and setters + Constructor with no args. Getters and setter are all written by IDEA, not Lombok.
#Entity
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String code;
private String capital;
private String description;
private String nationality;
private String continent;
#OneToMany(mappedBy="country")
private List<State> states;
public Country() {
}`
Here goes CountryRepository:
#Repository
public interface CountryRepository extends JpaRepository<Country, Integer> {}
Here goes CountryService:
#Service
public class CountryService {
#Autowired
private CountryRepository countryRepository;
public List<Country> getListOfCountries() {
return countryRepository.findAll();
}
public void addNewCountry(Country country) {
countryRepository.save(country);
}
}
and CountryController:
#Controller
public class CountryController {
#Autowired
private CountryService countryService;
#GetMapping("/countries")
private String getListOfCountries(Model model) {
List<Country> listOfCountries = countryService.getListOfCountries();
model.addAttribute("countries", listOfCountries);
return "countries";
}
#PostMapping("/countries/addNew")
private String addNewCountry(#RequestParam String code,
#RequestParam String capital,
#RequestParam String description,
#RequestParam String nationality,
#RequestParam String continent) {
Country country = new Country();
country.setCode(code);
country.setCapital(capital);
country.setDescription(description);
country.setNationality(nationality);
country.setContinent(continent);
countryService.addNewCountry(country);
return "redirect:/countries";
}
}
and here is the form that's supposed to take input, but unfortunately nothing happens(
<div class="modal-body">
<form th:action="#{/countries/addNew}" method="post">
<div class="form-group">
<label for="recipient-name" class="col-form-label">Code:</label>
<input type="text" class="form-control" id="recipient-name" name="code">
</div>
<div class="form-group">
<label for="recipient-name1" class="col-form-label">Capital:</label>
<input type="text" class="form-control" id="recipient-name1" name="capital">
</div>
<div class="form-group">
<label for="recipient-name2" class="col-form-label">Description:</label>
<input type="text" class="form-control" id="recipient-name2" name="description">
</div>
<div class="form-group">
<label for="recipient-name3" class="col-form-label">Nationality:</label>
<input type="text" class="form-control" id="recipient-name3" name="nationality">
</div>
<div class="form-group">
<label for="recipient-name4" class="col-form-label">Continent:</label>
<input type="text" class="form-control" id="recipient-name4" name="continent">
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary" data-dismiss="modal">Add</button>
</div>
</form>
</div>
If I add data manually to the DB everything works fine, but when using this form nothing happens. At the same time I didn't get to errors or whatever. Server runs OK. Instead of JPARepository I tried using CRUDRepository. Also doblechecked the names of the form so they have the same values as Country fields. Realy lost here...

how to bind list of object for sending post request in spring boot and thymeleaf

I have a booking entity and another entity is guest. the relation between them onetomany.
booking entity:
#Entity
public class Booking {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String nameInit;
private String firstName;
private String lastName;
private String email;
private String numberInit;
private String number;
private boolean status;
#JsonIgnore
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<Guest>guests;
Guest entity:
#Entity
public class Guest{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String nameInit;
private String name;
private String age;
private String gender;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "booking_id")
private Booking booking;
thymeleaf form:
<div class="guest-inputs-wrapper" th:each="item, stat : *{guests}">
<div class="row">
<div class="col-md-1">
<div class="input-field col s12">
<div class="guest-number">
Guest <span class="number">1</span>
</div>
</div>
</div>
<div class="col-md-2">
<div class="input-field col s12">
<select name="nameInit" th:field="*{guests[__${stat.index}__].nameInit}" id="g-title-1">
<option value="" disabled selected>Title</option>
<option value="1">Mr.</option>
<option value="2">Mrs.</option>
<option value="3">Ms.</option>
</select>
</div>
</div>
<div class="col-md-4">
<div class="input-field col s12">
<input type="text" class="validate" name="name" th:field="*{guests[__${stat.index}__].name}" id="g-fullname-1" required>
<label>Full Name</label>
</div>
</div>
<div class="col-md-1">
<div class="input-field col s12">
<input type="text" class="validate" name="age" th:field="*{guests[__${stat.index}__].age}" id="g-age-1" required>
<label>Age</label>
</div>
</div>
<div class="col-md-3">
<div class="input-field col s12">
<div class="custom-radio">
<input type="radio" id="m-gender-1" name="gender" th:field="*{guests[__${stat.index}__].gender}" value="Male" checked>
<label for="m-gender-1">Male</label>
</div>
<div class="custom-radio">
<input type="radio" id="f-gender-1" name="gender" th:field="*{guests[__${stat.index}__].gender}" Value="Female">
<label for="f-gender-1">Female</label>
</div>
</div>
</div>
Controller:
#GetMapping("/booking/room/{roomId}")
public String bookingPage(Model model, #PathVariable Long roomId, HttpSession session){
Booking booking = new Booking();
booking.getGuests().add(new Guest());
model.addAttribute("booking", booking);
return "web/cart";
}
#PostMapping("/room/save-booking")
public String createBooking(Model model,#Valid Booking booking, BindingResult result, HttpSession session){
if (result.hasErrors()){
model.addAttribute("error", true);
return null;
}
hotelBookingService.save(booking);
guestService.saveAll(booking.getGuests());
model.addAttribute("success", true);
return "redirect:/main";
}
after submitting only one guest information is saved in db with booking information. but i want a list of guest. where is my worng i can't find. why form do not pass list of guest ? please help
For starters, within your th:each loop you have element ids with are not unique and don't use the stat index, for example g-title-1.
Secondly, the same goes for the name on each input. The th:each loop is an abstraction for document generation. As far as the browser is concerned, there is no "list" associated with the loop. What does that mean? When it comes time to submit, you will have a bunch of duplicate names as well, which will cause problems.
You could refactor your code/script to save one guest to a booking at a time, or you could use javascript to build a FormData object that grabs data from the inputs and keeps the lists like you want. I'm sure there are other solutions as well.

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";
}

Issue with kendo datepicker in Spring MVC

I have a form for adding students. For the date of birth i want to use kendo ui datepicker, but i don't know how the controller is making the binding with the model. If the name attribute of the date picker matches the class element, then i get the following error: The request sent by the client was syntactically incorrect. If the name attribute of the date picker is different, then on save button clicked the student is inserted into the database, but with the field date of birth being null.
Below is the content of the jsp file, the controller and the Student class.
What i am doing wrong?
jsp file
<div id="addStudent" class="space">
<div class="page-title">Add student</div>
<form:form commandName="addForm" method="post">
<div class="editor-field">
<label for="firstName">First name</label> <input
class="input k-popup k-list-container k-group k-reset" type="text"
name="firstName" />
</div>
<div class="editor-field">
<label for="lastName">Last name</label> <input
class="input k-popup k-list-container k-group k-reset" type="text"
name="lastName" />
</div>
<div class="editor-field">
<label for="dateOfBirth">Date of birth</label>
<kendo:datePicker name="dateOfBirth"></kendo:datePicker> //name attribute
</div>
<div class="editor-field left form-actions">
<a href="http://localhost:8080/GasfProject/gasf/main/menu/students"
class="k-button">Cancel</a>
<input class="k-button" type="submit" name="add" value="Save">
</div>
</form:form>
</div>
Controller
#RequestMapping(value = "/menu/addStudent", method = RequestMethod.POST)
public String addStudent(#ModelAttribute("addForm") Student model) {
logger.debug("Received request in add student post");
// insert in database
StudentDatabaseAccess.addNewStudent(model);
return "redirect:students";
}
Student
public class Student {
private String firstName;
private String lastName;
private Date dateOfBirth;
//getters and setters
}
You can try adding a DateTimeFormat annotation on the dateOfBirth field
public class Student {
private String firstName;
private String lastName;
#DateTimeFormat(pattern = "yyyy/MM/dd")
private Date dateOfBirth;
//getters and setters
}
This will tell spring how to convert the data from Date to String and from String to Date.
Make sure the pattern you set in the annotation is the same as the one you probably set on the kendo datepicker field in javascript.

Resources