Spring4 Form Validation - spring-mvc

I have a situation similar to the followa:
public class Shop {
#NotNull
String name;
#NotNull
String desc;
}
a button to show a form where I have to insert my user:
<form:form method="post" action="saveShop.html" modelAttribute="Shop">
<form:label path="name">Name:</form:label>
<form:input path="name" value="${shop.name}" />
<form:label path="desc">desc:</form:label>
<form:input path="desc" value="${shop.desc}" />
<input type="submit" value="Submit"/>
</form:form>
Controller:
#RequestMapping("/addShop")
public ModelAndView LoadFormPage(#ModelAttribute("Shop")Shop shop) {
ModelAndView model = new ModelAndView();
model.setViewName("/shop/addShop");
return model;
}
#RequestMapping(value = "/saveShop", method = RequestMethod.POST)
public ModelAndView saveShop(#Valid #ModelAttribute("Shop") Shop shop, BindingResult result) {
if (result.hasErrors()) { *do some*
} else { *do someelse* }
}
Even if I leave all fields blank (I have tried even with different data type) and submit the form the controller never recognize errors.
Can you help me?

Make sure to add below configs.
<bean id="myBeansValidator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
and
<mvc:annotation-driven validator="myBeansValidator">
and
<!-- Hibernate Validator -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.2.0.Final</version>
</dependency>
Adapted from Spring MVC form validation not working

Related

Getting null values in Spring MVC controller when submitting data from the jsp

I have a jsp form with an input box, a domain object with get/set methods, and a controller. When I submit the form I get null values in the controller. The "set" method is never being called in the domain object when i submit the form but the object itself is being called.
Order.jsp
<portlet:defineObjects />
<portlet:actionURL portletMode="view" var="createNewOrderURL">
<portlet:param name="action" value="createNewOrder" />
</portlet:actionURL>
<div>
<form:form name="form" method="post" commandName="refOrder" action="${createNewOrderURL}" id="createOrder">
TestName : ${refOrder.name}<br/> <!-- here I get the correct value to display -->
<form:input path="referenceNum" />
<input type="submit" value="Submit" />
</form:form>
</div>
Order.java
public class Order {
private String name = "Name1";
private String referenceNum;
public Order(){
System.out.println("Inside Order.java");
System.out.println(getReferenceNum());
}
public Order(String name, String referenceNum) {
this.name = name;
this.referenceNum = referenceNum;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getReferenceNum() {
return referenceNum;
}
public void setReferenceNum(String referenceNum) {
this.referenceNum = referenceNum;
}
SalesOrderController.java
#RenderMapping
public String defaultRender(RenderRequest request, RenderResponse response, Model model) throws SQLException, NamingException{
model.addAttribute("refOrder",new Order());
return "SalesOrderEntry";
}
#ActionMapping(params={"action=createNewOrder"})
public void addNewOrder(ActionRequest request, ActionResponse response, #ModelAttribute("refOrder") Order order)throws NamingException, SQLException{
System.out.println("Inside addNewOrder method");
System.out.println("New Order is --> "+order.toString());
System.out.println("RefNum - "+order.getReferenceNum());
System.out.println("request.getParameter is "+request.getParameter("referenceNum"));
}
I get null for all the print statements in the controller. Have been trying to fix this for two days now and I can't find what's wrong. Would really appreciate if someone can help me get this to work.
Do you have the following in your src/main/webapp/WEB-INF/liferay-portlet.xml descriptor?
<requires-namespaced-parameters>false</requires-namespaced-parameters>
Also, you might want to take a look at the PortletMVC4Spring project, which is the successor to Spring Portlet MVC. The GitHub project contains archetypes that work in Apache Pluto and Liferay Portal. The requires-namespaced-parameters config option is conveniently set in the archetypes.

Mapping Multiple Controllers in Spring MVC

Define two controllers user and data as follows:
// 1st Controller
#Controller
#RequestMapping(value = {"/", "user"})
public class UserLoginController {
#Autowired
private UserLoginService userLoginService;
#RequestMapping(value = "/", method = RequestMethod.GET)
public String showLoginForm(#ModelAttribute UserLogin userLogin) {
//model.addAttribute(new UserLogin());
//System.out.println("showLoginForm() is called");
return "loginForm";
}
}
//Second COntroller
#Controller
#RequestMapping(value = "user/data/")
public class WorkplanController {
#Autowired
private WorkplanService WorkplanService;
#RequestMapping(value = "importForm", method = RequestMethod.GET)
public ModelAndView importForm(#ModelAttribute SheetUpload sheetUpload){
return new ModelAndView("uploadWorkplan");
}
#RequestMapping(value= "doUpload", method = RequestMethod.POST)
public ModelAndView doUpload(#RequestParam CommonsMultipartFile[] uploadFile, SheetUpload fileUpload, Workplan workplan, HttpServletRequest request) {
return new ModelAndView("uploadSucess");
}
}
When i make request to the doUpload(), it shows HTTP Status 400 Error.
My question is two-fold:
1. Why do have i have to include the user like this: #RequestMapping(value = "user/data/") to make request to the 2nd controller why not like this #RequestMapping(value = "data/")?
2. What do i need to change to make a successful call to the 2nd method in the second controller?
Here is the form am trying to submit:
<form:form action="doUpload" modelAttribute="sheetUpload" method="post"
enctype="multipart/form-data">
<form:select class="createusers_select_menu" path="From">
<form:option value="">Select...</form:option>
<form:option value="A">A</form:option>
<form:option value="B">B</form:option>
<form:option value="C">C</form:option>
</form:select>
<form:input class="browse_btn" path="uploadFile" type="file" />
<input type="submit" class="selct_workplan_2_btn" name="" value=" "/>
</form:form>
Why do have i have to include the user like this: #RequestMapping(value = "user/data/") to make request to the 2nd controller why not like this #RequestMapping(value = "data/")?
You don't have to. Change it to #RequestMapping(value="/data")
What do i need to change to make a successful call to the 2nd method in the second controller?
Try to get it working with a single file field only, then report back. There are lots of tutorials on the web to show how to upload files with Spring.

#RequestParam custom object

I use Spring MVC 3.1 in my app. Say I have a methods in controller as follows:
#RequestMapping(value = "/assignUser", method = RequestMethod.GET)
public String assignUserToCompany(ModelMap map){
List<CompanyDetails> companies = //companies list from DAO
List<UserDetails> users = //users list from DAO
map.addAttribute("companiesList",companies);
map.addAttribute("usersList",users);
return "someView";
}
#RequestMapping(value = "/assignUser", method = RequestMethod.POST)
public String assignUserToCompany(#RequestParam("user")UserDetails user,
#RequestParam("company")CompanyDetails company){
if(user!=null && company!=null){
// some operations with entities
}
return "someView";
}
and I have a form on the view side:
<form method="post" action="assignUser.html">
<label for="select-users"><spring:message code="assignUser.label.users"/> </label>
<select id="select-users" name="user">
<c:forEach items="${usersList}" var="user">
<option value="${user}">${user.firstName} ${user.legalName}</option>
</c:forEach>
</select>
<label for="select-companies"><spring:message code="assignUser.label.companies"/> </label>
<select id="select-companies" name="company">
<c:forEach items="${companiesList}" var="company">
<option value="${company}">${company.name}</option>
</c:forEach>
</select>
<input type="submit" value="<spring:message code="assignUser.label.submit"/>"/>
</form>
I want to pass object I select in input as request parameters and perform some operations with them but standart #RequestParam permit me only primitive types and wrappers as we know.
Can I customize this in order to pass my objects? Thank you.
If the pojo relates directly to a form,decalre a spring form in your jsp (assuming yourDTO has a property name...
<form:form id="yourForm" commandName="yourDTO" action="Save" method="POST">
<form:input path="name" maxlength="90" cssStyle="width: 650px;" id="name"/>
and your controller :
#RequestMapping(value = "/Save", method = RequestMethod.POST)
public ModelAndView save(final yourDTO yourDTO) {
Or if converting one field to a complex class you will have to provide a conversion service :
#Component
public class FooConverter implements Converter<String, Foo> {
#Override public Foo convert(String source) {
//do covnersion from string to Foo
Foo foo = new Foo(source)
return Foo;
}
}
and register it
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.yourcompany.controller.converters.FooConverter"/>
</set>
</property>
</bean>

Using beans in servlets

I has a jsp page (index.jsp) with a form with two text fileds username and password like.
<form action="MyClass">
<input type="text" name="username" id="username" />
<input type="password" name="password" id="password" />
<input type="submit" />
</form>
On form submition i am invocking a servlet. I know that we can get the entered username and password values by using request methods,
request.getParameter("username");
request.getParameter("password");
But i don't want to use them , instead i want to store these values in a bean called BeanClass and i want to retrieve values from the bean in the sevlet. How can i get it??
You have to use <jsp:useBean/> action to instantiate the BeanClass with request or session scope in JSP.
Sample - EmpServlet.java
package com.me;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class EmpServlet extends HttpServlet {
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter pw=response.getWriter();
Emp emp=(Emp)request.getAttribute("emp");
pw.print(emp);
}
}
Emp.java : Emp bean
package com.me;
public class Emp {
private int age;
private String name;
public Emp() {
name="";
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean valid()
{
return age!=0 && name.length()!=0;
}
#Override
public String toString() {
return "Emp{" + "age=" + age + ", name=" + name + '}';
}
}
emp.jsp (view)
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<%#taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<jsp:useBean id="emp" class="com.me.Emp" scope="request">
<jsp:setProperty name="emp" property="*"/>
</jsp:useBean>
<c:if test="${emp.valid()}">
<jsp:forward page="emp"/>
</c:if>
<form method="post" action="emp.jsp">
<br/><input type="text" name="age"/>
<br/><input type="text" name="name"/>
<br/><input type="submit"/>
</form>
web.xml
<servlet>
<servlet-name>EmpServlet</servlet-name>
<servlet-class>com.me.EmpServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>EmpServlet</servlet-name>
<url-pattern>/emp</url-pattern>
</servlet-mapping>
To the point, you're looking for a MVC framework like JSF or Spring MVC. With JSF it'll look something like this:
<h:form>
<h:inputText value="#{bean.username}" required="true" />
<h:inputSecret value="#{bean.password}" required="true" />
<h:commandButton value="submit" action="#{bean.submit}" />
<h:messages />
</h:form>
with
#ManagedBean
#RequestScoped
public class Bean {
private String username;
private String password;
public void submit() {
// Do here your job.
}
// Add/generate getters and setters.
}
That's all. No need for a servlet.
If you really want to do it the low level servlet way, you'd need to populate the bean yourself. This can be convenienced with Apache Commons BeanUtils to save boilerplate code.
Bean bean = new Bean();
BeanUtils.populate(bean, request.getParameterMap());
request.setAttribute("bean", bean);
// ...
The <jsp:useBean> does not allow for the MVC approach, it's more a MV. You have to mingle the conversion/validation into model and control the request/response inside the view, tasks which a controller should do. MVC frameworks offer you a controller which takes all this nasty boilerplate tasks from your hands.

Spring3 MVC - how to impliment CRUD correctly on the same controller?

I am trying to create simple CRUD controller and view using Spring mvc.
I am able to:
Get the document list
Upload document
Deleted Document
If I would like to send the request using FORM,
How do i implement Download Document?
Should I use for every document?
Another thing - am i using the MVC framework correctly?
<html>
<body>
<!-- the list: -->
<c:forEach items="${documentList}" var="documentRow">
<Generate table here>
<!-- upload part -->
<form:form modelAttribute="uploadDocument" method="post" enctype="multipart/form-data">
<form:input path="fileData" type="file"/>
<input type="hidden" id="actUploadocument" name="action" value="uploadDocument" />
</form:form>
<!-- delete part -->
<form:form method="post" enctype="multipart/form-data">
<input type="hidden" id="documentId" value="" />
<input type="hidden" id="actUploadocument" name="action" value="deleteDocument" />
</form:form>
</body>
</html>
The CRUD controller?
#Controller
#RequestMapping("/documents")
public class DocumentsController
{
#Autowired
private MainService mainService;
#RequestMapping(method = RequestMethod.GET)
public String listDocuments(Model model) {
List<Document> docs = mainService.getAllDocuments();
model.addAttribute("documentList",docs);
model.addAttribute(new UploadDocument());
return "admin/documents";
}
#RequestMapping(method = RequestMethod.POST , params="action=uploadDocument")
public String uploadDocument(UploadDocument uploadDocument){
savedocument(uploadDocument);
return "redirect:/admin/documents.do";
}
#RequestMapping(method = RequestMethod.POST , params="action=removeDocument")
public String removeDocument(#RequestParam(value="documentId", required=true) String documentId){
savedocument(documentId);
return "redirect:/admin/documents.do";
}
#RequestMapping(method = RequestMethod.POST , params="action=downloadDocument")
public String downloadDocument(#RequestParam(value="documentId", required=true) String documentId,
HttpServletRequest request,HttpServletResponse response ) {
writeDocToResponse(documentId,response);
return null;
}
Basically all you need to open file download dialog is a set response properties to identify HTTPresponce as attachment.
For instance:
response.reset();
response.setContentType(getYourFileContentType());
response.setHeader("Content-Disposition","attachment; filename=\""+getYourFileName()+"\"");
Then you may call your service method to stream file.

Resources