I familiarize myself with Thymeleaf.
I am trying to get data from a POST-mapping in the controller.
But I got null variables when I call employee.getName().
I looked a lot online but can't find a solution.
My controller class
#GetMapping
public String getEmployees(Model model) {
model.addAttribute("newEmployee", new Employee());
return "employees";
}
#PostMapping
public String addEmployee(#ModelAttribute("newEmployee") Employee employee) {
System.out.println(employee); // return object
System.out.println(employee.getFirstName()); // return null
return "employees";
}
HTML form with Thymeleaf
<div class="modal-body">
<form th:action="#{/employees}" th:object="${newEmployee}" method="post">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label class="col-form-label">First Name <span class="text-danger">*</span></label>
<input th:field="*{firstName}" class="form-control" type="text">
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label class="col-form-label">Last Name</label>
<input th:field="*{lastName}" class="form-control" type="text">
</div>
</div>
See tutorials:
Wim Deblauwe: Form handling with Thymeleaf
Baeldung: Binding a List in Thymeleaf
#GetMapping("/all")
public String showAll(Model model) {
model.addAttribute("employees", employeeService.findAll());
return "employees/all";
}
#GetMapping("/add")
public String createForm(Model model) {
model.addAttribute("newEmployee", new Employee()); // the form-data object as blank employee to be filled
return "employees/form"; // the page containing the form
}
#PostMapping
public String addEmployee(#ModelAttribute("newEmployee") Employee employee) {
System.out.println(employee); // return object
System.out.println(employee.getFirstName()); // return null if either not set in HTML-form or not mapped from HTML-form to POST correctly
// save new employee or add to a repository
employeeService.save(newEmployee);
model.addAttribute("employees", employeeService.findAll());
return "redirect:/employees/all"; // use a redirect
}
Client-Server interaction:
First in your browser you should navigate to the endpoint adding the form-data-object, i.e. GET /employees/add.
Then the form-page should load and you will have a blank object newEmployee to bind all the input-fields to for submitting.
After submitting the form via the submit-click, a POST /employees is sent. The server/controller should receive the form-data as model-attribute in employee parameter and can save it.
The controller-method redirects back to the list-endpoint (same as navigating in browser to) GET /employees/all
<h1>Create employee</h1>
<form th:object="${newEmployee}"
th:action="#{/employees}"
method="post">
<input type="text" name="firstName" id="firstName" th:field="*{firstName}" />
<input type="text" name="lastName" id="lastName" th:field="*{lastName}" />
<button type="submit">Submit new employee</button>
</form>
The th:object attribute refers to the key under which we put our Employee instance in the model (newEmployee in this example). The th:action has the URL for the #PostMapping method. Finally, the method attribute is set to "post" since we want to use the HTTP POST method.
Using th:field=*{…}, we can setup a two-way binding between the HTML input and the field in our form data object.
Related
So, my issue is that my Vehicle ID is being passed to the GET mapping and it populates if I print statement and on the JSP. But when I try and set it to my Customer object, which has Vehicle variable, it keeps coming back null, like it's creating a new Vehicle object when you submit.
I've tried creating a "model" (Customer_And_Vehicle) class that has both variables, and the vehicle is still being nulled.
Using the vehicleOne attributes and calling the ID in the Post Mapping works. The vehicle does get passed through and attached to the customer.
The vehicle ID is getting passed through the requestID in the GETmapping.
CustomerController
#GetMapping("/buy-vehicle")
public String addCustomer(Model model, #RequestParam String id, HttpSession session) {
Vehicle vehicle = vehicleService.getVehicle(id);
//Vehicle vehicle = vehicleService.findById(id);
model.addAttribute("vehicle", vehicle);
//model.addAttribute("customer", new Customer());
Customer_And_Vehicle cv = new Customer_And_Vehicle();
cv.setVehicle(vehicle);
cv.setCustomer(new Customer());
model.addAttribute("cv", cv);
System.out.println(vehicle);
return "buy-vehicle";
}
#PostMapping("/buy-vehicle")
public String handleBuyVehicle(Model model, #ModelAttribute("customer") Customer customer, #ModelAttribute("vehicleOne") Vehicle vehicle,
#ModelAttribute("cv") Customer_And_Vehicle cv, HttpSession session) {
//Vehicle vehicleOne = vehicleService.findById("123");
//vehicleOne.setBought(true);
model.getAttribute("customer");
model.getAttribute("vehicle");
//model.addAttribute("vehicle", vehicleService.getVehicle(vehicle.getId()));
//model.addAttribute("vehicleOne", vehicleService.findById("123"));
//cv.getVehicle().setBought(true);
customer.setEmail(cv.getCustomer().getEmail());
customer.setfName(cv.getCustomer().getfName());
//customer.setVehicle(vehicleOne);
//customer.setAmountSpent(vehicleOne.getPrice());
customerService.addCustomer(customer);
return "index";
}
If I specify which ID("123") - in vehicleOne - in the Post Mapping, the vehicle does get passed through and attached to the customer.
/buy-vehicle
<body>
<form:form modelAttribute="cv" action="/buy-vehicle"
method="post">
<div>
<label for="inputFirstName">First Name</label>
<form:input path="customer.fName" type="text" id="inputFirstName" />
</div>
<div>
<label for="inputLastName">Last Name</label>
<form:input path="customer.lName" type="text" id="inputLastName" />
</div>
<div>
<label for="inputEmail">Email</label>
<form:input path="customer.email" type="email" id="inputEmail" />
</div>
<div>
<label for="inputPassword">Password</label>
<form:input path="customer.password" type="password" id="inputPassword" />
</div>
<button type="submit">work</button>
</form:form>
</body>
index - to show printout on local
<body>
Work please
<div>
Auto list
</div>
<div>${customer.vehicle.id}</div>
<div>${vehicleOne }</div>
<div>${customer.fName}</div>
<div>${customer.amountSpent}</div>
<div>${cv}</div>
<div>${cv.customer}</div>
<div>${cv.vehicle}</div>
<div>Create Account</div>
</body>
Screenshot of vehicle getting passed to buy-vehicle
Screenshot of index printout
Hi guys hope you can help me, because i cant get further at the moment
I have my Controller.
#RequestMapping(value="/kundenseite", method= RequestMethod.GET)
public String kundenLogin(ModelMap model) {
if(kundeComponent.getKunde() != null) {
List<Restaurant> restaurants = restaurantService.alleRestaurants();
model.addAttribute("restaurants", restaurants);
return "kundenseite";
}else {
return "redirect:/kunde/login";
}
}
#RequestMapping(value="/kundenseite", method= RequestMethod.POST)
public String kundenLoginAnswer(ModelMap model, #ModelAttribute Restaurant restaurant) {
System.out.println(restaurant.toString());
return "kundenseite";
And my jsp file
<%# include file="common/header.jspf" %>
<div class="jumbotron text-center">
<h1>MiMiMi Lieferservice</h1>
<p>Der schnellste Lieferservice von Passpick</p>
</div>
<div style="margin-right:auto; margin-left:auto; width: 33%">
<h2 style="text-align: center">Restaurant wählen</h2>
<div class="well">
<c:forEach items="${restaurants}" var="restaurant">
<form:form modelAttribute="${restaurant}" method="post">
<div style="margin-top: 8px" class=col-sm-4 >${restaurant.name}</div>
<div style="margin-top: 8px" class=col-sm-4 >${restaurant.restaurantTyp}</div>
<button type="submit">Bestellen</button>
</form:form>
<br style="clear:both;" />
</c:forEach>
</div>
</div>
</body>
</html>
If the user presses a button i want to return a restaurant.
But i don't know how to make that happen, my thought was to use a form but i cant get it to send a complete restaurant object back
If there is no solution for this i have to write the id with the button.
You need input hidden inside the form tab as below input hidden:
<input type="hidden" name="name" value="${restaurant.name}">
<input type="hidden" name="restaurantTyp" value="${restaurant.restaurantTyp}">
I have a page with two forms, and want to add object from first form when submitting second one. Basically it looks like this:
First form:
<form action="#" method="POST" enctype="multipart/form-data" th:action="#{/foo}" th:object="${prop1}" id="form1">
<input type="file" name="file" class="form-control"/>
<input type="text" th:value="${prop1.taskSheetName}" name="taskSheetName"/>
<input type="number" th:value="${prop1.descriptionColumnPosition}" name="descriptionColumnPosition"/>
</form>
Second form:
<form th:if="${resourceId}" action="#" method=" th:object="${prop2}" id="prop2" th:action="#{/foo/{id}(id=${resourceId})}">
<input type="url" th:value="${prop2.url}" name="url"/>
<input type="text" th:value="${prop2.username}" name="username"/>
<input type="password" th:value="${prop2.password}" name="password"/>
</form>
And controller methods:
#RequestMapping(value = "/foo", method = POST)
public String uploadFile(#RequestParam("file") MultipartFile file, final ExcelProperties properties, final Model model) {
//some logic here
}
#RequestMapping(value = "/process/{id}", method = POST)
public String processResource(#PathVariable("id") String id, final Prop2 prop2, final Prop1 prop1, final Model model) {
}
And I need to pass the values from first form values to second method with second form values, but it passes empty form object. I tried to add
<div th:with="p1=${prop1}">
since I know that this data is present in page, but it didn't help.
If this even possible or should I just give up and write custom submit handler in javascript?
According to MDN, it's impossible to attach 1 input into 2 forms,
You need to do some work with JavaScript.
Hello I'm tryin to developpe a page that can delete users but when I click on submit I have an error Etat HTTP 400 - La requête envoyée par le client était syntaxiquement incorrecte.
Jsp file
</div>
<form method="POST" action="Users">
User ID
<input type="text" name="idUser" /><br><br>
<input type="submit" name="Supprimer" value="Supprimer"/>
</form>
Controller
#RequestMapping(value = "/Users")
public String goUsers(Model model)
{
model.addAttribute("AllUsers", UserS.getAllUsers());
return "Users";
}
#RequestMapping(value = "/Users", method = RequestMethod.POST)
public String goUsers(#ModelAttribute User user,BindingResult result,#RequestParam int id, Map<String, Object> model)
{
UserS.deleteUser(id);
return "Users";
}
thank you
Your controller wrong. You expect oen User and one param with name id but you send one param with name idUser.
Eliminate ModelAttribute and force de name of RequestParam:
#RequestMapping(value = "/Users", method = RequestMethod.POST)
public String goUsers(BindingResult result,#RequestParam(name="idUser") int id, Map<String, Object> model)
{
UserS.deleteUser(id);
return "Users";
}
1.first you need to add modelattribute to your form like this :
Notice how i am using spring forms. You can use them by adding
<%# taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
before DOCTYPE html>
Then you need to add hidden path to attribute "id" so when you controller gets the request you will know which user you will need to delete or edit.
This is example form :
`<form:form method="POST" modelAttribute="User" action="Users">
<form:hidden path="id"/>
<div class="form-group">
<label for="usernameId">Username</label>
<form:input path="username" id="usernameId" class="form-control" />
<form:errors path="username" style="color:red;"></form:errors>
</div>
<div class="form-group">
<label for="fullNameId">Full Name</label>
<form:input path="firstLastName" id="firstLastName" class="form-control"/>
<form:errors path="firstLastName" style="color:red;"></form:errors>
</div>
<div class="form-group">
<label for="passwordId">Password</label>
<form:password path="password" id="passwordId" class="form-control"/>
<form:errors path="password" style="color:red;"></form:errors>
</div>
<div class="form-group">
<label for="emailId">Email</label>
<form:input path="email" id="emailId" class="form-control"/>
<form:errors path="email" style="color:red;"></form:errors>
</div>
<input type="submit" class="btn btn-default" value="Register"/>
</form:form>`
finally you will add to your controller class.
#ModelAttribute("User")
public User getUser(){
return new User();
}
Then you will need to adjust your controller like this :
#RequestMapping(value="/Users", method=RequestMethod.POST)
public String deleteUser(User user){
getRegisterService().deleteUser(user.getId());
return "home";
}
Note : You will have to create class = User : with id attribute(and all others you need). You will also need to create a method for deleting user in your service and repository layer.
P.S. User user in your deleteUser method is actually the same user you created with #modelAttribute annotation.
If you have any additional questions feel free to ask!
I have given you almost exact form i use for register/editing or deleting Users. When you submit form, everything will be saved into object User with annotation #modelAttribute. Hidden id field is crucial here. When you have id, which is primary key you can just create method in repository (something like this)
public void deleteUser(UserJPA userJPA){
getEntityManager().remove(UserJPA);
}
Hope you find this post helpful.
What's the best practice to pre-populate an object before saving this object with hibernate?
What i've done:
My controller:
//The Form
#RequestMapping(value = "user/{id}/edit", method = RequestMethod.GET)
public String edit(#PathVariable("id") Long userId, ModelMap modelMap) {
modelMap.addAttribute("user", userService.find(userId));
return "user/userEdit";
}
//Updating database
#RequestMapping(value = "user/edit", method = RequestMethod.POST)
public String update(#ModelAttribute("user") #Valid User user, BindingResult result,
RedirectAttributes redirectAttrs) {
if (result.hasErrors()) {
return "user/userEdit";
}else{
userService.update(user);
redirectAttrs.addFlashAttribute("message", "Success");
return "redirect:user/userEdit";
}
}
It works if i make a form containing all fields (username, password and id) , but what should i do if i want the user to update only the password?
Since i have a #NotEmpty at username, i get an error that username is null, since its not in the form, but i dont want to put the username field, just the password.
My html form:
<c:url var="url" value="/user/edit" />
<form:form method="post" action="${url}" modelAttribute="user" class="form-horizontal">
<form:hidden path="id"/>
<form:hidden path="version"/>
<fieldset>
<div class="control-group">
<form:label cssClass="control-label" path="password"><spring:message code="user.label.password"/>: </form:label>
<div class="controls">
<form:input cssClass="input-xlarge" path="password" />
</div>
<form:errors path="password"/>
</div>
<div class="control-group">
<form:label cssClass="control-label" path="userRole"><spring:message code="user.label.role"/>: </form:label>
<div class="controls">
<form:select path="userRole">
<form:options items="${userRoleList}" itemValue="id" itemLabel="name"/>
</form:select>
</div>
<form:errors path="userRole"/>
</div>
<div class="control-group">
<form:label cssClass="control-label" path="costumer.id"><spring:message code="user.label.costumer"/>: </form:label>
<div class="controls">
<form:select path="costumer.id">
<form:options items="${costumerList}" itemValue="id" itemLabel="name"/>
</form:select>
</div>
<form:errors path="costumer.id"/>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">Save changes</button>
<a class="btn cancel link" href="<c:url value="/user" />">Cancel</a>
</div>
</fieldset>
</form:form>
I tried using #Sessionattributes, but it doesnt work well if i try to
edit two or more users using browser tabs.
I tried using property editors, but didnt work with #ModelAtrribute
User user.
I tried using convertors but didnt work.
Is the only way to make a User user = userService.find(id) first, and then set the updated values? Something like:
#RequestMapping(value = "user/edit", method = RequestMethod.POST)
public String update(#RequestParam("password") String password, BindingResult result, RedirectAttributes redirectAttrs) {
User user = userService.find(id);
if (password == null{
return "user/userEdit";
}else{
user.setPassword("password");
userService.update(user);
redirectAttrs.addFlashAttribute("message", "Success");
return "redirect:user/userEdit";
}
}
Which seens wrong, because there is no validation.
An alternate way, that I think is less messy and accident-prone, is to create a class that models the UI form, for example
public class EditUserForm {
// getters and setters for password and other fields...
}
and in the controller's update(EditUserForm,...) method, you simply map any fields populated by the user in the EditUserForm to the instance of User you wish to update.
In the code you posted it's obviously clear that you need some external helper classes to associate with your GUI side updating before you implement the move-control and persistence operations.
I've run into this problem too, if there's only a couple fields I use your second example and validate the fields one by one. Otherwise, you're going to have to do what the other posters have said and make a new class to match your form.
Try to use:
#PrePersist
#PreUpdate
public void prepare(){
//DO SOMETHING WITH YOUR ENTITY
//For example: if(name==null){ name="MYNAMEVALUE";}
}