How to handle forms mapped to more than one entity using Thymeleaf + Hibernate + Spring Boot? - spring

I have a form in Thymeleaf that I want to link to two different entity to be persisted to the database using Hibernate
I have the following form using Thymeleaf:
<form th:action="#{/app/handleForm}" th:object="${entity1}"
method="post">
<input type="text" th:field="*{field1}" />
<input type="text" th:field="*{field2}" />
<input type="text" th:field="*{field3}" />
</form>
Let's supposea the first two fields are bound to entity1 and the third field to be bound to entity2 (not entity1) how should I do this?
Also, in the controller method, I have two DAO implementation for persisting them:
#PostMapping("app/handleForm")
public String RHTraiterDemande(Model m, Entity1 entity1, Entity2
entity2) {
entity1Service.add(entity1);
entity2Service.add(entity2);
return "showResults";
}
How to do this?

You could create a custom object with the required information and mapped it using th:object.
New Class
public class MyClass {
private Entity1 entity1;
private Entity2 entity2;
// Getters and setters.
}
Form
<form th:action="#{/app/handleForm}" th:object="${myClass}"
method="post">
<input type="text" th:field="*{entity1.field1}"/>
<input type="text" th:field="*{entity1.field2}"/>
<input type="text" th:field="*{entity2.field3}"/>
</form>
Controller
#PostMapping("app/handleForm")
public String RHTraiterDemande(Model m, MyClass myClass) {
entity1Service.add(myClass.entity1);
entity2Service.add(myClass.entity2);
return "showResults";
}

Related

handle one to many relationship in thymeleaf using spring mvc

I'm having One entity as Vendor and Another as Address and the relationship between both of them is One To Many form Vendor to Address.
Note : I am using JPA
My Vendor Entity
public class Vendor {
private Integer id;
private String name;
private List<Address> address;
// getter and setters
}
Address class:
public class Address {
private Integer id;
private String addressline1;
private String addressline2;
//getter and setters
}
Now I am using Thymeleaf , I have a scenario where I need to add the address dynamically to a form for the particular vendor.
How do I do Object binding for the Address object in Vendor using Thymeleaf in spring mvc?
Comment if i didn't understand your question correct, it's a bit unclear to me...
In order to access the address(s) of a vendor, you provide a vendor within your controller (something like model.addAttribute("vendor", currentVendor);) and call vendor.address in your html file. Please note that this will give you a list so you need to iterate to show all address:
<tr th:each="address : ${vendor.address}">
<td th:text="${address.id}">1</td>
<td th:text="${address.addressline1}"></td>
<td th:text="${address.addressline2}"></td>
</tr>
Uhhh, that's tricky because binding to form doesn't work in a dynamic way. That means you can't do something like #Viergelenker suggests AND bind each address-object to his own form.
You can add a single address object to the model, e.g.
model.addAttribute("address", addressObject); // Snippet for Model-object
modelAndView.addObject("address", addressObject); // Snippet for ModelAndView object
and then define a form in yout template like:
<form .... method=".." th:object="${address}">
<input type="hidden" th:field="*{id}" >
<input type="text" th:field="*{addressline1}" >
<input type="text" th:field="*{addressline2}" >
</form>
Unfortunately it is not possible to add a array or list to the model and bind each object in that collection to his own form:
/* The following code doesn't work */
<th:block th:each="address : ${addresses}">
<form .... method=".." th:object="${address}">
<input type="text" th:field="*{addressline1}" >
...
</form>
</th:block>
or
/* The following code doesn't work */
<th:block th:each="address, stat : ${addresses}">
<form .... method=".." th:object="${addresses[__stat.index__]}">
<input type="text" th:field="*{addressline1}" >
...
</form>
</th:block>
What you can do is not to use form binding and just send some name-value pairs from forms without the binding (just use the name and the th:value attributes and not the th:field attribute in your forms) to the controller, get them there from the HttpServletRequest object and create/update/delete address-objects ... or bind the whole Vendor object to a form (note the use of stat.index):
<form th:object="${vendor}">
<input type="hidden" th:field="*{id}">
<input type="hidden" th:field="*{name}"> // feel free to make that field editable
<th:block th:each="addr, stat : *{address}">
<input type="hidden" th:field="*{address[__${stat.index}__].id}">
<input type="text" th:field="*{address[__${stat.index}__].addressline1}">
<input type="text" th:field="*{address[__${stat.index}__].addressline2}">
</th:block>
</form>

how to get form values to controller in spring mvc

I am trying to get form values from jsp to controller in spring mvc, but i am not able to get form data.
This is my DTO (bean)
public class LoginDTO implements Serializable {
private Long id;
private String username;
private String password;
// setter and getter methods
}
and my Jsp
<form class="form-signin" action="test" method="get" modelAttribute="userFormData">
<input type="text" class="form-control"
placeholder="Email" required autofocus>
<input type="password" class="form-control"
placeholder="Password" required>
<input class="btn btn-md btn-success btn-block"
type="submit" value="Signin">
</form>
and my controller
#RequestMapping(value = "/test", method = RequestMethod.GET)
public String checkLogin(#ModelAttribute("userFormData") LoginDTO formData, BindingResult
result) {
System.out.println("Controller...");
System.out.println("=====> " + formData.getUsername());
System.out.println("=====> " + formData.getPassword());
}
Add names to the controls on your JSP pages.
<input type="text" name="username" ...>
<input type="password" name="password" ...>
To let spring understand which form control value should go to which property of the LoginDTO
we can also use the springframework has given us a form tags.so that we can also use that but in that case you have to define your the input path same as the member varibale given in your class.
like this
<form:form method="post" modelAttribute="userFormData">
<form:input path="username" />
<form:input path="password" />
Then in the controller you can write like this as you have written
public String checkLogin(#ModelAttribute("userFormData") LoginDTO formData, BindingResult
result)
In case you want to get the result on other jsp page as well as on console then do:
public String checkLogin(#ModelAttribute("userFormData") LoginDTO formData, BindingResult
result , Model model){
System.out.println("=====> " + formData.getUsername()); //this outputs username on console
System.out.println("=====> " + formData.getPassword()); //this outputs password on console
model.addAttribute("LoginDTO ", LoginDTO );
return "success"; //this is the return page where the username and password will be rendered as view
}

How to validate just one field for register a user for spring project with hibernate validator?

<input name="id" placeholder="input your id"/>
<button id="id_check">check</button>
<input name="password" placeholder="input your id"/>
<input type="submit" value="register" />
Currently, I uses a controller for user.
Controller code following...
#Controller
public class UserController {
#GetMapping("...")
public String registerForm(...) { ... }
#PostMapping("...")
public String register(#ModelAttribute #Validated ...) { ... }
.....
}
I want to check id using ajax call.
For id duplication check, can I use hibernate validator? (for one field. not submit action) Also it should be validate duplication of id.(using dao).
For example, one field for validation should be checked duplication and validated by hibernate validator(#NotEmpty, #Email...)

Spring/Hibernate not persisting all data submited from HTML Form

In my current spring pŕoject, I have a form like that:
<form role="form" class="form" id="form" method="post" action="/loja/pagina/insert" enctype="multipart/form-data">
<input class="form-control" type="hidden" name="id" />
<label>Title</label>
<input class="form-control" type="text" name="titulo" />
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active">
pt-BR
</li>
<li role="presentation">
es-ES</li>
<li role="presentation">en-US</li>
</ul>
<div class="tab-content">
<div role="tabpane1" class="tab-pane active" id="pt-BR">
<input type="hidden" name="textos.idioma" value="pt-BR" />
<textarea class="summernote" name="textos.conteudo"></textarea>
</div>
<div role="tabpane1" class="tab-pane" id="es-ES">
<input type="hidden" name="textos.idioma" value="es-ES" />
<textarea class="summernote" name="textos.conteudo"></textarea>
</div>
<div role="tabpane1" class="tab-pane" id="en-US">
<input type="hidden" name="textos.idioma" value="en-US" />
<textarea class="summernote" name="textos.conteudo"></textarea>
</div>
</div>
</form>
When I submit this form to this methods:
controller
#RequestMapping(value = "/insert", method=RequestMethod.POST)
#ResponseBody
#PreAuthorize("hasPermission(#user, 'insert_'+#this.this.name)")
public void insert(#Valid E object, BindingResult result) {
serv.insert(object);
}
service
#Transactional
public void insert(E object) {
dao.insert(object);
}
dao
#Transactional
public void insert(E object) {
Session session = sessionFactory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
session.persist(object);
tx.commit();
} catch (Exception e) {
if(tx != null)
tx.rollback();
} finally {
session.close();
}
}
Only the field titulo is persisted. the field textos , which is represented by this entity class (getters and setter omitted):
#Entity
public class Texto extends Model {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#Column
private String idioma;
#Column
private String conteudo;
}
is not saved on the database. Anyone can tell what's the right way to implement the form to properly store this data? I check the browser's developer tools, and the data is being submitted, it's only not being persisted in the database.
I assume, that your model class Texto has a #OneToMany relation to class E, so that one E references multiple instances of Texto. If this is what your model expresses, you have to use a different syntax for your textarea names to Spring being able to parse your request payload.
In your case Spring would search for a property textos.conteudo on your class E. As I assume, that textos will be a collection, Spring will ignore this.
Assuming, that textos will be modeled as an indexed based collection like List, try to rename your textareas names to name="textos[0].conteudo" and so on to tell Spring that textos is a List and Spring will be able to parse the POST payload.
With the hint given to me by the user #AnsgarSchulte in this question, I change the html code in the form for name="textos[0] and change my PropertyEditorSupport class to handle this array and return a Texto object with the property idioma being the first element of the vector and the property conteudo being all the elements left (concatenating all of them in one string).

how to intercept #modelattribute binding

Everyone.
I am using spring mvc framework, and spring form tag. I found unexpected thing when using form dynamically. For example,
public class Person {
public List<Car> myCars = new ArrayList<Car>();
// getter and setter
}
below code is html form
<form:form modelAttribute="car" ...>
<input type="hidden" name="myCars[0].id">
<input type="text" name="myCars[0].name">
<input type="hidden" name="myCars[1].id">
<input type="text" name="myCars[1].name">
<input type="hidden" name="myCars[2].id">
<input type="text" name="myCars[2].name">
</form:form>
and next code is a spring form controller
#Controller
#SessionAttribute({"car"})
public class CarController {
...
#RequestMapping(".....")
public String form(#ModelAttribute Car car, BindingResult result, ...) {
if (result.hasErrors()) {
....
return viewName;
}
....
return "redirect:/" + someWhere;
}
}
1) I entered data into html form.
2) I can confirm that there are 3 Car objects in car.getMyCars()
3) There are some errors as binding, so it's redirected to viewName
4) I changed html form using jQuery like this
<form:form modelAttribute="car" ...>
<input type="hidden" name="myCars[0].id">
<input type="text" name="myCars[0].name">
<input type="hidden" name="myCars[1].id">
<input type="text" name="myCars[1].name">
</form:form>
and, submit. The result of this test is that #ModelAttribue Car car still remains 3rd element in List myCars. I expected to remain 2 Car elements, but it wasn't. I think it remained in session. And it was overwritten new form data to #ModelAttribute Car car object, but last 3rd element wasn't. My test shows that if form elements increase dynamically, binding object using #ModelAttribute have them. But though decreased dynamically, binding object still have them. I hope that Car car object have accurate number of form inputs. What should I do?
Thanks in advance.

Resources