Web Development
Using Spring MVC
Wenjie He
Gateway JUG, Nov. 4, 2008
Project Description
Mobile Member Portal
for Express Scripts, Inc. (ESI)
Main Requirements:
Built in ESI Framework -- Spring MVC/Castrol/XSL Capable of being viewed from the Blackberry (and iPhone) mobile web browser
ESI Member Portal (1)
Regular Web Version Login page
ESI Member Portal (2)
Regular Web Version Main page
ESI Member Portal (3)
Regular Web Version My Prescriptions Check Order Status
Demonstration of Mobile Version
Still under development Look and feel on iPhone
Background of Development Team
16 students in my Advanced Java class A few students in my Independent Study class At least half of the students only know core Java, but not Java EE. None of the students knows about the Spring Framework. The students are organized in four groups.
Development Phases
Develop using Servlets and JSP
Teaching Java EE basics Get experience in web development Two months
Develop using Spring and Hibernate
Learning + Developing in one months Only use Spring MVC basic features
8
Development Tools
Database: HSQLDB IDE: Eclipse Build tool: Ant Server: Tomcat Framework: Spring Persistence: Hibernate
9
User Interface Design
Login page and main page HTLM + CSS
10
Introduction to Spring Framework
Target on Enterprise JavaBeans (EJB)
Heavy weight vs. light weight Example: transaction support
Testing: Test-Driven Design (TDD)
Tight coupling vs. loose coupling
11
Why Spring in This Project?
ESI requirements Make web development more efficient
Streamline the procedure
Regular Servlets & JSP vs. Spring approach
Testability Easy maintenance
12
Spring Web MVC
One of the several modules in Spring Model-View-Controller (MVC) pattern
Separate user interface from application logic View user interface Model data and business services Controller interactions between model and view Easier to reuse code Easier to maintain web applications Other popular MVC frameworks: Struts, JSF 13
Front Controller Design Pattern
A front controller is a common web-application pattern
Entry point of the framework The first place a request meets the application A central servlet that dispatches requests to controllers The Spring web MVC is designed around
org.springframework.web.servlet.DispatcherServlet
It is integrated with the Spring IoC container. IoC Inverse of Control 14
15
Diagram of Request Processing Workflow
Library JAR Files
Database: server + driver
hsqldb.jar (691k)
Spring MVC: spring.jar, spring-webmvc.jar JSTL: jstl.jar, standard.jar Hibernate3: hibernate3.jar, and some more Hibernate tools:
hibernate-tools.jar, freemaker.jar
Servlets: servlet-api.jar
16
Setting Properties for Database
In build.properties
hsqldb.lib=/JavaEE/DBMS/hsqldb/lib db.name=esimobiledb hsqldb.dbfile=file:db/${db.name} hsqldb.dbalias=${db.name} db.driver=org.hsqldb.jdbcDriver db.url=jdbc:hsqldb:hsql://localhost/${db.name} db.user=sa db.pw= 17
Ant Target to Start DB Server
<path id="hsqldb.lib.path"> <fileset dir="${hsqldb.lib}"> <include name="hsqldb.jar" /> </fileset> </path> <target name="dbserver"> <java classname="org.hsqldb.Server fork="yes"> <classpath refid="hsqldb.lib.path"/> <arg value="-database.0"/> <arg value="${hsqldb.dbfile}"/> <arg value="-dbname.0"/> <arg value="${hsqldb.dbalias}"/> </java> </target>
18
Setting Properties for Tomcat
In build.properties
appserver.home=/JavaEE/Servers/Tomcat/apache-tomcat6.0.18 appserver.bin=${appserver.home}/bin appserver.lib=${appserver.home}/lib deploy.path=${appserver.home}/webapps tomcat.manager.url=http://localhost:8080/manager tomcat.manager.username=tomcat tomcat.manager.password=javaee
19
Ant Target to Start Tomcat
<target name="startTomcat"> <exec executable="cmd"> <arg value="/c"/> <arg value="${appserver.bin}/startup.bat"/> </exec> </target>
20
Configuration of Front Controller
In web.xml
<servlet> <servlet-name>esiMobile</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>esiMobile</servlet-name> <url-pattern>*.htm</url-pattern> </servlet-mapping>
21
Loading Spring Application Context
<servlet-name>: Developer chooses the servlet name for DispatcherServlet In this example, we use esiMobile
Default Spring application context file:
esiMobile-servlet.xml
When DispatcherServlet is loaded, the Spring application context in esiMobile-servlet.xml is loaded.
22
Choosing URL Pattern for Spring MVC
We can choose any URL pattern for
DispatcherServlet
<servlet-mapping> <servlet-name>esiMobile</servlet-name> <url-pattern>*.htm</url-pattern> </servlet-mapping>
Convention for most Spring MVC applications:
*.htm
They are virtual URLs. No such HTML files exist.
23
Object/Relational Mapping by Hibernate
Mapping Java objects to database tables Most useful in the Java-based middle-tier Encapsulate vendor-specific SQL code Reduces the effort needed to convert between relational database result-sets and graphs of Java objects
24
Start with a Table in Database
create table USER ( userid varchar(30) not null, username varchar(30), password varchar(30), firstname varchar(40), lastname varchar(40), email varchar(50), accountType varchar(20), lastlogintime date, primary key (userid) ); 25
Persistent Class for the Table
public class User { private String userid; private String username; private String password; private String firstname; private String lastname; private String email; private String accountType; private Date lastlogintime; public void setUserid(String userid) { this.userid = userid; }
26
Hibernate Mapping Files
User.hbm.xml
<hibernate-mapping> <class name="com.javux.esimobile.entity.User table="USER"> <id name="userid" type="string" unsaved-value="null" > <column name="userid" sql-type="varchar(30)" notnull="true"/> <generator class="assigned"/> </id> <property name="username" type="string" length="30"/>
27
Hibernate Configuration File
Hibernate.cfg.xml
<session-factory> <property name="connection.driver_class"> org.hsqldb.jdbcDriver</property> <property name="connection.url"> jdbc:hsqldb:hsql://localhost/esimobiledb</property> <property name="connection.username">sa</property> <property name="connection.password"></property> <property name="dialect"> org.hibernate.dialect.HSQLDialect</property> <mapping resource="com/javux/esimobile/entity/DrugOrder.hbm.xml"/>
28
Using Hibernate Tools to Generate Artifacts
Create Hibernate mapping files, e.g. User.hbm.xml Create Hibernate configuration file, hibernate.cfg.xml Run an Ant target to generate database schema Run an Ant target to generate persistent classes
29
Generate Database Schema
<taskdef name="htools" classname="org.hibernate.tool.ant.HibernateToolTask" classpathref="htools.lib" /> <target name="schemaGen"> <htools destdir="db"> <configuration configurationfile="${src.dir}/hibernate.cfg.xml" /> <hbm2ddl drop="true" outputfilename="ESImobileTables.sql" /> </htools> </target>
30
Generate Java Persistent Classes
<property name="src.dir" value="src" /> <target name="javaGen"> <htools destdir="${src.dir}"> <configuration configurationfile="${src.dir}/hibernate.cfg.xml" /> <hbm2java jdk5="true"/> </htools> </target> 31
Data Access Objects: Base Class
public class DAO { public static Session getSession() { Session session = (Session) DAO.session.get(); if (session == null) { session = sessionFactory.openSession(); DAO.session.set(session); } return session; } protected void begin() { getSession().beginTransaction(); }
32
Data Access Object for a Table
public class UserDAO extends DAO { public User getByUsername(String username) throws DatabaseException { try { begin(); Query q = getSession().createQuery( "from User where username = :username"); q.setString("username", username); User user = (User) q.uniqueResult(); commit(); return user; }
33
Bird View of Following Steps
Data binding Validation Authentication (services) Navigation
All built around controllers
34
Spring MVC Controllers
Central piece in Spring MVC pattern Responsible for dealing with browser requests Bridge between end user and applications services A controller is configured as another JavaBean in the Spring application context.
web web Dispatcher Servlet 35 Controller Service
Mapping URLs to Controllers
In esiMobile-servlet.xml
<bean id="simpleUrlMapping" class =
"org.springframework.web.servlet.handler.SimpleUrlHandler Mapping"> <property name ="mappings">
<props> <prop key ="/login.htm"> loginESImobileController</prop> <prop key ="/activate.htm"> activateController</prop> <prop key ="/activateA.htm"> activateAController</prop> <prop key ="/username.htm"> usernameController</prop>
36
Spring MVC Command Objects
A command object is a bean that holds the request parameters for easy access. A POJO (Plain Old Java Object) that has fields that can be accessed via setters and getters Data binding mapping form fields to the command class Store the data form fields properties of command Populate the fields of the form properties of command form fields 37
An Example of Command Class
public class LoginCommand { private String userId; private String password; public String getPassword() { return password; } public void setPassword(String password) { this.password = password; }
38
Presenting Model with a View
After processing, the controller sends the results back to browser.
Mapping view names to actual pages Displaying data in the model in the view pages
The view and model data is encapsulated in a ModelAndView object. Every controller execution method must return a ModelAndView object.
39
Declaring a View Resolver
The ModelAndView object contains a logical view name of the view page. A view resolver maps the logical view name to a real view page. In esiMobile-servlet.xml
<bean id="viewResolver" class =
"org.springframework.web.servlet.view.InternalResourceViewResolve r"> MainPage <property name="viewClass"><value>
org.springframework.web.servlet.view.JstlView </value></property> <property name ="prefix"><value> /WEB-INF/jsp/MainPage.jsp /WEB-INF/jsp/</value></property> <property name ="suffix"><value>.jsp</value></property> </bean>
40
Building a Controller:
LoginESImobileController (1)
package com.javux.esimobile.controllers; import import import import import import import import import com.javux.esimobile.commands.LoginCommand; com.javux.esimobile.dao.UserDAO; com.javux.esimobile.services.AuthenticationService; javax.servlet.http.HttpServletRequest; javax.servlet.http.HttpServletResponse; javax.servlet.http.HttpSession; org.springframework.validation.BindException; org.springframework.web.servlet.ModelAndView; org.springframework.web.servlet.mvc.SimpleFormController;
public class LoginESImobileController extends SimpleFormController { private AuthenticationService authenticationService; private UserDAO userDAO;
41
Building a Controller:
LoginESImobileController (2)
protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception{ HttpSession session = request.getSession( true ); LoginCommand loginCommand = (LoginCommand) command; String username = loginCommand.getUserId(); session.setAttribute("username",username); if ( authenticationService.authenticate(request, loginCommand, userDAO) ) { return new ModelAndView(getSuccessView()); } else { request.setAttribute("pass","fail"); return showForm(request, response, errors); } }
42
Building a Controller:
LoginESImobileController (3)
public void setAuthenticationService( AuthenticationService authenticationService) { this.authenticationService = authenticationService; } public void setUserDAO(UserDAO udao) { userDAO = udao; } 43
Dependency Injection (DI)
Making code simpler, easier to understand, and easier to test. Traditional way:
Objects responsible for obtaining its own references Lead to highly coupled and hard-to-test code
DI way:
Objects are given their dependencies at creation time by the container Loose coupling 44
Benefit of Loose Coupling
The depending object only knows about its dependencies by their interface
Not their implementation Not how they are instantiated
The dependency can be swapped out with a different implementation
ClassA
Injected into implementation1
InterfaceB
implementation2
45
Breaking up Application Context
Splitting the application context file into logical pieces can make maintenance easier. Putting the beans of services in
esiMobile-services.xml
Configuring the context loader
<context-param> <param-name> contextConfigLocation</param-name> <param-value> /WEB-INF/esiMobile-services.xml</param-value> </context-param>
Configuring Beans in esiMobile-services.xml
<beans> <bean id="userDAO" class="com.javux.esimobile.dao.UserDAO"> </bean>
UserDAO userDAO = new UserDAO();
<bean id="authenticationService" class="com.javux.esimobile.services.AuthenticationService"> </bean> <bean id="loginValidator" class="com.javux.esimobile.validators.LoginValidator"> </bean>
47
Configuring Controllers in Application Context (1)
In esiMobile-servlet.xml Configuring the command
<bean id="loginESImobileController" class="com.javux.esimobile.controllers.LoginESImo bileController"> <property name="sessionForm"><value>true</value></property> <property name="commandName"> <value>loginCommand</value></property> <property name="commandClass"> <value>com.javux.esimobile.commands.LoginComman d</value></property> 48
Configuring Controllers in Application Context (2)
Configuring bean properties
<property name="validator"> <ref bean="loginValidator" /> </property> <property name="authenticationService"> <ref bean="authenticationService" /> </property> <property name="userDAO"> <ref bean="userDAO" /> </property>
49
Configuring Controllers in Application Context (3)
Configuring views
<property name="formView"> <value>SignIn</value> </property> <property name="successView"> <value>MainPage</value> </property> </bean> 50
How DI Works
When creating bean loginESImobileController
Instantiating an instance of UserDAO UserDAO userDAO = new UserDAO(); Injecting userDAO into loginESImobileController loginESImobileController.setUserDAO(userDAO);
It is done by the container implicitly.
51
Validating Form Input
public class EmailLoginValidator implements Validator { public boolean supports(Class clazz) { return EmailLoginCommand.class.equals(clazz); } public void validate(Object obj, Errors errors) { ValidationUtils.rejectIfEmptyOrWhitespace(errors, "email", "error.email.empty"); EmailLoginCommand elc = (EmailLoginCommand) obj; if ( elc.getEmail().length() > 0) { if (elc.getEmail().indexOf("@") < 0) { errors.rejectValue("email", "error.email.invaid"); } } }
52
Rendering Externalized Mesages
Put all the messages in the file
resources/messages.properties
In esiMobile-servlet.xml
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessag eSource"> <property name="basename" value="resources/messages"/> </bean>
In JSP
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<spring:message code="esimobile.title"/> 53
Binding Form Data (1)
<%@ page session="true"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <form:form method="post" commandName="loginCommand"> </form:form>
54
Binding Form Data (2)
<form:form method="post" commandName="loginCommand"> <td class='center' width='80'>Username: </td> <td class='left' width='120> <form:input path="userId"/> </td> <td class='center' width='80'>Password: </td> <td class='left' width='120'><form:password path="password"/></td> <form:errors path="userId" cssClass="errormsg"/> <form:errors path="password" cssClass="errormsg2"/> <input class='imgButton' type="image src="images/btnSignIn.gif" > </form:form>
55
Binding to a Drop Down Box (1)
Binding to a Drop Down Box (2)
<span id='selectInputKnow'> <form:select path='hearAboutId'> <form:option value='0' label='Select One'/> <form:option value='1' label='E-mail'/> <form:option value='2' label='Mail materials'/> <form:option value='3' label='Customer service phone line'/> <form:option value='4' label='Materials provided with your prescription'/> <form:option value='5' label='Pharmacist'/> <form:option value='6' label='Communication from your employer'/> <form:option value='7' label='Benefits ID card'/> <form:option value='8' label='Other'/> </form:select> </span>
Summarize
Dependency Injection Loose coupling Spring MVC configuration
Bean (service) configuration Controller configuration
Validation Data binding
Thank You!