我们沿用Spring+Hibernate+DWR的例子,做一个Ajax+Struts2.0+Spring+Hibernate整合,许多步骤大体相似, 我就直接搬过来了: 首先,建一个web project,然后添加对hibernate和spring的支持,我们使用的是hibernate3.2和spring2.0,然后导入xwork-2.0.3.jar struts2-core-2.0.8.jar struts2-spring-plugin-2.0.8.jar ognl-2.6.11.jar freemarker-2.3.8.jar commons-logging-api-1.1.jar和commons-pool-1.3.jar(不知道myeclipse怎么搞的,添加Spring功能支持的时候就有了commons-dbcp.jar,居然没有其依赖的commons-pool-x.jar,只好单独添加了,另外,需要将Spring2.0 AOP Liberaries里的asm2.2.3.jar删除,因为好像和Hiberate中的生成代理用的asm.jar冲突,我把Spring2.0 AOP Liberaries排到最后仍然有冲突,所以只好删掉了,不知道大家遇到过这种情况么)。 我们使用myeclise自带的Derby数据库,在里面建一个表BOOK: ID bigint primary key,autoincrement NAME varchar(20) ISBM varchar(20) AUTHOR varchar(15) 然后利用myeclipse的hibernate反向工程生成领域模型:Book.java, DAO:BookDAO.jar, Book 的映射文件Book.hbm.xml: 生成的代码及配置文件如下:
Book.java:
package
edu.jlu.fuliang.domain;
/** */
/** * Book generated by MyEclipse Persistence Tools */
public
class
Book
implements
java.io.Serializable
{ // Fields private long id; private String name; private String isbm; private String author; // Constructors /** */ /** default constructor */ public Book() { } /** */ /** minimal constructor */ public Book(String name, String isbm) { this .name = name; this .isbm = isbm; } /** */ /** full constructor */ public Book(String name, String isbm, String author) { this .name = name; this .isbm = isbm; this .author = author; } // Property accessors public long getId() { return this .id; } public void setId( long id) { this .id = id; } public String getName() { return this .name; } public void setName(String name) { this .name = name; } public String getIsbm() { return this .isbm; } public void setIsbm(String isbm) { this .isbm = isbm; } public String getAuthor() { return this .author; } public void setAuthor(String author) { this .author = author; } }
BookDAO.java:
package
edu.jlu.fuliang.dao;
import
java.util.List;
import
org.apache.commons.logging.Log;
import
org.apache.commons.logging.LogFactory;
import
org.hibernate.LockMode;
import
org.springframework.context.ApplicationContext;
import
org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import
edu.jlu.fuliang.domain.Book;
/** */
/** * Data access object (DAO) for domain model class Book. * * @see edu.jlu.fuliang.domain.Book * @author MyEclipse Persistence Tools */
public
class
BookDAO
extends
HibernateDaoSupport
...
{ private static final Log log = LogFactory.getLog(BookDAO. class ); // property constants public static final String NAME = " name " ; public static final String ISBM = " isbm " ; public static final String AUTHOR = " author " ; protected void initDao() ... { // do nothing } public void save(Book transientInstance) ... { log.debug( " saving Book instance " ); try ... { getHibernateTemplate().save(transientInstance); log.debug( " save successful " ); } catch (RuntimeException re) ... { log.error( " save failed " , re); throw re; } } public void delete(Book persistentInstance) ... { log.debug( " deleting Book instance " ); try ... { getHibernateTemplate().delete(persistentInstance); log.debug( " delete successful " ); } catch (RuntimeException re) ... { log.error( " delete failed " , re); throw re; } } public Book findById(Long id) ... { log.debug( " getting Book instance with id: " + id); try ... { Book instance = (Book) getHibernateTemplate().get( " edu.jlu.fuliang.domain.Book " , id); return instance; } catch (RuntimeException re) ... { log.error( " get failed " , re); throw re; } } public List findByExample(Book instance) ... { log.debug( " finding Book instance by example " ); try ... { List results = getHibernateTemplate().findByExample(instance); log.debug( " find by example successful, result size: " + results.size()); return results; } catch (RuntimeException re) ... { log.error( " find by example failed " , re); throw re; } } public List findByProperty(String propertyName, Object value) ... { log.debug( " finding Book instance with property: " + propertyName + " , value: " + value); try ... { String queryString = " from Book as model where model. " + propertyName + " = ? " ; return getHibernateTemplate().find(queryString, value); } catch (RuntimeException re) ... { log.error( " find by property name failed " , re); throw re; } } public List findByName(Object name) ... { return findByProperty(NAME, name); } public List findByIsbm(Object isbm) ... { return findByProperty(ISBM, isbm); } public List findByAuthor(Object author) ... { return findByProperty(AUTHOR, author); } public List findAll() ... { log.debug( " finding all Book instances " ); try ... { String queryString = " from Book " ; return getHibernateTemplate().find(queryString); } catch (RuntimeException re) ... { log.error( " find all failed " , re); throw re; } } public Book merge(Book detachedInstance) ... { log.debug( " merging Book instance " ); try ... { Book result = (Book) getHibernateTemplate().merge(detachedInstance); log.debug( " merge successful " ); return result; } catch (RuntimeException re) ... { log.error( " merge failed " , re); throw re; } } public void attachDirty(Book instance) ... { log.debug( " attaching dirty Book instance " ); try ... { getHibernateTemplate().saveOrUpdate(instance); log.debug( " attach successful " ); } catch (RuntimeException re) ... { log.error( " attach failed " , re); throw re; } } public void attachClean(Book instance) ... { log.debug( " attaching clean Book instance " ); try ... { getHibernateTemplate().lock(instance, LockMode.NONE); log.debug( " attach successful " ); } catch (RuntimeException re) ... { log.error( " attach failed " , re); throw re; } } public static BookDAO getFromApplicationContext(ApplicationContext ctx) ... { return (BookDAO) ctx.getBean( " BookDAO " ); } }
Book.hbm.xml:
<?
xml version="1.0" encoding="utf-8"
?>
<!
DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
>
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<
hibernate-mapping
>
<
class
name
="edu.jlu.fuliang.domain.Book"
table
="BOOK"
schema
="CLASSICCARS"
>
<
id
name
="id"
type
="long"
>
<
column
name
="ID"
/>
<
generator
class
="identity"
></
generator
>
</
id
>
<
property
name
="name"
type
="string"
>
<
column
name
="NAME"
length
="20"
not-null
="true"
/>
</
property
>
<
property
name
="isbm"
type
="string"
>
<
column
name
="ISBM"
length
="20"
not-null
="true"
unique
="true"
/>
</
property
>
<
property
name
="author"
type
="string"
>
<
column
name
="AUTHOR"
length
="15"
/>
</
property
>
</
class
>
</
hibernate-mapping
>
下面我们配置一下Spring,我们把applicationContext.xml分成了三个,分别是applicationContext-db.xml,applicationContext-dao.xml,applicationContext-service.我们看看如何配置:
applicationContext-db.xml:
<?
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.0.xsd"
>
<
bean
id
="dataSource"
class
="org.apache.commons.dbcp.BasicDataSource"
>
<
property
name
="driverClassName"
value
="org.apache.derby.jdbc.ClientDriver"
>
</
property
>
<
property
name
="url"
value
="jdbc:derby://localhost:1527/myeclipse;create=true"
>
</
property
>
<
property
name
="username"
value
="classiccars"
></
property
>
<
property
name
="password"
value
="myeclipse"
></
property
>
</
bean
>
<
bean
id
="sessionFactory"
class
="org.springframework.orm.hibernate3.LocalSessionFactoryBean"
>
<
property
name
="dataSource"
>
<
ref
bean
="dataSource"
/>
</
property
>
<
property
name
="hibernateProperties"
>
<
props
>
<
prop
key
="hibernate.dialect"
>
org.hibernate.dialect.DerbyDialect
</
prop
>
</
props
>
</
property
>
<
property
name
="mappingResources"
>
<
list
>
<
value
>
edu/jlu/fuliang/domain/Book.hbm.xml
</
value
></
list
>
</
property
>
</
bean
>
</
beans
>
applicationContext-dao.xml:
<?
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.0.xsd"
>
<
bean
id
="bookDAO"
class
="edu.jlu.fuliang.dao.BookDAO"
>
<
property
name
="sessionFactory"
>
<
ref
bean
="sessionFactory"
/>
</
property
>
</
bean
>
</
beans
>
接下来我们来写我们的Service层:
BookManageService.java:
package
edu.jlu.fuliang.service;
import
java.util.List;
import
edu.jlu.fuliang.domain.Book;
public
interface
BookManageService
...
{ public List < Book > getAllBooks(); public List < Book > getBookByName(String name); public void updateBook(Book book); public void addBook(Book book); public void deleteBook( long id); public Book getBookById(Long id); }
BookManageServiceImpl.java:
package
edu.jlu.fuliang.serviceImpl;
import
java.util.List;
import
edu.jlu.fuliang.dao.BookDAO;
import
edu.jlu.fuliang.domain.Book;
import
edu.jlu.fuliang.service.BookManageService;
public
class
BookManageServiceImpl
implements
BookManageService
...
{ private BookDAO bookDAO; @Override public void addBook(Book book) ... { bookDAO.save(book); } @Override public void deleteBook( long id) ... { Book book = bookDAO.findById(id); bookDAO.delete(book); } @Override public List < Book > getAllBooks() ... { return bookDAO.findAll(); } @Override public List < Book > getBookByName(String name) ... { return bookDAO.findByName(name); } @Override public void updateBook(Book book) ... { bookDAO.attachDirty(book); } public void setBookDAO(BookDAO bookDAO) ... { this .bookDAO = bookDAO; } @Override public Book getBookById(Long id) ... { return bookDAO.findById(id); } }
然后写一个struts的Action,他完全是一个POJO:
package
edu.jlu.fuliang.action;
import
java.util.List;
import
com.opensymphony.xwork2.Action;
import
com.opensymphony.xwork2.Preparable;
import
edu.jlu.fuliang.domain.Book;
import
edu.jlu.fuliang.service.BookManageService;
public
class
BookAction
implements
Preparable
...
{ private BookManageService bookManageService; private List < Book > books; private Book book; private Long id; public String execute() ... { this .books = bookManageService.getAllBooks(); return Action.SUCCESS; } public String save() ... { this .bookManageService.addBook(book); return execute(); } public void prepare() throws Exception ... { if (id != null ) book = bookManageService.getBookById(id); } public String remove() ... { bookManageService.deleteBook(id); return execute(); } public List < Book > getBooks() ... { return books; } public void setBooks(List < Book > books) ... { this .books = books; } public Book getBook() ... { return book; } public void setBook(Book book) ... { this .book = book; } public Long getId() ... { return id; } public void setId(Long id) ... { this .id = id; } public void setBookManageService(BookManageService bookManageService) ... { this .bookManageService = bookManageService; } }
然后我们来配置Service、事务以及struts的action:
applicationContext-service.xml:
<?
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.0.xsd"
>
<
bean
id
="bookManageServiceTarget"
class
="edu.jlu.fuliang.serviceImpl.BookManageServiceImpl"
>
<
property
name
="bookDAO"
>
<
ref
bean
="bookDAO"
/>
</
property
>
</
bean
>
<
bean
id
="transactionManager"
class
="org.springframework.orm.hibernate3.HibernateTransactionManager"
>
<
property
name
="sessionFactory"
>
<
ref
bean
="sessionFactory"
/>
</
property
>
</
bean
>
<
bean
id
="bookManageService"
class
="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
>
<
property
name
="transactionManager"
>
<
ref
bean
="transactionManager"
/>
</
property
>
<
property
name
="target"
>
<
ref
bean
="bookManageServiceTarget"
/>
</
property
>
<
property
name
="transactionAttributes"
>
<
props
>
<
prop
key
="get*"
>
PROPAGATION_REQUIRED,readOnly
</
prop
>
<
prop
key
="*"
>
PROPAGATION_REQUIRED
</
prop
>
</
props
>
</
property
>
</
bean
>
/* configure struts action as bean in spring*/
<
bean
id
="bookAction"
scope
="prototype"
class
="edu.jlu.fuliang.action.BookAction"
>
<
property
name
="bookManageService"
>
<
ref
bean
="bookManageService"
/>
</
property
>
</
bean
>
</
beans
>
配置struts.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
>
<
constant
name
="struts.objectFactory"
value
="spring"
/>
<
constant
name
="struts.devMode"
value
="true"
/>
<
package
name
="book"
extends
="struts-default"
>
<
action
name
="list"
method
="execute"
class
="bookAction"
>
<
result
>
list.jsp
</
result
>
<
result
name
="input"
>
list.jsp
</
result
>
</
action
>
<
action
name
="remove"
method
="remove"
class
="bookAction"
>
<
result
>
list.jsp
</
result
>
<
result
name
="input"
>
list.jsp
</
result
>
</
action
>
<
action
name
="save"
method
="save"
class
="bookAction"
>
<
result
>
list.jsp
</
result
>
<
result
name
="input"
>
list.jsp
</
result
>
</
action
>
</
package
>
</
struts
>
配置WEB-INF/web.xml:
<?
xml version="1.0" encoding="UTF-8"
?>
<
web-app
version
="2.4"
xmlns
="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation
="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
>
<
filter
>
<
filter-name
>
struts
</
filter-name
>
<
filter-class
>
org.apache.struts2.dispatcher.FilterDispatcher
</
filter-class
>
</
filter
>
<
filter-mapping
>
<
filter-name
>
struts
</
filter-name
>
<
url-pattern
>
/*
</
url-pattern
>
</
filter-mapping
>
<
welcome-file-list
>
<
welcome-file
>
index.jsp
</
welcome-file
>
</
welcome-file-list
>
<
context-param
>
<
param-name
>
contextConfigLocation
</
param-name
>
<
param-value
>
classpath:applicationContext-*.xml
</
param-value
>
</
context-param
>
<
listener
>
<
listener-class
>
org.springframework.web.context.ContextLoaderListener
</
listener-class
>
</
listener
>
</
web-app
>
配置一下log:
# This is the configuring for logging displayed in the Application Server # log4j.rootCategory
=
INFO
,
stdout
,
logfile log4j.rootCategory
=
DEBUG
,
A1 #console configure log4j.appender.A1
=
org.apache.log4j.ConsoleAppender log4j.appender.A1.layout
=
org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern
=
%-4r
[
%t
]
%-5p %c %x - %m%n #stdout configure 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 #logfile configure log4j.appender.logfile
=
org.apache.log4j.DailyRollingFileAppender log4j.appender.logfile.File
=
log4j.log log4j.appender.logfile.layout
=
org.apache.log4j.PatternLayout log4j.appender.logfile.layout.ConversionPattern
=
%d %p
[
%c
]
- <%m>%n # Control logging for other open source packages # Changing the log level to DEBUG when debug log4j.logger.org.springframework
=
ERROR log4j.logger.org.springframework.web.context.support.XmlWebApplicationContext
=
INFO log4j.logger.org.hibernate
=
ERROR log4j.logger.org.hibernate.cfg.HbmBinder
=
INFO log4j.logger.org.hibernate.SQL
=
ERROR log4j.logger.org.hibernate.cache
=
ERROR log4j.logger.org.hibernate.transaction
=
INFO log4j.logger.net.sf.ehcache
=
ERROR log4j.logger.org.apache.struts
=
ERROR log4j.logger.com.htxx.service.dao
=
INFO log4j.logger.org.apache.commons
=
INFO log4j.logger.org.directwebremoting
=
INFO
写两个页面index.jsp,list.jsp,使用了Ajax--dojo::
index.jsp:
<%
...
@ taglib prefix = " s " uri = " /struts-tags "
%>
<
html
>
<
head
>
<
s:head
theme
="ajax"
debug
="true"
/>
<
script
type
="text/javascript"
>
...
dojo.event.topic.subscribe(" /save " , function (data, type, request) ... { if (type == " load " ) ... { dojo.byId( " id " ).value = "" ; dojo.byId( " name " ).value = "" ; dojo.byId( " isbm " ).value = "" ; dojo.byId( " author " ).value = "" ; } }); dojo.event.topic.subscribe( " /edit " , function (data, type, request) ... { if (type == " before " ) ... { var id = data.split( " _ " )[ 1 ]; var tr = dojo.byId( " row_ " + id); var tds = tr.getElementsByTagName( " td " ); dojo.byId( " id " ).value = id; dojo.byId( " name " ).value = dojo.string.trim(dojo.dom.textContent(tds[ 0 ])); dojo.byId( " isbm " ).value = dojo.string.trim(dojo.dom.textContent(tds[ 1 ])); dojo.byId( " author " ).value = dojo.string.trim(dojo.dom.textContent(tds[ 1 ])); } });
</
script
>
</
head
>
<
body
>
<
s:url
action
="list"
id
="descrsUrl"
/>
<
div
style
="width: 300px;border-style: solid"
>
<
div
style
="text-align: right;"
>
<
s:a
theme
="ajax"
notifyTopics
="/refresh"
>
Refresh
</
s:a
>
</
div
>
<
s:div
id
="books"
theme
="ajax"
href
="%{descrsUrl}"
loadingText
="Loading..."
listenTopics
="/refresh"
/>
</
div
>
<
br
/>
<
div
style
="width: 300px;border-style: solid"
>
<
p
>
Book Data
</
p
>
<
s:form
action
="save"
validate
="true"
>
<
s:textfield
id
="id"
name
="person.id"
cssStyle
="display:none"
/>
<
s:textfield
id
="name"
label
="Name"
name
="book.name"
/>
<
s:textfield
id
="isbm"
label
="ISBN"
name
="book.isbm"
/>
<
s:textfield
id
="author"
label
="Author"
name
="book.author"
/>
<
s:submit
theme
="ajax"
targets
="books"
notifyTopics
="/save"
/>
</
s:form
>
</
div
>
</
body
>
</
html
>
list.jsp:
<%
...
@ taglib prefix = " s " uri = " /struts-tags "
%>
<
p
>
Books
</
p
>
<
s:if
test
="books.size > 0"
>
<
table
>
<
s:iterator
value
="books"
>
<
tr
id
="row_<s:property value="
id"
/>
">
<
td
>
<
s:property
value
="name"
/>
</
td
>
<
td
>
<
s:property
value
="isbm"
/>
</
td
>
<
td
>
<
s:property
value
="author"
/>
</
td
>
<
td
>
<
s:url
id
="removeUrl"
action
="remove"
>
<
s:param
name
="id"
value
="id"
/>
</
s:url
>
<
s:a
href
="%{removeUrl}"
theme
="ajax"
targets
="books"
>
Remove
</
s:a
>
<
s:a
id
="a_%{id}"
theme
="ajax"
notifyTopics
="/edit"
>
Edit
</
s:a
>
</
td
>
</
tr
>
</
s:iterator
>
</
table
>
</
s:if
>
在浏览器中输入地址,我们就可以在一个页面进行CRUD操作了.