Save all object with th:object - java

I want to sent object with model.addAttribute and get all object's variable after saving.
Controller
#GetMapping(value = "/passport/details/{id}")
#PreAuthorize("isAuthenticated()")
public String passportDetails(Model model, #PathVariable(name = "id") Long id) {
PassportRequest passportRequest = businessService.getPassportRequestById(id);
model.addAttribute("passport", passportRequest);
return "/user/passport/create";
}
#PostMapping(value = "/passport/save")
#PreAuthorize("isAuthenticated()")
public String savePassport(PassportRequest passport) {
businessService.savePassportRequest(passport);
return "redirect:/passport/details/" + passport.getId();
}
html-code:
<form enctype="multipart/form-data" method="post" th:action="#{/passport/save}"
data-parsley-validate="" role="form"
novalidate="" th:object="${passport}" id="sign-form">
<input type="hidden" th:field="*{id}">
<input type="hidden" th:field="*{stage}">
<div class="col-6 m-input-group">
<label>Кем командирован</label>
<input type="text" name="postedBy" placeholder="Введите" th:field="*{postedBy}" required>
</div>
</form
The problem is I need to make <input type="hidden" th:field="*{objectVariable}"></input> to every variable to send them. Is there any easier way to do?

One way of doing this is annotating your controller with #SessionAttributes("passport") (which means it will store the object on the session and keep all it's properties during this controllers methods).
You might also need to change
public String savePassport(PassportRequest passport) {
to
public String savePassport(#ModelAttribute("passport") PassportRequest passport) {
to make sure all the attributes line up.

Related

#ModelAttribute return null thymeleaf

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.

Neither BindingResult nor plain target object for bean name 'matrix[0][0]' available as request attribute

I have a matrix (array of arrays) of boolean values which I want to show in a form and then submit after changing. I have problems rendering this and I have no more ideas why it is not working. Can anybody give me an advice?
My Controller:
#Controller
#RequestMapping(value = "/konfiguration")
public class VerteilungController {
#ModelAttribute("matrix")
public List<List<Boolean>> getVerteilungenMatrix() {
List<List<Boolean>> result2 = new ArrayList<>();
for (int i = 0; i < kategorien.size(); i++) {
result2.add(new ArrayList<>());
}
//...
return result2;
}
#RequestMapping(value = "/verteilung", method = RequestMethod.GET)
public String showPage(Model model) {
model.addAttribute("matrix", getVerteilungenMatrix());
return "konfiguration/verteilung";
}
}
The form:
<form id="verteilung_form" class="form-horizontal" method="post" action="/verteilung"
th:action="#{/konfiguration/verteilung}"
th:object="${matrix}">
<table class="table-hover">
<tr th:each="row: ${matrix}">
<td th:each="value: ${row}">
<input type="checkbox" th:field="${matrix[__${rowStat.index}__][__${valueStat.index}__]}"/>
</td>
</tr>
</table>
<div >
<button th:text="#{button.save}" class="btn btn-default" type="submit" name="save">Speichern</button>
<button th:text="#{button.reset}" name="reset" class="btn btn-default">Zurücksetzen</button>
</div>
</form>
Openening the page I get
Exception: Error during execution of processor 'org.thymeleaf.spring4.processor.attr.SpringInputCheckboxFieldAttrProcessor'
And in the log
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'matrix[0][0]' available as request attribute
You've misused th:object and th:field. th:object stands for command objects which represents the entire form.
Command object is the name Spring MVC gives to form-backing beans, this is, to objects that model a form’s fields and provide getter and setter methods that will be used by the framework for establishing and obtaining the values input by the user at the browser side.
On the other hand th:field does all the heavy work of binding your input with a property in the form-backing bean. Values inside th:field should point to a field of the object from th:object.
Values for th:field attributes must be selection expressions (*{...}), which makes sense given the fact that they will be evaluated on the form-backing bean and not on the context variables (or model attributes in Spring MVC jargon).
Please check it out here.
So back to your code. To fix it you should create a form-backing bean class and provide the matrix as a field inside that class, for example:
public class FormBean {
private List<List<Boolean>> matrix;
FormBean() { }
public FormBean(List<List<Boolean>> matrix) {
this.matrix = matrix;
}
public List<List<Boolean>> getMatrix() {
return matrix;
}
public void setMatrix(List<List<Boolean>> matrix) {
this.matrix = matrix;
}
}
Next please provide object of FormBean as a model attribute. When you provide method marked as #ModelAttribute then assignment to a model will be done for you. Update your controller body to the following:
#ModelAttribute("formBean")
public FormBean getFormBean() {
return new FormBean(getVerteilungenMatrix());
}
#RequestMapping(value = "/verteilung", method = RequestMethod.GET)
public String showPage() {
return "konfiguration/verteilung";
}
private List<List<Boolean>> getVerteilungenMatrix() {
List<List<Boolean>> result2 = new ArrayList<>();
for (int i = 0; i < kategorien.size(); i++) {
result2.add(new ArrayList<>());
}
//...
return result2;
}
Finally please update your form to the following:
<form id="verteilung_form" class="form-horizontal" method="post" action="/verteilung"
th:action="#{/konfiguration/verteilung}"
th:object="${formBean}">
<table class="table-hover">
<tr th:each="row: *{matrix}">
<td th:each="value: ${row}">
<input type="checkbox" th:field="*{matrix[__${rowStat.index}__][__${valueStat.index}__]}"/>
</td>
</tr>
</table>
<div >
<button th:text="#{button.save}" class="btn btn-default" type="submit" name="save">Speichern</button>
<button th:text="#{button.reset}" name="reset" class="btn btn-default">Zurücksetzen</button>
</div>
</form>
Now everything should work as expected.

Propagate object in thymeleaf form

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.

Hibernate spring mvc formulaire

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.

associate form with Object

#ModelAttribute annotation(Spring) allows for html to create an object.
For example there is a class
class Vasya{
int id;
String name;
//set get
}
and html form
<form action='path'>
<input type='text' name = 'id'/>
<input type='text' name = 'name'/>
<input type='submit'/>
</form>
#controller method:
#RequestMapping("/path")
public String processSkill( #ModelAttribute Vasya vasya) {...}
here it works.
Question:
how can I write html form using *checkbox*es for id and name that my controller method works?
Dont understand how to pass id using checkbox, but you can pass checkbox value that way:
#RequestMapping(value = "/test", method = RequestMethod.POST)
public String form(#RequestParam(required = false) Integer check) {
if(check != null) { // if checkbox is not selected it is null
System.out.println(check);
}
return "your-view";
}
jsp:
<form action="${home}/test" method="POST">
<input type="checkbox" value="1" name="check" />
<input type="submit" />
</form>

Categories