/**
作者:Willpower
来源:Rifoo Technology(http://www.rifoo.com)
时间:2006-01-08
备注:转载请保留以上声明
**/
本文讲解2.2节使用Web MVC构建一个表现层视图(View)。我们会使用Spring MVC创建一个简单的web用户接口。相信大家对MVC模式都比较熟悉了,这里就不罗嗦了。不熟悉的补一下基础。下面是MVC模式的简图,将web应用分离成三个不同的部分,M模型,V视图,C控制器。Struts框架就是一种流行的MVC模式的实现框架。

我们先建立include.jsp,这个jsp用来引入一些通用的标签。这里我们要使用到JSTL标签,所以我们需要在include.jsp中加入以下两行:
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %>
然后从下载的Spring包中找到standard.jar,jstl.jar,c.tld,fmt.tld这几个文件,将它们复制到WEB-INF/lib下。
我们下面来编写一个jsp,这个jsp页面可以让我们从一个列表中选择一个山地车,选择后可以删除或编辑它。也可以添加一个山地车,不过添加页面是另一个页面。代码如下:
Example 2-6. bikes.jsp
<%@ page import="com.springbook.*"%>
<%@ include file="include.jsp" %>
<html>
<head>
<title>
<c:out value="${rentaBike.storeName}"/>
</title>
</head>
<body>
<h1><c:out value="${rentaBike.storeName}"/></h1>
Edit a bike: <br/>
<c:forEach items="${rentaBike.bikes}" var="bike">
<a href="editBike.bikes?bikeSerialNo=<c:out _fcksavedurl=""editBike.bikes?bikeSerialNo=<c:out" _fcksavedurl=""editBike.bikes?bikeSerialNo=<c:out"
value="${bike.serialNo}"/>">
<c:out value="${bike.manufacturer}"/> -
<c:out value="${bike.model}"/><br/>
</c:forEach>
<br/><br/>
<a href="newBike.bikes">Add a new bike</a>
</body>
</html>
这个页面使用了RentABike接口来查询要获取的值。JSTL标签<c:out>和<c:forEach>被用来查询RentABike接口实现类中的属性值。比如rentaBike.storeName,rentaBike.bikes等。
大家也许注意到了,这里都转发到了.bikes结尾的文件,比如rentaBike.bikes,这个我们后面会看到,在web.xml中配置了凡是以.bikes的请求都会经过spring来转发。
下面我们看看编辑页面editBike.jsp,下面可以看到这个页面其实和新增连接到的页面是同一个:
Example 2-7. editBike.jsp
<%@ page import="com.springbook.*"%>
<%@ include file="include.jsp" %>
<html>
<head>
<title>
Edit Bike
</title>
</head>
<body>
<h1>Edit Bike</h1>
<form method="POST" action="submitBike.bikes">
<table border="1" cellspacing="2" cellpadding="2">
<tr>
<td align="right">Manufacturer:</td>
<td>
<input type="text" name="manufacturer"
value="<c:out value="${bike.manufacturer}"/>">
</td>
</tr>
<tr>
<td align="right">Model:</td>
<td>
<input type="text" name="model"
value="<c:out value="${bike.model}"/>">
</td>
</tr>
<tr>
<td align="right">Frame:</td>
<td>
<input type="text" name="frame"
value="<c:out value="${bike.frame}"/>">
</td>
</tr>
<tr>
<td align="right">Serial Number:</td>
<td>
<input type="text" name="serialno"
value="<c:out value="${bike.serialNo}"/>">
</td>
</tr>
<tr>
<td align="right">Weight:</td>
<td>
<input type="text" name="weight"
value="<c:out value="${bike.weight}"/>">
</td>
</tr>
<tr>
<td align="right">Status:</td>
<td>
<input type="text" name="status"
value="<c:out value="${bike.status}"/>">
</td>
</tr>
</table>
<input type="submit" value="Submit">
</form>
</body>
</html>
这里同样使用了<c:out>来输出一个对象的属性,比如bike.weight,bike.status等。我们输出的是Bike这个对象。注意:如果对象为空,标签只会输入空字符串""而不会抛出异常。因此,这个页面如果用做编辑,那么这些属性值会自动填充进去。如果是用做新增的话,那么会留空以让用户来填写。
我们已经完成了两个jsp文件,一个是列表,一个是编辑。现在,我们要为它们编写控制器,每个控制器返回的一个模型和视图的组合(ModelAndView对象)。
我们先看看控制器文件BikesController.java:
Example 2-8. BikesController.java
package com.springbook;
import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
public class BikesController implements Controller {
private RentABike facade;
public RentABike getFacade( ) { return facade;}
public void setFacade(RentABike facade) { this.facade = facade; }
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
return new ModelAndView("bikes.jsp", "rentaBike", facade);
}
}
这个控制器就是简单的将用户请求转发到bikes.jsp,并且将一个rentaBike对象放到request中,这个rentaBike对象是facade接口的一个具体实现类的引用,这里的facade接口是RentABike接口,至于具体实现类是什么,由Spring依赖注入得到的。
我们接着看另一个控制器文件EditBikeController.java:
Example 2-9. EditBikeController.java
package com.springbook;
import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class EditBikeController implements Controller {
private RentABike facade;
public RentABike getFacade( ) { return facade; }
public void setFacade(RentABike facade) { this.facade = facade; }
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
if(request.getParameter("bikeSerialNo") == null) {
//这一段用于新增操作
System.out.println("bikeSerialNo was null");
return new ModelAndView("editBike.jsp");
} else {
//这一段用于编辑操作
System.out.println("bikeSerialNo == " +
request.getParameter("bikeSerialNo"));
Bike bike =
facade.getBike(request.getParameter("bikeSerialNo"));
return new ModelAndView("editBike.jsp", "bike", bike);
}
}
}
这个文件先通过request.getParameter("bikeSerialNo") 判断传入的request里是否有带参数bikeSerialNo,也就是山地车的序列号,如果没有,那么直接转发到editBike.jsp。如果有,那么会根据这个传入的山地车序列号从facade中去获取到一个山地车对象bike,并且在转发到editBike.jsp时,将这个对象放到request中,以使得转发到的editBike.jsp可以在request中得到这个对象。
不知道大家看明白了没有,上面的editBike.jsp文件里使用<c:out value="${bike.manufacturer}"/>去从request中寻找bike对象,如果有,直接输出该对象的属性,如果没有找到,则直接新增一个bike对象,并将属性值留空。
我们再看看editBike.jsp提交的控制器文件,也就是<form method="POST" action="submitBike.bikes">中的submitBike。
Example 2-10. SubmitBikeController.java
package com.springbook;
import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SubmitBikeController implements Controller {
private RentABike facade;
public RentABike getFacade( ) { return facade; }
public void setFacade(RentABike facade) { this.facade = facade; }
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
//从传入的参数来构建一个bike对象
Bike bike = new Bike(request.getParameter("manufacturer"),
request.getParameter("model"),
Integer.parseInt(request.getParameter("frame")),
request.getParameter("serialNo"),
Double.parseDouble(request.getParameter("weight")),
request.getParameter("status"));
//通过facade来保存这个山地车对象
facade.saveBike(bike);
//返回到列表页面
return new ModelAndView("bikes.jsp", "rentaBike", facade);
}
}
最后,我们来看看需要的配置文件:
Example 2-11. web.xml
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
<web-app>
<taglib>
<taglib-uri>http://java.sun.com/jstl/core</taglib-uri>
<taglib-location>/WEB-INF/lib/c.tld</taglib-location>
</taglib>
<servlet>
<servlet-name>rentaBikeApp</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>rentaBikeApp</servlet-name>
<url-pattern>*.bikes</url-pattern>
</servlet-mapping>
</web-app>
首先我们需要在web.xml中加入JSTL标签库的定义,然后我们需要定义一个servlet,这个servlet是org.springframework.web.servlet.DispatcherServlet。所有以.bikes后缀结尾的请求都会提交到这个servlet中。
这个servlet定义的名称是rentaBikeApp,那么在Spring的基类DispatcherServlet中,会从WEB-INF中去初始化rentaBikeApp-servlet.xml,这个xml文件就是Spring依赖注入所需要的配置文件。具体的bean都在这里面定义。代码如下:
Example 2-12. rentaBikeApp-servlet.xml
<beans>
<bean id="rentaBike" class="com.springbook.ArrayListRentABike">
<property name="storeName"><value>Bruce's Bikes</value></property>
</bean>
<bean id="bikesController" class="com.springbook.BikesController">
<property name="facade"><ref bean="rentaBike"/></property>
</bean>
<bean id="editBikeController" class="com.springbook.EditBikeController">
<property name="facade"><ref bean="rentaBike"/></property>
</bean>
<bean id="submitBikeController" class="com.springbook.SubmitBikeController">
<property name="facade"><ref bean="rentaBike"/></property>
</bean>
<bean id="urlMapping"
<property name="mappings">
<props>
<prop key="/bikes.bikes">bikesController</prop>
<prop key="/editBike.bikes">editBikeController</prop>
<prop key="/newBike.bikes">editBikeController</prop>
<prop key="/submitBike.bikes">submitBikeController</prop>
</props>
</property>
</bean>
</beans>
现在,我们完成了所有文件的编写,我们可以编译并在Tomcat或其他web容器中进行发布,访问路径http://localhost:8080/bikes.bikes。可以看到以下页面:
如果你没有看到这个页面,请将错误信息告诉我,可以到论坛中提出你的疑问。
作者:Willpower
来源:Rifoo Technology(http://www.rifoo.com)
时间:2006-01-08
备注:转载请保留以上声明
**/
本文讲解2.2节使用Web MVC构建一个表现层视图(View)。我们会使用Spring MVC创建一个简单的web用户接口。相信大家对MVC模式都比较熟悉了,这里就不罗嗦了。不熟悉的补一下基础。下面是MVC模式的简图,将web应用分离成三个不同的部分,M模型,V视图,C控制器。Struts框架就是一种流行的MVC模式的实现框架。

我们先建立include.jsp,这个jsp用来引入一些通用的标签。这里我们要使用到JSTL标签,所以我们需要在include.jsp中加入以下两行:
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %>
然后从下载的Spring包中找到standard.jar,jstl.jar,c.tld,fmt.tld这几个文件,将它们复制到WEB-INF/lib下。
我们下面来编写一个jsp,这个jsp页面可以让我们从一个列表中选择一个山地车,选择后可以删除或编辑它。也可以添加一个山地车,不过添加页面是另一个页面。代码如下:
Example 2-6. bikes.jsp
<%@ page import="com.springbook.*"%>
<%@ include file="include.jsp" %>
<html>
<head>
<title>
<c:out value="${rentaBike.storeName}"/>
</title>
</head>
<body>
<h1><c:out value="${rentaBike.storeName}"/></h1>
Edit a bike: <br/>
<c:forEach items="${rentaBike.bikes}" var="bike">
<a href="editBike.bikes?bikeSerialNo=<c:out _fcksavedurl=""editBike.bikes?bikeSerialNo=<c:out" _fcksavedurl=""editBike.bikes?bikeSerialNo=<c:out"
value="${bike.serialNo}"/>">
<c:out value="${bike.manufacturer}"/> -
<c:out value="${bike.model}"/><br/>
</c:forEach>
<br/><br/>
<a href="newBike.bikes">Add a new bike</a>
</body>
</html>
这个页面使用了RentABike接口来查询要获取的值。JSTL标签<c:out>和<c:forEach>被用来查询RentABike接口实现类中的属性值。比如rentaBike.storeName,rentaBike.bikes等。
大家也许注意到了,这里都转发到了.bikes结尾的文件,比如rentaBike.bikes,这个我们后面会看到,在web.xml中配置了凡是以.bikes的请求都会经过spring来转发。
下面我们看看编辑页面editBike.jsp,下面可以看到这个页面其实和新增连接到的页面是同一个:
Example 2-7. editBike.jsp
<%@ page import="com.springbook.*"%>
<%@ include file="include.jsp" %>
<html>
<head>
<title>
Edit Bike
</title>
</head>
<body>
<h1>Edit Bike</h1>
<form method="POST" action="submitBike.bikes">
<table border="1" cellspacing="2" cellpadding="2">
<tr>
<td align="right">Manufacturer:</td>
<td>
<input type="text" name="manufacturer"
value="<c:out value="${bike.manufacturer}"/>">
</td>
</tr>
<tr>
<td align="right">Model:</td>
<td>
<input type="text" name="model"
value="<c:out value="${bike.model}"/>">
</td>
</tr>
<tr>
<td align="right">Frame:</td>
<td>
<input type="text" name="frame"
value="<c:out value="${bike.frame}"/>">
</td>
</tr>
<tr>
<td align="right">Serial Number:</td>
<td>
<input type="text" name="serialno"
value="<c:out value="${bike.serialNo}"/>">
</td>
</tr>
<tr>
<td align="right">Weight:</td>
<td>
<input type="text" name="weight"
value="<c:out value="${bike.weight}"/>">
</td>
</tr>
<tr>
<td align="right">Status:</td>
<td>
<input type="text" name="status"
value="<c:out value="${bike.status}"/>">
</td>
</tr>
</table>
<input type="submit" value="Submit">
</form>
</body>
</html>
这里同样使用了<c:out>来输出一个对象的属性,比如bike.weight,bike.status等。我们输出的是Bike这个对象。注意:如果对象为空,标签只会输入空字符串""而不会抛出异常。因此,这个页面如果用做编辑,那么这些属性值会自动填充进去。如果是用做新增的话,那么会留空以让用户来填写。
我们已经完成了两个jsp文件,一个是列表,一个是编辑。现在,我们要为它们编写控制器,每个控制器返回的一个模型和视图的组合(ModelAndView对象)。
我们先看看控制器文件BikesController.java:
Example 2-8. BikesController.java
package com.springbook;
import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
public class BikesController implements Controller {
private RentABike facade;
public RentABike getFacade( ) { return facade;}
public void setFacade(RentABike facade) { this.facade = facade; }
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
return new ModelAndView("bikes.jsp", "rentaBike", facade);
}
}
这个控制器就是简单的将用户请求转发到bikes.jsp,并且将一个rentaBike对象放到request中,这个rentaBike对象是facade接口的一个具体实现类的引用,这里的facade接口是RentABike接口,至于具体实现类是什么,由Spring依赖注入得到的。
我们接着看另一个控制器文件EditBikeController.java:
Example 2-9. EditBikeController.java
package com.springbook;
import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class EditBikeController implements Controller {
private RentABike facade;
public RentABike getFacade( ) { return facade; }
public void setFacade(RentABike facade) { this.facade = facade; }
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
if(request.getParameter("bikeSerialNo") == null) {
//这一段用于新增操作
System.out.println("bikeSerialNo was null");
return new ModelAndView("editBike.jsp");
} else {
//这一段用于编辑操作
System.out.println("bikeSerialNo == " +
request.getParameter("bikeSerialNo"));
Bike bike =
facade.getBike(request.getParameter("bikeSerialNo"));
return new ModelAndView("editBike.jsp", "bike", bike);
}
}
}
这个文件先通过request.getParameter("bikeSerialNo") 判断传入的request里是否有带参数bikeSerialNo,也就是山地车的序列号,如果没有,那么直接转发到editBike.jsp。如果有,那么会根据这个传入的山地车序列号从facade中去获取到一个山地车对象bike,并且在转发到editBike.jsp时,将这个对象放到request中,以使得转发到的editBike.jsp可以在request中得到这个对象。
不知道大家看明白了没有,上面的editBike.jsp文件里使用<c:out value="${bike.manufacturer}"/>去从request中寻找bike对象,如果有,直接输出该对象的属性,如果没有找到,则直接新增一个bike对象,并将属性值留空。
我们再看看editBike.jsp提交的控制器文件,也就是<form method="POST" action="submitBike.bikes">中的submitBike。
Example 2-10. SubmitBikeController.java
package com.springbook;
import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SubmitBikeController implements Controller {
private RentABike facade;
public RentABike getFacade( ) { return facade; }
public void setFacade(RentABike facade) { this.facade = facade; }
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
//从传入的参数来构建一个bike对象
Bike bike = new Bike(request.getParameter("manufacturer"),
request.getParameter("model"),
Integer.parseInt(request.getParameter("frame")),
request.getParameter("serialNo"),
Double.parseDouble(request.getParameter("weight")),
request.getParameter("status"));
//通过facade来保存这个山地车对象
facade.saveBike(bike);
//返回到列表页面
return new ModelAndView("bikes.jsp", "rentaBike", facade);
}
}
最后,我们来看看需要的配置文件:
Example 2-11. web.xml
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
<web-app>
<taglib>
<taglib-uri>http://java.sun.com/jstl/core</taglib-uri>
<taglib-location>/WEB-INF/lib/c.tld</taglib-location>
</taglib>
<servlet>
<servlet-name>rentaBikeApp</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>rentaBikeApp</servlet-name>
<url-pattern>*.bikes</url-pattern>
</servlet-mapping>
</web-app>
首先我们需要在web.xml中加入JSTL标签库的定义,然后我们需要定义一个servlet,这个servlet是org.springframework.web.servlet.DispatcherServlet。所有以.bikes后缀结尾的请求都会提交到这个servlet中。
这个servlet定义的名称是rentaBikeApp,那么在Spring的基类DispatcherServlet中,会从WEB-INF中去初始化rentaBikeApp-servlet.xml,这个xml文件就是Spring依赖注入所需要的配置文件。具体的bean都在这里面定义。代码如下:
Example 2-12. rentaBikeApp-servlet.xml
<beans>
<bean id="rentaBike" class="com.springbook.ArrayListRentABike">
<property name="storeName"><value>Bruce's Bikes</value></property>
</bean>
<bean id="bikesController" class="com.springbook.BikesController">
<property name="facade"><ref bean="rentaBike"/></property>
</bean>
<bean id="editBikeController" class="com.springbook.EditBikeController">
<property name="facade"><ref bean="rentaBike"/></property>
</bean>
<bean id="submitBikeController" class="com.springbook.SubmitBikeController">
<property name="facade"><ref bean="rentaBike"/></property>
</bean>
<bean id="urlMapping"
<property name="mappings">
<props>
<prop key="/bikes.bikes">bikesController</prop>
<prop key="/editBike.bikes">editBikeController</prop>
<prop key="/newBike.bikes">editBikeController</prop>
<prop key="/submitBike.bikes">submitBikeController</prop>
</props>
</property>
</bean>
</beans>
现在,我们完成了所有文件的编写,我们可以编译并在Tomcat或其他web容器中进行发布,访问路径http://localhost:8080/bikes.bikes。可以看到以下页面:

如果你没有看到这个页面,请将错误信息告诉我,可以到论坛中提出你的疑问。