JBuilder開發(fā)Spring
1. 下載spring包,網(wǎng)址如下
http://www.springframework.org/download.html
解壓后的目錄中包含了dist、lib等子目錄
2. 在JBuilder2005中增加spring庫,選擇菜單Tools-Configure-Libraries,在彈出的對話框中點(diǎn)擊New按鈕,輸入spring庫的名稱:spring,點(diǎn)擊Add按鈕,將dist目錄中的所有jar文件增加到spring庫中
3. 新建工程文件,選菜單File-New Project,給工程文件取名為myProject
設(shè)置工程文件的屬性,選菜單Project-Project Properties,選擇Tomcat作為服務(wù)器,將spring庫加入Path/Required Libraries。因?yàn)槔又杏玫搅薼og4j,將包含了log4j的庫加入Path/Required Libraries,注意到lib目錄下有兩個(gè)子目錄log4j和jakarta-commons,它們的用法是不同的,如下面的代碼片斷所示:
log4j
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
public class SpringappController implements Controller {
/** Logger for this class and subclasses */
static Logger logger = Logger.getLogger(SpringappController.class);
jakarta-commons
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class SpringappController implements Controller {
/** Logger for this class and subclasses */
protected final Log logger = LogFactory.getLog(getClass());
4. 新建Web模塊,選菜單File-New,給Web模塊取名為springapp
5. 新建hello.jsp文件如下:
<%@ page contentType="text/html; charset=Big5" %>
<html>
<head><title>Example :: Spring Application</title></head>
<body>
<h1>Hello - Spring Application</h1>
<p>Greetings.</p>
</body>
</html>
6. 新建類文件SpringappController.java如下:
package spring;
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;
//import org.apache.commons.logging.Log;
//import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
public class SpringappController implements Controller {
/** Logger for this class and subclasses */
// protected final Log logger = LogFactory.getLog(getClass());
static Logger logger = Logger.getLogger(SpringappController.class);
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
logger.info("SpringappController - returning hello view");
return new ModelAndView("hello.jsp");
}
}
7. 修改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>
8. 在web-inf目錄中新建springapp-servlet.xml文件如下
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "
<!-- - Application context definition for "springapp" DispatcherServlet. --> <beans> <bean id="springappController" class="spring.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> 9. 在web-inf目錄中新建log4j.properties文件如下: log4j.rootCategory=INFO, stdout, logfile log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n log4j.appender.logfile=org.apache.log4j.RollingFileAppender log4j.appender.logfile.File=springapp.log log4j.appender.logfile.MaxFileSize=512KB # Keep three backup files log4j.appender.logfile.MaxBackupIndex=3 log4j.appender.logfile.layout=org.apache.log4j.PatternLayout #Pattern to output : date priority [category] - <message>line_separator log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - <%m>%n 10. 設(shè)置web模塊springapp的屬性Content,加入文件log4j.properties,因?yàn)閏lasses目錄是自動(dòng)產(chǎn)生的,這一步是為了把文件log4j.properties加到classes目錄。 11. 設(shè)置Run Configuration,選菜單Run-Configurations,新建一個(gè)Run Configuration,Type選Server,Launch URI設(shè)置為:/springapp/hello.htm,給它取名為hello 12. 運(yùn)行,你會(huì)在messages窗口中看到如下信息: 資訊: Server startup in 9253 ms 2004-11-05 15:05:00,585 INFO [spring.SpringappController] - <SpringappController - returning hello view> 2004/11/5 下午 03:05:00 org.springframework.web.servlet.view.AbstractCachingViewResolver resolveViewName 資訊: Cached view 'hello.jsp' 在myProject/Tomcat/springapp.log文件中增加了一行如下所示: 2004-11-05 15:11:32,348 INFO [spring.SpringappController] - <SpringappController - returning hello view> 這說明你已成功建立了基本的spring應(yīng)用。 13. 增加對jstl的支持,設(shè)置工程文件的屬性,選菜單Project-Project Properties,將jstl庫加入Path/Required Libraries。 14. 改進(jìn)前面的例子,改進(jìn)的文件如下: 增加“header”文件include.jsp,這是一些jsp文件的公用部分,這樣可以使得開發(fā)和維護(hù)更容易。所有jsp文件放在web-inf/jsp目錄下,為的是只有Controller可以訪問View。 springapp/war/WEB-INF/jsp/include.jsp 利用JSTL,<c:redirect>將頁面重定向到Controller,這樣就建立了index.jsp和應(yīng)用架構(gòu)的聯(lián)系。 springapp/war/index.jsp 利用JSTL的<c:out>標(biāo)記,把從Model提取的,傳遞給View的當(dāng)前日期和時(shí)間作為輸出。 springapp/war/WEB-INF/jsp/hello.jsp 在SpringappController.java中增加包含了當(dāng)前日期和時(shí)間的string作為Model springapp/src/SpringappController.java 15. 瀏覽改進(jìn)后的結(jié)果http://localhost:8080/springapp,首先訪問index.jsp,然后重定向到hello.htm,接著把控制交給Controller,Controller把日期和時(shí)間傳送給View。 只能在瀏覽器這樣測試。在JBuilder2005中設(shè)置Run Configuration不能訪問http://localhost:8080/springapp,但可以訪問http://localhost:8080/springapp/index.jsp 在上面的例子中,Controller指定了View的完全路徑,使得Controller和View之間存在不必要的依賴。為了移出這種依賴,我們可以用類ResourceBundleViewResolver 和 a SimpleUrlHandlerMapping在屬性文件中定義這種依賴,對于簡單的情形,我們也可以利用InternalResourceViewResolver設(shè)置前綴和后綴,下面就用第二種方法。修改文件springapp-servlet.xml包含ViewResolver設(shè)置,我們還選擇使用JstlView,這使得我們可以結(jié)合使用JSTL和message resource bundles,因此可以支持國際化。 springapp/war/WEB-INF/springapp-servlet.xml 現(xiàn)在,我們就可以移出Controller中View名稱的前綴和后綴了。 springapp/src/SpringappController.java 這樣修改后的例子應(yīng)該仍能運(yùn)行。 16. 增加商業(yè)邏輯類 為了分開Web邏輯和商業(yè)邏輯,我們建立兩個(gè)不同的包,web和bus springapp/src/bus/Product.java springapp/src/bus/ProductManager.java 修改SpringappController.java springapp/src/web/SpringappController.java 17. 修改View以便顯示商業(yè)數(shù)據(jù),增加對message bundle的支持 springapp/war/WEB-INF/jsp/hello.jsp 18. 增加一些測試數(shù)據(jù) 我們現(xiàn)在還不打算增加代碼,從數(shù)據(jù)庫裝載商業(yè)對象。我們只springapp-servlet.xml中增加bean和messageSource設(shè)置,提供一些測試數(shù)據(jù)和對messages resource bundle的支持。 19. 增加message bundle springapp/war/WEB-INF/classes/messages.properties 20. 瀏覽改進(jìn)后的結(jié)果http://localhost:8080/springapp 實(shí)現(xiàn)數(shù)據(jù)庫持久層 21. 設(shè)置HSQL數(shù)據(jù)庫,在JBuilder2005中增加HSQL庫,選擇菜單Tools-Configure-Libraries,在彈出的對話框中點(diǎn)擊New按鈕,輸入HSQL庫的名稱:HSQL,點(diǎn)擊Add按鈕,將lib/hsqldb目錄下的文件hsqldb.jar增加到HSQL庫中。 選擇菜單Enterprise-Enterprise Setup,在彈出的對話框中選擇Database Drivers,按Add按鈕增加HSQL庫。 選擇菜單Tools-Database Pilot,然后選擇菜單Files-New輸入Driver:org.hsqldb.jdbcDriver,URL:jdbc:hsqldb:db/test, 雙擊hsqldb:db/test,輸入U(xiǎn)serName:sa,不必輸入Passsword。輸入如下的SQL語句并執(zhí)行 CREATE TABLE products ( id INTEGER NOT NULL PRIMARY KEY, description varchar(255), price decimal(15,2) ); CREATE INDEX products_description ON products(description); INSERT INTO products (id, description, price) values(1, 'Lamp', 5.78); INSERT INTO products (id, description, price) values(2, 'Table', 75.29); INSERT INTO products (id, description, price) values(3, 'Chair', 22.81); 這樣就會(huì)在JBuilder_Home/bin目錄下創(chuàng)建一個(gè)目錄db,存放了數(shù)據(jù)庫test的數(shù)據(jù) 22. 創(chuàng)建JDBC DAO (Data Access Object)實(shí)現(xiàn) springapp/src/db/ProductManagerDao.java springapp/src/db/ProductManagerDaoJdbc.java springapp/src/bus/Product.java springapp/src/test/TestProductManagerDaoJdbc.java 23. 修改Web應(yīng)用使其使用數(shù)據(jù)庫持久層 springapp/src/bus/ProductManager.java springapp/src/tests/MockProductManagerDaoImpl.java springapp/src/tests/WEB-INF/springapp-servlet.xml springapp/src/tests/TestProductManager .java
<%@ page session="false"%>
<%@ taglib prefix="c" uri="java.sun.com/jstl/core">http://java.sun.com/jstl/core" %>
<%@ taglib prefix="fmt" uri="java.sun.com/jstl/fmt">http://java.sun.com/jstl/fmt" %>
<%@ include file="/WEB-INF/jsp/include.jsp" %>
<%-- Redirected because we can't set the welcome page to a virtual URL. --%>
<c:redirect url="/hello.htm"/>
<%@ include file="/WEB-INF/jsp/include.jsp" %>
<html>
<head><title>Hello :: Spring Application</title></head>
<body>
<h1>Hello - Spring Application</h1>
<p>Greetings, it is now <c:out value="${now}"/>
</p>
</body>
</html>
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;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class SpringappController implements Controller {
/** Logger for this class and subclasses */
protected final Log logger = LogFactory.getLog(getClass());
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String now = (new java.util.Date()).toString();
logger.info("returning hello view with " + now);
return new ModelAndView("WEB-INF/jsp/hello.jsp", "now", now);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "
<!--
- 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>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"><value>org.springframework.web.servlet.view.JstlView</value></property>
<property name="prefix"><value>/WEB-INF/jsp/</value></property>
<property name="suffix"><value>.jsp</value></property>
</bean>
</beans>
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;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class SpringappController implements Controller {
/** Logger for this class and subclasses */
protected final Log logger = LogFactory.getLog(getClass());
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String now = (new java.util.Date()).toString();
logger.info("returning hello view with " + now);
return new ModelAndView("hello", "now", now);
}
}
package bus;
import java.io.Serializable;
public class Product implements Serializable {
private String description;
private Double price;
public void setDescription(String s) {
description = s;
}
public String getDescription() {
return description;
}
public void setPrice(Double d) {
price = d;
}
public Double getPrice() {
return price;
}
}
package bus;
import java.io.Serializable;
import java.util.List;
public class ProductManager implements Serializable {
private List products;
public void setProducts(List p) {
products = p;
}
public List getProducts() {
return products;
}
}
package web;
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;
import java.util.Map;
import java.util.HashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import bus.Product;
import bus.ProductManager;
public class SpringappController implements Controller {
/** Logger for this class and subclasses */
protected final Log logger = LogFactory.getLog(getClass());
private ProductManager prodMan;
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String now = (new java.util.Date()).toString();
logger.info("returning hello view with " + now);
Map myModel = new HashMap();
myModel.put("now", now);
myModel.put("products", getProductManager().getProducts());
return new ModelAndView("hello", "model", myModel);
}
public void setProductManager(ProductManager pm) {
prodMan = pm;
}
public ProductManager getProductManager() {
return prodMan;
}
}
<%@ include file="/WEB-INF/jsp/include.jsp" %>
<html>
<head><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>
</body>
</html>
title=SpringApp
heading=Hello :: SpringApp
greeting=Greetings, it is now
package db;
import bus.Product;
import java.util.List;
public interface ProductManagerDao {
public List getProductList();
public void increasePrice(Product prod, int pct);
}
package db;
import bus.Product;
import java.util.List;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.object.MappingSqlQuery;
import org.springframework.jdbc.object.SqlUpdate;
import org.springframework.jdbc.core.SqlParameter;
public class ProductManagerDaoJdbc implements ProductManagerDao {
/** Logger for this class and subclasses */
protected final Log logger = LogFactory.getLog(getClass());
private DataSource ds;
public List getProductList() {
logger.info("Getting products!");
ProductQuery pq = new ProductQuery(ds);
return pq.execute();
}
public void increasePrice(Product prod, int pct) {
logger.info("Increasing price by " + pct + "%");
SqlUpdate su =
new SqlUpdate(ds, "update products set price = price * (100 + ?) / 100 where id = ?");
su.declareParameter(new SqlParameter("increase", Types.INTEGER));
su.declareParameter(new SqlParameter("ID", Types.INTEGER));
su.compile();
Object[] oa = new Object[2];
oa[0] = new Integer(pct);
oa[1] = new Integer(prod.getId());
int count = su.update(oa);
logger.info("Rows affected: " + count);
}
public void setDataSource(DataSource ds) {
this.ds = ds;
}
class ProductQuery extends MappingSqlQuery {
ProductQuery(DataSource ds) {
super(ds, "SELECT id, description, price from products");
compile();
}
protected Object 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 bus;
import java.io.Serializable;
public class Product implements Serializable {
private int id;
private String description;
private Double price;
public void setId(int i) {
id = i;
}
public int getId() {
return id;
}
public void setDescription(String s) {
description = s;
}
public String getDescription() {
return description;
}
public void setPrice(Double d) {
price = d;
}
public Double getPrice() {
return price;
}
}
package tests;
import java.util.List;
import java.util.ArrayList;
import junit.framework.TestCase;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import db.ProductManagerDaoJdbc;
import bus.Product;
public class TestProductManagerDaoJdbc extends TestCase {
private ProductManagerDaoJdbc pmdao;
public void setUp() {
pmdao = new ProductManagerDaoJdbc();
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("org.hsqldb.jdbcDriver");
ds.setUrl("jdbc:hsqldb:db/test");
ds.setUsername("sa");
ds.setPassword("");
pmdao.setDataSource(ds);
}
public void testGetProductList() {
List l = pmdao.getProductList();
Product p1 = (Product) l.get(0);
assertEquals("Lamp", p1.getDescription());
Product p2 = (Product) l.get(1);
assertEquals("Table", p2.getDescription());
}
public void testIncreasePrice() {
List l1 = pmdao.getProductList();
Product p1 = (Product) l1.get(0);
assertEquals(new Double("5.78"), p1.getPrice());
pmdao.increasePrice(p1, 10);
List l2 = pmdao.getProductList();
Product p2 = (Product) l2.get(0);
assertEquals(new Double("6.36"), p2.getPrice());
}
}
package bus;
import java.io.Serializable;
import java.util.ListIterator;
import java.util.List;
import db.ProductManagerDao;
public class ProductManager implements Serializable {
private ProductManagerDao pmd;
private List products;
public void setProductManagerDao(ProductManagerDao pmd) {
this.pmd = pmd;
}
/*
public void setProducts(List p) {
products = p;
}
*/
public List getProducts() {
products = pmd.getProductList();
return products;
}
public void increasePrice(int pct) {
ListIterator li = products.listIterator();
while (li.hasNext()) {
Product p = (Product) li.next();
/*
double newPrice = p.getPrice().doubleValue() * (100 + pct)/100;
p.setPrice(new Double(newPrice));
*/
pmd.increasePrice(p, pct);
}
}
}
package tests;
import bus.Product;
import java.util.List;
import db.ProductManagerDao;
import bus.Product;
public class MockProductManagerDaoImpl implements ProductManagerDao {
private List products;
public void setProducts(List p) {
products = p;
}
public List getProductList() {
return products;
}
public void increasePrice(Product prod, int pct) {
double newPrice = prod.getPrice().doubleValue() * (100 + pct)/100;
prod.setPrice(new Double(newPrice));
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "
<!--
- Application context definition for "springapp" DispatcherServlet.
-->
<beans>
<bean id="springappController" class="web.SpringappController">
<property name="productManager">
<ref bean="prodMan"/>
</property>
</bean>
<bean id="prodManDao" class="tests.MockProductManagerDaoImpl">
<property name="products">
<list>
<ref bean="product1"/>
<ref bean="product2"/>
<ref bean="product3"/>
</list>
</property>
</bean>
<bean id="prodMan" class="bus.ProductManager">
<property name="productManagerDao">
<ref bean="prodManDao"/>
</property>
<!--
<property name="products">
<list>
<ref bean="product1"/>
<ref bean="product2"/>
<ref bean="product3"/>
</list>
</property>
-->
</bean>
<bean id="product1" class="bus.Product">
<property name="description"><value>Lamp</value></property>
<property name="price"><value>5.75</value></property>
</bean>
<bean id="product2" class="bus.Product">
<property name="description"><value>Table</value></property>
<property name="price"><value>75.25</value></property>
</bean>
<bean id="product3" class="bus.Product">
<property name="description"><value>Chair</value></property>
<property name="price"><value>22.79</value></property>
</bean>
</beans>
package tests;
import java.util.List;
import java.util.ArrayList;
import junit.framework.TestCase;
import db.ProductManagerDao;
import bus.ProductManager;
import bus.Product;
public class TestProductManager extends TestCase {
private ProductManager pm;
public void setUp() {
pm = new ProductManager();
Product p = new Product();
p.setDescription("Chair");
p.setPrice(new Double("20.50"));
ArrayList al = new ArrayList();
al.add(p);
p = new Product();
p.setDescription("Table");
p.setPrice(new Double("150.10"));
al.add(p);
/*
pm.setProducts(al);
*/
MockProductManagerDaoImpl pmdao = new MockProductManagerDaoImpl();
pmdao.setProducts(al);
pm.setProductManagerDao(pmdao);
pm.getProducts();
}
public void testGetProducs() {
List l = pm.getProducts();
Product p1 = (Product) l.get(0);
assertEquals("Chair", p1.getDescription());
Product p2 = (Product) l.get(1);
assertEquals("Table", p2.getDescription());
}
public void testIncreasePrice() {
pm.increasePrice(10);
List l = pm.getProducts();
Product p = (Product) l.get(0);
assertEquals(new Double("22.55"), p.getPrice());
p = (Product) l.get(1);
assertEquals(new Double("165.11"), p.getPrice());
}
}