Usually i have seen a server side validation in spring mvc like this for example there is customer page which contains customer related information like customerName ,customerAddress,customerPhoneNumber for this we going to have
customer model object then in the spring controller we are going to call like this
Spring Controller
#RequestMapping(value = "/customerRegistrationScreen")
public String customerRegistrationScreen(Model model) {
Customer customer= new Customer();
model.addAttribute("customer", customer);
return "customerRegistrationScreen";
}
#RequestMapping(value = "/doCustomerRegistration", method = RequestMethod.POST)
public ModelAndView registerCustomer(#ModelAttribute("customer") #Validated Customer customer, BindingResult result,Model model) {
if (result.hasErrors()) {
} else {
}
}
CustomerValidator class
#Component
public class CustomerValidator implements Validator {
#Override
public boolean supports(Class<?> clazz) {
return Customer.class.equals(clazz);
}
#Override
public void validate(Object obj, Errors err) {
ValidationUtils.rejectIfEmpty(err, "name", "customer.name.empty");
ValidationUtils.rejectIfEmpty(err, "email", "customer.email.empty");
ValidationUtils.rejectIfEmpty(err, "gender", "customer.gender.empty");
ValidationUtils.rejectIfEmpty(err, "languages", "customer.languages.empty");
User user = (User) obj;
Pattern pattern = Pattern.compile("^[A-Z0-9._%+-]+#[A-Z0-9.-]+\\.[A-Z]{2,6}$",
Pattern.CASE_INSENSITIVE);
if (!(pattern.matcher(customer.getEmail()).matches())) {
err.rejectValue("email", "user.email.invalid");
}
}
}
customerRegistration.jsp
<form:form method="post" modelAttribute="customer" action="doCustomerRegistration">
</form:form>
what if the jsp have two model object information like Customer and product information like customerName,customerAddress,customerPhoneNumber,productID,productName,productPrice here i like to have two model object like customer
& Product if i have two model object how can i map model attribute from jsp and Spring contoller and how can i do server side validation for both the validation
Although it is a good idea to keep models separate in each form, but for this particular use case it can be achieved by following below steps.
The best way to achieve this is to wrap both the Model attributes in one wrapper class and use it in validation.
Lets say Product class looks like this.
public class Product{
String productName;
// other fields and their getter setters
}
Create a wrapper class which wraps both models Customer and Product
public class CustomerProductWrapper {
private Customer customer;
private Product product;
//getter setter
}
In your validator class , change the implementation of supports() method as below
#Override
public boolean supports(Class clazz) {
return CustomerProductWrapper .class.equals(clazz);
}
2.1 Change the implementation of Validation Method as below
#Override
public void validate(Object obj, Errors err) {
//The object that you get now is CustomerProductWrapper object
// refer the fields using this object
ValidationUtils.rejectIfEmpty(err, "customer.name", "customer.name.empty");
ValidationUtils.rejectIfEmpty(err, "customer.email", "customer.email.empty");
ValidationUtils.rejectIfEmpty(err, "customer.gender", "customer.gender.empty");
ValidationUtils.rejectIfEmpty(err, "customer.languages", "customer.languages.empty");
CustomerProductWrapper cpw= (CustomerProductWrapper ) obj;
Pattern pattern = Pattern.compile("^[A-Z0-9._%+-]+#[A-Z0-9.-]+\\.[A-Z]{2,6}$",
Pattern.CASE_INSENSITIVE);
if (!(pattern.matcher(cpw.getCustomer().getEmail()).matches())) {
err.rejectValue("customer.email", "user.email.invalid");
}
//validate a Product field
ValidationUtils.rejectIfEmpty(err, "product.productName", "product.name.empty");
}
In your controller mapping ,
public String customerRegistrationScreen(Model model) {
CustomerProductWrapper cpw= new CustomerProductWrapper ();
model.addAttribute("cpw", cpw);
return "customerRegistrationScreen";
}
And
#RequestMapping(value = "/doCustomerRegistration", method = RequestMethod.POST)
public ModelAndView registerCustomer(#ModelAttribute("cpw") #Validated CustomerProductWrapper cpw, BindingResult result,Model model) {
if (result.hasErrors()) {
} else {
}
}
And finally in your view page
<form:form method="post" modelAttribute="cpw" action="doCustomerRegistration">
</form:form>
Also refer fields using cpw's attributes that is
<form:input path="name" />
<form:errors path="name" cssClass="error" />
will change to
<form:input path="customer.name" />
<form:errors path="customer.name" cssClass="error" />
Similarly for product validation you can use
<form:input path="product.productName" />
<form:errors path="product.productName" cssClass="error" />
That's all.
Hi I'm trying to post an object that is like :
public class myobj
{
public string name {get;set;}
public myEntity myentity {get;set;}
public mySecondEntity mySecondEntity {get;set;}
}
public class myEntity {get;set;}
{
public string name {get;set;}
public string description {get;set;}
}
public class mySecondEntity {get;set;}
{
public string name {get;set;}
public string description {get;set;}
}
When I use generate a new object of myObj and use PostUrlEncodedAsync it is posting it as :
name : "myname",
myentity : "detex.Models.DTO.myEntity",
mysecondentity : "detex.Models.DTO.mySecondEntity
Not sure what my namespace/class is doing in those fields. I'm posting this as
await "myurl.com".PostUrlEncodedAsync(_model).
Flurl assumes that objects passed to PostUrlEncodedAsync represent simple name/value pairs. It simply does a ToString on your values, which is why you're getting detex.Models.DTO.myEntity. Do you want those values serialized to JSON? If so you'll need to do that yourself:
"myurl.com".PostUrlEncodedAsync(new {
name = _model.name,
myentity = JsonConvert.SerializeObject(_model.myentity),
mysecondentity = JsonConvert.SerializeObject(_model.mySecondEntity)
});
Posting complex objects as URL-encoded is not typical, which is why serializing those values is not built into Flurl.
How to bind a map property of the model and send the selected value back to the controller?
i am able to populate the drop down but on submitting the form getting error 400 - bad request.
MyModel.java:
public class MyModel{
private Map<MySubModel, String> subModel = new HashMap<MySubModel, String>();
private SubModel subModelSearched;
}
SubModel.java:
public class SubModel{
public String id;
public String name;
}
JSP:
<form:form action="/mySearch" modelAttribute="myModel" method="post">
<form:select path="subModelSearched">
<form:options items="${myModel.subModel}/>
</form:select>
.....
</form:form>
I am trying to send parameters from UI to Spring MVC controller. My parameter looks like
caseId=23951910&serviceProvided%5B0%5D.id=25989&serviceProvided%5B0%5D.desc=24-Hour+Service&serviceProvided%5B0%5D.duration=1&serviceProvided%5B0%5D.pages=--&serviceProvided%5B1%5D.id=25988&serviceProvided%5B1%5D.desc=3rd+Party+Contact&serviceProvided%5B1%5D.duration=2&serviceProvided%5B1%5D.pages=--&serviceProvided%5B2%5D.id=25980&serviceProvided%5B2%5D.desc=Advice&serviceProvided%5B2%5D.duration=3&serviceProvided%5B2%5D.pages=--&serviceProvided%5B3%5D.id=25982&serviceProvided%5B3%5D.desc=Document+Preparation&serviceProvided%5B3%5D.duration=4&serviceProvided%5B3%5D.pages=--&serviceProvided%5B4%5D.id=DOCREVIEW&serviceProvided%5B4%5D.desc=Document+Review&serviceProvided%5B4%5D.duration=5&serviceProvided%5B4%5D.pages=6
To match this parameter I am using custom class as
Class MyDto {
private Long caseId;
private List<ServiceProvided> serviceProvided;
//getter and setter
}
Class ServiceProvided {
private String id;
private String desc;
private Long duration;
private Long pages;
//getter and setter
}
I have controller as
#RequestMapping(value = "/cases/resolveClaim.htm", method = RequestMethod.POST)
public ModelAndView createClaim(#ModelAttribute("claimInfo") MyDto myDto, BindingResult result) { ... }
I am getting 404 error so I am guessing "serviceProvided" list couldn't match to myDto. So my questions are:
Is this a really a reason I am getting 404 error?
If yes I guess I have to solve with PropertyEditor or Converter? Am I correct?
Is there any example code that I can refer to?
Thanks
Thanks in advance for any help.
I have a form that is being validated with JSR 303. After validation fails, the controller returns the form, shows validation errors, and renders the form with the original values. This works fine with all types of form elements except the mutli-select element.
The command object:
public class TaskOrder implements Serializable {
private static final long serialVersionUID = 1L;
...
#XmlTransient
#ManyToMany
#<OtherJPAAnnotations...>
private List<Contractor> subcontractors;
...
}
Contractor class:
public class Contractor implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#<OtherJPAAnnotations...>
private Integer id;
#<OtherJPAAnnotations...>
private String name;
}
Controller:
#RequestMapping(value="processingPath", method=RequestMethod.POST)
public String createNewTaskOrder(#Valid #ModelAttribute TaskOrder taskOrder,
BindingResult result,
Model model) {
...
if (!result.hasErrors()) {
//No binding errors, lots of processing...
else {
model.addAllAttributes(result.getModel());
model.addAttribute(taskOrder);
model.addAttribute("subs", myDAOInstance.getSubs());
return this.setupNewTaskOrder(model);
}
}
#RequestMapping("getFormPath")
public String setupNewTaskOrder(Model model) {
if (!model.containsAttribute("taskOrder")) {
TaskOrder taskOrder = new TaskOrder();
taskOrder.setId(0);
model.addAttribute(taskOrder);
}
return "_n/admin/taskOrder/new";
}
The form:
<form:form commandName="taskOrder" action="processPath">
...
<form:select path="subcontractors">
<form:options items="${subs}" itemValue="id" itemLabel="name"/>
</form:select>
...
</form>
When I open an existing "TaskOrder" with the same form, the values are selected in the "subcontractors" multi-select.
However, trying to add a new "TaskOrder", when it returns from validation the values aren't selected. I know that the selected values are being attached to the model and returned, but just not being selected in the select element.
Thanks for any help!
Thanks for the help. Biju...you were correct!
For those who may stumble across this issue, I added the "EqualsUtil" class described here to my project:
http://www.javapractices.com/topic/TopicAction.do?Id=17
Then added the following method to my Contractor class:
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Contractor)) return false;
Contractor c = (Contractor) o;
//Here I ignore the other properties since "id" and "name" are what
//I'm primarily concerned with...
return EqualsUtil.areEqual(this.name, c.name) &&
EqualsUtil.areEqual(this.id, c.id);
}