一、架构
Struts + Spring + Hibernate
二、Hibernate持久层
1 .编写PO类
====================================================================================
package org.prolove.model;
import java.io.Serializable;
/** */ /**
* Base class for Model objects. Child objects should implement toString(),
* equals() and hashCode();
*
* <p>
* <a href="BaseObject.java.html"><i>View Source</i></a>
* </p>
*
* @author <a href="mailto:prolove@live.cn">PROLOVE</a>
*/
public abstract class BaseObject implements Serializable ... {
public abstract String toString();
public abstract boolean equals(Object o);
public abstract int hashCode();
}
====================================================================================
package org.prolove.model;
import java.util.Date;
import java.util.Set;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
/** */ /**
* @hibernate.class table="news"
* @struts.form include-all="false" extends="BaseForm"
*/
public class News extends BaseObject ... {
private Long id;// pk,required
private String title;// required
private String content;// required
private User poster;// fk,required
private Date postDate;// required
private Date lastModifyDate;// required
private Category category;// required
private Set newsReviews;
public News() ...{
}
/** *//**
* @return Returns the newsReview.
*/
public Set getNewsReviews() ...{
return newsReviews;
}
/** *//**
* @param newsReview
* The newsReview to set.
*/
public void setNewsReviews(Set newsReviews) ...{
this.newsReviews = newsReviews;
}
/** *//**
* @hibernate.many-to-one column="id" not-null="true"
*/
public Category getCategory() ...{
return category;
}
public void setCategory(Category category) ...{
this.category = category;
}
/** *//**
* @hibernate.property column="last_modify_date" not-null="true"
*/
public Date getLastModifyDate() ...{
return lastModifyDate;
}
public void setLastModifyDate(Date lastModifyDate) ...{
this.lastModifyDate = lastModifyDate;
}
/** *//**
* @hibernate.property column="post_date" not-null="true"
*/
public Date getPostDate() ...{
return postDate;
}
public void setPostDate(Date postDate) ...{
this.postDate = postDate;
}
/** *//**
* @hibernate.many-to-one column="username" not-null="true"
*/
public User getPoster() ...{
return poster;
}
public void setPoster(User poster) ...{
this.poster = poster;
}
/** *//**
* @hibernate.property column="content" length="3000" not-null="true"
*/
public String getContent() ...{
return content;
}
public void setContent(String content) ...{
this.content = content;
}
/** *//**
* @return Returns the id.
* @hibernate.id column="id" generator-class="increment"
* unsaved-value="null"
*/
public Long getId() ...{
return id;
}
public void setId(Long id) ...{
this.id = id;
}
/** *//**
* @hibernate.property column="title" length="50" not-null="true"
*/
public String getTitle() ...{
return title;
}
public void setTitle(String title) ...{
this.title = title;
}
/** *//**
* @see java.lang.Object#equals(Object)
*/
public boolean equals(Object object) ...{
if (!(object instanceof News)) ...{
return false;
}
News rhs = (News) object;
return this.poster.equals(rhs.getPoster())
&& this.postDate.equals(rhs.getPostDate());
/**//*
* return new EqualsBuilder().append(this.newsReviews, rhs.newsReviews)
* .append(this.title, rhs.title).append(this.category,
* rhs.category).append(this.content, rhs.content).append(
* this.postDate, rhs.postDate).append( this.lastModifyDate,
* rhs.lastModifyDate).append( this.id, rhs.id).append(this.poster,
* rhs.poster) .isEquals();
*/
}
/** *//**
* @see java.lang.Object#hashCode()
*/
public int hashCode() ...{
return this.poster.hashCode() + this.postDate.hashCode();
/**//*
* return new HashCodeBuilder(1595611275, -1477459617).append(
* this.newsReviews).append(this.title).append(this.category)
* .append(this.content).append(this.postDate).append(
* this.lastModifyDate).append(this.id)
* .append(this.poster).toHashCode();
*/
}
/** *//**
* @see java.lang.Object#toString()
*/
public String toString() ...{
return new ToStringBuilder(this).append("id", this.id).append("title",
this.title).append("postDate", this.postDate).append("content",
this.content).append("lastModifyDate", this.lastModifyDate)
.append("poster", this.poster)
.append("category", this.category).append("newsReviews",
this.newsReviews).toString();
}
}
2 .编写PO的映射配置文件
====================================================================================
<? 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 " >
< hibernate - mapping >
< class name = " org.prolove.model.News " table = " news " >
< id name = " id " column = " id " unsaved - value = " null " >
<!-- The generator - class attribute of @hibernate.id is deprecated, use the @hibernate.generator tag instead -->
< generator class = " increment " >
</ generator >
</ id >
< many - to - one name = " category " class = " org.prolove.model.Category " column = " category_id " not - null = " true " >
</ many - to - one >
< property name = " lastModifyDate " column = " last_modify_date " not - null = " true " >
</ property >
< property name = " postDate " column = " post_date " not - null = " true " >
</ property >
< many - to - one name = " poster " column = " username " not - null = " true " >
</ many - to - one >
< property name = " content " column = " content " length = " 3000 " not - null = " true " >
</ property >
< property name = " title " column = " title " length = " 50 " not - null = " true " >
</ property >
<!-- bi - directional one - to - many association to NewsReview -->
< set name = " newsReviews " lazy = " false " inverse = " true " cascade = " all-delete-orphan " >
< meta attribute = " field-description " >
@hibernate.list lazy = " true " inverse = " false " cascade = " none "
@hibernate.collection - key column = " id "
@hibernate.collection - one - to - many class = " org.prolove.model.NewsReview "
</ meta >
< key >
< column name = " news_id " />
</ key >
< one - to - many class = " org.prolove.model.NewsReview " />
</ set >
</ class >
</ hibernate - mapping >
3 .连接数据库
applicationContext - hibernate.xml
<? xml version = " 1.0 " encoding = " UTF-8 " ?>
<! DOCTYPE beans PUBLIC " -//SPRING//DTD BEAN//EN "
" http://www.springframework.org/dtd/spring-beans.dtd " >
< beans >
< bean id = " dataSource " class = " org.apache.commons.dbcp.BasicDataSource " destroy - method = " close " >
< property name = " driverClassName " value = " oracle.jdbc.driver.OracleDriver " />
<!-- property name = " driverClassName " value = " net.sourceforge.jtds.jdbc.Driver " /-->
< property name = " url " value = " jdbc:oracle:thin:@10.200.3.81:1521:oranet " />
< property name = " username " value = " hm " />
< property name = " password " value = " hm123 " />
< property name = " maxActive " value = " 100 " />
< property name = " maxIdle " value = " 30 " />
< property name = " maxWait " value = " 1000 " />
< property name = " defaultAutoCommit " value = " true " />
< property name = " removeAbandoned " value = " true " />
< property name = " removeAbandonedTimeout " value = " 60 " />
< property name = " logAbandoned " value = " true " />
</ bean >
<!-- Hibernate SessionFactory -->
< bean id = " sessionFactory " class = " org.springframework.orm.hibernate3.LocalSessionFactoryBean " >
< property name = " dataSource " ref = " dataSource " />
< property name = " mappingResources " >
< list >
< value > org / prolove / model / User.hbm.xml </ value >
< value > org / prolove / model / News.hbm.xml </ value >
< value > org / prolove / model / NewsReview.hbm.xml </ value >
< value > org / prolove / model / Category.hbm.xml </ value >
</ list >
</ property >
<!-- The property below is commented out b / c it doesn ' t work when run via
Ant in Eclipse. It works fine for individual JUnit tests and in IDEA ??
< property name = " mappingJarLocations " >
< list >< value > file:dist / appfuse - dao.jar </ value ></ list >
</ property >
-->
< property name = " hibernateProperties " >
< props >
< prop key = " hibernate.dialect " > @HIBERNATE - DIALECT@ </ prop >
<!-- Create / update the database tables automatically when the JVM starts up
< prop key = " hibernate.hbm2ddl.auto " > update </ prop > -->
<!-- Turn batching off for better error messages under PostgreSQL
< prop key = " hibernate.jdbc.batch_size " > 0 </ prop > -->
</ props >
</ property >
</ bean >
<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
< bean id = " transactionManager " class = " org.springframework.orm.hibernate3.HibernateTransactionManager " >
< property name = " sessionFactory " ref = " sessionFactory " />
</ bean >
<!-- Generic DAO - can be used when doing standard CRUD -->
< bean id = " dao " class = " org.prolove.dao.hibernate.BaseDAOHibernate " >
< property name = " sessionFactory " ref = " sessionFactory " />
</ bean >
<!-- UserDAO: Hibernate implementation -->
< bean id = " userDAO " class = " org.prolove.dao.hibernate.UserDAOHibernate " >
< property name = " sessionFactory " ref = " sessionFactory " />
</ bean >
<!-- Add new DAOs here -->
< bean id = " newsDAO " class = " org.prolove.dao.hibernate.NewsDAOHibernate " >
< property name = " sessionFactory " ref = " sessionFactory " />
</ bean >
< bean id = " newsReviewDAO " class = " org.prolove.dao.hibernate.NewsReviewDAOHibernate " >
< property name = " sessionFactory " ref = " sessionFactory " />
</ bean >
< bean id = " categoryDAO " class = " org.prolove.dao.hibernate.CategoryDAOHibernate " >
< property name = " sessionFactory " ref = " sessionFactory " />
</ bean >
<!-- PersonDAO: Hibernate implementation -->
< bean id = " personDAO " class = " org.appfuse.dao.hibernate.PersonDAOHibernate " >
< property name = " sessionFactory " ref = " sessionFactory " />
</ bean >
</ beans >
=====================================================================
applicationContext.xml
<? xml version = " 1.0 " encoding = " UTF-8 " ?>
<! DOCTYPE beans PUBLIC " -//SPRING//DTD BEAN//EN "
" http://www.springframework.org/dtd/spring-beans.dtd " >
< beans >
<!-- hibernate datasource -->
< 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/newsboard " />
< property name = " username " value = " root " />
< property name = " password " value = " root " />
< property name = " maxActive " value = " 20 " />
< property name = " maxIdle " value = " 10 " />
< property name = " initialSize " value = " 1 " />
< property name = " maxWait " value = " 1000 " />
< property name = " defaultAutoCommit " value = " true " />
< property name = " removeAbandoned " value = " true " />
< property name = " removeAbandonedTimeout " value = " 60 " />
< property name = " logAbandoned " value = " true " />
</ bean >
<!-- Hibernate SessionFactory -->
< bean id = " sessionFactory " class = " org.springframework.orm.hibernate3.LocalSessionFactoryBean " >
< property name = " dataSource " ref = " dataSource " />
< property name = " mappingResources " >
< list >
< value > org / prolove / model / User.hbm.xml </ value >
< value > org / prolove / model / News.hbm.xml </ value >
< value > org / prolove / model / NewsReview.hbm.xml </ value >
< value > org / prolove / model / Category.hbm.xml </ value >
</ list >
</ property >
< property name = " hibernateProperties " >
< props >
< prop key = " hibernate.dialect " > org.hibernate.dialect.MySQLDialect </ prop >
< prop key = " hibernate.hbm2ddl.auto " > update </ prop >
< prop key = " hibernate.jdbc.batch_size " > 20 </ prop >
</ props >
</ property >
</ bean >
<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
< bean id = " transactionManager " class = " org.springframework.orm.hibernate3.HibernateTransactionManager " >
< property name = " sessionFactory " ref = " sessionFactory " />
</ bean >
<!-- service manager Template -->
< bean id = " txProxyTemplate " abstract = " true "
class = " org.springframework.transaction.interceptor.TransactionProxyFactoryBean " >
< property name = " transactionManager " ref = " transactionManager " />
< property name = " transactionAttributes " >
< props >
< prop key = " save* " > PROPAGATION_REQUIRED </ prop >
< prop key = " remove* " > PROPAGATION_REQUIRED </ prop >
< prop key = " * " > PROPAGATION_REQUIRED,readOnly </ prop >
</ props >
</ property >
</ bean >
<!-- service manager -->
< bean id = " facadeManager " parent = " txProxyTemplate " >
< property name = " target " >
< bean class = " org.prolove.service.impl.FacadeManagerImpl " >
< property name = " newsDAO " ref = " newsDAO " />
< property name = " newsReviewDAO " ref = " newsReviewDAO " />
< property name = " categoryDAO " ref = " categoryDAO " />
< property name = " userDAO " ref = " userDAO " />
</ bean >
</ property >
</ bean >
</ beans >
三、DAO组件层
1 .DAO组件的结构
为了让逻辑组件与具体的DAO组件分离,还必须有一个DAO工厂。
2 .编写DAO接口
package org.prolove.dao;
import java.io.Serializable;
import java.util.List;
/** */ /**
* Data Access Object (DAO) interface. This is an interface
* used to tag our DAO classes and to provide common methods to all DAOs.
*
* <p><a href="DAO.java.html"><i>View Source</i></a></p>
*
* @author <a href="mailto:matt@raibledesigns.com">Matt Raible</a>
*/
public interface DAO ... {
/** *//**
* Generic method used to get all objects of a particular type. This
* is the same as lookup up all rows in a table.
* @param clazz the type of objects (a.k.a. while table) to get data from
* @return List of populated objects
*/
public List getObjects(Class clazz);
/** *//**
* Generic method to get an object based on class and identifier. An
* ObjectRetrievalFailureException Runtime Exception is thrown if
* nothing is found.
*
* @param clazz model class to lookup
* @param id the identifier (primary key) of the class
* @return a populated object
* @see org.springframework.orm.ObjectRetrievalFailureException
*/
public Object getObject(Class clazz, Serializable id);
/** *//**
* Generic method to save an object - handles both update and insert.
* @param o the object to save
*/
public void saveObject(Object o);
/** *//**
* Generic method to delete an object based on class and id
* @param clazz model class to lookup
* @param id the identifier (primary key) of the class
*/
public void removeObject(Class clazz, Serializable id);
}
=========================================================================
package org.prolove.dao;
import java.util.List;
import org.prolove.model.User;
/** */ /**
* User Data Access Object (DAO) interface.
*
* <p>
* <a href="UserDAO.java.html"><i>View Source</i></a>
* </p>
*
* @author <a href="mailto:matt@raibledesigns.com">Matt Raible</a>
*/
public interface UserDAO extends DAO ... {
/** *//**
* Gets users information based on login name.
* @param username the current username
* @return user populated user object
*/
public User getUser(String username);
/** *//**
* Gets a list of users based on parameters passed in.
*
* @return List populated list of users
*/
public List getUsers(User user);
/** *//**
* Saves a user's information
* @param user the object to be saved
*/
public void saveUser(User user);
/** *//**
* Removes a user from the database by id
* @param username the user's username
*/
public void removeUser(String username);
}
……
3 .编写DAO的具体实现
package org.prolove.dao.hibernate;
import java.io.Serializable;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.prolove.dao.DAO;
/** */ /**
* This class serves as the Base class for all other DAOs - namely to hold
* common methods that they might all use. Can be used for standard CRUD
* operations.</p>
*
* <p><a href="BaseDAOHibernate.java.html"><i>View Source</i></a></p>
*
* @author <a href="mailto:matt@raibledesigns.com">Matt Raible</a>
*/
public class BaseDAOHibernate extends HibernateDaoSupport implements DAO ... {
protected final Log log = LogFactory.getLog(getClass());
/** *//**
* @see org.leecode.dao.DAO#saveObject(java.lang.Object)
*/
public void saveObject(Object o) ...{
getHibernateTemplate().saveOrUpdate(o);
}
/** *//**
* @see org.leecode.dao.DAO#getObject(java.lang.Class, java.io.Serializable)
*/
public Object getObject(Class clazz, Serializable id) ...{
Object o = getHibernateTemplate().get(clazz, id);
if (o == null) ...{
throw new ObjectRetrievalFailureException(clazz, id);
}
return o;
}
/** *//**
* @see org.leecode.dao.DAO#getObjects(java.lang.Class)
*/
public List getObjects(Class clazz) ...{
return getHibernateTemplate().loadAll(clazz);
}
/** *//**
* @see org.leecode.dao.DAO#removeObject(java.lang.Class, java.io.Serializable)
*/
public void removeObject(Class clazz, Serializable id) ...{
getHibernateTemplate().delete(getObject(clazz, id));
}
}
======================================================================================
package org.prolove.dao.hibernate;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.prolove.dao.NewsDAO;
import org.prolove.model.News;
public class NewsDAOHibernate extends BaseDAOHibernate implements NewsDAO ... {
public News getNews(Long id) ...{
News news = (News) getHibernateTemplate().get(News.class, id);
if (news == null) ...{
throw new ObjectRetrievalFailureException(News.class, id);
}
return news;
}
public void saveNews(News news) ...{
getHibernateTemplate().saveOrUpdate(news);
}
public void removeNews(Long id) ...{
// object must be loaded before it can be deleted
getHibernateTemplate().delete(getNews(id));
}
}
……
4 .用Spring容器代替DAO工厂
见上文applicationContext - hibernate.xml
以及
daoContext.xml
<? xml version = " 1.0 " encoding = " GBK " ?>
<! DOCTYPE beans PUBLIC " -//SPRING//DTD BEAN//EN "
" http://www.springframework.org/dtd/spring-beans.dtd " >
< beans >
<!-- DAO模板,用于被其他的DAO组件继承 -->
< bean id = " daoTemplate " abstract = " true " lazy - init = " true " >
< property name = " sessionFactory " ref = " sessionFactory " />
</ bean >
<!-- Generic DAO - can be used when doing standard CRUD -->
< bean id = " dao " class = " org.prolove.dao.hibernate.BaseDAOHibernate "
parent = " daoTemplate " />
<!-- UserDAO: Hibernate implementation -->
< bean id = " userDAO " class = " org.prolove.dao.hibernate.UserDAOHibernate "
parent = " daoTemplate " />
<!-- NewsDAO Hibernate implementation -->
< bean id = " newsDAO " class = " org.prolove.dao.hibernate.NewsDAOHibernate "
parent = " daoTemplate " />
<!-- NewsReviewDAO Hibernate implementation -->
< bean id = " newsReviewDAO " class = " org.prolove.dao.hibernate.NewsReviewDAOHibernate "
parent = " daoTemplate " />
<!-- CategoryDAO Hibernate implementation -->
< bean id = " categoryDAO " class = " org.prolove.dao.hibernate.CategoryDAOHibernate "
parent = " daoTemplate " />
</ beans >
四、业务逻辑层
1 .业务逻辑组件的结构
每个模块设计一个业务逻辑组件。
2 .业务逻辑组件的接口
package org.prolove.service;
import java.util.List;
import org.prolove.dao.CategoryDAO;
import org.prolove.dao.NewsDAO;
import org.prolove.dao.NewsReviewDAO;
import org.prolove.dao.UserDAO;
import org.prolove.model.Category;
import org.prolove.model.News;
import org.prolove.model.NewsReview;
import org.prolove.model.User;
// 该接口是对DAO的正面包装
public interface FacadeManager ... {
// category的业务方法
public void setCategoryDAO(CategoryDAO dao);
public Category getCategory(String id);
public void saveCategory(Category category);
public void removeCategory(String id);
public List getCategories();
// news的业务方法
public void setNewsDAO(NewsDAO dao);
public News getNews(String id);
public void saveNews(News news);
public void removeNews(String id);
// newsReview的业务方法
public void setNewsReviewDAO(NewsReviewDAO dao);
public NewsReview getNewsReview(String id);
public void saveNewsReview(NewsReview newsReview);
public void removeNewsReview(String id);
// user的业务方法
public void setUserDAO(UserDAO dao);
public User getUser(String username);
public List getUsers(User user);
public void saveUser(User user) throws Exception;
public void removeUser(String username);
public boolean validateUser(User user);
}
3 .业务逻辑组件的实现类
package org.prolove.service;
import java.io.Serializable;
import java.util.List;
import org.prolove.dao.DAO;
public interface Manager ... {
/** *//**
* Expose the setDAO method for testing purposes
* @param dao
*/
public void setDAO(DAO dao);
/** *//**
* Generic method used to get a all objects of a particular type.
* @param clazz the type of objects
* @return List of populated objects
*/
public List getObjects(Class clazz);
/** *//**
* Generic method to get an object based on class and identifier.
*
* @param clazz model class to lookup
* @param id the identifier (primary key) of the class
* @return a populated object
* @see org.springframework.orm.ObjectRetrievalFailureException
*/
public Object getObject(Class clazz, Serializable id);
/** *//**
* Generic method to save an object.
* @param o the object to save
*/
public void saveObject(Object o);
/** *//**
* Generic method to delete an object based on class and id
* @param clazz model class to lookup
* @param id the identifier of the class
*/
public void removeObject(Class clazz, Serializable id);
}
package org.prolove.service.impl;
import java.io.Serializable;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.prolove.dao.DAO;
import org.prolove.service.Manager;
/** */ /**
* Base class for Business Services - use this class for utility methods and
* generic CRUD methods.
*
* <p><a href="BaseManager.java.html"><i>View Source</i></a></p>
*
* @author <a href="mailto:prolove@live.cn">Matt Raible</a>
*/
public class BaseManager implements Manager ... {
protected DAO dao = null;
protected final Log log = LogFactory.getLog(getClass());
/** *//**
* @see org.leecode.service.Manager#setDAO(org.leecode.dao.DAO)
*/
public void setDAO(DAO dao) ...{
this.dao = dao;
}
/** *//**
* @see org.leecode.service.Manager#getObject(java.lang.Class, java.io.Serializable)
*/
public Object getObject(Class clazz, Serializable id) ...{
return dao.getObject(clazz, id);
}
/** *//**
* @see org.leecode.service.Manager#getObjects(java.lang.Class)
*/
public List getObjects(Class clazz) ...{
return dao.getObjects(clazz);
}
/** *//**
* @see org.leecode.service.Manager#removeObject(java.lang.Class, java.io.Serializable)
*/
public void removeObject(Class clazz, Serializable id) ...{
dao.removeObject(clazz, id);
}
/** *//**
* @see org.leecode.service.Manager#saveObject(java.lang.Object)
*/
public void saveObject(Object o) ...{
dao.saveObject(o);
}
}
package org.prolove.service.impl;
import java.util.List;
import org.springframework.dao.DataIntegrityViolationException;
import org.prolove.dao.CategoryDAO;
import org.prolove.dao.NewsDAO;
import org.prolove.dao.NewsReviewDAO;
import org.prolove.dao.UserDAO;
import org.prolove.model.Category;
import org.prolove.model.News;
import org.prolove.model.NewsReview;
import org.prolove.model.User;
import org.prolove.service.FacadeManager;
public class FacadeManagerImpl extends BaseManager implements
FacadeManager ... {
private CategoryDAO categoryDAO;
private NewsDAO newsDAO;
private NewsReviewDAO newsReviewDAO;
private UserDAO userDAO;
public void setCategoryDAO(CategoryDAO categoryDAO) ...{
this.categoryDAO = categoryDAO;
}
public Category getCategory(String id) ...{
return categoryDAO.getCategory(Long.valueOf(id));
}
public void saveCategory(Category category) ...{
categoryDAO.saveCategory(category);
}
public void removeCategory(String id) ...{
categoryDAO.removeCategory(Long.valueOf(id));
}
public List getCategories() ...{
return categoryDAO.getCategories();
}
public void setNewsDAO(NewsDAO newsDAO) ...{
this.newsDAO = newsDAO;
}
public News getNews(String id) ...{
return newsDAO.getNews(Long.valueOf(id));
}
public void saveNews(News news) ...{
newsDAO.saveNews(news);
}
public void removeNews(String id) ...{
newsDAO.removeNews(Long.valueOf(id));
}
public void setNewsReviewDAO(NewsReviewDAO newsReviewDAO) ...{
this.newsReviewDAO = newsReviewDAO;
}
public NewsReview getNewsReview(String id) ...{
return newsReviewDAO.getNewsReview(Long.valueOf(id));
}
public void saveNewsReview(NewsReview newsReview) ...{
newsReviewDAO.saveNewsReview(newsReview);
}
public void removeNewsReview(String id) ...{
newsReviewDAO.removeNewsReview(Long.valueOf(id));
}
public void setUserDAO(UserDAO userDAO) ...{
this.userDAO = userDAO;
}
public User getUser(String username) ...{
return userDAO.getUser(username);
}
public List getUsers(User user) ...{
return userDAO.getUsers(user);
}
public void saveUser(User user) throws Exception ...{
try ...{
userDAO.saveUser(user);
} catch (DataIntegrityViolationException e) ...{
throw new Exception("User '" + user.getUsername()
+ "' already exists!");
}
}
public void removeUser(String username) ...{
userDAO.removeUser(username);
}
public boolean validateUser(User aUser) ...{
User user = getUser(aUser.getUsername());
if (user != null && user.getPassword().equals(aUser.getPassword()))
return true;
else
return false;
}
}
4 .业务逻辑组件的配置
在applicationContext.xml配置FacadeManager组件
五、Web层设计
1 .Action的实现
package org.prolove.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForward;
import org.apache.struts.validator.DynaValidatorForm;
import org.prolove.action.base.BaseAction;
import org.prolove.webapp.util.AppConstants;
import org.prolove.model. * ;
import java.util. * ;
/** */ /**
* @author PROLOVE prolve@live.cn
* @version 1.0
* <br>Copyright (C), 2006-2008, PROLOVE
* <br>This program is protected by copyright laws.
* <br>Program Name:
* <br>Date:
*/
public class AddReviewAction extends BaseAction
... {
//必须重写该核心方法,该方法actionForm将表单的请求参数封装成值对象
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)throws Exception
...{
DynaValidatorForm addForm = (DynaValidatorForm)form;
String content = (String)addForm.get("content");
String newsId = (String)addForm.get("newsId");
try
...{
News news = mgr.getNews(newsId);
String username = (String)request.getSession(true).getAttribute(AppConstants.LOGIN_USER);
User poster = mgr.getUser(username);
NewsReview newsReview = new NewsReview();
newsReview.setNews(news);
newsReview.setPoster(poster);
newsReview.setContent(content);
newsReview.setPostDate(new Date());
newsReview.setLastModifyDate(new Date());
mgr.saveNewsReview(newsReview);
}
catch (Exception e)
...{
request.setAttribute("newsId" , newsId);
return mapping.findForward("failure");
}
request.setAttribute("newsId" , newsId);
return mapping.findForward("success");
}
}
package org.prolove.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForward;
import org.apache.struts.validator.DynaValidatorForm;
import org.prolove.action.base.BaseAction;
import org.prolove.model.News;
import java.util.Set;
/** */ /**
* @author PROLOVE prolve@live.cn
* @version 1.0
* <br>Copyright (C), 2006-2008, PROLOVE
* <br>This program is protected by copyright laws.
* <br>Program Name:
* <br>Date:
*/
public class LoadReviewsByNews extends BaseAction
... {
//必须重写该核心方法,该方法actionForm将表单的请求参数封装成值对象
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)throws Exception
...{
String newsId = null;
if(request.getAttribute("newsId") == null)
...{
newsId = request.getParameter("newsId");
}
else
...{
newsId = (String)request.getAttribute("newsId");
}
News news = mgr.getNews(newsId);
request.setAttribute("news" , news);
request.setAttribute("reviews",news.getNewsReviews());
return mapping.findForward("success");
}
}
……
2 .Spring管理容器Action
采用DelegatingRequestProcessor的整合策略。
struts - config.xml
<? xml version = " 1.0 " encoding = " GBK " ?>
<! DOCTYPE struts - config PUBLIC
" -//Apache Software Foundation//DTD Struts Configuration 1.2//EN "
" http://struts.apache.org/dtds/struts-config_1_2.dtd " >
< struts - config >
< form - beans >
<!-- 配置登陆所使用的Form -->
< form - bean name = " loginForm " type = " org.apache.struts.validator.DynaValidatorForm " >
< form - property name = " user " type = " java.lang.String " />
< form - property name = " pass " type = " java.lang.String " />
</ form - bean >
<!-- 添加新闻所用的Form -->
< form - bean name = " addNewsForm " type = " org.apache.struts.validator.DynaValidatorForm " >
< form - property name = " title " type = " java.lang.String " />
< form - property name = " content " type = " java.lang.String " />
< form - property name = " categoryId " type = " java.lang.String " />
</ form - bean >
<!-- 添加新闻评论所用的Form -->
< form - bean name = " addNewsReviewForm " type = " org.apache.struts.validator.DynaValidatorForm " >
< form - property name = " content " type = " java.lang.String " />
< form - property name = " newsId " type = " java.lang.String " />
</ form - bean >
</ form - beans >
< global - forwards >
</ global - forwards >
<!-- ========================================= Action Mapping Definitions -->
< action - mappings >
<!-- 处理登陆 -->
< action path = " /processLogin "
name = " loginForm "
scope = " request "
validate = " true "
input = " input " >
< forward name = " input " path = " /index.jsp " />
< forward name = " success " path = " /listCate.do " />
</ action >
<!-- 登出系统 -->
< action path = " /logout " scope = " request " >
< forward name = " success " path = " /index.jsp " />
</ action >
<!-- 进入主页面 -->
< action path = " /listCate " scope = " request " >
< forward name = " success " path = " /main.jsp " />
</ action >
<!-- 根据种类加载所有新闻 -->
< action path = " /loadNewsByCategory " scope = " request " >
< forward name = " failure " path = " /listCate.do " />
< forward name = " success " path = " /category_view.jsp " />
</ action >
<!-- 添加新闻 -->
< action path = " /addNews "
name = " addNewsForm "
scope = " request "
validate = " true "
input = " input " >
< forward name = " failure " path = " /loadNewsByCategory.do " />
< forward name = " success " path = " /loadNewsByCategory.do " />
</ action >
<!-- 根据新闻id加载所有评论 -->
< action path = " /loadNewsReviewByNews " scope = " request " >
< forward name = " success " path = " /news_view.jsp " />
</ action >
<!-- 添加新闻评论 -->
< action path = " /addNewsReview "
name = " addNewsReviewForm "
scope = " request "
validate = " true "
input = " input " >
< forward name = " failure " path = " /loadNewsReviewByNews.do " />
< forward name = " success " path = " /loadNewsReviewByNews.do " />
</ action >
</ action - mappings >
< controller inputForward = " true " processorClass = " org.springframework.web.struts.DelegatingRequestProcessor " />
< message - resources parameter = " resource " />
< plug - in className = " org.apache.struts.validator.ValidatorPlugIn " >
< set - property property = " pathnames " value = " /WEB-INF/validator-rules.xml,
/ WEB - INF / validation.xml " />
< set - property property = " stopOnFirstError " value = " true " />
</ plug - in >
< plug - in className = " org.springframework.web.struts.ContextLoaderPlugIn " >
< set - property property = " contextConfigLocation " value = " /WEB-INF/daoContext.xml,
/ WEB - INF / applicationContext.xml,
/ WEB - INF / action - Servlet.xml " />
</ plug - in >
</ struts - config >
action - Servlet.xml
<? xml version = " 1.0 " encoding = " GBK " ?>
<! DOCTYPE beans PUBLIC " -//SPRING//DTD BEAN//EN "
" http://www.springframework.org/dtd/spring-beans.dtd " >
< beans >
< bean id = " actionTemplate " abstract = " true " singleton = " false " >
< property name = " mgr " ref = " facadeManager " />
</ bean >
<!-- 处理登陆 -->
< bean name = " /processLogin " class = " org.prolove.action.LoginAction " parent = " actionTemplate " />
<!-- 登出系统 -->
< bean name = " /logout " class = " org.prolove.action.Logout " />
<!-- 列出所有的新闻分类 -->
< bean name = " /listCate " class = " org.prolove.action.ListCate " parent = " actionTemplate " />
<!-- 根据种类列出所有新闻 -->
< bean name = " /loadNewsByCategory " class = " org.prolove.action.LoadNewsByCategory " parent = " actionTemplate " />
<!-- 添加新闻 -->
< bean name = " /addNews " class = " org.prolove.action.AddNewsAction " parent = " actionTemplate " />
<!-- 根据新闻查看所有的评论 -->
< bean name = " /loadNewsReviewByNews " class = " org.prolove.action.LoadReviewsByNews " parent = " actionTemplate " />
<!-- 添加新闻评论 -->
< bean name = " /addNewsReview " class = " org.prolove.action.AddReviewAction " parent = " actionTemplate " />
</ beans >
3 .数据校验的选择
validation.xml
<? xml version = " 1.0 " encoding = " iso-8859-1 " ?>
<! DOCTYPE form - validation PUBLIC
" -//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.3//EN "
" http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd " >
< form - validation >
< formset >
< form name = " loginForm " >
< field property = " user " depends = " required,minlength " >
< arg key = " loginForm.user " position = " 0 " />
< arg name = " minlength " key = " ${var:minlength} " resource = " false " position = " 1 " />
< var >
< var - name > minlength </ var - name >
< var - value > 4 </ var - value >
</ var >
</ field >
< field property = " pass " depends = " required,minlength " >
< arg key = " loginForm.pass " position = " 0 " />
< arg name = " minlength " key = " ${var:minlength} " resource = " false " position = " 1 " />
< var >
< var - name > minlength </ var - name >
< var - value > 4 </ var - value >
</ var >
</ field >
</ form >
< form name = " addNewsForm " >
< field property = " title " depends = " required " >
< arg key = " addNewsForm.title " position = " 0 " />
</ field >
< field property = " content " depends = " required " >
< arg key = " addNewsForm.content " position = " 0 " />
</ field >
< field property = " categoryId " depends = " required,integer " >
< arg key = " addNewsForm.categoryId " position = " 0 " />
</ field >
</ form >
< form name = " addNewsReviewForm " >
< field property = " content " depends = " required " >
< arg key = " addNewsReviewForm.content " position = " 0 " />
</ field >
< field property = " newsId " depends = " required,integer " >
< arg key = " addNewsReviewForm.categoryId " position = " 0 " />
</ field >
</ form >
</ formset >
</ form - validation >
4 .访问权限的控制
package org.prolove.webapp.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.prolove.webapp.util.AppConstants;
/** */ /**
* 设置字符集、过滤未登录的非法请求
*/
public class UserLoginFilter implements Filter ... {
protected String encoding = null;
protected FilterConfig filterConfig = null;
protected boolean ignore = false;
protected String forwardPath = null;
public void destroy() ...{
this.encoding = null;
this.filterConfig = null;
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException ...{
// 设置编码方式,web.xml里面有filter参数的初始化设置
if (ignore || (request.getCharacterEncoding() == null)) ...{
String encoding = selectEncoding(request);
if (encoding != null)
request.setCharacterEncoding(encoding);
}
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
String requesturi = httpServletRequest.getRequestURI();
// 通过检查session中的变量,过虑请求
HttpSession session = httpServletRequest.getSession();
Object currentUser = session.getAttribute(AppConstants.LOGIN_USER);
// 当前会话用户为空而且不是请求登录,退出登录,欢迎页面和根目录则退回到应用的根目录
if (currentUser == null
&& !requesturi.endsWith("/processLogin.do")
&& !requesturi.endsWith("/logout.do")
&& !requesturi.endsWith("/index.jsp")
&& !requesturi.endsWith(httpServletRequest.getContextPath()
+ "/")) ...{
httpServletResponse.sendRedirect(httpServletRequest
.getContextPath()
+ "/");
return;
}
chain.doFilter(request, response);
}
public void init(FilterConfig filterConfig) throws ServletException ...{
this.filterConfig = filterConfig;
this.encoding = filterConfig.getInitParameter("encoding");
this.forwardPath = filterConfig.getInitParameter("forwardpath");
String value = filterConfig.getInitParameter("ignore");
if (value == null)
this.ignore = true;
else if (value.equalsIgnoreCase("true"))
this.ignore = true;
else if (value.equalsIgnoreCase("yes"))
this.ignore = true;
else
this.ignore = false;
}
protected String selectEncoding(ServletRequest request) ...{
return (this.encoding);
}
}
5 .解决中文编码问题
代码同上,另
web.xml
<? xml version = " 1.0 " encoding = " UTF-8 " ?>
< web - app 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 "
version = " 2.4 " >
< filter >
< filter - name > Login Filter </ filter - name >
< filter - class >
org.prolove.webapp.filter.UserLoginFilter
</ filter - class >
< init - param >
< param - name > encoding </ param - name >
< param - value > GBK </ param - value >
</ init - param >
< init - param >
< param - name > ignore </ param - name >
< param - value > false </ param - value >
</ init - param >
< init - param >
< param - name > forwardpath </ param - name >
< param - value > index.jsp </ param - value >
</ init - param >
</ filter >
< filter - mapping >
< filter - name > Login Filter </ filter - name >
< url - pattern > /**/ /*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<jsp-config>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<taglib>
<taglib-uri>/tags/struts-bean</taglib-uri>
<taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/tags/struts-html</taglib-uri>
<taglib-location>/WEB-INF/struts-html.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/tags/struts-logic</taglib-uri>
<taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
</taglib>
</jsp-config>
</web-app>
6.JSP页面输出
-->main.jsp
<%@ page language="java" contentType="text/html;charset=GBK"%>
<%@ include file="taglibs.jsp"%>
<html>
<head>
<title>版面分类</title>
<link href="styles/news.css" rel="stylesheet" type="text/css">
</head>
<script language="javascript">
function verifyValue(){
if(loadNewsForm.categoryId.checked)
{
loadNewsForm.submit();
return true;
}
for (var i = 0 ; i < loadNewsForm.categoryId.length ; i++)
{
if( loadNewsForm.categoryId[i].checked )
{
loadNewsForm.submit();
return true;
}
}
alert('请选择要查看的版面!');
return false;
}
function logout(){
logoutForm.submit();
}
</script>
<body>
<table width="500" align="center" cellpadding="1" bgcolor="#99CCCC">
<form name="loadNewsForm" action="loadNewsByCategory.do" method="POST">
<tr>
<td width="40%" colspan="2" align="center">
<p>欢迎,<bean:write name="login_user"/></p>
</td>
</tr>
<tr>
<td width="10%" align="center">
请选择
</td>
<td width="30%" align="center">
版面名
</td>
</tr>
<logic:iterate id="item" name="categories" indexId="index" scope="request">
<tr>
<td width="10%" align="center">
<input type="radio" name="categoryId" value='<bean:write name="item" property="id"/>'>
</td>
<td width="30%" align="center">
<bean:write name="item" property="name"/>
</td>
</tr>
</logic:iterate>
<tr>
<td colspan="2" align="center">
<input type="button" value="查看" onClick="verifyValue();">
<input type="button" value="登出" onClick="logout();">
</td>
</tr>
</form>
<form name="logoutForm" action="logout.do" method="post"">
</form>
</table>
</body>
</html>
-->index.jsp
<%@ page language="java" contentType="text/html;charset=GBK"%>
<%@ include file="taglibs.jsp"%>
<html>
<head>
<title>登陆系统</title>
<link href="styles/news.css" rel="stylesheet" type="text/css">
</head>
<body>
<logic:messagesPresent>
<div class="title">
<bean:message key="errors.header"/>
<ul>
<html:messages id="error">
<li><bean:write name="error"/></li>
</html:messages>
</ul>
</div>
</logic:messagesPresent>
<logic:present name="errMsg">
<div class="title">
<li><bean:write name="errMsg" scope="request"/>
</div>
</logic:present>
<logic:present name="logout">
<div class="title">
<li><bean:write name="logout" scope="request"/>
</div>
</logic:present>
<table width="400" align="center" bgcolor="#99CCCC">
<html:form action="/processLogin">
<tr>
<td>
请输入用户名:
</td>
<td>
<html:text property="user" size="20"/>
</td>
</tr>
<tr>
<td>
请输入密码:
</td>
<td>
<input type="password" name="pass" size="20">
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="确定"> <input type="reset" value="重置">
</td>
</tr>
</html:form>
</table>
</body>
</html>
-->category_view.jsp
<%@ page language="java" contentType="text/html;charset=GBK"%>
<%@ include file="taglibs.jsp"%>
<html>
<head>
<title>分类新闻</title>
<link href="styles/news.css" rel="stylesheet" type="text/css">
</head>
<script language="javascript">
function verifyValue(){
if(loadNewsForm.newsId.checked)
{
loadNewsForm.submit();
return true;
}
for (var i = 0 ; i < loadNewsForm.newsId.length ; i++)
{
if( loadNewsForm.newsId[i].checked )
{
loadNewsForm.submit();
return true;
}
}
alert('请选择要查看的新闻!');
return false;
}
function goMain(){
mainForm.submit();
}
</script>
<body>
<table width="600" align="center" cellpadding="1" bgcolor="#99CCCC">
<form name="loadNewsForm" action="loadNewsReviewByNews.do" method="POST">
<tr>
<td width="60%" colspan="6" align="center">
<p>新闻列表</p> </td>
</tr>
<tr>
<td width="10%" align="center">
请选择 </td>
<td width="10%" align="center">
主题 </td>
<td width="10%" align="center">
发布人 </td>
<td width="10%" align="center">
发布时间 </td>
<td width="10%" align="center">
最后评论时间 </td>
</tr>
<logic:iterate id="item" name="news" indexId="index" scope="request">
<tr>
<td width="10%" align="center">
<input type="radio" name="newsId" value='<bean:write name="item" property="id"/>'>
</td>
<td width="10%" align="center">
<bean:write name="item" property="title"/>
</td>
<td width="10%" align="center">
<bean:write name="item" property="content"/>
</td>
<td width="10%" align="center">
<bean:write name="item" property="postDate"/>
</td>
<td width="10%" align="center">
<bean:write name="item" property="lastModifyDate"/>
</td>
</tr>
</logic:iterate>
<tr>
<td height="52" colspan="6" align="center">
<input type="button" value="查看" onClick="verifyValue();"> <input type="reset" value="重置"> </td>
</tr>
<tr>
<td height="25" colspan="6" align="center"> </td>
</tr>
<tr>
<td height="25" colspan="6" align="center">发表新的新闻</td>
</tr>
</form>
<html:form action="/addNews">
<tr>
<td colspan="6" align="center">
主题: </td>
</tr>
<tr>
<td colspan="6" align="center">
<html:text property="title" size="80"/>
<input type="hidden" name="categoryId" value='<bean:write name="categoryId"/>'>
</td>
</tr>
<tr>
<td colspan="6" align="center">
内容: </td>
</tr>
<tr>
<td colspan="6" align="center">
<html:textarea property="content" cols="80" rows="20"></html:textarea> </td>
</tr>
<tr>
<td colspan="6" align="center">
<input type="submit" value="提交">
<input type="reset" value="重置">
<input type="button" value="返回" onClick="history.go(-1);">
<input type="reset" value="主页" onClick="goMain();"> </td>
</tr>
</html:form>
<form name="mainForm" action="listCate.do" method="post"">
</form>
</table>
</body>
</html>
-->news_view.jsp
<%@ page language="java" contentType="text/html;charset=GBK"%>
<%@ include file="taglibs.jsp"%>
<html>
<head>
<title>新闻详细内容</title>
<link href="styles/news.css" rel="stylesheet" type="text/css">
</head>
<script language="javascript">
function verifyValue(){
if(addNewsReviewForm.content.value == ""){
alert('请输入评论内容!');
addNewsReviewForm.content.focus();
return false;
}
addNewsReviewForm.submit();
}
function goMain(){
mainForm.submit();
}
</script>
<body>
<table width="600" align="center" cellpadding="1" bgcolor="#99CCCC">
<tr>
<td colspan="2" align="center" bgcolor="#999999"><p>新闻标题:<bean:write name="news" property="title"/></p></td>
</tr>
<tr>
<td width="20%" align="center">新闻内容:</td>
<td width="80%" align="center" bgcolor="#eeeeee"><bean:write name="news" property="content"/></td>
</tr>
<tr>
<td colspan="2" align="center" bgcolor="#999999">所有评论如下:</td>
</tr>
<logic:iterate id="item" name="reviews" indexId="index" scope="request">
<tr>
<td colspan="2" bgcolor="#96dede">由网友${item.poster.username}于<bean:write name="item" property="postDate"/>发表的评论如下:</td>
</tr>
<tr>
<td colspan="2" align="center" bgcolor="#ffffff"><bean:write name="item" property="content"/> </td>
</tr>
</logic:iterate>
<html:form action="/addNewsReview">
<input type="hidden" name="newsId" value='<bean:write name="news" property="id"/>'>
<tr>
<td colspan="2" align="center"> 我要评论: </tr>
<tr>
<td colspan="2" align="center"><textarea name="content" cols="80" rows="6"></textarea> </td>
</tr>
<tr>
<td colspan="2" align="center"><input name="button" type="submit" value="提交">
<input name="reset" type="reset" value="重置">
<input name="button" type="button" onClick="history.go(-1);" value="返回">
<input name="reset" type="reset" onClick="goMain();" value="主页"> </td>
</tr>
</html:form>
<form name="mainForm" action="listCate.do" method="post"">
</form>
</table>
</body>
</html>
Struts + Spring + Hibernate
二、Hibernate持久层
1 .编写PO类
====================================================================================
package org.prolove.model;
import java.io.Serializable;
/** */ /**
* Base class for Model objects. Child objects should implement toString(),
* equals() and hashCode();
*
* <p>
* <a href="BaseObject.java.html"><i>View Source</i></a>
* </p>
*
* @author <a href="mailto:prolove@live.cn">PROLOVE</a>
*/
public abstract class BaseObject implements Serializable ... {
public abstract String toString();
public abstract boolean equals(Object o);
public abstract int hashCode();
}
====================================================================================
package org.prolove.model;
import java.util.Date;
import java.util.Set;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
/** */ /**
* @hibernate.class table="news"
* @struts.form include-all="false" extends="BaseForm"
*/
public class News extends BaseObject ... {
private Long id;// pk,required
private String title;// required
private String content;// required
private User poster;// fk,required
private Date postDate;// required
private Date lastModifyDate;// required
private Category category;// required
private Set newsReviews;
public News() ...{
}
/** *//**
* @return Returns the newsReview.
*/
public Set getNewsReviews() ...{
return newsReviews;
}
/** *//**
* @param newsReview
* The newsReview to set.
*/
public void setNewsReviews(Set newsReviews) ...{
this.newsReviews = newsReviews;
}
/** *//**
* @hibernate.many-to-one column="id" not-null="true"
*/
public Category getCategory() ...{
return category;
}
public void setCategory(Category category) ...{
this.category = category;
}
/** *//**
* @hibernate.property column="last_modify_date" not-null="true"
*/
public Date getLastModifyDate() ...{
return lastModifyDate;
}
public void setLastModifyDate(Date lastModifyDate) ...{
this.lastModifyDate = lastModifyDate;
}
/** *//**
* @hibernate.property column="post_date" not-null="true"
*/
public Date getPostDate() ...{
return postDate;
}
public void setPostDate(Date postDate) ...{
this.postDate = postDate;
}
/** *//**
* @hibernate.many-to-one column="username" not-null="true"
*/
public User getPoster() ...{
return poster;
}
public void setPoster(User poster) ...{
this.poster = poster;
}
/** *//**
* @hibernate.property column="content" length="3000" not-null="true"
*/
public String getContent() ...{
return content;
}
public void setContent(String content) ...{
this.content = content;
}
/** *//**
* @return Returns the id.
* @hibernate.id column="id" generator-class="increment"
* unsaved-value="null"
*/
public Long getId() ...{
return id;
}
public void setId(Long id) ...{
this.id = id;
}
/** *//**
* @hibernate.property column="title" length="50" not-null="true"
*/
public String getTitle() ...{
return title;
}
public void setTitle(String title) ...{
this.title = title;
}
/** *//**
* @see java.lang.Object#equals(Object)
*/
public boolean equals(Object object) ...{
if (!(object instanceof News)) ...{
return false;
}
News rhs = (News) object;
return this.poster.equals(rhs.getPoster())
&& this.postDate.equals(rhs.getPostDate());
/**//*
* return new EqualsBuilder().append(this.newsReviews, rhs.newsReviews)
* .append(this.title, rhs.title).append(this.category,
* rhs.category).append(this.content, rhs.content).append(
* this.postDate, rhs.postDate).append( this.lastModifyDate,
* rhs.lastModifyDate).append( this.id, rhs.id).append(this.poster,
* rhs.poster) .isEquals();
*/
}
/** *//**
* @see java.lang.Object#hashCode()
*/
public int hashCode() ...{
return this.poster.hashCode() + this.postDate.hashCode();
/**//*
* return new HashCodeBuilder(1595611275, -1477459617).append(
* this.newsReviews).append(this.title).append(this.category)
* .append(this.content).append(this.postDate).append(
* this.lastModifyDate).append(this.id)
* .append(this.poster).toHashCode();
*/
}
/** *//**
* @see java.lang.Object#toString()
*/
public String toString() ...{
return new ToStringBuilder(this).append("id", this.id).append("title",
this.title).append("postDate", this.postDate).append("content",
this.content).append("lastModifyDate", this.lastModifyDate)
.append("poster", this.poster)
.append("category", this.category).append("newsReviews",
this.newsReviews).toString();
}
}
2 .编写PO的映射配置文件
====================================================================================
<? 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 " >
< hibernate - mapping >
< class name = " org.prolove.model.News " table = " news " >
< id name = " id " column = " id " unsaved - value = " null " >
<!-- The generator - class attribute of @hibernate.id is deprecated, use the @hibernate.generator tag instead -->
< generator class = " increment " >
</ generator >
</ id >
< many - to - one name = " category " class = " org.prolove.model.Category " column = " category_id " not - null = " true " >
</ many - to - one >
< property name = " lastModifyDate " column = " last_modify_date " not - null = " true " >
</ property >
< property name = " postDate " column = " post_date " not - null = " true " >
</ property >
< many - to - one name = " poster " column = " username " not - null = " true " >
</ many - to - one >
< property name = " content " column = " content " length = " 3000 " not - null = " true " >
</ property >
< property name = " title " column = " title " length = " 50 " not - null = " true " >
</ property >
<!-- bi - directional one - to - many association to NewsReview -->
< set name = " newsReviews " lazy = " false " inverse = " true " cascade = " all-delete-orphan " >
< meta attribute = " field-description " >
@hibernate.list lazy = " true " inverse = " false " cascade = " none "
@hibernate.collection - key column = " id "
@hibernate.collection - one - to - many class = " org.prolove.model.NewsReview "
</ meta >
< key >
< column name = " news_id " />
</ key >
< one - to - many class = " org.prolove.model.NewsReview " />
</ set >
</ class >
</ hibernate - mapping >
3 .连接数据库
applicationContext - hibernate.xml
<? xml version = " 1.0 " encoding = " UTF-8 " ?>
<! DOCTYPE beans PUBLIC " -//SPRING//DTD BEAN//EN "
" http://www.springframework.org/dtd/spring-beans.dtd " >
< beans >
< bean id = " dataSource " class = " org.apache.commons.dbcp.BasicDataSource " destroy - method = " close " >
< property name = " driverClassName " value = " oracle.jdbc.driver.OracleDriver " />
<!-- property name = " driverClassName " value = " net.sourceforge.jtds.jdbc.Driver " /-->
< property name = " url " value = " jdbc:oracle:thin:@10.200.3.81:1521:oranet " />
< property name = " username " value = " hm " />
< property name = " password " value = " hm123 " />
< property name = " maxActive " value = " 100 " />
< property name = " maxIdle " value = " 30 " />
< property name = " maxWait " value = " 1000 " />
< property name = " defaultAutoCommit " value = " true " />
< property name = " removeAbandoned " value = " true " />
< property name = " removeAbandonedTimeout " value = " 60 " />
< property name = " logAbandoned " value = " true " />
</ bean >
<!-- Hibernate SessionFactory -->
< bean id = " sessionFactory " class = " org.springframework.orm.hibernate3.LocalSessionFactoryBean " >
< property name = " dataSource " ref = " dataSource " />
< property name = " mappingResources " >
< list >
< value > org / prolove / model / User.hbm.xml </ value >
< value > org / prolove / model / News.hbm.xml </ value >
< value > org / prolove / model / NewsReview.hbm.xml </ value >
< value > org / prolove / model / Category.hbm.xml </ value >
</ list >
</ property >
<!-- The property below is commented out b / c it doesn ' t work when run via
Ant in Eclipse. It works fine for individual JUnit tests and in IDEA ??
< property name = " mappingJarLocations " >
< list >< value > file:dist / appfuse - dao.jar </ value ></ list >
</ property >
-->
< property name = " hibernateProperties " >
< props >
< prop key = " hibernate.dialect " > @HIBERNATE - DIALECT@ </ prop >
<!-- Create / update the database tables automatically when the JVM starts up
< prop key = " hibernate.hbm2ddl.auto " > update </ prop > -->
<!-- Turn batching off for better error messages under PostgreSQL
< prop key = " hibernate.jdbc.batch_size " > 0 </ prop > -->
</ props >
</ property >
</ bean >
<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
< bean id = " transactionManager " class = " org.springframework.orm.hibernate3.HibernateTransactionManager " >
< property name = " sessionFactory " ref = " sessionFactory " />
</ bean >
<!-- Generic DAO - can be used when doing standard CRUD -->
< bean id = " dao " class = " org.prolove.dao.hibernate.BaseDAOHibernate " >
< property name = " sessionFactory " ref = " sessionFactory " />
</ bean >
<!-- UserDAO: Hibernate implementation -->
< bean id = " userDAO " class = " org.prolove.dao.hibernate.UserDAOHibernate " >
< property name = " sessionFactory " ref = " sessionFactory " />
</ bean >
<!-- Add new DAOs here -->
< bean id = " newsDAO " class = " org.prolove.dao.hibernate.NewsDAOHibernate " >
< property name = " sessionFactory " ref = " sessionFactory " />
</ bean >
< bean id = " newsReviewDAO " class = " org.prolove.dao.hibernate.NewsReviewDAOHibernate " >
< property name = " sessionFactory " ref = " sessionFactory " />
</ bean >
< bean id = " categoryDAO " class = " org.prolove.dao.hibernate.CategoryDAOHibernate " >
< property name = " sessionFactory " ref = " sessionFactory " />
</ bean >
<!-- PersonDAO: Hibernate implementation -->
< bean id = " personDAO " class = " org.appfuse.dao.hibernate.PersonDAOHibernate " >
< property name = " sessionFactory " ref = " sessionFactory " />
</ bean >
</ beans >
=====================================================================
applicationContext.xml
<? xml version = " 1.0 " encoding = " UTF-8 " ?>
<! DOCTYPE beans PUBLIC " -//SPRING//DTD BEAN//EN "
" http://www.springframework.org/dtd/spring-beans.dtd " >
< beans >
<!-- hibernate datasource -->
< 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/newsboard " />
< property name = " username " value = " root " />
< property name = " password " value = " root " />
< property name = " maxActive " value = " 20 " />
< property name = " maxIdle " value = " 10 " />
< property name = " initialSize " value = " 1 " />
< property name = " maxWait " value = " 1000 " />
< property name = " defaultAutoCommit " value = " true " />
< property name = " removeAbandoned " value = " true " />
< property name = " removeAbandonedTimeout " value = " 60 " />
< property name = " logAbandoned " value = " true " />
</ bean >
<!-- Hibernate SessionFactory -->
< bean id = " sessionFactory " class = " org.springframework.orm.hibernate3.LocalSessionFactoryBean " >
< property name = " dataSource " ref = " dataSource " />
< property name = " mappingResources " >
< list >
< value > org / prolove / model / User.hbm.xml </ value >
< value > org / prolove / model / News.hbm.xml </ value >
< value > org / prolove / model / NewsReview.hbm.xml </ value >
< value > org / prolove / model / Category.hbm.xml </ value >
</ list >
</ property >
< property name = " hibernateProperties " >
< props >
< prop key = " hibernate.dialect " > org.hibernate.dialect.MySQLDialect </ prop >
< prop key = " hibernate.hbm2ddl.auto " > update </ prop >
< prop key = " hibernate.jdbc.batch_size " > 20 </ prop >
</ props >
</ property >
</ bean >
<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
< bean id = " transactionManager " class = " org.springframework.orm.hibernate3.HibernateTransactionManager " >
< property name = " sessionFactory " ref = " sessionFactory " />
</ bean >
<!-- service manager Template -->
< bean id = " txProxyTemplate " abstract = " true "
class = " org.springframework.transaction.interceptor.TransactionProxyFactoryBean " >
< property name = " transactionManager " ref = " transactionManager " />
< property name = " transactionAttributes " >
< props >
< prop key = " save* " > PROPAGATION_REQUIRED </ prop >
< prop key = " remove* " > PROPAGATION_REQUIRED </ prop >
< prop key = " * " > PROPAGATION_REQUIRED,readOnly </ prop >
</ props >
</ property >
</ bean >
<!-- service manager -->
< bean id = " facadeManager " parent = " txProxyTemplate " >
< property name = " target " >
< bean class = " org.prolove.service.impl.FacadeManagerImpl " >
< property name = " newsDAO " ref = " newsDAO " />
< property name = " newsReviewDAO " ref = " newsReviewDAO " />
< property name = " categoryDAO " ref = " categoryDAO " />
< property name = " userDAO " ref = " userDAO " />
</ bean >
</ property >
</ bean >
</ beans >
三、DAO组件层
1 .DAO组件的结构
为了让逻辑组件与具体的DAO组件分离,还必须有一个DAO工厂。
2 .编写DAO接口
package org.prolove.dao;
import java.io.Serializable;
import java.util.List;
/** */ /**
* Data Access Object (DAO) interface. This is an interface
* used to tag our DAO classes and to provide common methods to all DAOs.
*
* <p><a href="DAO.java.html"><i>View Source</i></a></p>
*
* @author <a href="mailto:matt@raibledesigns.com">Matt Raible</a>
*/
public interface DAO ... {
/** *//**
* Generic method used to get all objects of a particular type. This
* is the same as lookup up all rows in a table.
* @param clazz the type of objects (a.k.a. while table) to get data from
* @return List of populated objects
*/
public List getObjects(Class clazz);
/** *//**
* Generic method to get an object based on class and identifier. An
* ObjectRetrievalFailureException Runtime Exception is thrown if
* nothing is found.
*
* @param clazz model class to lookup
* @param id the identifier (primary key) of the class
* @return a populated object
* @see org.springframework.orm.ObjectRetrievalFailureException
*/
public Object getObject(Class clazz, Serializable id);
/** *//**
* Generic method to save an object - handles both update and insert.
* @param o the object to save
*/
public void saveObject(Object o);
/** *//**
* Generic method to delete an object based on class and id
* @param clazz model class to lookup
* @param id the identifier (primary key) of the class
*/
public void removeObject(Class clazz, Serializable id);
}
=========================================================================
package org.prolove.dao;
import java.util.List;
import org.prolove.model.User;
/** */ /**
* User Data Access Object (DAO) interface.
*
* <p>
* <a href="UserDAO.java.html"><i>View Source</i></a>
* </p>
*
* @author <a href="mailto:matt@raibledesigns.com">Matt Raible</a>
*/
public interface UserDAO extends DAO ... {
/** *//**
* Gets users information based on login name.
* @param username the current username
* @return user populated user object
*/
public User getUser(String username);
/** *//**
* Gets a list of users based on parameters passed in.
*
* @return List populated list of users
*/
public List getUsers(User user);
/** *//**
* Saves a user's information
* @param user the object to be saved
*/
public void saveUser(User user);
/** *//**
* Removes a user from the database by id
* @param username the user's username
*/
public void removeUser(String username);
}
……
3 .编写DAO的具体实现
package org.prolove.dao.hibernate;
import java.io.Serializable;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.prolove.dao.DAO;
/** */ /**
* This class serves as the Base class for all other DAOs - namely to hold
* common methods that they might all use. Can be used for standard CRUD
* operations.</p>
*
* <p><a href="BaseDAOHibernate.java.html"><i>View Source</i></a></p>
*
* @author <a href="mailto:matt@raibledesigns.com">Matt Raible</a>
*/
public class BaseDAOHibernate extends HibernateDaoSupport implements DAO ... {
protected final Log log = LogFactory.getLog(getClass());
/** *//**
* @see org.leecode.dao.DAO#saveObject(java.lang.Object)
*/
public void saveObject(Object o) ...{
getHibernateTemplate().saveOrUpdate(o);
}
/** *//**
* @see org.leecode.dao.DAO#getObject(java.lang.Class, java.io.Serializable)
*/
public Object getObject(Class clazz, Serializable id) ...{
Object o = getHibernateTemplate().get(clazz, id);
if (o == null) ...{
throw new ObjectRetrievalFailureException(clazz, id);
}
return o;
}
/** *//**
* @see org.leecode.dao.DAO#getObjects(java.lang.Class)
*/
public List getObjects(Class clazz) ...{
return getHibernateTemplate().loadAll(clazz);
}
/** *//**
* @see org.leecode.dao.DAO#removeObject(java.lang.Class, java.io.Serializable)
*/
public void removeObject(Class clazz, Serializable id) ...{
getHibernateTemplate().delete(getObject(clazz, id));
}
}
======================================================================================
package org.prolove.dao.hibernate;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.prolove.dao.NewsDAO;
import org.prolove.model.News;
public class NewsDAOHibernate extends BaseDAOHibernate implements NewsDAO ... {
public News getNews(Long id) ...{
News news = (News) getHibernateTemplate().get(News.class, id);
if (news == null) ...{
throw new ObjectRetrievalFailureException(News.class, id);
}
return news;
}
public void saveNews(News news) ...{
getHibernateTemplate().saveOrUpdate(news);
}
public void removeNews(Long id) ...{
// object must be loaded before it can be deleted
getHibernateTemplate().delete(getNews(id));
}
}
……
4 .用Spring容器代替DAO工厂
见上文applicationContext - hibernate.xml
以及
daoContext.xml
<? xml version = " 1.0 " encoding = " GBK " ?>
<! DOCTYPE beans PUBLIC " -//SPRING//DTD BEAN//EN "
" http://www.springframework.org/dtd/spring-beans.dtd " >
< beans >
<!-- DAO模板,用于被其他的DAO组件继承 -->
< bean id = " daoTemplate " abstract = " true " lazy - init = " true " >
< property name = " sessionFactory " ref = " sessionFactory " />
</ bean >
<!-- Generic DAO - can be used when doing standard CRUD -->
< bean id = " dao " class = " org.prolove.dao.hibernate.BaseDAOHibernate "
parent = " daoTemplate " />
<!-- UserDAO: Hibernate implementation -->
< bean id = " userDAO " class = " org.prolove.dao.hibernate.UserDAOHibernate "
parent = " daoTemplate " />
<!-- NewsDAO Hibernate implementation -->
< bean id = " newsDAO " class = " org.prolove.dao.hibernate.NewsDAOHibernate "
parent = " daoTemplate " />
<!-- NewsReviewDAO Hibernate implementation -->
< bean id = " newsReviewDAO " class = " org.prolove.dao.hibernate.NewsReviewDAOHibernate "
parent = " daoTemplate " />
<!-- CategoryDAO Hibernate implementation -->
< bean id = " categoryDAO " class = " org.prolove.dao.hibernate.CategoryDAOHibernate "
parent = " daoTemplate " />
</ beans >
四、业务逻辑层
1 .业务逻辑组件的结构
每个模块设计一个业务逻辑组件。
2 .业务逻辑组件的接口
package org.prolove.service;
import java.util.List;
import org.prolove.dao.CategoryDAO;
import org.prolove.dao.NewsDAO;
import org.prolove.dao.NewsReviewDAO;
import org.prolove.dao.UserDAO;
import org.prolove.model.Category;
import org.prolove.model.News;
import org.prolove.model.NewsReview;
import org.prolove.model.User;
// 该接口是对DAO的正面包装
public interface FacadeManager ... {
// category的业务方法
public void setCategoryDAO(CategoryDAO dao);
public Category getCategory(String id);
public void saveCategory(Category category);
public void removeCategory(String id);
public List getCategories();
// news的业务方法
public void setNewsDAO(NewsDAO dao);
public News getNews(String id);
public void saveNews(News news);
public void removeNews(String id);
// newsReview的业务方法
public void setNewsReviewDAO(NewsReviewDAO dao);
public NewsReview getNewsReview(String id);
public void saveNewsReview(NewsReview newsReview);
public void removeNewsReview(String id);
// user的业务方法
public void setUserDAO(UserDAO dao);
public User getUser(String username);
public List getUsers(User user);
public void saveUser(User user) throws Exception;
public void removeUser(String username);
public boolean validateUser(User user);
}
3 .业务逻辑组件的实现类
package org.prolove.service;
import java.io.Serializable;
import java.util.List;
import org.prolove.dao.DAO;
public interface Manager ... {
/** *//**
* Expose the setDAO method for testing purposes
* @param dao
*/
public void setDAO(DAO dao);
/** *//**
* Generic method used to get a all objects of a particular type.
* @param clazz the type of objects
* @return List of populated objects
*/
public List getObjects(Class clazz);
/** *//**
* Generic method to get an object based on class and identifier.
*
* @param clazz model class to lookup
* @param id the identifier (primary key) of the class
* @return a populated object
* @see org.springframework.orm.ObjectRetrievalFailureException
*/
public Object getObject(Class clazz, Serializable id);
/** *//**
* Generic method to save an object.
* @param o the object to save
*/
public void saveObject(Object o);
/** *//**
* Generic method to delete an object based on class and id
* @param clazz model class to lookup
* @param id the identifier of the class
*/
public void removeObject(Class clazz, Serializable id);
}
package org.prolove.service.impl;
import java.io.Serializable;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.prolove.dao.DAO;
import org.prolove.service.Manager;
/** */ /**
* Base class for Business Services - use this class for utility methods and
* generic CRUD methods.
*
* <p><a href="BaseManager.java.html"><i>View Source</i></a></p>
*
* @author <a href="mailto:prolove@live.cn">Matt Raible</a>
*/
public class BaseManager implements Manager ... {
protected DAO dao = null;
protected final Log log = LogFactory.getLog(getClass());
/** *//**
* @see org.leecode.service.Manager#setDAO(org.leecode.dao.DAO)
*/
public void setDAO(DAO dao) ...{
this.dao = dao;
}
/** *//**
* @see org.leecode.service.Manager#getObject(java.lang.Class, java.io.Serializable)
*/
public Object getObject(Class clazz, Serializable id) ...{
return dao.getObject(clazz, id);
}
/** *//**
* @see org.leecode.service.Manager#getObjects(java.lang.Class)
*/
public List getObjects(Class clazz) ...{
return dao.getObjects(clazz);
}
/** *//**
* @see org.leecode.service.Manager#removeObject(java.lang.Class, java.io.Serializable)
*/
public void removeObject(Class clazz, Serializable id) ...{
dao.removeObject(clazz, id);
}
/** *//**
* @see org.leecode.service.Manager#saveObject(java.lang.Object)
*/
public void saveObject(Object o) ...{
dao.saveObject(o);
}
}
package org.prolove.service.impl;
import java.util.List;
import org.springframework.dao.DataIntegrityViolationException;
import org.prolove.dao.CategoryDAO;
import org.prolove.dao.NewsDAO;
import org.prolove.dao.NewsReviewDAO;
import org.prolove.dao.UserDAO;
import org.prolove.model.Category;
import org.prolove.model.News;
import org.prolove.model.NewsReview;
import org.prolove.model.User;
import org.prolove.service.FacadeManager;
public class FacadeManagerImpl extends BaseManager implements
FacadeManager ... {
private CategoryDAO categoryDAO;
private NewsDAO newsDAO;
private NewsReviewDAO newsReviewDAO;
private UserDAO userDAO;
public void setCategoryDAO(CategoryDAO categoryDAO) ...{
this.categoryDAO = categoryDAO;
}
public Category getCategory(String id) ...{
return categoryDAO.getCategory(Long.valueOf(id));
}
public void saveCategory(Category category) ...{
categoryDAO.saveCategory(category);
}
public void removeCategory(String id) ...{
categoryDAO.removeCategory(Long.valueOf(id));
}
public List getCategories() ...{
return categoryDAO.getCategories();
}
public void setNewsDAO(NewsDAO newsDAO) ...{
this.newsDAO = newsDAO;
}
public News getNews(String id) ...{
return newsDAO.getNews(Long.valueOf(id));
}
public void saveNews(News news) ...{
newsDAO.saveNews(news);
}
public void removeNews(String id) ...{
newsDAO.removeNews(Long.valueOf(id));
}
public void setNewsReviewDAO(NewsReviewDAO newsReviewDAO) ...{
this.newsReviewDAO = newsReviewDAO;
}
public NewsReview getNewsReview(String id) ...{
return newsReviewDAO.getNewsReview(Long.valueOf(id));
}
public void saveNewsReview(NewsReview newsReview) ...{
newsReviewDAO.saveNewsReview(newsReview);
}
public void removeNewsReview(String id) ...{
newsReviewDAO.removeNewsReview(Long.valueOf(id));
}
public void setUserDAO(UserDAO userDAO) ...{
this.userDAO = userDAO;
}
public User getUser(String username) ...{
return userDAO.getUser(username);
}
public List getUsers(User user) ...{
return userDAO.getUsers(user);
}
public void saveUser(User user) throws Exception ...{
try ...{
userDAO.saveUser(user);
} catch (DataIntegrityViolationException e) ...{
throw new Exception("User '" + user.getUsername()
+ "' already exists!");
}
}
public void removeUser(String username) ...{
userDAO.removeUser(username);
}
public boolean validateUser(User aUser) ...{
User user = getUser(aUser.getUsername());
if (user != null && user.getPassword().equals(aUser.getPassword()))
return true;
else
return false;
}
}
4 .业务逻辑组件的配置
在applicationContext.xml配置FacadeManager组件
五、Web层设计
1 .Action的实现
package org.prolove.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForward;
import org.apache.struts.validator.DynaValidatorForm;
import org.prolove.action.base.BaseAction;
import org.prolove.webapp.util.AppConstants;
import org.prolove.model. * ;
import java.util. * ;
/** */ /**
* @author PROLOVE prolve@live.cn
* @version 1.0
* <br>Copyright (C), 2006-2008, PROLOVE
* <br>This program is protected by copyright laws.
* <br>Program Name:
* <br>Date:
*/
public class AddReviewAction extends BaseAction
... {
//必须重写该核心方法,该方法actionForm将表单的请求参数封装成值对象
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)throws Exception
...{
DynaValidatorForm addForm = (DynaValidatorForm)form;
String content = (String)addForm.get("content");
String newsId = (String)addForm.get("newsId");
try
...{
News news = mgr.getNews(newsId);
String username = (String)request.getSession(true).getAttribute(AppConstants.LOGIN_USER);
User poster = mgr.getUser(username);
NewsReview newsReview = new NewsReview();
newsReview.setNews(news);
newsReview.setPoster(poster);
newsReview.setContent(content);
newsReview.setPostDate(new Date());
newsReview.setLastModifyDate(new Date());
mgr.saveNewsReview(newsReview);
}
catch (Exception e)
...{
request.setAttribute("newsId" , newsId);
return mapping.findForward("failure");
}
request.setAttribute("newsId" , newsId);
return mapping.findForward("success");
}
}
package org.prolove.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForward;
import org.apache.struts.validator.DynaValidatorForm;
import org.prolove.action.base.BaseAction;
import org.prolove.model.News;
import java.util.Set;
/** */ /**
* @author PROLOVE prolve@live.cn
* @version 1.0
* <br>Copyright (C), 2006-2008, PROLOVE
* <br>This program is protected by copyright laws.
* <br>Program Name:
* <br>Date:
*/
public class LoadReviewsByNews extends BaseAction
... {
//必须重写该核心方法,该方法actionForm将表单的请求参数封装成值对象
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)throws Exception
...{
String newsId = null;
if(request.getAttribute("newsId") == null)
...{
newsId = request.getParameter("newsId");
}
else
...{
newsId = (String)request.getAttribute("newsId");
}
News news = mgr.getNews(newsId);
request.setAttribute("news" , news);
request.setAttribute("reviews",news.getNewsReviews());
return mapping.findForward("success");
}
}
……
2 .Spring管理容器Action
采用DelegatingRequestProcessor的整合策略。
struts - config.xml
<? xml version = " 1.0 " encoding = " GBK " ?>
<! DOCTYPE struts - config PUBLIC
" -//Apache Software Foundation//DTD Struts Configuration 1.2//EN "
" http://struts.apache.org/dtds/struts-config_1_2.dtd " >
< struts - config >
< form - beans >
<!-- 配置登陆所使用的Form -->
< form - bean name = " loginForm " type = " org.apache.struts.validator.DynaValidatorForm " >
< form - property name = " user " type = " java.lang.String " />
< form - property name = " pass " type = " java.lang.String " />
</ form - bean >
<!-- 添加新闻所用的Form -->
< form - bean name = " addNewsForm " type = " org.apache.struts.validator.DynaValidatorForm " >
< form - property name = " title " type = " java.lang.String " />
< form - property name = " content " type = " java.lang.String " />
< form - property name = " categoryId " type = " java.lang.String " />
</ form - bean >
<!-- 添加新闻评论所用的Form -->
< form - bean name = " addNewsReviewForm " type = " org.apache.struts.validator.DynaValidatorForm " >
< form - property name = " content " type = " java.lang.String " />
< form - property name = " newsId " type = " java.lang.String " />
</ form - bean >
</ form - beans >
< global - forwards >
</ global - forwards >
<!-- ========================================= Action Mapping Definitions -->
< action - mappings >
<!-- 处理登陆 -->
< action path = " /processLogin "
name = " loginForm "
scope = " request "
validate = " true "
input = " input " >
< forward name = " input " path = " /index.jsp " />
< forward name = " success " path = " /listCate.do " />
</ action >
<!-- 登出系统 -->
< action path = " /logout " scope = " request " >
< forward name = " success " path = " /index.jsp " />
</ action >
<!-- 进入主页面 -->
< action path = " /listCate " scope = " request " >
< forward name = " success " path = " /main.jsp " />
</ action >
<!-- 根据种类加载所有新闻 -->
< action path = " /loadNewsByCategory " scope = " request " >
< forward name = " failure " path = " /listCate.do " />
< forward name = " success " path = " /category_view.jsp " />
</ action >
<!-- 添加新闻 -->
< action path = " /addNews "
name = " addNewsForm "
scope = " request "
validate = " true "
input = " input " >
< forward name = " failure " path = " /loadNewsByCategory.do " />
< forward name = " success " path = " /loadNewsByCategory.do " />
</ action >
<!-- 根据新闻id加载所有评论 -->
< action path = " /loadNewsReviewByNews " scope = " request " >
< forward name = " success " path = " /news_view.jsp " />
</ action >
<!-- 添加新闻评论 -->
< action path = " /addNewsReview "
name = " addNewsReviewForm "
scope = " request "
validate = " true "
input = " input " >
< forward name = " failure " path = " /loadNewsReviewByNews.do " />
< forward name = " success " path = " /loadNewsReviewByNews.do " />
</ action >
</ action - mappings >
< controller inputForward = " true " processorClass = " org.springframework.web.struts.DelegatingRequestProcessor " />
< message - resources parameter = " resource " />
< plug - in className = " org.apache.struts.validator.ValidatorPlugIn " >
< set - property property = " pathnames " value = " /WEB-INF/validator-rules.xml,
/ WEB - INF / validation.xml " />
< set - property property = " stopOnFirstError " value = " true " />
</ plug - in >
< plug - in className = " org.springframework.web.struts.ContextLoaderPlugIn " >
< set - property property = " contextConfigLocation " value = " /WEB-INF/daoContext.xml,
/ WEB - INF / applicationContext.xml,
/ WEB - INF / action - Servlet.xml " />
</ plug - in >
</ struts - config >
action - Servlet.xml
<? xml version = " 1.0 " encoding = " GBK " ?>
<! DOCTYPE beans PUBLIC " -//SPRING//DTD BEAN//EN "
" http://www.springframework.org/dtd/spring-beans.dtd " >
< beans >
< bean id = " actionTemplate " abstract = " true " singleton = " false " >
< property name = " mgr " ref = " facadeManager " />
</ bean >
<!-- 处理登陆 -->
< bean name = " /processLogin " class = " org.prolove.action.LoginAction " parent = " actionTemplate " />
<!-- 登出系统 -->
< bean name = " /logout " class = " org.prolove.action.Logout " />
<!-- 列出所有的新闻分类 -->
< bean name = " /listCate " class = " org.prolove.action.ListCate " parent = " actionTemplate " />
<!-- 根据种类列出所有新闻 -->
< bean name = " /loadNewsByCategory " class = " org.prolove.action.LoadNewsByCategory " parent = " actionTemplate " />
<!-- 添加新闻 -->
< bean name = " /addNews " class = " org.prolove.action.AddNewsAction " parent = " actionTemplate " />
<!-- 根据新闻查看所有的评论 -->
< bean name = " /loadNewsReviewByNews " class = " org.prolove.action.LoadReviewsByNews " parent = " actionTemplate " />
<!-- 添加新闻评论 -->
< bean name = " /addNewsReview " class = " org.prolove.action.AddReviewAction " parent = " actionTemplate " />
</ beans >
3 .数据校验的选择
validation.xml
<? xml version = " 1.0 " encoding = " iso-8859-1 " ?>
<! DOCTYPE form - validation PUBLIC
" -//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.3//EN "
" http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd " >
< form - validation >
< formset >
< form name = " loginForm " >
< field property = " user " depends = " required,minlength " >
< arg key = " loginForm.user " position = " 0 " />
< arg name = " minlength " key = " ${var:minlength} " resource = " false " position = " 1 " />
< var >
< var - name > minlength </ var - name >
< var - value > 4 </ var - value >
</ var >
</ field >
< field property = " pass " depends = " required,minlength " >
< arg key = " loginForm.pass " position = " 0 " />
< arg name = " minlength " key = " ${var:minlength} " resource = " false " position = " 1 " />
< var >
< var - name > minlength </ var - name >
< var - value > 4 </ var - value >
</ var >
</ field >
</ form >
< form name = " addNewsForm " >
< field property = " title " depends = " required " >
< arg key = " addNewsForm.title " position = " 0 " />
</ field >
< field property = " content " depends = " required " >
< arg key = " addNewsForm.content " position = " 0 " />
</ field >
< field property = " categoryId " depends = " required,integer " >
< arg key = " addNewsForm.categoryId " position = " 0 " />
</ field >
</ form >
< form name = " addNewsReviewForm " >
< field property = " content " depends = " required " >
< arg key = " addNewsReviewForm.content " position = " 0 " />
</ field >
< field property = " newsId " depends = " required,integer " >
< arg key = " addNewsReviewForm.categoryId " position = " 0 " />
</ field >
</ form >
</ formset >
</ form - validation >
4 .访问权限的控制
package org.prolove.webapp.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.prolove.webapp.util.AppConstants;
/** */ /**
* 设置字符集、过滤未登录的非法请求
*/
public class UserLoginFilter implements Filter ... {
protected String encoding = null;
protected FilterConfig filterConfig = null;
protected boolean ignore = false;
protected String forwardPath = null;
public void destroy() ...{
this.encoding = null;
this.filterConfig = null;
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException ...{
// 设置编码方式,web.xml里面有filter参数的初始化设置
if (ignore || (request.getCharacterEncoding() == null)) ...{
String encoding = selectEncoding(request);
if (encoding != null)
request.setCharacterEncoding(encoding);
}
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
String requesturi = httpServletRequest.getRequestURI();
// 通过检查session中的变量,过虑请求
HttpSession session = httpServletRequest.getSession();
Object currentUser = session.getAttribute(AppConstants.LOGIN_USER);
// 当前会话用户为空而且不是请求登录,退出登录,欢迎页面和根目录则退回到应用的根目录
if (currentUser == null
&& !requesturi.endsWith("/processLogin.do")
&& !requesturi.endsWith("/logout.do")
&& !requesturi.endsWith("/index.jsp")
&& !requesturi.endsWith(httpServletRequest.getContextPath()
+ "/")) ...{
httpServletResponse.sendRedirect(httpServletRequest
.getContextPath()
+ "/");
return;
}
chain.doFilter(request, response);
}
public void init(FilterConfig filterConfig) throws ServletException ...{
this.filterConfig = filterConfig;
this.encoding = filterConfig.getInitParameter("encoding");
this.forwardPath = filterConfig.getInitParameter("forwardpath");
String value = filterConfig.getInitParameter("ignore");
if (value == null)
this.ignore = true;
else if (value.equalsIgnoreCase("true"))
this.ignore = true;
else if (value.equalsIgnoreCase("yes"))
this.ignore = true;
else
this.ignore = false;
}
protected String selectEncoding(ServletRequest request) ...{
return (this.encoding);
}
}
5 .解决中文编码问题
代码同上,另
web.xml
<? xml version = " 1.0 " encoding = " UTF-8 " ?>
< web - app 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 "
version = " 2.4 " >
< filter >
< filter - name > Login Filter </ filter - name >
< filter - class >
org.prolove.webapp.filter.UserLoginFilter
</ filter - class >
< init - param >
< param - name > encoding </ param - name >
< param - value > GBK </ param - value >
</ init - param >
< init - param >
< param - name > ignore </ param - name >
< param - value > false </ param - value >
</ init - param >
< init - param >
< param - name > forwardpath </ param - name >
< param - value > index.jsp </ param - value >
</ init - param >
</ filter >
< filter - mapping >
< filter - name > Login Filter </ filter - name >
< url - pattern > /**/ /*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<jsp-config>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<taglib>
<taglib-uri>/tags/struts-bean</taglib-uri>
<taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/tags/struts-html</taglib-uri>
<taglib-location>/WEB-INF/struts-html.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/tags/struts-logic</taglib-uri>
<taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
</taglib>
</jsp-config>
</web-app>
6.JSP页面输出
-->main.jsp
<%@ page language="java" contentType="text/html;charset=GBK"%>
<%@ include file="taglibs.jsp"%>
<html>
<head>
<title>版面分类</title>
<link href="styles/news.css" rel="stylesheet" type="text/css">
</head>
<script language="javascript">
function verifyValue(){
if(loadNewsForm.categoryId.checked)
{
loadNewsForm.submit();
return true;
}
for (var i = 0 ; i < loadNewsForm.categoryId.length ; i++)
{
if( loadNewsForm.categoryId[i].checked )
{
loadNewsForm.submit();
return true;
}
}
alert('请选择要查看的版面!');
return false;
}
function logout(){
logoutForm.submit();
}
</script>
<body>
<table width="500" align="center" cellpadding="1" bgcolor="#99CCCC">
<form name="loadNewsForm" action="loadNewsByCategory.do" method="POST">
<tr>
<td width="40%" colspan="2" align="center">
<p>欢迎,<bean:write name="login_user"/></p>
</td>
</tr>
<tr>
<td width="10%" align="center">
请选择
</td>
<td width="30%" align="center">
版面名
</td>
</tr>
<logic:iterate id="item" name="categories" indexId="index" scope="request">
<tr>
<td width="10%" align="center">
<input type="radio" name="categoryId" value='<bean:write name="item" property="id"/>'>
</td>
<td width="30%" align="center">
<bean:write name="item" property="name"/>
</td>
</tr>
</logic:iterate>
<tr>
<td colspan="2" align="center">
<input type="button" value="查看" onClick="verifyValue();">
<input type="button" value="登出" onClick="logout();">
</td>
</tr>
</form>
<form name="logoutForm" action="logout.do" method="post"">
</form>
</table>
</body>
</html>
-->index.jsp
<%@ page language="java" contentType="text/html;charset=GBK"%>
<%@ include file="taglibs.jsp"%>
<html>
<head>
<title>登陆系统</title>
<link href="styles/news.css" rel="stylesheet" type="text/css">
</head>
<body>
<logic:messagesPresent>
<div class="title">
<bean:message key="errors.header"/>
<ul>
<html:messages id="error">
<li><bean:write name="error"/></li>
</html:messages>
</ul>
</div>
</logic:messagesPresent>
<logic:present name="errMsg">
<div class="title">
<li><bean:write name="errMsg" scope="request"/>
</div>
</logic:present>
<logic:present name="logout">
<div class="title">
<li><bean:write name="logout" scope="request"/>
</div>
</logic:present>
<table width="400" align="center" bgcolor="#99CCCC">
<html:form action="/processLogin">
<tr>
<td>
请输入用户名:
</td>
<td>
<html:text property="user" size="20"/>
</td>
</tr>
<tr>
<td>
请输入密码:
</td>
<td>
<input type="password" name="pass" size="20">
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="确定"> <input type="reset" value="重置">
</td>
</tr>
</html:form>
</table>
</body>
</html>
-->category_view.jsp
<%@ page language="java" contentType="text/html;charset=GBK"%>
<%@ include file="taglibs.jsp"%>
<html>
<head>
<title>分类新闻</title>
<link href="styles/news.css" rel="stylesheet" type="text/css">
</head>
<script language="javascript">
function verifyValue(){
if(loadNewsForm.newsId.checked)
{
loadNewsForm.submit();
return true;
}
for (var i = 0 ; i < loadNewsForm.newsId.length ; i++)
{
if( loadNewsForm.newsId[i].checked )
{
loadNewsForm.submit();
return true;
}
}
alert('请选择要查看的新闻!');
return false;
}
function goMain(){
mainForm.submit();
}
</script>
<body>
<table width="600" align="center" cellpadding="1" bgcolor="#99CCCC">
<form name="loadNewsForm" action="loadNewsReviewByNews.do" method="POST">
<tr>
<td width="60%" colspan="6" align="center">
<p>新闻列表</p> </td>
</tr>
<tr>
<td width="10%" align="center">
请选择 </td>
<td width="10%" align="center">
主题 </td>
<td width="10%" align="center">
发布人 </td>
<td width="10%" align="center">
发布时间 </td>
<td width="10%" align="center">
最后评论时间 </td>
</tr>
<logic:iterate id="item" name="news" indexId="index" scope="request">
<tr>
<td width="10%" align="center">
<input type="radio" name="newsId" value='<bean:write name="item" property="id"/>'>
</td>
<td width="10%" align="center">
<bean:write name="item" property="title"/>
</td>
<td width="10%" align="center">
<bean:write name="item" property="content"/>
</td>
<td width="10%" align="center">
<bean:write name="item" property="postDate"/>
</td>
<td width="10%" align="center">
<bean:write name="item" property="lastModifyDate"/>
</td>
</tr>
</logic:iterate>
<tr>
<td height="52" colspan="6" align="center">
<input type="button" value="查看" onClick="verifyValue();"> <input type="reset" value="重置"> </td>
</tr>
<tr>
<td height="25" colspan="6" align="center"> </td>
</tr>
<tr>
<td height="25" colspan="6" align="center">发表新的新闻</td>
</tr>
</form>
<html:form action="/addNews">
<tr>
<td colspan="6" align="center">
主题: </td>
</tr>
<tr>
<td colspan="6" align="center">
<html:text property="title" size="80"/>
<input type="hidden" name="categoryId" value='<bean:write name="categoryId"/>'>
</td>
</tr>
<tr>
<td colspan="6" align="center">
内容: </td>
</tr>
<tr>
<td colspan="6" align="center">
<html:textarea property="content" cols="80" rows="20"></html:textarea> </td>
</tr>
<tr>
<td colspan="6" align="center">
<input type="submit" value="提交">
<input type="reset" value="重置">
<input type="button" value="返回" onClick="history.go(-1);">
<input type="reset" value="主页" onClick="goMain();"> </td>
</tr>
</html:form>
<form name="mainForm" action="listCate.do" method="post"">
</form>
</table>
</body>
</html>
-->news_view.jsp
<%@ page language="java" contentType="text/html;charset=GBK"%>
<%@ include file="taglibs.jsp"%>
<html>
<head>
<title>新闻详细内容</title>
<link href="styles/news.css" rel="stylesheet" type="text/css">
</head>
<script language="javascript">
function verifyValue(){
if(addNewsReviewForm.content.value == ""){
alert('请输入评论内容!');
addNewsReviewForm.content.focus();
return false;
}
addNewsReviewForm.submit();
}
function goMain(){
mainForm.submit();
}
</script>
<body>
<table width="600" align="center" cellpadding="1" bgcolor="#99CCCC">
<tr>
<td colspan="2" align="center" bgcolor="#999999"><p>新闻标题:<bean:write name="news" property="title"/></p></td>
</tr>
<tr>
<td width="20%" align="center">新闻内容:</td>
<td width="80%" align="center" bgcolor="#eeeeee"><bean:write name="news" property="content"/></td>
</tr>
<tr>
<td colspan="2" align="center" bgcolor="#999999">所有评论如下:</td>
</tr>
<logic:iterate id="item" name="reviews" indexId="index" scope="request">
<tr>
<td colspan="2" bgcolor="#96dede">由网友${item.poster.username}于<bean:write name="item" property="postDate"/>发表的评论如下:</td>
</tr>
<tr>
<td colspan="2" align="center" bgcolor="#ffffff"><bean:write name="item" property="content"/> </td>
</tr>
</logic:iterate>
<html:form action="/addNewsReview">
<input type="hidden" name="newsId" value='<bean:write name="news" property="id"/>'>
<tr>
<td colspan="2" align="center"> 我要评论: </tr>
<tr>
<td colspan="2" align="center"><textarea name="content" cols="80" rows="6"></textarea> </td>
</tr>
<tr>
<td colspan="2" align="center"><input name="button" type="submit" value="提交">
<input name="reset" type="reset" value="重置">
<input name="button" type="button" onClick="history.go(-1);" value="返回">
<input name="reset" type="reset" onClick="goMain();" value="主页"> </td>
</tr>
</html:form>
<form name="mainForm" action="listCate.do" method="post"">
</form>
</table>
</body>
</html>