转 Struts2+Spring2+Hibernate3 图书管理
这篇文章是从网友http://www.blogjava.net/sterning/archive/2007/09/30/149775.html转来的,
他真是一位大好人,虽然在别的网站有很多转走的这篇文章,但我也想在自己的BLOG上再转一次,
理由很简单,想自己收藏一份,感谢原创sterning
Struts作为MVC 2的Web框架,自推出以来不断受到开发者的追捧,得到广泛的应用。作为最成功的Web框架,Struts自然拥有众多的优点:MVC 2模型的使用、功能齐全的标志库(Tag Library)、开放源代码。而Spring的出现,在某些方面极大的方面了Struts的开发。同时,Hibernate作为对象持久化的框架,能显示的提高软件开发的效率与生产力。这三种流行框架的整合应用,可以发挥它们各自的优势,使软件开发更加的快速与便捷。
struts2发布已经很久了,但关于如何使用它的教程及实例并不多。特别是与Spring及Hibernate等流行框架的集成,并不多见。现在就将笔者使用Myeclipse工具应用struts2 + spring2 + hibernate3?实现CRUD操作的步骤一一纪录下来,为初学者少走弯路略尽绵薄之力!在本文中,笔者将Struts2.0.6、Spring2.0.6和Hibernate3.1进行整合,希望通过这样的整合示例,让读者了解这些框架各自的特点,以便于在自己的项目中,根据实际情况,尽快的过渡到Struts2的时代。本文的内容基于Struts2.0.6。
?一、???????准备工作
spring2与1.x区别不大,可以平滑的过度,笔者也是把spring1.28换成了spring2.0.6,算是升级到spring 2.0了。struts2基本就是webwork2.2,与以前的struts1.x可以说没任何关系了。因为是第一次用struts2,也是第一次用webwork,所以有很多不完善,不规范的地方,还望大家来拍砖。
开发环境:MyEclipse5.0+Eclipse3.2+JDK5.0+
Tomcat5.5+struts2+Spring2.0.6+Hibernate3.1。本示例通过对一个图书进行管理的系统,提供基本的增加、删除、修改、查询等功能。
lib包需要以下右图所示的这些包。其中Struts2.0.6的下载地址为:

?????? http://people.apache.org/builds/struts/2.0.6
Hibernate3.1的下载地址为:
http://www.hibernate.org
spring2.0.6的下载地址为:
http://www.springframework.org
使用的数据库为mysql 5.0,使用的JDBC驱动JAR包为:mysql-connection-java-5.0.4-bin
创建数据表的sql语句为:
create database game
CREATE?TABLE?`books`?(
??`book_id`?int(11)?NOT?NULL?default?'0',
??`book_name`?varchar(200)?character?set?gb2312?default?NULL,
??`book_author`?varchar(100)?character?set?gb2312?default?NULL,
??`book_publish`?varchar(100)?character?set?gb2312?default?NULL,
??`book_date`?date?default?NULL,
??`book_isbn`?varchar(20)?default?NULL,
??`book_page`?int(11)?default?NULL,
??`book_price`?decimal(10,2)?default?NULL,
??`book_content`?varchar(100)?character?set?gb2312?default?NULL,
??PRIMARY?KEY??(`book_id`)
)?ENGINE=InnoDB?DEFAULT?CHARSET=gbk?ROW_FORMAT=COMPRESSED;

二、???????建立公共类
1、AbstractAction类
?Struts2和Struts1.x的差别,最明显的就是Struts2是一个pull-MVC架构。Struts1.x?必须继承org.apache.struts.action.Action或者其子类,表单数据封装在FormBean中。Struts 2无须继承任何类型或实现任何接口,表单数据包含在Action中,通过Getter和Setter获取。
虽然,在理论上Struts2的Action无须实现任何接口或者是继承任何的类,但是,在实际编程过程中,为了更加方便的实现Action,大多数情况下都会继承com.opensymphony.xwork2.ActionSupport类,并且重载(Override)
package?com.sterning.commons;
import?com.opensymphony.xwork2.ActionSupport;
public?class?AbstractAction?extends?ActionSupport?{
}
com.sterning.commons.AbstractAction.java
参考JavaDoc,可知ActionSupport类实现了接口:
com.opensymphony.xwork2.Action
com.opensymphony.xwork2.LoaleProvider
com.opensymphony.xwork2.TextProvider
com.opensymphony.xwork2.Validateable
com.opensymphony.xwork2.ValidationAware
com.uwyn.rife.continuations.ContinuableObject
java.io.Searializable
java.lang.Cloneable
2、Pager分页类
为了增加程序的分页功能,特意建立共用的分页类。
package?com.sterning.commons;
import?java.math.*;
public?class?Pager?{
????private?int?totalRows;?//总行数
????private?int?pageSize?=?5;?//每页显示的行数
????private?int?currentPage;?//当前页号
????private?int?totalPages;?//总页数
????private?int?startRow;?//当前页在数据库中的起始行
????
????public?Pager()?{
????}
????
????public?Pager(int?_totalRows)?{
????????totalRows?=?_totalRows;
????????totalPages=totalRows/pageSize;
????????int?mod=totalRows%pageSize;
????????if(mod>0){
????????????totalPages++;
????????}
????????currentPage?=?1;
????????startRow?=?0;
????}
????
????public?int?getStartRow()?{
????????return?startRow;
????}
????public?int?getTotalPages()?{
????????return?totalPages;
????}
????public?int?getCurrentPage()?{
????????return?currentPage;
????}
????public?int?getPageSize()?{
????????return?pageSize;
????}
????public?void?setTotalRows(int?totalRows)?{
????????this.totalRows?=?totalRows;
????}
????public?void?setStartRow(int?startRow)?{
????????this.startRow?=?startRow;
????}
????public?void?setTotalPages(int?totalPages)?{
????????this.totalPages?=?totalPages;
????}
????public?void?setCurrentPage(int?currentPage)?{
????????this.currentPage?=?currentPage;
????}
????public?void?setPageSize(int?pageSize)?{
????????this.pageSize?=?pageSize;
????}
????public?int?getTotalRows()?{
????????return?totalRows;
????}
????public?void?first()?{
????????currentPage?=?1;
????????startRow?=?0;
????}
????public?void?previous()?{
????????if?(currentPage?==?1)?{
????????????return;
????????}
????????currentPage--;
????????startRow?=?(currentPage?-?1)?*?pageSize;
????}
????public?void?next()?{
????????if?(currentPage?<?totalPages)?{
????????????currentPage++;
????????}
????????startRow?=?(currentPage?-?1)?*?pageSize;
????}
????public?void?last()?{
????????currentPage?=?totalPages;
????????startRow?=?(currentPage?-?1)?*?pageSize;
????}
????public?void?refresh(int?_currentPage)?{
????????currentPage?=?_currentPage;
????????if?(currentPage?>?totalPages)?{
????????????last();
????????}
????}
}
com.sterning.commons.Pager.java
同时,采用PagerService类来发布成为分页类服务PagerService,代码如下:
同时,采用PagerService类来发布成为分页类服务PagerService,代码如下:
package?com.sterning.commons;
public?class?PagerService?{
????public?Pager?getPager(String?currentPage,String?pagerMethod,int?totalRows)?{
????????//????定义pager对象,用于传到页面
????????Pager?pager?=?new?Pager(totalRows);
????????//????如果当前页号为空,表示为首次查询该页
????????//????如果不为空,则刷新pager对象,输入当前页号等信息
????????if?(currentPage?!=?null)?{
????????????pager.refresh(Integer.parseInt(currentPage));
????????}
????????//????获取当前执行的方法,首页,前一页,后一页,尾页。
????????if?(pagerMethod?!=?null)?{
????????????if?(pagerMethod.equals("first"))?{
????????????????pager.first();
????????????}?else?if?(pagerMethod.equals("previous"))?{
????????????????pager.previous();
????????????}?else?if?(pagerMethod.equals("next"))?{
????????????????pager.next();
????????????}?else?if?(pagerMethod.equals("last"))?{
????????????????pager.last();
????????????}
????????}
????????return?pager;
????}
}
com.sterning.commons.PagerService.java三、???????建立数据持久化层
1、编写实体类Books及books.hbm.xml映射文件。
package?com.sterning.books.model;
import?java.util.Date;
public?class?Books?{
????//????Fields?
????private?String?bookId;//编号
????private?String?bookName;//书名
????private?String?bookAuthor;//作者
????private?String?bookPublish;//出版社
????private?Date?bookDate;//出版日期
????private?String?bookIsbn;//ISBN
????private?String?bookPage;//页数
????private?String?bookPrice;//价格
????private?String?bookContent;//内容提要
????
????//????Constructors
????public?Books(){}
????
????//????Property?accessors
????public?String?getBookId()?{
????????return?bookId;
????}
????public?void?setBookId(String?bookId)?{
????????this.bookId?=?bookId;
????}
????public?String?getBookName()?{
????????return?bookName;
????}
????public?void?setBookName(String?bookName)?{
????????this.bookName?=?bookName;
????}
????public?String?getBookAuthor()?{
????????return?bookAuthor;
????}
????public?void?setBookAuthor(String?bookAuthor)?{
????????this.bookAuthor?=?bookAuthor;
????}
????public?String?getBookContent()?{
????????return?bookContent;
????}
????public?void?setBookContent(String?bookContent)?{
????????this.bookContent?=?bookContent;
????}
????public?Date?getBookDate()?{
????????return?bookDate;
????}
????public?void?setBookDate(Date?bookDate)?{
????????this.bookDate?=?bookDate;
????}
????public?String?getBookIsbn()?{
????????return?bookIsbn;
????}
????public?void?setBookIsbn(String?bookIsbn)?{
????????this.bookIsbn?=?bookIsbn;
????}
????public?String?getBookPage()?{
????????return?bookPage;
????}
????public?void?setBookPage(String?bookPage)?{
????????this.bookPage?=?bookPage;
????}
????public?String?getBookPrice()?{
????????return?bookPrice;
????}
????public?void?setBookPrice(String?bookPrice)?{
????????this.bookPrice?=?bookPrice;
????}
????public?String?getBookPublish()?{
????????return?bookPublish;
????}
????public?void?setBookPublish(String?bookPublish)?{
????????this.bookPublish?=?bookPublish;
????}
}
??com.sterning.books.model.Books.java???????接下来要把实体类Books的属性映射到books表,编写下面的books.hbm.xml文件:
<?xml?version="1.0"?>
<!DOCTYPE?hibernate-mapping?PUBLIC?"-//Hibernate/Hibernate?Mapping?DTD?3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
?????<class?name="com.sterning.books.model.Books"?table="books"?>
?????????<id?name="bookId"?type="string">
????????????<column?name="book_id"?length="5"?/>
????????????<generator?class="assigned"?/>
????????</id>
????????<property?name="bookName"?type="string">
????????????<column?name="book_name"?length="100"?/>
????????</property>
?????????<property?name="bookAuthor"?type="string">
????????????<column?name="book_author"?length="100"?/>
????????</property>
????????<property?name="bookPublish"?type="string">
????????????<column?name="book_publish"?length="100"?/>
????????</property>
?????????<property?name="bookDate"?type="java.sql.Timestamp">
????????????<column?name="book_date"?length="7"?/>
????????</property>
??????????<property?name="bookIsbn"?type="string">
????????????<column?name="book_isbn"?length="20"?/>
????????</property>
????????<property?name="bookPage"?type="string">
????????????<column?name="book_page"?length="11"?/>
????????</property>
????????<property?name="bookPrice"?type="string">
????????????<column?name="book_price"?length="4"?/>
????????</property>?
?????????<property?name="bookContent"?type="string">
????????????<column?name="book_content"?length="100"?/>
????????</property>
?????</class>
</hibernate-mapping>
??????? com.sterning.books.model.books.hbm.xml2、hibernate.cfg.xml配置文件如下:(注意它的位置在scr/hibernate.cfg.xml)
<?xml?version="1.0"?encoding="ISO-8859-1"?>
<!DOCTYPE?hibernate-configuration?PUBLIC
????"-//Hibernate/Hibernate?Configuration?DTD?3.0//EN"
????"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
????<property?name="show_sql">true</property>
????<mapping?resource="com/sterning/books/model/books.hbm.xml"></mapping>
</session-factory>
</hibernate-configuration>
??Com.sterning.bean.hibernate.hibernate.cfg.xml四、???????建立DAO层?
DAO访问层负责封装底层的数据访问细节,不仅可以使概念清晰,而且可以提高开发效率。
1、建立DAO的接口类:BooksDao
package?com.sterning.books.dao.iface;
import?java.util.List;
import?com.sterning.books.model.Books;
public?interface?BooksDao?{
????List?getAll();//获得所有记录
????List?getBooks(int?pageSize,?int?startRow);//获得所有记录
????int?getRows();//获得总行数
????int?getRows(String?fieldname,String?value);//获得总行数
????List?queryBooks(String?fieldname,String?value);//根据条件查询
????List?getBooks(String?fieldname,String?value,int?pageSize,?int?startRow);//根据条件查询
????Books?getBook(String?bookId);//根据ID获得记录
????String?getMaxID();//获得最大ID值
????void?addBook(Books?book);//添加记录
????void?updateBook(Books?book);//修改记录
????void?deleteBook(Books?book);//删除记录????
}
??com.sterning.books.dao.iface.BooksDao.java?
2、实现此接口的类文件,BooksMapDao
package?com.sterning.books.dao.hibernate;
import?java.sql.SQLException;
import?java.util.Iterator;
import?java.util.List;
import?org.hibernate.HibernateException;
import?org.hibernate.Query;
import?org.hibernate.Session;
import?org.springframework.orm.hibernate3.HibernateCallback;
import?org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import?com.sterning.books.dao.iface.BooksDao;
import?com.sterning.books.model.Books;
import?com.sterning.commons.PublicUtil;

/**
?*?@author?cwf
?*
?*/
public?class?BooksMapDao?extends?HibernateDaoSupport?implements?BooksDao?{
????public?BooksMapDao(){}
????/**
?????*?函数说明:添加信息
?????*?参数说明:对象?
?????*?返回值:
?????*/
????public?void?addBook(Books?book)?{
????????this.getHibernateTemplate().save(book);
????}
????/**
?????*?函数说明:删除信息
?????*?参数说明:?对象
?????*?返回值:
?????*/
????public?void?deleteBook(Books?book)?{
????????this.getHibernateTemplate().delete(book);
????}
????/**
?????*?函数说明:获得所有的信息
?????*?参数说明:?
?????*?返回值:信息的集合
?????*/
????public?List?getAll()?{
????????String?sql="FROM?Books?ORDER?BY?bookName";
????????return?this.getHibernateTemplate().find(sql);
????}
????
????/**
?????*?函数说明:获得总行数
?????*?参数说明:?
?????*?返回值:总行数
?????*/
????public?int?getRows()?{
????????String?sql="FROM?Books?ORDER?BY?bookName";
????????List?list=this.getHibernateTemplate().find(sql);
????????return?list.size();
????}
????
????/**
?????*?函数说明:获得所有的信息
?????*?参数说明:?
?????*?返回值:信息的集合
?????*/
????public?List?getBooks(int?pageSize,?int?startRow)?throws?HibernateException?{
????????final?int?pageSize1=pageSize;
????????final?int?startRow1=startRow;
????????return?this.getHibernateTemplate().executeFind(new?HibernateCallback(){
????????????public?List?doInHibernate(Session?session)?throws?HibernateException,?SQLException?{
????????????????//?TODO?自动生成方法存根
????????????????Query?query=session.createQuery("FROM?Books?ORDER?BY?bookName");
????????????????query.setFirstResult(startRow1);
????????????????query.setMaxResults(pageSize1);
????????????????return?query.list();
????????????}
????????});
????}
????/**
?????*?函数说明:获得一条的信息
?????*?参数说明:?ID
?????*?返回值:对象
?????*/
????public?Books?getBook(String?bookId)?{
????????return?(Books)this.getHibernateTemplate().get(Books.class,bookId);
????}
????/**
?????*?函数说明:获得最大ID
?????*?参数说明:?
?????*?返回值:最大ID
?????*/
????public?String?getMaxID()?{
????????String?date=PublicUtil.getStrNowDate();
????????String?sql="SELECT?MAX(bookId)+1?FROM?Books??";
????????String?noStr?=?null;
????????List?ll?=?(List)?this.getHibernateTemplate().find(sql);
????????Iterator?itr?=?ll.iterator();
????????if?(itr.hasNext())?{
????????????Object?noint?=?itr.next();
????????????if(noint?==?null){
????????????????noStr?=?"1";????????????????
????????????}else{
????????????????noStr?=?noint.toString();
????????????}
????????}
????????
????????if(noStr.length()==1){
????????????noStr="000"+noStr;
????????}else?if(noStr.length()==2){
????????????noStr="00"+noStr;
????????}else?if(noStr.length()==3){
????????????noStr="0"+noStr;
????????}else{
????????????noStr=noStr;
????????}
????????return?noStr;
????}
????/**
?????*?函数说明:修改信息
?????*?参数说明:?对象
?????*?返回值:
?????*/
????public?void?updateBook(Books?pd)?{
????????this.getHibernateTemplate().update(pd);
????}
????/**
?????*?函数说明:查询信息
?????*?参数说明:?集合
?????*?返回值:
?????*/
????public?List?queryBooks(String?fieldname,String?value)?{
????????System.out.println("value:?"+value);
????????String?sql="FROM?Books?where?"+fieldname+"?like?'%"+value+"%'"+"ORDER?BY?bookName";
????????return?this.getHibernateTemplate().find(sql);
????}
????
????/**
?????*?函数说明:获得总行数
?????*?参数说明:?
?????*?返回值:总行数
?????*/
????public?int?getRows(String?fieldname,String?value)?{
????????String?sql="";
????????if(fieldname==null||fieldname.equals("")||fieldname==null||fieldname.equals(""))
????????????sql="FROM?Books?ORDER?BY?bookName";
????????else????
????????????sql="FROM?Books?where?"+fieldname+"?like?'%"+value+"%'"+"ORDER?BY?bookName";
????????List?list=this.getHibernateTemplate().find(sql);
????????return?list.size();
????}
????
????/**
?????*?函数说明:查询信息
?????*?参数说明:?集合
?????*?返回值:
?????*/
????public?List?getBooks(String?fieldname,String?value,int?pageSize,?int?startRow)?{
????????final?int?pageSize1=pageSize;
????????final?int?startRow1=startRow;
????????final?String?queryName=fieldname;
????????final?String?queryValue=value;
????????String?sql="";
????????
????????if(queryName==null||queryName.equals("")||queryValue==null||queryValue.equals(""))
????????????sql="FROM?Books?ORDER?BY?bookName";
????????else????
????????????sql="FROM?Books?where?"+fieldname+"?like?'%"+value+"%'"+"ORDER?BY?bookName";
????????
????????final?String?sql1=sql;
????????return?this.getHibernateTemplate().executeFind(new?HibernateCallback(){
????????????public?List?doInHibernate(Session?session)?throws?HibernateException,?SQLException?{
????????????????//?TODO?自动生成方法存根
????????????????Query?query=session.createQuery(sql1);
????????????????query.setFirstResult(startRow1);
????????????????query.setMaxResults(pageSize1);
????????????????return?query.list();
????????????}
????????});
????}
}
?com.sterning.books.dao.hibernate.BooksMapDao.java五、???????业务逻辑层
?
在业务逻辑层需要认真思考每个业务逻辑所能用到的持久层对象和DAO。DAO层之上是业务逻辑层,DAO类可以有很多个,但业务逻辑类应该只有一个,可以在业务逻辑类中调用各个DAO类进行操作。
1、创建服务接口类IBookService
1、????创建服务接口类IBookService
package?com.sterning.books.services.iface;
import?java.util.List;
import?com.sterning.books.model.Books;
public?interface?IBooksService?{
????List?getAll();//获得所有记录
????List?getBooks(int?pageSize,?int?startRow);//获得所有记录
????int?getRows();//获得总行数
????int?getRows(String?fieldname,String?value);//获得总行数
????List?queryBooks(String?fieldname,String?value);//根据条件查询
????List?getBooks(String?fieldname,String?value,int?pageSize,?int?startRow);//根据条件查询
????Books?getBook(String?bookId);//根据ID获得记录
????String?getMaxID();//获得最大ID值
????void?addBook(Books?pd);//添加记录
????void?updateBook(Books?pd);//修改记录
????void?deleteBook(String?bookId);//删除记录????
}
??com.sterning.books.services.iface.IBookService.java2、实现此接口类:BookService:
package?com.sterning.books.services;
import?java.util.List;
import?com.sterning.books.dao.iface.BooksDao;
import?com.sterning.books.model.Books;
import?com.sterning.books.services.iface.IBooksService;
public?class?BooksService?implements?IBooksService{
????private?BooksDao?booksDao;
????
????public?BooksService(){}
????
????/**
?????*?函数说明:添加信息
?????*?参数说明:对象?
?????*?返回值:
?????*/
????public?void?addBook(Books?book)?{
????????booksDao.addBook(book);
????}
????/**
?????*?函数说明:删除信息
?????*?参数说明:?对象
?????*?返回值:
?????*/
????public?void?deleteBook(String?bookId)?{
????????Books?book=booksDao.getBook(bookId);
????????booksDao.deleteBook(book);
????}
????/**
?????*?函数说明:获得所有的信息
?????*?参数说明:?
?????*?返回值:信息的集合
?????*/
????public?List?getAll()?{
????????return?booksDao.getAll();
????}
????
????/**
?????*?函数说明:获得总行数
?????*?参数说明:?
?????*?返回值:总行数
?????*/
????public?int?getRows()?{
????????return?booksDao.getRows();
????}
????
????/**
?????*?函数说明:获得所有的信息
?????*?参数说明:?
?????*?返回值:信息的集合
?????*/
????public?List?getBooks(int?pageSize,?int?startRow)?{
????????return?booksDao.getBooks(pageSize,?startRow);
????}
????/**
?????*?函数说明:获得一条的信息
?????*?参数说明:?ID
?????*?返回值:对象
?????*/
????public?Books?getBook(String?bookId)?{
????????return?booksDao.getBook(bookId);
????}
????/**
?????*?函数说明:获得最大ID
?????*?参数说明:?
?????*?返回值:最大ID
?????*/
????public?String?getMaxID()?{
????????return?booksDao.getMaxID();
????}
????/**
?????*?函数说明:修改信息
?????*?参数说明:?对象
?????*?返回值:
?????*/
????public?void?updateBook(Books?book)?{
????????booksDao.updateBook(book);
????}
????/**
?????*?函数说明:查询信息
?????*?参数说明:?集合
?????*?返回值:
?????*/
????public?List?queryBooks(String?fieldname,String?value)?{
????????return?booksDao.queryBooks(fieldname,?value);
????}
????
????/**
?????*?函数说明:获得总行数
?????*?参数说明:?
?????*?返回值:总行数
?????*/
????public?int?getRows(String?fieldname,String?value)?{
????????return?booksDao.getRows(fieldname,?value);
????}
????
????/**
?????*?函数说明:查询信息
?????*?参数说明:?集合
?????*?返回值:
?????*/
????public?List?getBooks(String?fieldname,String?value,int?pageSize,?int?startRow)?{
????????return?booksDao.getBooks(fieldname,?value,pageSize,startRow);
????}
????public?BooksDao?getBooksDao()?{
????????return?booksDao;
????}
????public?void?setBooksDao(BooksDao?booksDao)?{
????????this.booksDao?=?booksDao;
????}
}
? com.sterning.books.services.BookService.java六、????????创建Action类:BookAction?
有Struts 1.x经验的朋友都知道Action是Struts的核心内容,当然Struts 2.0也不例外。不过,Struts 1.x与Struts 2.0的Action模型很大的区别。
??Struts 1.x
Stuts 2.0
接口
必须继承org.apache.struts.action.Action或者其子类
无须继承任何类型或实现任何接口
表单数据
表单数据封装在FormBean中
表单数据包含在Action中,通过Getter和Setter获取
1、建立BookAction类
package?com.sterning.books.web.actions;
import?java.util.Collection;
import?com.sterning.books.model.Books;
import?com.sterning.books.services.iface.IBooksService;
import?com.sterning.commons.AbstractAction;
import?com.sterning.commons.Pager;
import?com.sterning.commons.PagerService;
public?class?BooksAction?extends?AbstractAction?
{
????
????private?IBooksService?booksService;
????private?PagerService?pagerService;
????
????private?Books?book;
????private?Pager?pager;
????
????protected?Collection?availableItems;
????protected?String?currentPage;
????protected?String?pagerMethod;
????protected?String?totalRows;
????protected?String?bookId;
????protected?String?queryName;
????protected?String?queryValue;
????protected?String?searchName;
????protected?String?searchValue;
????protected?String?queryMap;
????
????public?String?list()?throws?Exception?
{
????????if(queryMap?==null||queryMap.equals(""))
{
????????????
????????}else
{
????????????String[]?str=queryMap.split("~");
????????????this.setQueryName(str[0]);
????????????this.setQueryValue(str[1]);
????????}
????????
????????System.out.println("asd"+this.getQueryValue());
????????int?totalRow=booksService.getRows(this.getQueryName(),this.getQueryValue());
????????pager=pagerService.getPager(this.getCurrentPage(),?this.getPagerMethod(),?totalRow);
????????this.setCurrentPage(String.valueOf(pager.getCurrentPage()));
????????this.setTotalRows(String.valueOf(totalRow));
????????availableItems=booksService.getBooks(this.getQueryName(),this.getQueryValue(),pager.getPageSize(),?pager.getStartRow());
????????
????????this.setQueryName(this.getQueryName());
????????this.setQueryValue(this.getQueryValue());
????????
????????this.setSearchName(this.getQueryName());
????????this.setSearchValue(this.getQueryValue());
????????
????????return?SUCCESS;?????????
????}
????
????public?String?load()?throws?Exception?
{
????????if(bookId!=null)
????????????book?=?booksService.getBook(bookId);
????????else
????????????bookId=booksService.getMaxID();
????????return?SUCCESS;
????}
????
????public?String?save()?throws?Exception?
{
????????if(this.getBook().getBookPrice().equals(""))
{
????????????this.getBook().setBookPrice("0.0");
????????}
????????
????????String?id=this.getBook().getBookId();
????????Books?book=booksService.getBook(id);
????????
????????
????????
????????if(book?==?null)
????????????booksService.addBook(this.getBook());
????????else
????????????booksService.updateBook(this.getBook());
????????
????????this.setQueryName(this.getQueryName());
????????this.setQueryValue(this.getQueryValue());
????????
????????if(this.getQueryName()==null||this.getQueryValue()==null||this.getQueryName().equals("")||this.getQueryValue().equals(""))
{
????????????
????????}else
{
????????????queryMap=this.getQueryName()+"~"+this.getQueryValue();
????????}????????
????????
????????return?SUCCESS;
????}
????
????public?String?delete()?throws?Exception?
{
????????booksService.deleteBook(this.getBookId());
????????
????????if(this.getQueryName()==null||this.getQueryValue()==null||this.getQueryName().equals("")||this.getQueryValue().equals(""))
{
????????????
????????}else
{
????????????queryMap=this.getQueryName()+"~"+this.getQueryValue();
????????}
????????return?SUCCESS;
????}????
????
????public?Books?getBook()?
{
????????return?book;
????}
????public?void?setBook(Books?book)?
{
????????this.book?=?book;
????}
????public?IBooksService?getBooksService()?
{
????????return?booksService;
????}
????public?void?setBooksService(IBooksService?booksService)?
{
????????this.booksService?=?booksService;
????}
????public?Collection?getAvailableItems()?
{
????????return?availableItems;
????}
????public?String?getCurrentPage()?
{
????????return?currentPage;
????}
????public?void?setCurrentPage(String?currentPage)?
{
????????this.currentPage?=?currentPage;
????}
????public?String?getPagerMethod()?
{
????????return?pagerMethod;
????}
????public?void?setPagerMethod(String?pagerMethod)?
{
????????this.pagerMethod?=?pagerMethod;
????}
????public?Pager?getPager()?
{
????????return?pager;
????}
????public?void?setPager(Pager?pager)?
{
????????this.pager?=?pager;
????}
????public?String?getTotalRows()?
{
????????return?totalRows;
????}
????public?void?setTotalRows(String?totalRows)?
{
????????this.totalRows?=?totalRows;
????}
????????
????public?String?getBookId()?
{
????????return?bookId;
????}
????public?void?setBookId(String?bookId)?
{
????????this.bookId?=?bookId;
????}
????public?String?getQueryName()?
{
????????return?queryName;
????}
????public?void?setQueryName(String?queryName)?
{
????????this.queryName?=?queryName;
????}
????public?String?getQueryValue()?
{
????????return?queryValue;
????}
????public?void?setQueryValue(String?queryValue)?
{
????????this.queryValue?=?queryValue;
????}
????
????public?String?getSearchName()?
{
????????return?searchName;
????}
????public?void?setSearchName(String?searchName)?
{
????????this.searchName?=?searchName;
????}
????public?String?getSearchValue()?
{
????????return?searchValue;
????}
????public?void?setSearchValue(String?searchValue)?
{
????????this.searchValue?=?searchValue;
????}
????
????public?String?getQueryMap()?
{
????????return?queryMap;
????}
????public?void?setQueryMap(String?queryMap)?
{
????????this.queryMap?=?queryMap;
????}
????
????public?PagerService?getPagerService()?
{
????????return?pagerService;
????}

????public?void?setPagerService(PagerService?pagerService)?
{
????????this.pagerService?=?pagerService;
????}????
}
com.sterning.books.web.actions.BookAction.java
(1)、默认情况下,当请求bookAction.action发生时(这个会在后面的Spring配置文件中见到的),Struts运行时(Runtime)根据struts.xml里的Action映射集(Mapping),实例化com.sterning.books.web.actions.BookAction类,并调用其execute方法。当然,我们可以通过以下两种方法改变这种默认调用。这个功能(Feature)有点类似Struts 1.x中的LookupDispathAction。
在classes/sturts.xml中新建Action,并指明其调用的方法;
访问Action时,在Action名后加上“!xxx”(xxx为方法名)。
(2)、细心的朋友应该可能会发现com.sterning.books.web.actions.BookAction.java中Action方法(execute)返回都是SUCCESS。这个属性变量我并没有定义,所以大家应该会猜到它在ActionSupport或其父类中定义。没错,SUCCESS在接口com.opensymphony.xwork2.Action中定义,另外同时定义的还有ERROR,?INPUT,?LOGIN,?NONE。
此外,我在配置Action时都没有为result定义名字(name),所以它们默认都为success。值得一提的是Struts 2.0中的result不仅仅是Struts 1.x中forward的别名,它可以实现除forward外的很激动人心的功能,如将Action输出到FreeMaker模板、Velocity模板、JasperReports和使用XSL转换等。这些都过result里的type(类型)属性(Attribute)定义的。另外,您还可以自定义result类型。
(3)、使用Struts 2.0,表单数据的输入将变得非常方便,和普通的POJO一样在Action编写Getter和Setter,然后在JSP的UI标志的name与其对应,在提交表单到Action时,我们就可以取得其值。
(4)、Struts 2.0更厉害的是支持更高级的POJO访问,如this.getBook().getBookPrice()。private Books book所引用的是一个关于书的对象类,它可以做为一个属性而出现在BookActoin.java类中。这样对我们开发多层系统尤其有用。它可以使系统结构更清晰。
(5)、有朋友可能会这样问:“如果我要取得Servlet API中的一些对象,如request、response或session等,应该怎么做?这里的execute不像Struts 1.x的那样在参数中引入。”开发Web应用程序当然免不了跟这些对象打交道。在Strutx 2.0中可以有两种方式获得这些对象:非IoC(控制反转Inversion of Control)方式和IoC方式。
非IoC方式
要获得上述对象,关键是Struts 2.0中com.opensymphony.xwork2.ActionContext类。我们可以通过它的静态方法getContext()获取当前Action的上下文对象。另外,org.apache.struts2.ServletActionContext作为辅助类(Helper Class),可以帮助您快捷地获得这几个对象。
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
HttpSession session = request.getSession();
如果你只是想访问session的属性(Attribute),你也可以通过ActionContext.getContext().getSession()获取或添加session范围(Scoped)的对象。
IoC方式
要使用IoC方式,我们首先要告诉IoC容器(Container)想取得某个对象的意愿,通过实现相应的接口做到这点。如实现SessionAware, ServletRequestAware, ServletResponseAware接口,从而得到上面的对象。
1、对BookAction类的Save方法进行验证
正如《Writing Secure Code》文中所写的名言All input is evil:“所有的输入都是罪恶的”,所以我们应该对所有的外部输入进行校验。而表单是应用程序最简单的入口,对其传进来的数据,我们必须进行校验。Struts2的校验框架十分简单方便,只在如下两步:
在Xxx-validation.xml文件中的<message>元素中加入key属性;
在相应的jsp文件中的<s:form>标志中加入validate="true"属性,就可以在用Javascript在客户端校验数据。
其验证文件为:BooksAction-save-validation.xml
<?xml?version="1.0"?encoding="UTF-8"?>
<!DOCTYPE?validators?PUBLIC?"-//OpenSymphony?Group//XWork?Validator?1.0//EN"?"http://www.opensymphony.com/xwork/xwork-validator-1.0.dtd">
<validators>
????<!--?Field-Validator?Syntax?-->
????<field?name="book.bookName">
????????<field-validator?type="requiredstring">
????????????<message?key="book.bookName.required"/>
????????</field-validator>
????</field>
????<field?name="book.bookAuthor">
????????<field-validator?type="requiredstring">
????????????<message?key="book.bookAuthor.required"/>
????????</field-validator>
????</field>
????<field?name="book.bookPublish">
????????<field-validator?type="requiredstring">
????????????<message?key="book.bookPublish.required"/>
????????</field-validator>
????</field>
</validators>
?com.sterning.books.web.actions.BooksAction-save-validation.xml1、对BookAction类的Save方法进行验证的资源文件
???????注意配置文件的名字应该是:配置文件(类名-validation.xml)的格式。BooksAction类的验证资源文件为:BooksAction.properties
book=Books
book.bookName.required=\u8bf7\u8f93\u5165\u4e66\u540d
book.bookAuthor.required=\u8bf7\u8f93\u5165\u4f5c\u8005
book.bookPublish.required=\u8bf7\u8f93\u5165\u51fa\u7248\u793e
format.date={0,date,yyyy-MM-dd}
com.sterning.books.web.actions.BooksAction.properties
???????资源文件的查找顺序是有一定规则的。之所以说Struts 2.0的国际化更灵活是因为它可以根据不同需要配置和获取资源(properties)文件。在Struts 2.0中有下面几种方法:
(1)、使用全局的资源文件。这适用于遍布于整个应用程序的国际化字符串,它们在不同的包(package)中被引用,如一些比较共用的出错提示;
(2)、使用包范围内的资源文件。做法是在包的根目录下新建名的package.properties和package_xx_XX.properties文件。这就适用于在包中不同类访问的资源;
(3)、使用Action范围的资源文件。做法为Action的包下新建文件名(除文件扩展名外)与Action类名同样的资源文件。它只能在该Action中访问。如此一来,我们就可以在不同的Action里使用相同的properties名表示不同的值。例如,在ActonOne中title为“动作一”,而同样用title在ActionTwo表示“动作二”,节省一些命名工夫;
(4)、使用<s:i18n>标志访问特定路径的properties文件。在使用这一方法时,请注意<s:i18n>标志的范围。在<s:i18n name="xxxxx">到</s:i18n>之间,所有的国际化字符串都会在名为xxxxx资源文件查找,如果找不到,Struts 2.0就会输出默认值(国际化字符串的名字)。
例如:某个ChildAction中调用了getText("user.title"),Struts 2.0的将会执行以下的操作:
查找ChildAction_xx_XX.properties文件或ChildAction.properties;
查找ChildAction实现的接口,查找与接口同名的资源文件MyInterface.properties;
查找ChildAction的父类ParentAction的properties文件,文件名为ParentAction.properties;
判断当前ChildAction是否实现接口ModelDriven。如果是,调用getModel()获得对象,查找与其同名的资源文件;
查找当前包下的package.properties文件;
查找当前包的父包,直到最顶层包;
在值栈(Value Stack)中,查找名为user的属性,转到user类型同名的资源文件,查找键为title的资源;
查找在struts.properties配置的默认的资源文件,参考例1;
输出user.title。
七、???????Web页面
?
在这一节中,主要使用到了Struts2的标签库。在这里,会对所用到的主要标签做一个初步的介绍。更多的知识请读者访问Struts的官方网站做更多的学习。在编写Web页面之前,先从总体上,对Struts 1.x与Struts 2.0的标志库(Tag Library)作比较。
Struts 1.x
Struts 2.0
分类
将标志库按功能分成HTML、Tiles、Logic和Bean等几部分
严格上来说,没有分类,所有标志都在URI为“/struts-tags”命名空间下,不过,我们可以从功能上将其分为两大类:非UI标志和UI标志
表达式语言(expression languages)
不支持嵌入语言(EL)
OGNL、JSTL、Groovy和Velcity
?
1、主页面:index.jsp,其代码如下:
?
<%@page?pageEncoding="UTF-8"?contentType="text/html;?charset=UTF-8"?%>
<%@?taglib?prefix="s"?uri="/struts-tags"?%>
<html>
<head>
<meta?http-equiv="Content-Type"?content="text/html;?charset=GBK"/>
<title>图书管理系统</title>
</head>
<body>
<p><a?href="<s:url?action="list"?/>">进入图书管理系统</a></p>
</body>
</html>
?
WebRoot/index.jsp
要在JSP中使用Struts 2.0标志,先要指明标志的引入。通过在JSP的代码的顶部加入以下代码可以做到这点。<%@taglib prefix="s" uri="/struts-tags" %>
1、<s:url>标签:该标签用于创建url,可以通过"param"标签提供request参数。当includeParams的值时'all'或者'get', param标签中定义的参数将有优先权,也就是说其会覆盖其他同名参数的值。
2、列表页面:list.jsp
?
<%@page?pageEncoding="gb2312"?contentType="text/html;?charset=UTF-8"?%>
<%@?taglib?prefix="s"?uri="/struts-tags"?%>
<html>
<head><title>图书管理系统</title></head>
????<style?type="text/css">
????????table?{
????????????border:?1px?solid?black;
????????????border-collapse:?collapse;
????????}
????????
????????table?thead?tr?th?{
????????????border:?1px?solid?black;
????????????padding:?3px;
????????????background-color:?#cccccc;
????????????background-color:?expression(this.rowIndex?%?2?==?0???"#FFFFFF"?:?"#EEEEEE");
????????}
????????
????????table?tbody?tr?td?{
????????????border:?1px?solid?black;
????????????padding:?3px;
????????}
????????.trs{
????????????background-color:?expression(this.rowIndex?%?2?==?0???"#FFFFFF"?:?"#EEEEEE");
????????}
????</style>
????<script?language="JavaScript">???
????????function?doSearch(){
????????????if(document.all.searchValue.value=="")
????????????{????
????????????????alert("请输入查询关键字!");
????????????}else{
????????????????window.location.href="bookAdmin/list.action?queryName="+document.all.searchName.value+"&&queryValue="+document.all.searchValue.value;
?????????????}
????????}
????</script>
<body>
<table?align="center">
<tr?align="center">
????<td>
????????<select?name="searchName">
????????????<option?value="bookName">书名</option>
????????????<option?value="bookAuthor">作者</option>
????????????<option?value="bookPublish">出版社</option>
????????????<option?value="bookDate">出版日期</option>
????????????<option?value="bookIsbn">ISNB</option>
????????????<option?value="bookPage">页数</option>
????????</select>
????????<input?type="text"?name="searchValue"?value=""?size="10"/>
????????<input?type="button"?value="查询"?onClick="doSearch();">
????</td>
</tr>
<tr?align="center">????
????<td>
????????<a?href="<s:url?action="list"?includeParams="none"/>">全部</a>
????????<a?href='<s:url?action="edit"?></s:url>'>增加</a>
????</td>
</tr>
<tr>
<td>
<table?cellspacing="0"?align="center">
????<thead>
????<tr>
????????<th>书名</th>
????????<th>作者</th>
????????<th>出版社</th>
????????<th>出版日期</th>
????????<th>ISNB</th>
????????<th>页数</th>
????????<th>价格</th>
????????<th>内容提要</th>
????????<th>删除</th>
????</tr>
????</thead>
????<tbody>
????<s:iterator?value="availableItems">
????????<tr?class="trs">
????????????<td>
????????????<a?href='<s:url?action="edit"?><s:param?name="bookId"?value="bookId"?/></s:url>'>
????????????<s:property?value="bookName"/>
????????????</a>
????????????</td>
????????????<td><s:property?value="bookAuthor"/></td>
????????????<td><s:property?value="bookPublish"/></td>
????????????<td><s:text?name="format.date"><s:param?value="bookDate"/></s:text></td>?????
????????????<td><s:property?value="bookIsbn"?/></td>
????????????<td><s:property?value="bookPage"?/></td>
????????????<td><s:property?value="bookPrice"/></td>
????????????<td><s:property?value="bookContent"/></td>
????????????
????????????<td><a?href='<s:url?action="delete"><s:param?name="bookId"?value="bookId"?/></s:url>'>删除</a></td>
????????</tr>
????</s:iterator>
????<tr?align="right">
????????<td?colspan="9">
????????????共<s:property?value="totalRows"/>行
????????????第<s:property?value="currentPage"/>页
????????????共<s:property?value="pager.getTotalPages()"/>页
????????????<a?href="<s:url?value="list.action">
????????????????<s:param?name="currentPage"?value="currentPage"/>
????????????????<s:param?name="pagerMethod"?value="'first'"/>
????????????????
????????????</s:url>">首页</a>
????????????<a?href="<s:url?value="list.action">
????????????????<s:param?name="currentPage"?value="currentPage"/>
????????????????<s:param?name="pagerMethod"?value="'previous'"/>
????????????</s:url>">上一页</a>
????????????<a?href="<s:url?value="list.action">
????????????????<s:param?name="currentPage"?value="currentPage"/>
????????????????<s:param?name="pagerMethod"?value="'next'"/>
????????????</s:url>">下一页</a>
????????????<a?href="<s:url?value="list.action">
????????????????<s:param?name="currentPage"?value="currentPage"/>
????????????????<s:param?name="pagerMethod"?value="'last'"/>
????????????</s:url>">尾页</a>
????????</td>
????</tr>????
????</tbody>
</table>
</td>
</tr>
</table>
</body>
</html>
/WebRoot/list.jsp
(1)、<s:property> :得到'value'的属性,如果value没提供,默认为堆栈顶端的元素。其相关的参数及使用如下表所示:
名称
必需
默认
类型
描述
default
否
String
如果属性是null则显示的default值
escape
否
true
Booelean
是否escape HTML
value
否
栈顶
Object
要显示的值
id
否
Object/String
用来标识元素的id。在UI和表单中为HTML的id属性
(2)、<s:Iterator>:用于遍历集合(java.util.Collection)或枚举值(java.util.Iterator)。其相关的参数及使用如下表所示:??
名称
必需
默认
类型
描述
status
否
String
如果设置此参数,一个IteratorStatus的实例将会压入每个遍历的堆栈
value
否
Object/String
要遍历的可枚举的(iteratable)数据源,或者将放入新列表(List)的对象
id
否
Object/String
用来标识元素的id。在UI和表单中为HTML的id属性
(3)、<s:param>:为其他标签提供参数,比如include标签和bean标签.?参数的name属性是可选的,如果提供,会调用Component的方法addParameter(String, Object),?如果不提供,则外层嵌套标签必须实现UnnamedParametric接口(如TextTag)。?value的提供有两种方式,通过value属性或者标签中间的text,不同之处我们看一下例子:
<param name="color">blue</param><!-- (A) -->
<param name="color" value="blue"/><!-- (B) -->
(A)参数值会以String的格式放入statck.?
(B)该值会以java.lang.Object的格式放入statck.
其相关的参数及使用如下表所示:
名称
必需
默认
类型
描述
name
否
String
参数名
value
否
String
value表达式
id
否
Object/String
用来标识元素的id。在UI和表单中为HTML的id属性
(4)、国际化是商业系统中不可或缺的一部分,所以无论您学习的是什么Web框架,它都是必须掌握的技能。其实,Struts 1.x在此部分已经做得相当不错了。它极大地简化了我们程序员在做国际化时所需的工作,例如,如果您要输出一条国际化的信息,只需在代码包中加入FILE-NAME_xx_XX.properties(其中FILE-NAME为默认资源文件的文件名),然后在struts-config.xml中指明其路径,再在页面用<bean:message>标志输出即可。
不过,所谓“没有最好,只有更好”。Struts 2.0并没有在这部分止步,而是在原有的简单易用的基础上,将其做得更灵活、更强大。
(5)、list.jsp文件中:
<s:text name="format.date"><s:param value="bookDate"/></s:text>,为了正确的输出出版日期的格式,采用在资源文件中定义输出的格式,并在页面上调用。format.date就是在资源文件com.sterning.books.web.actions.BooksAction.properties中定义。当然也可以别的文件,放在别的路径下,但此时需要在web.xml中注册才可以使用它。
正如读者所见,在pojo(本例为Books.java)中将日期字段设置为java.util.Date,在映射文件中(books.hbm.xml)设置为timestamp(包括日期和时间)。为了便于管理,将日期格式保存在国际化资源文件中。如:globalMessages或globalMessages_zh_CN文件。
其内容为:
format.date={0,date,yyyy-MM-dd}
在页面显示日期时间时:<s:text name="format.date"><s:param value="bookDate"/></s:text>。这样就解决了日期(时间)的显示格式化问题。
?
3、增加/修改页面:editBook.jsp?
?
?
<%@page?pageEncoding="UTF-8"?contentType="text/html;?charset=UTF-8"?%>
<%@?taglib?prefix="s"?uri="/struts-tags"?%>
<html>
<head>
????<title>编辑图书</title>
????<s:head/>
</head>
<body>
????<h2>
????????<s:if?test="null?==?book">
????????????增加图书
????????</s:if>
????????<s:else>
????????????编辑图书
????????</s:else>
????</h2>
????<s:form?name="editForm"?action="save"?validate="true">
????
?????????<s:textfield?label="书名"?name="book.bookName"/>
?????????<s:textfield?label="作者"?name="book.bookAuthor"/>
?????????<s:textfield?label="出版社"?name="book.bookPublish"/>
?????????<s:datetimepicker?label="出版日期"?name="book.bookDate"></s:datetimepicker>
?????????<s:textfield?label="ISBN"?name="book.bookIsbn"/>
?????????<s:textfield?label="页数"?name="book.bookPage"/>
?????????<s:textfield?label="价格(元)"?name="book.bookPrice"/>
?????????<s:textfield?label="内容摘要"?name="book.bookContent"/>
?????????<s:if?test="null?==?book">
?????????????<s:hidden?name="book.bookId"?value="%{bookId}"/>
?????????</s:if>?????????
?????????<s:else>
?????????????<s:hidden?name="book.bookId"?/>
?????????</s:else>
?????????<s:hidden?name="queryName"?/>
?????????<s:hidden?name="queryValue"?/>
?????????<s:submit?value="%{getText('保存')}"?/>
????</s:form>
<p><a?href="<s:url?action="list"/>">返回</a></p>
</body>
</html>
?
WebRoot/editBook.jsp
(1)、<s:if>、<s:elseif>和<s:else>?:执行基本的条件流转。其相关的参数及使用如下表所示:
名称
必需
默认
类型
描述
备注
test
是
?Boolean
决定标志里内容是否显示的表达式
else标志没有这个参数
id
否
?Object/String
用来标识元素的id。在UI和表单中为HTML的id属性
?(2)、<s:text>:支持国际化信息的标签。国际化信息必须放在一个和当前action同名的resource bundle中,如果没有找到相应message,tag body将被当作默认message,如果没有tag body,message的name会被作为默认message。其相关的参数及使用如下表所示:
名称
必需
默认
类型
描述
name
是
?String
资源属性的名字
id
否
?Object/String
用来标识元素的id。在UI和表单中为HTML的id属性
八、???????配置Struts2
?
Struts的配置文件都会在web.xml中注册的。
a)????????Struts的配置文件如下:
?
<?xml?version="1.0"?encoding="UTF-8"??>
<!DOCTYPE?struts?PUBLIC
????"-//Apache?Software?Foundation//DTD?Struts?Configuration?2.0//EN"
????"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
????<constant?name="struts.enable.DynamicMethodInvocation"?value="false"?/>
????<constant?name="struts.devMode"?value="true"?/>
????<constant?name="struts.i18n.encoding"?value="GBK"?/>???
????<!--?Add?packages?here?-->
</struts>
?
Src/struts.xml
b)????????struts_book.xml配置文件如下:
?
<?xml?version="1.0"?encoding="UTF-8"??>
<!DOCTYPE?struts?PUBLIC
????????"-//Apache?Software?Foundation//DTD?Struts?Configuration?2.0//EN"
????????"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
????<package?name="products"?extends="struts-default">
????????<!--default-interceptor-ref?name="validation"/-->
?????????<!--?Add?actions?here?-->
????????<action?name="list"?class="bookAction"?method="list">????????????
????????????<result>/list.jsp</result>
????????</action>
????<action?name="delete"?class="bookAction"?method="delete">????????????
????????????<result?type="redirect">list.action?queryMap=${queryMap}</result>
????????</action>
????????<action?name="*"?class="com.sterning.commons.AbstractAction">
????????????<result>/{1}.jsp</result>
????????</action>
????????
????<action?name="edit"?class="bookAction"?method="load">
????????????<result>/editBook.jsp</result>
????????</action>
???????
???????<action?name="save"?class="bookAction"?method="save">
???????????<interceptor-ref?name="params"/>
???????????<interceptor-ref?name="validation"/>
????????????<result?name="input">/editBook.jsp</result>
????????????<result?type="redirect">list.action?queryMap=${queryMap}</result>
??????????????
????????</action>
????</package>
</struts>
?
文件中的<interceptor-ref name="params"/>,使用了struts2自己的拦截器,拦截器在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。拦截是AOP的一种实现策略。
Struts 2已经提供了丰富多样的,功能齐全的拦截器实现。大家可以到struts2-all-2.0.6.jar或struts2-core-2.0.6.jar包的struts-default.xml查看关于默认的拦截器与拦截器链的配置。
在struts-default.xml中已经配置了大量的拦截器。如果您想要使用这些已有的拦截器,只需要在应用程序struts.xml文件中通过“<include file="struts-default.xml" />”将struts-default.xml文件包含进来,并继承其中的struts-default包(package),最后在定义Action时,使用“<interceptor-ref name="xx" />”引用拦截器或拦截器栈(interceptor stack)。一旦您继承了struts-default包(package),所有Action都会调用拦截器栈?——defaultStack。当然,在Action配置中加入“<interceptor-ref name="xx" />”可以覆盖defaultStack。
作为“框架(framework)”,可扩展性是不可或缺的,因为世上没有放之四海而皆准的东西。虽然,Struts 2为我们提供如此丰富的拦截器实现,但是这并不意味我们失去创建自定义拦截器的能力,恰恰相反,在Struts 2自定义拦截器是相当容易的一件事。所有的Struts 2的拦截器都直接或间接实现接口com.opensymphony.xwork2.interceptor.Interceptor。除此之外,大家可能更喜欢继承类com.opensymphony.xwork2.interceptor.AbstractInterceptor。
?
九、???????配置Spring
?
1、Spring的配置文件如下:
?
<?xml?version="1.0"?encoding="UTF-8"?>
<!DOCTYPE?beans?PUBLIC?"-//SPRING//DTD?BEAN//EN"?"http://www.springframework.org/dtd/spring-beans.dtd">
?
<beans>
????<!--?dataSource?config?-->
????<bean?id?="dataSource"?class?="org.apache.commons.dbcp.BasicDataSource"?destroy-method="close">?
????????<property?name="driverClassName"?value="com.mysql.jdbc.Driver"?/>?
????????<property?name="url"?value="jdbc:mysql://localhost:3306/game"?/>?
????????<property?name="username"?value="root"?/>?
????????<property?name="password"?value="root"/>?
????</bean>?
????
????<!--?SessionFactory?-->
????<bean?id="sessionFactory"
????????class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
????????<property?name="dataSource">
????????????<ref?bean="dataSource"/>
????????</property>
????????<property?name="configLocation">
????????????<value>classpath:com\sterning\bean\hibernate\hibernate.cfg.xml</value>
????????</property>????????
????</bean>
????
????<!--?TransactionManager??不过这里暂时没注入-->
????<bean?id="transactionManager"
????????class="org.springframework.orm.hibernate3.HibernateTransactionManager">
????????<property?name="sessionFactory">
????????????<ref?local="sessionFactory"/>
????????</property>
????</bean>
????
????<!--?DAO?-->
????<bean?id="booksDao"?class="com.sterning.books.dao.hibernate.BooksMapDao">
????????<property?name="sessionFactory">
????????????<ref?bean="sessionFactory"/>
????????</property>
????</bean>
????
????<!--?Services?-->
????<bean?id="booksService"?class="com.sterning.books.services.BooksService">
????????<property?name="booksDao">
????????????<ref?bean="booksDao"/>
????????</property>
????</bean>
????
????<bean?id="pagerService"?class="com.sterning.commons.PagerService"/>
????
????<!--?view?-->
????<bean?id="bookAction"?class="com.sterning.books.web.actions.BooksAction"?singleton="false">
????????<property?name="booksService">
????????????<ref?bean="booksService"/>
????????</property>
????????<property?name="pagerService">
????????????<ref?bean="pagerService"/>
????????</property>
????</bean>??
????
</beans>
? WebRoot/WEB-INF/srping-content/applicationContent.xml
2、Struts.properties.xml
本来此文件应该写在struts?配置一节,但主要是考虑这体现了集成spring的配置,所以放在spring的配置这里来讲。
?
struts.objectFactory?=?spring??
struts.locale=zh_CN
struts.i18n.encoding?=?GBK
?
struts.objectFactory:ObjectFactory?实现了?com.opensymphony.xwork2.ObjectFactory接口(spring)。struts.objectFactory=spring,主要是告知Struts 2运行时使用Spring来创建对象(如Action等)。当然,Spring的ContextLoaderListener监听器,会在web.xml文件中编写,负责Spring与Web容器交互。
struts.locale:The default locale for the Struts application。?默认的国际化地区信息。
struts.i18n.encoding:国际化信息内码。
十、???????Web.xml配置
?

<?xml?version="1.0"?encoding="GB2312"?>
<!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>
????<display-name>图书管理系统</display-name>
????<context-param>
????????<param-name>log4jConfigLocation</param-name>
????????<param-value>/WEB-INF/classes/log4j.properties</param-value>
????</context-param>
????<!--?ContextConfigLocation?-->
????<context-param>
????????<param-name>contextConfigLocation</param-name>
????????<param-value>/WEB-INF/spring-context/applicationContext.xml</param-value>
??????</context-param>
????
????<filter>
????????<filter-name>encodingFilter</filter-name>
????????<filter-class>com.sterning.commons.SetCharacterEncodingFilter</filter-class>
????????<init-param>
????????????<param-name>encoding</param-name>
????????????<param-value>UTF-8</param-value>
????????</init-param>
????????<init-param>
????????????<param-name>forceEncoding</param-name>
????????????<param-value>true</param-value>
????????</init-param>
????</filter>
?????<filter>
????????<filter-name>struts2</filter-name>
????????<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
????????<init-param>
????????????<param-name>config</param-name>
????????????<param-value>struts-default.xml,struts-plugin.xml,struts.xml,struts_books.xml</param-value>
????????</init-param>
????</filter>????
????<filter-mapping>
????????<filter-name>encodingFilter</filter-name>
????????<url-pattern>/*</url-pattern>
????</filter-mapping>
????<filter-mapping>
????????<filter-name>struts2</filter-name>
????????<url-pattern>/*</url-pattern>
????</filter-mapping>????????
????
????<!--?Listener?contextConfigLocation?-->
??????<listener>
????????<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
??????</listener>
????<!--?Listener?log4jConfigLocation?-->
??????<listener>
????????<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
??????</listener>
?
????<!--?The?Welcome?File?List?-->
????<welcome-file-list>
????????<welcome-file>index.jsp</welcome-file>
????</welcome-file-list>
</web-app>
?
在Struts 2中,配置有少许改变,最明显的是分发器(dispatcher)已由Servlet转为Servlet Filter,?其配置和Servlet一样简单。和Servlet配置一样,Filter配置中定义了Filter的名称(作为引用)和类名。Filter Mapping通过URI和名称匹配来调用相应的Filter。默认情况下,扩展名为“.action”,这是在default.properties文件(在Struts 2 JAR文件里)的“struts.action.extension”属性定义的。
十一、???????运行结果
1、主页面

2、图书列表页面

3、增加页面

4、修改页面

十二、???????总结
从上面的struts2.0.6+spring2.0.6+hibernate3.1的示例代码可以看出,从struts1过渡到Struts2的时候,发现非常方便,标签变得更加的简洁,从而使代码量简缩了,同时整个体系沿用了webwork的精华和struts1的精髓,Struts2的Action不再依耐于Servlet容器,从而可以进行单独的测试。另外对于表达式语言方面,不仅支持原有的JSTL,还支持OGNL(全称是Object Graph Notation Language)。在校验方面,没有再直接使用Common-validator,用的是xwork框架校验。其实说这些,主要把webwork2的特性简单描述一下而已,话说回来,发现struts2跟ajax的某些框架结合得不好,比如流行的dwr,连最简单的页面theme都用不了ajax,这个问题主要出在模版上面,具体位置在Struts2-core-2.0.6.jar包的template/ajax里面的form-close.ftl等几个文件的代码有bug,比如dojo.widget.html.Tooltip问题,是没有这个属性的,应为dojo.widget.Tooltip,这个已经在官方的bug跟踪系统提出了,官方说会在2.1版本时解决(其实在Struts2.0.8中已经有解决的痕迹了)。当然,还有其他一系列的bug,不过大体沿用了webwork2的东西,拿官方说:?struts2 = webwork2 +?struts?。