Spring Web MVC Module



Spring Web MVC Module

Introduction to Controller interface
Spring Web MVC module is similar to other web application frameworks like Struts which is having only one FrontController servlet that servlet only manages form processing of many HTML forms.
The FrontController servlet name in Spring Web MVC is DispatcherServlet.
Spring Web MVC recommends to configure this class in web.xml file with servlet-name as disp and its url-pattern as *.htm
Hence every HTML form when submitting its request the action path must ends with .htm extension. For instance if we submit NewEmp.html file its action path must be named something like ./newEmp.htm
Because of action path ended with .htm extension the request connects to DispatcherServlet first, DS reads spring config file which is prefixed with its name and with the suffix of -servlet.xml. The name of the spring config file is disp-servlet.xml
In disp-servlet.xml we must map one bean whose name matches with action path, DS instantiates that class.
<bean name="/newEmp.htm" class="beans.NewEmpController">
This bean class is the actual form processing class that DispatcherServlet instantiates.
When writing such form processing classes the class must implement from Controller interface and also must implement handleRequest() in it.
handleRequest() method receives request and response objects as arguments.
In the handleRequest() method we need to read all request parameters and perform insert operation on DB using class something like JdbcTemplate or HibernateTemplate.
eid is generated during this process. At the end of the function we need to store response JSP file name, eid (the output var), eid value (the output value) into ModelAndView class constructor, create and one object of that class and return it to DS.
DS reads output var name, its value, stores both into request scope using request.setAttribute() method and forwards response JSP file to browser.
Example on Controller
open web.xml
<servlet>
 <servlet-name>disp</servlet-name>
 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
 <servlet-name>disp</servlet-name>
 <url-pattern>*.htm</url-pattern>
</servlet-mapping>

Create a HTML
Name: NewEmp.html
<PRE>
 <FORM method="POST" action="./newEmp.htm">
  EName   <input type="text" name="ename"/>
  Sal     <input type="text" name="sal"/>
  Desig   <input type="text" name="desig"/>
  <input type="submit" name="submit" value="Save Emp">
 </FORM>
</PRE>

Create a Java class
package: beans
Name: NewEmpController
Super interface: Controller
super class: JdbcDaoSupport

public class NewEmpController extends JdbcDaoSupport implements Controller {

  public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) throws Exception
  {
    String ename=req.getParameter("ename").trim();
    double sal=Double.parseDouble(req.getParameter("sal").trim());
    String desig=req.getParameter("desig").trim();

    int eid=getJdbcTemplate().queryForInt("SELECT emp3_seq.nextval from dual");

    getJdbcTemplate().execute("INSERT INTO emp3 VALUES ("+eid+",'"+ename+"',"+sal+",'"+desig+"')");

    return new ModelAndView("/NewEmpSuccess.jsp", "eid", new Integer(eid));
  }
}

disp-servlet.xml
<bean id="ds" class="org.apache.commons.dbcp.BasicDataSource">
 <property name="driverClassName" value="sun.jdbc.odbc.JdbcOdbcDriver"/>
 <property name="url" value="jdbc:odbc:oracledsn"/>
 <property name="username" value="username"/>
 <property name="password" value="passwod"/>
</bean>

<bean id="jt" class="org.springframework.jdbc.core.JdbcTemplate">
 <constructor-arg ref="ds"/>
</bean>

<bean name="/newEmp.htm" class="beans.NewEmpController">
 <property name="jdbcTemplate" ref="jt"/>
</bean>

Create one JSP
Name: NewEmpSuccess.jsp
EmpID is :<%=request.getAttribute("eid")%>

start tomcat
deploy web application
http://localhost:8080/spring_webmvc_4/NewEmp.html

Spring MultiActionController class
MultiActionController class is also a part of Spring Web MVC module using next to Controller interface.

As we already know that Spring Web MVC is similar to Struts architecture, this web application also contains only one single front controller servlet named DispatcherServlet that processes request coming from any number of HTML forms.

We already implemented one Spring Web MVC application with Controller interface but in that application the sub class of Controller interface can handle only one single HTML form submit button request.

But the sub class of MultiActionController can process request coming from different buttons of the same HTML form. For instance if web develop a single Emp.html form that consists of 5 buttons named save, update, delete, find and findAll.

The request on any of the button comes to a single EmpController class but EmpController contains 5 method names same as button values. Each button request comes to corresponding method of this class.

To ensure this while creating HTML form we need to name all the submit buttons with same name such as "submit" or "method" or "action" and button values same as method names in MAC.

The HTML form is submitted with "./emp.htm" as action path, because the action path suffixed .htm extension such all requests collectively comes to DispatcherServlet.

DispatcherServlet reads disp-servlet.xml ( a spring config file), find outs the bean named with the same name as action path /emp.htm, in disp-servlet.xml we need to map this name to EmpController class which is a sub class of MultiActionController class.

DispatcherServlet instantiate and invoke handleRequest() method on EmpController class

Into EmpController class the handleRequest() method derives from MultiActionController whose implementation is to read the submit value, the method found with the same name as submit button value in EmpController class that corresponding method is invoked by handleRequest() method.

But how handleRequest() method of MAC knows the submit button name?
For that in disp-servlet.xml file we need to configure one more bean named ParameterMethodNameResolver and into PMNR class we need to pass paramName as "submit" and the same pmnr object must injected into our EmpController class methodNameResolver property.

handleRequest() reads paramName from PMNR class, reads that request parameter (nothing but submit button value) whose value matches with one of the method name in our class. That is how handleRequest() method invokes save()/ update()/delete()/find()/findAll() functions in EmpController class.

In addition to that we are also required to inject EmpService class object the so-called business logic component of previous DAO application into our EmpController class constructor.

In save() method we instead of reading all the request parameters we need to create one object of Emp bean and pass hreq and Emp bean class as arguments into bind() function of MAC class. This bind() method reads and populates all request parameters into bean instance.

Soon after populating the form data into JavaBean we need to pass emp bean class object as argument into saveEmp() method of EmpService. saveEmp() interacts to DB through EmpJDBCDAO or EmpHibDAO, saves record into DB and returns eid to save() method.

In save() method we must pass view name ("NES") as first argument instead of view file path ("/NES.jsp"), "eid" as attribute name and new Integer(eid) as third argument in MAV class constructor, return that class object to DispatcherServlet.

DispatcherServler notices that the first argument in MAV is the view name but not file, hence in order to resolve view name to view file, it reads one more bean from disp-servlet, its id is "viewResolver" and its class is ResourceBundleViewResolver.

In ResourceBundleViewResolver we need to pass the basename of properties file, the value is views.

We need to place one views.properties file in WEB-INF/classes folder.

In views.properties file we need to write two properties with view name, one is view.class and the other one is view.url. DispatcherServlet class executes ViewResolver class first and the forwards view file name to browser.

NES.class=org.springframework.web.servlet.view.JstlView
NES.url=/NES.jsp
FAEs.class=beans.FAEsExcelView
FAEs.class=/FAEs.xls

Example on MultiActionController
+ open MyEclipse
+ Create a web project
Name: spring_mac_5
+ Right click on the project-> Choose Add Spring capabilities
Choose Spring Core, Core Persistence, Core JDBC, Spring Web and Hibernate 3.2 checkboxes
+ Copy Emp.java, EmpDAO.java, EmpJDBCDAO.java, EmpHibDAO.java, EmpService.java files of beans package of previous DAO project into our project's src directory.
+ Copy Emp.hbm.xml and applicationContext.xml files also from previous DAO project to our project's src folder
+ open web.xml
<servlet>
 <servlet-name>disp</servlet-name>
 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>

<servlet-mapping>
 <servlet-name>disp</servlet-name>
 <url-pattern>*.htm</url-pattern>
</servlet-mapping>

+ Create one HTML file
Name: Emp.html
<PRE>
 <FORM method="post" action="./emp.htm">
   EID   <input type="text" name="eid" value="0">
   ENAME <input type="text" name="ename">
   SAL   <input type="text" name="sal">
   DESIG <input type="text" name="desig">
   <input type="submit" name="submit" value="save"> <input type="submit" name="submit" value="update"> <input type="submit" name="submit" value="delete"> <input type="submit" name="submit" value="find"> <input type="submit" name="submit" value="findAll">
 </FORM>
</PRE>

+ Create a Java class
Package: beans
Name: EmpController
super class: MultiActionController (place cursor at the end of the class and press CTRL+SPACEBAR)
public class EmpController extends MultiActionController
{
  EmpService es;
  public EmpController(EmpService es)
  {
    this.es=es;
  }
  public ModelAndView save(HttpServletRequest req, HttpServletResponse resp) throws Exception
  {
    Emp e=new Emp();
    bind(req,e);
    int eid=es.saveEmp(e);
    return new ModelAndView("NES", "eid", new Integer(eid));
  }
  public ModelAndView update(HttpServletRequest req, HttpServletResponse resp) throws Exception
  {
    Emp e=new Emp();
    bind(req,e);
    boolean flag=es.updateEmp(e);
    return new ModelAndView("UES", "flag", new Boolean(flag));
  }
  public ModelAndView delete(HttpServletRequest req, HttpServletResponse resp) throws Exception
  {
    int eid=Integer.parseInt(req.getParameter("eid").trim());
    boolean flag=es.deleteEmp(eid);
    return new ModelAndView("DES", "flag", new Boolean(flag));
  }
  public ModelAndView find(HttpServletRequest req, HttpServletResponse resp) throws Exception
  {
    int eid=Integer.parseInt(req.getParameter("eid").trim());
    Emp e=es.findEmp(eid);
    return new ModelAndView("FES", "emp", e);
  }
  public ModelAndView findAll(HttpServletRequest req, HttpServletResponse resp) throws Exception
  {
    List empList=es.findAllEmps();
    Map map=new HashMap();
    map.put("empList", empList);
    return new ModelAndView("FAEs", map);
  }
}

+ Create one more java class
Package: beans
Name: FAEsExcelView
Super class: AbstractExcelView
public class FAEsExcelView extends AbstractExcelView
{
  public void buildExcelDocument(Map map, HSSFWorkBook book, HttpServletRequest req, HttpServletResponse resp) throws Exception
  {
    HSSFSheet sheet1=book.getSheet("Sheet1");
    HSSFCell cell=getCell(sheet1, 0, 0);
    cell.setCellValue("EID");
    cell=getCell(sheet1, 0, 1);
    cell.setCellValue("ENAME");
    cell=getCell(sheet1, 0, 2);
    cell.setCellValue("SAL");
    cell=getCell(sheet1, 0, 3);
    cell.setCellValue("DESIG");

    int row=1, col=0;
    List list=(List)map.get("empList");
    Iterator i=list.iterator();
    while(i.hasNext())
    {
      Emp e=(Emp)i.next();
      cell=getCell(sheet1, row, col++);
      cell.setCellValue(e.getEid()+"");
      cell=getCell(sheet1, row, col++);
      cell.setCellValue(e.getEname());
      cell=getCell(sheet1, row, col++);
      cell.setCellValue(e.getSal()+"");
      cell=getCell(sheet1, row, col);
      cell.setCellValue(e.getDesig());
      row++; col=0;
    }
  }
}

\WEB-INF\classes\views.properties
NES.class=org.springframework.web.servlet.view.JstlView
NES.url=/NES.jsp
UES.class=org.springframework.web.servlet.view.JstlView
UES.url=/UES.jsp
DES.class=org.springframework.web.servlet.view.JstlView
DES.url=/DES.jsp
FES.class=org.springframework.web.servlet.view.JstlView
FES.url=/FES.jsp
FAEs.class=beans.FAEsExcelView
FAEs.ur=/FAEs

disp-servlet.xml
<beans>

 <import resource="classes/applicationContext.xml"/>

 <bean id="pmnr" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">
  <property name="paramName" value="submit"/>
 </bean>

 <bean name="/emp.htm" class="beans.EmpController">
  <constructor-arg ref="es"/>
  <property name="methodNameResolver" ref="pmnr"/>
 </bean>

 <bean id="viewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
  <property name="basename" value="views"/>
 </bean>
</beans>

+ Create a JSP file
Name: NES.jsp
Emp record inserted. EmpID is : <%=request.getAttribute("eid")%>

+ Create one more JSP
Name: UES.jsp
Emp updation status is : <%=request.getAttribute("flag")%>

+ Create one more JSP
Name: DES.jsp
Emp deletion status is : <%=request.getAttribute("flag")%>

+ Create one more JSP
Name: FES.jsp
<%
 beans.Emp e=(beans.Emp)request.getAttribute("emp");
%>
EID   <%=e.getEid()%> <br/>
ENAME <%=e.getEname()%> <br/>
SAL   <%=e.getSal()%> <br/>
DESIG <%=e.getDesig()%> <br/>

+ open MS-Excel, create one file named FAEs.xls on desktop and copy the same into our project's WebRoot directory.

+ Add ojdbc14.jar, commons-pool.jar

+ start tomcat
+ deploy web application
+ open browser
http://localhost:8080/spring_mac_5/Emp.html

SimpleFormController in Spring Web MVC
// UserController.java
package beans;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
public class UserController extends SimpleFormController {

               UserService us;
              
               public UserController(UserService us)          {
                              this.us=us;
               }
              
               public ModelAndView onSubmit(Object command) {
                              User u=(User)command;
                              us.addUser(u);
                              return new ModelAndView("UserSuccess", "user", u);
               }
}

// User.java
package beans;
public class User {
               private String user;
               private String pass;
               public User(String user, String pass) {
                              super();
                              this.user = user;
                              this.pass = pass;
               }
               public User() {
                              super();
                              // TODO Auto-generated constructor stub
               }
               public String getUser() {
                              return user;
               }
               public void setUser(String user) {
                              this.user = user;
               }
               public String getPass() {
                              return pass;
               }
               public void setPass(String pass) {
                              this.pass = pass;
               }
              
              
}

// UserService.java
package beans;

public class UserService {

               public boolean addUser(User u)
               {
                              System.out.println("User added");
                              return true;
               }
}

messages.properties
user.required=<font color="red">User required</font>
pass.required=<font color="red">Pass required</font>

// MyValidator.java
package beans;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

public class MyValidator implements Validator {
              
               @Override
               public boolean supports(Class c) {
                              if(c.getName().equals("beans.User"))
                                             return true;
                              else
                                             return false;
               }
              
               @Override
               public void validate(Object target, Errors errors) {
                              ValidationUtils.rejectIfEmpty(errors, "user", "user.required");
                              ValidationUtils.rejectIfEmpty(errors, "pass", "pass.required");
               }
}

User.jsp
<%@taglib uri="/WEB-INF/spring-form.tld" prefix="form"%>
<%@taglib uri="/WEB-INF/spring.tld" prefix="s"%>

<style>
 .error{
   color:red;
   font-style:italic;
 }
</style>

<PRE>
<form:form commandName="user" method="post">
   <form:errors path="user" cssClass="error"/>
   User: <form:input path="user"/>
   <form:errors path="pass" cssClass="error"/>
   Pass: <form:input path="pass"/>
   <input type="submit"/>
</form:form>
</PRE>

web.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>

<servlet>
<servlet-name>disp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>disp</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>

  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans
               xmlns="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

 <bean id="us" class="beans.UserService"/>

 <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                <property name="prefix" value="/WEB-INF/jsp/"></property>
                <property name="suffix" value=".jsp"></property>
 </bean>

 <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
  <property name="basename" value="messages"/>
 </bean>

<bean id="mv" class="beans.MyValidator">
</bean>

 <bean name="/userRegistration.htm" class="beans.UserController">
  <constructor-arg ref="us"></constructor-arg>
  <property name="commandName" value="user"></property>
  <property name="commandClass" value="beans.User"></property>
  <property name="formView" value="User"></property>
  <property name="successView" value="UserSuccess"></property>
  <property name="validator" ref="mv"></property>
 </bean>
</beans>

UserSuccess.jsp
<%@taglib uri="/WEB-INF/spring.tld" prefix="s"%>
<%@taglib uri="http://java.sun.com/jstl/core" prefix="c"%>
<c:out value="${user.user}"></c:out> <br/>
<c:out value="${user.pass}"></c:out>