相关参考网址:
Spring 官网
http://www.springsource.org/
Spring 2.0 Web MVC framework
http://static.springsource.org/spring/docs/2.0.x/reference/mvc.html
Developing a Spring Framwork MVC application step-by-step(这个教程是基于Spring 2.5的)
http://static.springsource.org/docs/Spring-MVC-step-by-step/
可以从下面的网址下载Spring
http://www.springsource.org/download
或直接用下面的网址下载最新的Spring2.5.X的最新版
http://s3.amazonaws.com/dist.springframework.org/release/SPR/spring-framework-2.5.6.SEC02.zip
项目结构:
文件目录
Dao
JdbcProductDao.java ProductDao.java
Domain
Product.java
Model
PriceIncrease.java
Service
ProductManager.java SimpleProductManager.java
Validator
PriceIncreaseValidator.java
Web
InventoryController.java PriceIncreaseFormController.java
Properties
jdbc.properties messages.properties
Jsp
index.jsp hello.jsp include.jsp priceincrease.jsp
Tld
spring-form.tld
Xml
applicationContext.xml springapp-servlet.xml web.xml
相关jar包说明:
spring.jar和spring-webmvc.jar是应用Spring MVC的基础jar包。
commons-logging.jar是apache用来记录日志的包。
使用JSTL(JSP Standard Tag Library),我们需要拷贝jstl.jar和standard.jar到项目里面。
这两个jar包可以在apache-tomcat-6.0.30\webapps\examples\WEB-INF\lib找到
数据源的管理我们使用了apache的dbcp。制定了一个jdbc.properties文件作为数据库的连接文件。
对于事务的管理,我们应用了spring的AOP(Aspect Oriented Programming)面向切面的编程技术。
为了使用dbcp我们要将commons-dbcp-1.4.jar和commons-pool-1.6.jar放入项目中。
可以分别从http://commons.apache.org/dbcp/download_dbcp.cgi 和
http://commons.apache.org/pool/download_pool.cgi下载。
为了使用AOP,我们需要将aspectjweaver.jar放入项目中。
可以从http://eclipse.org/aspectj/downloads.php下载。
MVC的简单理解:
M:Model,是对于页面输入和输出数据的抽象。比如访问者要注册一个新用户,填写表单的所有数据就对应一个model。
V:View,就是jsp页面,经过处理,最终转换为html展现给用户。
C:Control,对于所有request和response的处理。将接收的html表单数据映射到Model进行处理,并用Model(新的Model,和接收到的Model是两个没有关系的对象)填充View,并将View转换为html反馈给用户。
Persistence的简单理解:
持久层基本上就是对数据库表的映射,并含有一些CUID的操作。
持久层大体上包含3个东西:domain,dao和dao.impl
domain:和数据库表的映射,基本上一个表映射一个POJO类,但这不是绝对的。Domain的POJO类只是完成了对于数据库查询结果的映射,以及更新等操作的数据对象化的输入,所以和数据库表一对一的关系只是一个大体的说法,比如对于多表联合查询,我们就可以设计一个Domain来承接查询的结果。
dao:domain操作的接口。
dao.impl:dao的实现。
服务和服务的实现:
服务就是接口,我们一般在Spring的控制器中(如果不用Spring,就是在相应的结构中,比如servlet中)使用服务。
我们用服务的实现来实例化服务,我们在使用服务时,只需要关系服务提供了哪些方法即可,而不用关系这些方法具体是如何实现的。
服务的实现中我们会用到dao来完成对数据库的操作。同样的道理,我们在服务的实现中只要关心我们可以使用哪些操作,而不必关系这些操作是如何实现的。
操作的具体实现是由dao.impl来完成的。
事务管理和AOP:
在本例中事务管理是在服务层的管理,使用AOP可以使编程人员在编写服务时不必在代码中实现对事务的控制,只要在配置文件中进行设置一下就可以了。AOP可以找到要添加事务的服务,以及服务的方法和如何进行操作的限制。
服务器是如何加载springapp-servlet.xml和applicationContext.xml的:
下面的web.xml解释了这点:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>SpringMVC2.5</display-name>
<!-- 加载applicationContext.xml -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 加载springapp-servlet.xml -->
<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>
<!-- 使用Spring的标记 -->
<jsp-config>
<taglib>
<taglib-uri>/spring</taglib-uri>
<taglib-location>/WEB-INF/tld/spring-form.tld</taglib-location>
</taglib>
</jsp-config>
</web-app>
package springapp.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcDaoSupport;
import springapp.dao.ProductDao;
import springapp.domain.Product;
public class JdbcProductDao extends SimpleJdbcDaoSupport implements ProductDao {
/** Logger for this class and subclasses */
protected final Log logger = LogFactory.getLog(getClass());
@Override
public List<Product> getProductList() {
logger.info("Getting products!");
List<Product> products = getSimpleJdbcTemplate().query(
"select id, description, price from products",
new ProductMapper());
return products;
}
@Override
public void saveProduct(Product prod) {
logger.info("Saving product: " + prod.getDescription());
int count = getSimpleJdbcTemplate().update(
"update products set description = :description, price = :price where id = :id",
new MapSqlParameterSource().addValue("description", prod.getDescription())
.addValue("price", prod.getPrice())
.addValue("id", prod.getId()));
logger.info("Rows affected: " + count);
}
private static class ProductMapper implements ParameterizedRowMapper<Product> {
@Override
public Product mapRow(ResultSet rs, int rowNum) throws SQLException {
Product prod = new Product();
prod.setId(rs.getInt("id"));
prod.setDescription(rs.getString("description"));
prod.setPrice(new Double(rs.getDouble("price")));
return prod;
}
}
}
package springapp.dao;
import java.util.List;
import springapp.domain.Product;
public interface ProductDao {
public List<Product> getProductList();
public void saveProduct(Product prod);
}
package springapp.domain;
import java.io.Serializable;
public class Product implements Serializable {
private static final long serialVersionUID = 1L;
private int id;
private String description;
private Double price;
public int getId(){
return id;
}
public void setId(int id){
this.id = id;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("Description: " + description + ";");
buffer.append("Price: " + price);
return buffer.toString();
}
}
package springapp.model;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class PriceIncrease {
/** Logger for this class and subclasses */
protected final Log logger = LogFactory.getLog(getClass());
private int percentage;
public void setPercentage(int i) {
percentage = i;
logger.info("Percentage set to " + i);
}
public int getPercentage() {
return percentage;
}
}
package springapp.service;
import java.util.List;
import springapp.domain.Product;
public interface ProductManager {
public void increasePrice(int percentage);
public List<Product> getProducts();
public void setProducts(List<Product> products);
}
SimpleProductManager.java [BACK]
package springapp.service;
import java.util.List;
import springapp.dao.ProductDao;
import springapp.domain.Product;
import springapp.service.ProductManager;
public class SimpleProductManager implements ProductManager {
//private List<Product> products;
private ProductDao productDao;
@Override
public void increasePrice(int percentage) {
//throw new UnsupportedOperationException();
List<Product> products = productDao.getProductList();
if (products != null) {
for (Product product : products) {
double newPrice = product.getPrice().doubleValue() *
(100 + percentage)/100;
product.setPrice(newPrice);
productDao.saveProduct(product);
}
}
}
@Override
public List<Product> getProducts() {
//return this.products;
return productDao.getProductList();
}
@Override
public void setProducts(List<Product> products) {
//this.products = products;
}
public void setProductDao(ProductDao productDao) {
this.productDao = productDao;
}
}
PriceIncreaseValidator.java [BACK]
package springapp.validator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import springapp.model.PriceIncrease;
public class PriceIncreaseValidator implements Validator {
private int DEFAULT_MIN_PERCENTAGE = 0;
private int DEFAULT_MAX_PERCENTAGE = 50;
private int minPercentage = DEFAULT_MIN_PERCENTAGE;
private int maxPercentage = DEFAULT_MAX_PERCENTAGE;
/** Logger for this class and subclasses */
protected final Log logger = LogFactory.getLog(getClass());
@SuppressWarnings("rawtypes")
@Override
public boolean supports(Class clazz) {
return PriceIncrease.class.equals(clazz);
}
@Override
public void validate(Object obj, Errors errors) {
PriceIncrease pi = (PriceIncrease) obj;
if (pi == null) {
errors.rejectValue("percentage", "error.not-specified", null,
"Value required.");
} else {
logger.info("Validating with " + pi + ": " + pi.getPercentage());
if (pi.getPercentage() > maxPercentage) {
errors.rejectValue("percentage", "error.too-high",
new Object[] { new Integer(maxPercentage) },
"Value too high.");
}
if (pi.getPercentage() <= minPercentage) {
errors.rejectValue("percentage", "error.too-low",
new Object[] { new Integer(minPercentage) },
"Value too low.");
}
}
}
public int getMinPercentage() {
return minPercentage;
}
public void setMinPercentage(int minPercentage) {
this.minPercentage = minPercentage;
}
public int getMaxPercentage() {
return maxPercentage;
}
public void setMaxPercentage(int maxPercentage) {
this.maxPercentage = maxPercentage;
}
}
InventoryController.java [BACK]
package springapp.web;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import springapp.service.ProductManager;
public class InventoryController implements Controller{
protected final Log logger = LogFactory.getLog(getClass());
private ProductManager productManager;
@Override
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
String now = (new Date()).toString();
logger.info("Returning hello view with:" + now);
Map<String, Object> myModel = new HashMap<String, Object>();
myModel.put("now", now);
myModel.put("products", this.productManager.getProducts());
return new ModelAndView("hello", "model", myModel);
}
public void setProductManager(ProductManager productManager) {
this.productManager = productManager;
}
}
PriceIncreaseFormController.java [BACK]
package springapp.web;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
import org.springframework.web.servlet.view.RedirectView;
import springapp.model.PriceIncrease;
import springapp.service.ProductManager;
public class PriceIncreaseFormController extends SimpleFormController {
/** Logger for this class and subclasses */
protected final Log logger = LogFactory.getLog(getClass());
private ProductManager productManager;
public ModelAndView onSubmit(Object command) throws ServletException {
int increase = ((PriceIncrease) command).getPercentage();
logger.info("Increasing prices by " + increase + "%.");
productManager.increasePrice(increase);
logger.info("returning from PriceIncreaseForm view to "
+ getSuccessView());
return new ModelAndView(new RedirectView(getSuccessView()));
}
protected Object formBackingObject(HttpServletRequest request)
throws ServletException {
PriceIncrease priceIncrease = new PriceIncrease();
priceIncrease.setPercentage(20);
return priceIncrease;
}
public void setProductManager(ProductManager productManager) {
this.productManager = productManager;
}
}
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=password
title=SpringApp
heading=Hello :: SpringApp
greeting=Greetings, it is now
priceincrease.heading=Price Increase :: SpringApp
error.not-specified=Percentage not specified!!!
error.too-low=You have to specify a percentage higher than {0}!
error.too-high=Don''t be greedy - you can''t raise prices by more than {0}%!
required=Entry required.
typeMismatch=Invalid data.
typeMismatch.percentage=That is not a number!!!
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/jsp/include.jsp" %>
<c:redirect url="/hello.htm" />
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/jsp/include.jsp" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><fmt:message key="title" /></title>
</head>
<body>
<h1><fmt:message key="heading" /></h1>
<p><fmt:message key="greeting"/> <c:out value="${model.now}" /></p>
<h3>Products</h3>
<c:forEach items="${model.products}" var="prod">
<c:out value="${prod.description}" />
<i><c:out value="${prod.price}" /></i>
<br /><br />
</c:forEach>
<br>
<a href="<c:url value="priceincrease.htm"/>">Increase Prices</a>
<br>
</body>
</html>
<%@ page session="false"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/jsp/include.jsp" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><fmt:message key="title"/></title>
<style type="text/css">
.error { color: red; }
</style>
</head>
<body>
<h1><fmt:message key="priceincrease.heading"/></h1>
<form:form method="post" commandName="priceIncrease4" id="myForm" name="myForm">
<table width="95%" bgcolor="f8f8ff" border="0" cellspacing="0" cellpadding="5">
<tr>
<td align="right" width="20%">Increase (%):</td>
<td width="20%">
<form:input path="percentage"/>
</td>
<td width="60%">
<form:errors path="percentage" cssClass="error"/>
</td>
</tr>
</table>
<br>
<input type="submit" value="Execute">
</form:form>
<a href="<c:url value="hello.htm"/>">Home</a>
</body>
</html>
可从spring的jar包中获取。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<!-- the parent application context definition for the springapp application -->
<bean id="productManager" class="springapp.service.SimpleProductManager">
<property name="productDao" ref="productDao"/>
</bean>
<bean id="productDao" class="springapp.dao.JdbcProductDao">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:jdbc.properties</value>
</list>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<aop:config>
<aop:advisor pointcut="execution(* *..ProductManager.*(..))" advice-ref="txAdvice"/>
</aop:config>
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="save*"/>
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
</beans>
<?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.5.xsd">
<!-- the application context definition for the springapp DispatcherServlet -->
<bean name="/hello.htm" class="springapp.web.InventoryController">
<property name="productManager" ref="productManager" />
</bean>
<bean name="/priceincrease.htm" class="springapp.web.PriceIncreaseFormController">
<property name="sessionForm" value="true"/>
<property name="commandName" value="priceIncrease4"/>
<property name="commandClass" value="springapp.model.PriceIncrease"/>
<property name="validator">
<bean class="springapp.validator.PriceIncreaseValidator"/>
</property>
<property name="formView" value="priceincrease"/>
<property name="successView" value="hello.htm"/>
<property name="productManager" ref="productManager"/>
</bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView"></property>
<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>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>SpringMVC2.5</display-name>
<!-- 加载applicationContext.xml -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 加载springapp-servlet.xml -->
<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>
<!-- 使用Spring的标记 -->
<jsp-config>
<taglib>
<taglib-uri>/spring</taglib-uri>
<taglib-location>/WEB-INF/tld/spring-form.tld</taglib-location>
</taglib>
</jsp-config>
</web-app>