一、架构 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>