Desing of form in spring - ajax

I am using spring framework. This question mainly concerns about design and implementation.
In my project, I have to use many forms and most of them are different. What is the recommended way of implementing forms in spring. Using Model?
I want to use ajax for forms submissions. The forms in the project are really huge having 8-15 fields. Is it a good way to use ajax for such huge forms? If yes, how can I do it? Can I use model attribute?

A typical way to do this is to use form backing objects. For example, with a form like
<form>
<input type="text" name="username">
<input type="password" name="password">
<input type="text" name="email">
<input type="submit" name="submit">
</form>
You would create a DTO class
public class UserForm {
private String username;
private String password;
private String email;
public UserForm() {}
// getters and setters
}
Then your #Controller handler method can map as
#RequestMapping(method = RequestMethod.POST)
public String handleFormSubmit(#ModelAttribute UserForm userForm /*, more */) {
/* logic and return */
}
And Spring will be able to bind the value from the name attribute of input elements to the fields of the class.
AJAX doesn't care about the size of your forms.

Related

How to transfer the list of strings in DTO using Thymeleaf

I'm developing Spring + Thymeleaf application. I'm implementing search with multiple params. I have a form with the corresponding DTO. Here is the code of the DTO:
public class ClassSearchDto {
private String searchParam;
private Long programId;
private List<String> teacherNames;
//getters, setters and constructor are omitted
}
As you see, I have a list of strings in my DTO called teacherNames. Here is the way I'm displaying my form:
<form th:action="#{/classes/search}" method="get" th:object="${classSearchDto}">
<div class="form-group">
<input type="hidden" class="form-control"
th:value="${classSearchDto.programId}" th:field="*{programId}"/>
<label for="searchParam">Search</label>
<input type="text" class="form-control" id="searchParam" placeholder="keyword"
th:value="${classSearchDto.searchParam}" th:field="*{searchParam}"/>
<div>
<th:block th:each="name, iter ${classSearchDto.teacherNames}">
<input th:value="${name}" th:field="*{teacherNames[__${iter.index}__]}/>
</th:block>
</div>
</div>
<button class="btn btn-default" type="submit">Find</button>
</form>
I want to implement my search with help of #RequestParam annotation on the back-end. This is my controller:
#RequestMapping(value = "/search")
public String findClassByName(#RequestParam("searchParam") final String searchParam,
#RequestParam("programId") final Long programId,
#RequestParam("teacherNames") final List<String> teacherNames,
final Model model) {
...
}
The problem is that I can't get the list of teacher names in this way. I get this exception:
org.springframework.web.bind.MissingServletRequestParameterException:Required List parameter 'teacherNames' is not present
Could you please help me to transfer the list of elements in DTO to my back-end with this approach? Maybe you know how to do it correctly in another way. Thank you in advance.
I can suggest you one thing, I don't know whether it works or not. Try changing
public String findClassByName(#RequestParam("searchParam") final String searchParam,#RequestParam("programId") final Long programId,#RequestParam("teacherNames") final List<String> teacherNames,final Model model)
to
public String findClassByName(#ModelAttribute("classSearchDto") ClassSearchDto classSearchDto,#RequestParam("searchParam") String searchParam,#RequestParam("programId") Long programId,#RequestParam("teacherNames") List<String> teacherNames,Model model)

Spring MVC <form:xxx> tags

I have a doubt that in our web applications generally we are using spring MVC and for view purpose Spring MVC tags, So while writing Spring MVC tags we are using <form:xxx> tags like <form:input> <form:option> <form:select> also <form:label> like this. My confusion is that generally in HTML we are using all these above tags without including <form:xxx> so what is the exact difference in between both the tags and why <form:xxx> tag is needed when it comes to Spring MVC. Is there any object associates to it or what?
If you want to bind the user values collected using form to Object, Then you will need to use Spring form tag. For example..
<form:form action="actionUrl" method="post" modelAttribute="loginForm">
<form:input path="empId" placeholder="Enter Employee Id"/>
<form:errors path="empId" cssClass="error"/>
<form:password path="password" placeholder="********"/>
<form:errors path="password" cssClass="error"/>
<input type="submit" value="Login"/>
</form:form>
Here modelAttribute="loginForm" , loginForm is a Object of Java Class with two fields empId and password.
public class LoginForm{
private Integer empId;
private String password;
//getters and setters
}
So, Now when you submit the Login form, the values are automatically bound to java object which you can access in your controller method. Like
#RequestMapping(value = {"/login"},method = RequestMethod.POST)
public String authLogin(#Valid LoginForm loginForm,BindingResult result,ModelMap model){
//Your code logic
}
So, spring form binds form values automatically to java object and saves from accessing each request parameter manually. These values can also be validated using validation framework.

Error handling with Spring CommandName

when using Spring framework and binding a form on a commandName object to add let's say a person with the following fields.
<form method="POST" action="addPerson.htm" commandName="person">
<input id="firstname" name="firstname"value="${person.firstname}"/>
<br>
<input id="name" name="name" value="${person.name}"/>
<br>
<input id="age" name="age" value="${person.age}"/>
</form>
On the server I've got the following code
#RequestMapping(value="/addPerson", method={RequestMethod.POST})
public String addPerson(#ModelAttribute(value="person") Person p){
service.addPerson(p);
return "redirect:/overview.htm";
}
How do I do error handling with this, so let's say for example the age must be a positive number and firstname can be left empty.
You need to create a new Validator class, implementing Validator interface.
Your validator can be something like this:
public class PersonValidator implements Validator {
public boolean supports(Class<?> clazz) {
return Person.class.equals(clazz);
}
public void validate(Object target, Errors errors) {
Person person=(Person)target;
if ( person.getAge() < 0 ) {
errors.rejectValue("age", "age_positive");
// Or you can use this approach as well to parametrize the error message:
//errors.rejectValue("age", "age_positive", ArrayParametersIfNeeded, "DefaultMessage");
}
}
}
You also need to have a error.properties file to hold the errors messages allowing i18n.
You can have all needed information about validators here: Validators
When you have it, you need to create the initBinder method in the controller:
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.addValidators(yourValidator);
}
Then, in the controller method, you can pass this additional parameter: BindingResult result and there you will have the information of the errors if you need it.
Also, you need to add this bit to the form:
<form:errors path="age"/></c:set>
Below your <input id="age" name="age" value="${person.age}"/>
I suggest you to change your <input> elements for the <form:input> tag.

hibernate validation - validate one of two paths

I use Spring MVC and Hibernate Validator. I have a OrderForm where you can choose from different payment methods. You have a radio button where you choose your payment method and enter the relevant parameters for the chosen payment methods.
Of course, if someone has chosen "Direct Debit" I don't want validation errors within the "PayPal" Form. At the time I do it like this:
public class OrderForm
{
#NotNull
private Integer customerId
private PaymentMethodDebitForm paymentMethodDebitForm;
private PaymentMethodPayPalForm paymentMethodPayPalForm;
private String paymentSelection;
#Valid
public PaymentForm getPaymentForm ( )
{
if (paymentSelection.equals("PayPal"))
{
return paymentMethodPayPalForm;
}
return paymentMethodDebitForm;
}
This way the validator gets only the form of the selected payment method.
I have two problems.
Spring generates error codes for this with the name of the abstract superclass ("PaymentForm") and not the concret class ("PaymentMethodDebitForm"). As I use this form at a different place as the concrete subclass, I get two different codes resolved. I worked around this by setting the code in the forms:
public class PaymentMethodDebitForm extends PaymentForm
{
#NotNull
#Size(min = 3, max = 50, message = "{paymentMethodDebitForm.iban.Size}")
private String iban;
}
In my jsp I need to refer to the concrete class when I render input field and refer to the super class when I render the error:
<form:input path="paymentMethodDebitForm.iban" size="40" maxlength="50" />
<form:errors path="paymentMethodForm.iban" />
not so nice.
How do you handle polymorphic stuff when it comes to forms and validation with spring/hibernate? Is there some advice how to handle situations like this?
I think I would try to use validation groups via <f:validateBean validationGroups="..." /> or I would separate the forms. This is also discussed here - Validating different Validation Groups JSF 2.0

Spring3 ModelAttribute from jsp request params

Is it possible to grab various form components and turn them into their corresponding DAO objects? I'm trying to avoid creating a custom Bean (which encapsulates all fields) for each Form.
Ex:
<form action="/add">
<input name="foo" id="foo" value="29"/>
<input name="bar" id="bar" value="63"/>
</form>
public void add(#ModelAttribute("foo") Foo myFoo, #ModelAttribute("bar") Bar myBar)
Currently, I'd have to use the HttpRequest, extract the values (29,63), and use them as primary keys to look up the correct database objects. I didn't know if there was a quick way to auto-wire this using ModelAttribute.
Thanks!
You should use #RequestParam
public void add(#RequestParam("foo") Foo myFoo, #RequestParam("bar") Bar myBar) {
}

Resources