I have an account class where I use notations as follows:
#NotNull
private String name;
In account there are many fields, which I use independently in two forms. The issue is that as my first form doesn't contain
private String name;
When I submit the form the validation check fails as a field that isn't in the actual form is being checked.
Essentially the validation will always fail as the variable is in the same class but isn't being used in this particular form.
To get around this would I have to use the Spring Validator class?
Thank you.
I think you may not overcome this kind of problem while having validation annotations. But you can try these:
Create two custom classes for two forms and validate name just for one of them, and do not validate for another.
And also you can try to validate your own field manually in the controller method. Autowire validator class, and validate inside the method.
#Autowired
Validator validator;
public methodA(Model model, #ModelAttribute("modelA") ModelA modelA, BindingResult result){
validator.validate(modelA, result);
if (result.hasErrors()){
// do something
}
else {
// do something else
}
}
I have a form that has two fields:
<input id="password"...
<input id="confirmpassword"...
I have a form binding object that binds to these two variables.
class FormBindingClass
{
private String password;
private String confirmPassword;
......
......
}
Now I validate the above two fields using #NotEmpty and #Pattern validators, however I need to make sure that confirmPassword matches the password on the server side!
If it does not then I need to fail the binding result and show the error back to the user. How can I accomplish this? I explored making custom annotations something like:
#MustMatch(password)
private String confirmPassword;
But I cannot pass dynamic values to annotation can I? How can I solve this tricky issue.
This is a validation at your dao layer andfor which ina general case you would throw an exception to the web layer and handle apprppriately.So you have to manually validate this in your business logic and construct the error response at the web layer.
The spring MVC validations are basically for form backed data and which doesn't have any business logic dependency.
Please correct me if I am wrong.
Both can be used for Data Binding.
The question is when to use #ModelAttribute?
#RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
public String processSubmit(#ModelAttribute Pet pet) { }
In addition, when to use #RequestBody?
#RequestMapping(value = "/user/savecontact", method = RequestMethod.POST
public String saveContact(#RequestBody Contact contact){ }
According to my understanding both serves the similar purpose.
Thanks!!
The simplest way for my understanding is, the #ModelAttribute will take a query string. so, all the data are being pass to the server through the url.
As for #RequestBody, all the data will be pass to the server through a full JSON body.
#ModelAttribute is used for binding data from request param (in key value pairs),
but #RequestBody is used for binding data from whole body of the request like POST,PUT.. request types which contains other format like json, xml.
If you want to do file upload, you have to use #ModelAttribute. With #RequestBody, it's not possible. Sample code
#RestController
#RequestMapping(ProductController.BASE_URL)
public class ProductController {
public static final String BASE_URL = "/api/v1/products";
private ProductService productService;
public ProductController(ProductService productService) {
this.productService = productService;
}
#PostMapping
#ResponseStatus(HttpStatus.CREATED)
public ProductDTO createProduct(#Valid #ModelAttribute ProductInput productInput) {
return productService.createProduct(productInput);
}
}
ProductInput class
#Data
public class ProductInput {
#NotEmpty(message = "Please provide a name")
#Size(min = 2, max = 250, message = "Product name should be minimum 2 character and maximum 250 character")
private String name;
#NotEmpty(message = "Please provide a product description")
#Size(min = 2, max = 5000, message = "Product description should be minimum 2 character and maximum 5000 character")
private String details;
#Min(value = 0, message = "Price should not be negative")
private float price;
#Size(min = 1, max = 10, message = "Product should have minimum 1 image and maximum 10 images")
private Set<MultipartFile> images;
}
I find that #RequestBody (also annotating a class as #RestController) is better for AJAX requests where you have complete control over the contents of the request being issued and the contents are sent as either XML or JSON (because of Jackson). This allows the contents to easily create a model object. Conversely, #ModelAttribute seems to be better suited to forms where there is a "command" object backing a form (which may not necessarily be a model object).
You can directly access your "pet" object in view layer, if you use ModelAttribute annotation. Also, you can instantiate this object in a method on your controller to put your model. see this.
ModelAttribute gives you a chance to use this object partial, but with RequestBody, you get all body of request.
I think #ModelAttribute and #RequestBody both are having same use, only difference
is #ModelAttribute use for normal spring MVC and #RequestBody use for REST web service. It is #PathVariable and #PathParam. But in in both the cases we can mix it. we can use #PathVariable in REST and vice versa.
With #ModelAttribute, you pass data in URL params and with #RequestBody you pass it as JSON body. If you're making a REST API then it's better to use #RequestBody. Over most youtube tutorials you might find use of #ModelAttribute - That's simply because they might be demonstrating concepts regarding Spring MVC and are using URL's to pass data.
We need to have the following jsp tag to data bind your entity to the jsp form fields:
The form is from the spring tag library:
The following is the not the full html, but I hope you can relate your self:
<%#taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<form:form action="save" method="post" modelAttribute="patient">
<table>
<tr>
<td>Name</td>
<td>
<form:input path="patient.patient_name" /> <br />
</td>
</tr>
<tr>
<td>Phone</td>
<td>
<form:input path="patient.phone_number" /> <br />
</td>
</tr>
<tr>
<td colspan="2"><button type="submit">Submit</button></td>
</tr>
</table>
</form:form>
The form has to be processed twice , once before rendering the form, during which we need to give the appropriate bean instantiation for the property value modelAttribute="patient".
For this the controller class(at the class defintion level) you need to have #RequestMapping annotation.
You need to have the handler method parameters as follows
#GetMapping("logincreate")
public String handleLoginCreate(#ModelAttribute("login") Login login, Model model)
{
System.out.println(" Inside handleLoginCreate ");
model.addAttribute("login",login);
return "logincreate";
}
Spring will scan all handler methods #ModelAttribute and instantiate it with default constructor of Login class, and call all of its getters and setters (for the jsp binding from form to the "login"). In case of missing any of the following the jsp will not be shown, various exceptions are thrown
getters/setters
default constructor
model.addAttribute("login",login);
class level #RequestMapping
method parameter level #ModelAttribute
Also, the handler method of action in the jsp, the in the above form action="save", also the handler method might look like this:
#PostMapping("save")
public String saveLoginDetails(#ModelAttribute("login") Login login, Model model) {
//write codee to insert record into DB
System.out.println(" Inside save login details ");
System.out.println("The login object is " + login.toString());
System.out.println("The model object contains the login attribute"+ model.getAttribute("login"));
loginService.saveLogin(login);
return "welcome";
}
Important learning is:
Before form is launched, spring should have appropriate annotation to indicate the backing bean of the form, in the above example the "backing bean" or "binding object" is Login login with appropriate handler method's parameter annotation #ModelAttribute("login") Login login
I have a requirement where i am using Struts2 as well as Jqgrid in JSP.
As per my requirement i am getting a list from different action class through interceptor.
I have to pass the list to JSP and from the Jgrid url back to respective action class.
When i am using request.setAttribute and passing the same value as parameter for
jqgrid action class url its working fine
[E.g showExcelGrid.action?LIST='+"<%=request.getAttribute("LIST")%>" but when list is large its not working properly.
Please suggest some ideas.
Thanks
I am not sure how JqGrid work but below describe the way value flow both way
To send List/Map or any other collection backed object from your action class to JSP all you need to create a list property in your action class and provide its getter and setters for this
Sample Action Class
public class SampleAction extends ActionSupport{
private List<String> listForJspPage;
//getter and setter for this list property
public String execute() throws Exception{
listForJspPage=new ArrayList<String>();
listForJspPage=fill this list with values
return SUCCESS;
}
}
with above code when your action will get executed you have listForJspPage in value stack and can be accessed using OGNL
Sample JSP
<s:iterator value="listForJspPage">
// do what ever you want to fo
</s:itertor>
here value="listForJspPage" will be interpreted by S2 as getListForJspPage() in your action class to fetch the values.
For sending the value back to action class we can make sure of the setter method with a little help from OGNL like
<s:iterator value="listForJspPage">
<s:textfield name="listForJspPage['%{id}'].value" value="%{value}" />
</s:itertor>
In this we iterate over the listForJspPage List. On the textfield tag we set the name to "listForJspPage['%{id}'].value", this would result in something that looks like "listForJspPage['1'].value". which further can be seen as
getListForJsppage().get(index).setvalue(out given value);
I know this late, but I found this one today which works.
You can pass the list from one action class to another via jsp using the s:select tag of struts2 as follows:
List<String> formList //getter and setter should be there in both the action classes
<div id="divList" style="display: none;">
<s:select list="formlist" multiple="true" id="selectedList" name="formListList"></s:select>
</div>
I started researching how to create a controller for a wizard-like form in Spring and came across the AbstractWizardFormController, which I quickly noticed was deprecated.
I then dug a bit further and found how to accomplish something similar with Spring 3. This example does not do any sort of validation though (e.g. via #Valid), so I'm wondering how does one validate each step of a wizard?
Would it be possible for each step have its own backing Form object and then use #SessionAttributes to store their values for when a final submit is called (presumably on the last page of the form)?
Thanks for any help.
(P.S.: Solutions that don't require WebFlow would be ideal.)
I don't know of a way to pull this off with the #Valid annotation, but you should be able to take advantage of the JSR-303 validation to accomplish this. As a somewhat contrived example:
public class User {
#NotNull(message = "First name can't be blank", groups = {Step1.class, FinalStep.class})
private String firstName;
#NotNull(message = "Last name can't be blank", groups = {Step1.class, FinalStep.class})
private String lastName;
#NotNull(message = "Email can't be blank", groups = {Step1.class, FinalStep.class})
private String emailAddress;
#NotNull(message = "Please provide a valid address", groups = {Step2.class, FinalStep.class})
private Address address;
// getters/setters...
public interface Step1 {}
public interface Step2 {}
public interface FinalStep {}
}
You can take advantage of the fact that JSR-303 supports validation groups by providing marker interfaces to represent your wizard steps.
Then, instead of relying on the #Valid annotation, inject a Validator instance into your controller and call:
validator.validate(user, /*<step interface>.class*/);
in your processPage method (referencing Controller in your linked question), and then
validator.validate(user, FinalStep.class);
in your processFinish call.
Use #Validated.
From Spring's documentation:
Variant of JSR-303's Valid, supporting the specification of validation groups. Designed for convenient use with Spring's JSR-303 support but not JSR-303 specific.
Can be used e.g. with Spring MVC handler methods arguments. Supported through SmartValidator's validation hint concept, with validation group classes acting as hint objects.
Can also be used with method level validation, indicating that a specific class is supposed to be validated at the method level (acting as a pointcut for the corresponding validation interceptor), but also optionally specifying the validation groups for method-level validation in the annotated class. Applying this annotation at the method level allows for overriding the validation groups for a specific method but does not serve as a pointcut; a class-level annotation is nevertheless necessary to trigger method validation for a specific bean to begin with. Can also be used as a meta-annotation on a custom stereotype annotation or a custom group-specific validated annotation.