UML软件工程组织

一步一步开发Spring Framework MVC应用程序
作者:Thomas Risberg   翻译 Shining Ray @ Nirvana Studio

这是一个关于如何使用Spring Framework从无到有开发一个Web应用的逐步的指南。本文分成几个部分。你可以按顺序阅读或者根据你对他们的熟悉程度,跳过某些章节。


 
目录

1部分 - 设置基本应用程序和环境.... 2

1 - 开发目录... 2

2 – index.jsp. 2

3将应用程序部署到Tomcat.. 2

4测试应用... 6

5下载Spring分发包... 7

6修改WEB-INF目录中的web.xml. 7

7 - jar文件复制到WEB-INF/lib.. 8

8 - 创建你的控制器... 9

9 - 构建应用程序... 9

10复制并修改log4j.properties. 9

11部署应用程序... 10

12 - 创建一个视图... 11

总结... 13

2部分 - 开发和配置应用程序.... 14

13改进index.jsp. 14

14改进视图和控制器... 14

15解耦视图和控制器... 16

16添加一些业务逻辑的类... 18

17 修改视图用于现实业务数据并且添加消息绑定的支持... 20

18添加一些测试数据来自动组装一些业务对象... 20

19添加消息绑定以及给build.xml添加“clean”目标... 21

3部分 - 为应用程序添加单元测试和表单.... 23

20SpringappController添加单元测试... 23

21ProductManager添加单元测试和新的功能... 25

22添加一个表单... 27

4部分 - 实现数据库持久.... 35

23添加Ant任务来创建和载入测试数据... 35

24JDBC创建一个数据访问对象(DAO)的实现... 38

25修改Web应用来使用数据库持久... 42

26修复损坏的测试... 45
 

第1部分-设置基本应用程序和环境

先决条件:

o       Java SDK我目前使用的是1.4.2

o       Ant  使用1.6.2

o       Apache Tomcat使用5.0.28

你应该已经对使用以上软件相当的自如了。

我不会在这篇文档里面涵盖很多背景信息或者理论——已经有很多书深入地讨论了这些东西。我们会直接投入开发程序的过程中。

第1步 - 开发目录

我们需要一个地方用来放置所有的源代码和其他我们将要创建的文件,所以我新建了一个目录,并命名为“springapp。你可以把这个目录放在你的主文件夹或者其它一些地方。我把我的新建在我已经放在主目录中的“projects目录下,这时我的目录的完整路径“/User/trisberg/projects/springapp。在这个目录中我新建了一个“src”目录来存放所有的Java源代码。然后我创建了另一个目录并命名为“war”。这个目录会存放所有将来进入WAR文件的东西,这个文件我们可以用来部署我们的应用程序。所有除了Java源代码的源文件,像JSP文件和配置文件,也属于这个目录。

第2步 – index.jsp

我将从建立一个叫做“index.jsp的文件(放在war目录中)开始。这是我们整个应用的入口点。

springapp/war/index.jsp

<html>
<head><title>Example :: Spring Application</title></head>
<body>
<h1>Example - Spring Application</h1>
<p>This is my test.</p>
</body>
</html>

只是为了Web应用的完整性,我在war目录中的WEB-INF目录中创建了一个web.xml

springapp/war/WEB-INF/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>
</web-app>

第3步 – 将应用程序部署到Tomcat

下面,我要写一个Ant构建脚本,贯穿这个文档我们都要使用它。一个独立的构建脚本包含了应用服务器特定的任务。同样还有用于控制Tomcat下的任务。

springapp/build.xml

<?xml version="1.0"?>
<project name="springapp" basedir="." default="usage">
    <property file="build.properties"/>
    <property name="src.dir" value="src"/>
    <property name="web.dir" value="war"/>
    <property name="build.dir" value="${web.dir}/WEB-INF/classes"/>
    <property name="name" value="springapp"/>
    <path id="master-classpath">
        <fileset dir="${web.dir}/WEB-INF/lib">
            <include name="*.jar"/>
        </fileset>
        <!-- We need the servlet API classes:        -->
        <!--   for Tomcat 4.1 use servlet.jar        -->
        <!--   for Tomcat 5.0 use servlet-api.jar    -->
        <!--   for Other app server - check the docs -->
        <fileset dir="${appserver.home}/common/lib">
            <include name="servlet*.jar"/>
        </fileset>
        <pathelement path="${build.dir}"/>
    </path>
    <target name="usage">
        <echo message=""/>
        <echo message="${name} build file"/>
        <echo message="-----------------------------------"/>
        <echo message=""/>
        <echo message="Available targets are:"/>
        <echo message=""/>
        <echo message="build     --> Build the application"/>
        <echo message="deploy    --> Deploy application as directory"/>
        <echo message="deploywar --> Deploy application as a WAR file"/>
        <echo message="install   --> Install application in Tomcat"/>
        <echo message="reload    --> Reload application in Tomcat"/>
        <echo message="start     --> Start Tomcat application"/>
        <echo message="stop      --> Stop Tomcat application"/>
        <echo message="list      --> List Tomcat applications"/>
        <echo message=""/>
    </target>
    <target name="build" description="Compile main source tree java files">
        <mkdir dir="${build.dir}"/>
        <javac destdir="${build.dir}" target="1.3" debug="true"
               deprecation="false" optimize="false" failonerror="true">
            <src path="${src.dir}"/>
            <classpath refid="master-classpath"/>
        </javac>
    </target>
    <target name="deploy" depends="build" description="Deploy application">
        <copy todir="${deploy.path}/${name}" preservelastmodified="true">
            <fileset dir="${web.dir}">
                <include name="**/*.*"/>
            </fileset>
        </copy>
    </target>
    <target name="deploywar" depends="build" description="Deploy application as a WAR file">
        <war destfile="${name}.war"
             webxml="${web.dir}/WEB-INF/web.xml">
            <fileset dir="${web.dir}">
                <include name="**/*.*"/>
            </fileset>
        </war>
        <copy todir="${deploy.path}" preservelastmodified="true">
            <fileset dir=".">
                <include name="*.war"/>
            </fileset>
        </copy>
    </target>
<!-- ============================================================== -->
<!-- Tomcat tasks - remove these if you don't have Tomcat installed -->
<!-- ============================================================== -->
    <taskdef name="install" classname="org.apache.catalina.ant.InstallTask">
        <classpath>
            <path location="${appserver.home}/server/lib/catalina-ant.jar"/>
        </classpath>
    </taskdef>
    <taskdef name="reload" classname="org.apache.catalina.ant.ReloadTask">
        <classpath>
            <path location="${appserver.home}/server/lib/catalina-ant.jar"/>
        </classpath>
    </taskdef>
    <taskdef name="list" classname="org.apache.catalina.ant.ListTask">
        <classpath>
            <path location="${appserver.home}/server/lib/catalina-ant.jar"/>
        </classpath>
    </taskdef>
    <taskdef name="start" classname="org.apache.catalina.ant.StartTask">
        <classpath>
            <path location="${appserver.home}/server/lib/catalina-ant.jar"/>
        </classpath>
    </taskdef>
    <taskdef name="stop" classname="org.apache.catalina.ant.StopTask">
        <classpath>
            <path location="${appserver.home}/server/lib/catalina-ant.jar"/>
        </classpath>
    </taskdef>
    <target name="install" description="Install application in Tomcat">
        <install url="${tomcat.manager.url}"
                 username="${tomcat.manager.username}"
                 password="${tomcat.manager.password}"
                 path="/${name}"
                 war="${name}"/>
    </target>
    <target name="reload" description="Reload application in Tomcat">
        <reload url="${tomcat.manager.url}"
                 username="${tomcat.manager.username}"
                 password="${tomcat.manager.password}"
                 path="/${name}"/>
    </target>
    <target name="start" description="Start Tomcat application">
        <start url="${tomcat.manager.url}"
                 username="${tomcat.manager.username}"
                 password="${tomcat.manager.password}"
                 path="/${name}"/>
    </target>
    <target name="stop" description="Stop Tomcat application">
        <stop url="${tomcat.manager.url}"
                 username="${tomcat.manager.username}"
                 password="${tomcat.manager.password}"
                 path="/${name}"/>
    </target>
    <target name="list" description="List Tomcat applications">
        <list url="${tomcat.manager.url}"
                 username="${tomcat.manager.username}"
                 password="${tomcat.manager.password}"/>
    </target>
<!-- End Tomcat tasks -->
</project>

这个脚本现在包含了所有我们需要的目标,以便使我们开发更加容易。这里我不会详细解释这个脚本,因为大部分内容都是比较标准AntTomcat的东西。你可以直接复制上面的构建文件并且把它放在你的开发目录的根目录中。我们还需要一个build.properties文件,你需要自定这个文件来配合你的服务器安装。这个文件和build.xml文件在同一个目录中。

springapp/build.properties

# Ant properties for building the springapp
appserver.home=${user.home}/jakarta-tomcat-5.0.28
deploy.path=${appserver.home}/webapps
tomcat.manager.url=http://localhost:8080/manager
tomcat.manager.username=admin
tomcat.manager.password=tomcat

如果你是在一个你不是Tomcat安装的所有者的系统中,那么Tomcat所有者必须给你访问webapps目录的全部权限,或者他可以在webapps目录下面新建一个“springapp”目录,并且给你全部权限来把程序部署到这个新建的目录中。在Linux上我运行chmod a+rwx springapp 来给与所有人对目录的访问权利。

如果你使用一个不用的Web应用服务器,那么你要删除在构建脚本底部的那些特定于Tomcat的任务。你还要依赖你服务器的热部署特定,否则你就需要手工重新启动你的应用服务器。

现在我运行Ant来确保所有的东西都工作正常。你应该把你当前的目录设置到“springapp”目录下。

[trisberg@localhost springapp]$ ant
Buildfile: build.xml
 
usage:
 
     [echo] springapp build file
     [echo] -----------------------------------
 
     [echo] Available targets are:
 
     [echo] build     --> Build the application
     [echo] deploy    --> Deploy application as directory
     [echo] deploywar --> Deploy application as a WAR file
     [echo] install   --> Install application in Tomcat
     [echo] reload    --> Reload application in Tomcat
     [echo] start     --> Start Tomcat application
     [echo] stop      --> Stop Tomcat application
     [echo] list      --> List Tomcat applications
 
 
BUILD SUCCESSFUL
Total time: 2 seconds

这里最后的动作是进行实际的部署。只要运行Ant并且指明“deploy”或者“deploywar”作为目标。

[trisberg@localhost springapp]$ ant deploy
Buildfile: build.xml
 
build:
    [mkdir] Created dir: /Users/trisberg/projects/springapp/war/WEB-INF/classes
deploy:
     [copy] Copying 2 files to /Users/trisberg/jakarta-tomcat-5.0.28/webapps/springapp
BUILD SUCCESSFUL
Total time: 2 seconds

第4步 – 测试应用

让我们立刻启动Tomcat并且确保我们可以访问这个应用程序。使用我们的构建脚本中的“list”任务来查看Tomcat是否已经载入了新的应用程序。

[trisberg@localhost springapp]$ ant list
Buildfile: build.xml
 
list:
     [list] OK - Listed applications for virtual host localhost
     [list] /admin:running:0:/Users/trisberg/jakarta-tomcat-5.0.28/server/webapps/admin
     [list] /webdav:running:0:/Users/trisberg/jakarta-tomcat-5.0.28/webapps/webdav
     [list] /servlets-examples:running:0:/Users/trisberg/jakarta-tomcat-5.0.28/webapps/servlets-examples
     [list] /springapp:running:0:/Users/trisberg/jakarta-tomcat-5.0.28/webapps/springapp
     [list] /jsp-examples:running:0:/Users/trisberg/jakarta-tomcat-5.0.28/webapps/jsp-examples
     [list] /balancer:running:0:balancer
     [list] /tomcat-docs:running:0:/Users/trisberg/jakarta-tomcat-5.0.28/webapps/tomcat-docs
     [list] /:running:0:/Users/trisberg/jakarta-tomcat-5.0.28/webapps/ROOT
     [list] /manager:running:0:/Users/trisberg/jakarta-tomcat-5.0.28/server/webapps/manager
 
 
BUILD SUCCESSFUL
Total time: 1 second

如果他没有被列出,使用“install任务来把应用程序安装到Tomcat中。

[trisberg@localhost springapp]$ ant install
Buildfile: build.xml
 
install:
  [install] OK - Installed application at context path /springapp
 
 
BUILD SUCCESSFUL
Total time: 2 seconds

现在打开一个浏览器并浏览http://localhost:8080/springapp/index.jsp.

5步 – 下载Spring分发包

如果你还没有下载Spring Framework的发布文件,那现在就行动吧。我目前使用的是“spring-framework-1.2-with-dependencies.zip,可以从www.springframework.org/download.html  下载到。我把文件解压缩到我的主目录中。我们后面将要用到里面的一些文件。

到此为止必要的环境安装已经完成了,现在我们要开始实际开发我们的Spring Framework MVC应用了。

6步 – 修改WEB-INF目录中的web.xml

进入“springapp/war/ WEB-INF目录。修改我们前面创建的最小“web.xml文件。现在我们要修改它来满足我们需求。我们定义一个将来控制我们所有请求转向的DispatcherServlet,它将根据我们以后某处输入的信息进行工作。同时还有一个标准的用来映射到我们使用的URL模式的servlet-mapping条目。我决定让所有带“.htm扩展名的URL转向到“springapp 分配器。

springapp/war/WEB-INF/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>springapp</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
 
  <servlet-mapping>
    <servlet-name>springapp</servlet-name>
    <url-pattern>*.htm</url-pattern>
  </servlet-mapping>
 
  <welcome-file-list>
    <welcome-file>
      index.jsp
    </welcome-file>
  </welcome-file-list>
</web-app>

下面,在springapp/war/WEB-INF目录下创建一个叫做“springapp-servlet.xml的文件(你可以直接从Spring分发包中复制一个范例文件,位于sample/skeletons/webapp-minimal 目录中)。DispatcherServlet所使用的定义就要放在这个文件中。文件名是web.xml中的servlet-name并加上“-servlet”后缀。这是Spring Framework所使用的标准命名约定。现在,添加一个叫做springappControllerbean条目并创建一个SpringappController类。这里将定义我们的应用程序所使用的控制器。我们还要添加一个URL映射 urlMapping这样DispatcherServlet就会知道对于不同的URL应该调用哪个控制器。

springapp/war/WEB-INF/springapp-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<!--
  - Application context definition for "springapp" DispatcherServlet.
  -->
<beans>
    <bean id="springappController" class="SpringappController"/>
    <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/hello.htm">springappController</prop>
            </props>
        </property>
    </bean>
</beans>

7 - jar文件复制到WEB-INF/lib

首先在“war/WEB-INF目录中创建一个“lib”目录。然后,从Spring分发包中,将spring.jar(spring-framework-1.2/dist/spring.jar)复制到新建的war/WEB-INF/lib目录中。同时把commons-loggingjar文件(spring-framework-1.2/lib/jakarta-commons/commons-logging.jar)也复制到war/WEB-INF/lib中。同时我们还需要log4j.jar。把log4j-1.2.9.jar(spring-framework-1.2/lib/log4j/log4j-1.2.9.jar)复制到 war/WEB-INF/lib目录。这些jar文件以后会被部署到服务器上而且他们在构建过程中也会被用到。

8 - 创建你的控制器

创建你的控制器——我把我的控制器命名为SpringappController.java并把它放在springapp/src目录下。

springapp/src/SpringappController.java

import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class SpringappController implements Controller {
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        return new ModelAndView("");
    }
}

这是非常基本的控制器。我们稍后会对他进行扩充,同时过会儿我们还要扩展一些已经提供的抽象的基本实现。这个控制器处理请求并返回一个ModelAndView。不过我们还没有定义任何视图,所以现在没什么可做的了。

9 - 构建应用程序

运行build.xml中的“build任务。基本上代码应该顺利通过编译。

[trisberg@localhost springapp]$ ant build