Spring + Struts + Hibernate联合开发(多对一关系)

来源:互联网 发布:苹果电脑截尺寸软件 编辑:程序博客网 时间:2024/06/06 07:40

一、项目搭建的整体效果:


1、建立好项目后,需要再建立两个单独的源文件夹,分别为test和config

在config下分别建立struts,spring和hibernate三个文件夹,以便分别放这三部分的配置
2、加入Spring支持
Spring的默认配置文件先使用-hibernate.xml,方便配置,将这个生成的配置文件复制多份:
1) -hibernate.xml:放入固定的数据库连接等相关配置
2) -dao.xml:放入DAO相关配置
3) -service.xml:放入Service相关配置
4) -struts.xml:放入Action相关配置
5) -transaction.xml:放入固定的事务处理相关配置。
3、加入Hibernate支持
在-hibernate.xml中补充其他配置 (配置包括dataSource配置、Hibernate的属性配置和hibernateTemplate配置)
在-transaction.xml中补充三个<bean>的配置(配置包括transactionManager配置、transactionInterceptor配置和BeanNameAutoProxyCreator配置)。
4、加入和struts的支持 
加入支持后,将Structs.xml放到config根目录下。Struts的配置文件拆分:
1)Struts.xml:放入一些公共的配置和包含信息
2)Struts-root.xml:里面配置所有不需要登陆就能访问的Action配置。
3)Struts-front.xml:前台普通用户登陆后才能处理的相关功能
4)Struts-back.xml:后台管理员登陆后才能处理的相关功能。
5、然后需要建立一些公共的文件夹或包,以及拷贝公共的类到项目中。
6、生成表的pojo映射
7、在web.xml 中加入监听配置。

8、最后启动服务器,检测环境是否正确

项目运行的效果:


建立数据库的两张表:

CREATE TABLE news_type (       tid                      number(8)           primary key ,       tname                    varchar2(50)        not null                    );INSERT INTO news_type VALUES (1,'经济');INSERT INTO news_type VALUES (2,'军事');INSERT INTO news_type VALUES (3,'娱乐');INSERT INTO news_type VALUES (4,'游戏');INSERT INTO news_type VALUES (5,'广告');CREATE TABLE news (       id                       number(8)           primary key ,       title                    varchar2(50)        not null,       content                  varchar2(500)       not null,       pub_date                 date                not null,       Photo                     varchar2(100),       type_id                  number(8)           not null,       foreign key (type_id) references news_type (tid) on delete cascade );commit;

二、按顺序加入Spring,Hibernate,Struts支持包

建立项目SSHDemo,加入ssh框架支持包的顺序:先Spring,再Hibernate,最后再Struts。
加入Spring支持包:

下一步:

加入Hibernate的支持包:

下一步:选择已经存在的

注意:这里不需要家里SessionFactory,因为这里要是建立,就是需要Hibernate自己管理连接。
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"><bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"><property name="driverClassName" value="oracle.jdbc.OracleDriver"></property><property name="url" value="jdbc:oracle:thin:@localhost:1521:ORCL"></property><property name="username" value="sunxun"></property><property name="password" value="123"></property></bean><bean id="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"><property name="dataSource"><ref bean="dataSource" /></property><property name="hibernateProperties"><props><prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop><prop key="hibernate.show_sql">true</prop><prop key="hibernate.format_sql">true</prop></props></property></bean></beans>
最后加入Struts支持包:Struts选择2.1版

三、Dao层

这里DAO层,有两个:INewsDAO 和 INewsTypeDAO:
IDAO:
public interface IDAO<K, V> {public void doCreate(V vo) throws Exception;public void doUpdate(V vo) throws Exception;public void doRemove(K id) throws Exception;public List<V> findAll() throws Exception;public V findById(K id) throws Exception;public List<V> findAll(int pageNo, int pageSize, String keyword,String column) throws Exception;public int getAllCount(String keyword, String column) throws Exception;}
INewsDAOINewsDAO继承IDAO这个通用抽象类;
public interface INewsDAO extends IDAO<Integer, News> {}
INewsTypeDAO:这是为添加,修改 新闻类型下拉框做准备的。
public interface INewsTypeDAO extends IDAO<Integer, NewsType> {}
INewsDAOImpl:
package org.liky.ssh.dao.impl;import java.util.List;import org.hibernate.criterion.DetachedCriteria;import org.hibernate.criterion.Restrictions;import org.liky.ssh.dao.INewsDAO;import org.liky.ssh.pojo.News;import org.springframework.orm.hibernate3.support.HibernateDaoSupport;public class NewsDAOImpl extends HibernateDaoSupport implements INewsDAO {public void doCreate(News vo) throws Exception {super.getHibernateTemplate().save(vo);}public void doRemove(Integer id) throws Exception {super.getHibernateTemplate().delete(findById(id));}public void doUpdate(News vo) throws Exception {super.getHibernateTemplate().update(vo);}public List<News> findAll() throws Exception {return getHibernateTemplate().loadAll(News.class);}public List<News> findAll(final int pageNo, final int pageSize,final String keyword, final String column) throws Exception {// Spring没有提供针对HQL方式的分页查询方法// 1、使用Criteria来完成分页查询DetachedCriteria c = DetachedCriteria.forClass(News.class);// 加入条件c.add(Restrictions.like(column, "%" + keyword + "%"));List all = super.getHibernateTemplate().findByCriteria(c,(pageNo - 1) * pageSize, pageSize);// 2、自行扩展Spring功能,添加分页查询方法,使用的方式为匿名内部类// List all = super.getHibernateTemplate().executeFind(// new HibernateCallback() {// public Object doInHibernate(Session session)// throws HibernateException, SQLException {// String hql = "FROM News AS n WHERE n." + column// + " LIKE ?";// Query query = session.createQuery(hql);// query.setString(0, "%" + keyword + "%");// query.setFirstResult((pageNo - 1) * pageSize);// query.setMaxResults(pageSize);//// return query.list();// }// });return all;}public News findById(Integer id) throws Exception {return super.getHibernateTemplate().get(News.class, id);}public int getAllCount(String keyword, String column) throws Exception {String hql = "SELECT COUNT(n) FROM News AS n WHERE n." + column+ " LIKE ?";List all = super.getHibernateTemplate().find(hql, "%" + keyword + "%");return ((Long) all.get(0)).intValue();}}
注:

在这里调用的HibernateTemplate的常用操作有以下几类:

1)  继承自Session操作:save(),update(),delete(),get/load(),saveOrUpdate()

2)  扩展Session的操作:loadAll()(查询全部数据),deleteAll(Collection)(删除一组数据),saveOrUpdateAll(Collection)

3)  HQL操作:find(hql,参数),返回的是List集合

4)  Criteria操作:findByCriteria,可以实现分页功能

5)  扩展操作:executeFind,execute,自行通过匿名内部类扩展Spring操作。

这里我们还要养成习惯:就是写完一部代码,就立刻写它的配置文件:

<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate"><property name="sessionFactory"><ref bean="sessionFactory" /></property></bean><bean id="newsDAOImpl" class="org.liky.dao.impl.NewsDAOImpl"><property name="hibernateTemplate"><ref bean="hibernateTemplate" /></property></bean>

INewsTypeDAOImpl:这里只需要加入一个查询全部的方法就可以了。
public List<NewsType> findAll() throws Exception {return super.getHibernateTemplate().loadAll(NewsType.class);}<strong></strong>

四、Service层

注:这一层我们需要注意,我们在DAO层用的是Spring提供的getHibernateTemplate来处理数据,那么我们希望是Spring的自动在这一层关闭连接和添加事务处理,那么我们就必须定义规则,Sping的AOP操作;
INewsService:
package org.liky.ssh.back.service;import java.util.List;import java.util.Map;import org.liky.ssh.pojo.News;import org.liky.ssh.pojo.NewsType;public interface INewsService {public List<NewsType> insertPre() throws Exception;public void insert(News news) throws Exception;public void update(News news) throws Exception;public void delete(int id) throws Exception;public Map<String, Object> updatePre(int id) throws Exception;public Map<String, Object> list(int pageNo, int pageSize, String column,String keyword) throws Exception;}
INewsServiceImpl:这里新闻的类型也加入进来
package org.liky.ssh.back.service.impl;import java.util.HashMap;import java.util.List;import java.util.Map;import org.liky.ssh.back.service.INewsService;import org.liky.ssh.dao.INewsDAO;import org.liky.ssh.dao.INewsTypeDAO;import org.liky.ssh.pojo.News;import org.liky.ssh.pojo.NewsType;public class NewsServiceImpl implements INewsService {private INewsDAO newsdao;private INewsTypeDAO typedao;public void delete(int id) throws Exception {newsdao.doRemove(id);}public Map<String, Object> updatePre(int id) throws Exception {Map<String, Object> map = new HashMap<String, Object>();map.put("allType", typedao.findAll());map.put("news", newsdao.findById(id));return map;}public void insert(News news) throws Exception {newsdao.doCreate(news);}public void update(News news) throws Exception {newsdao.doUpdate(news);}public Map<String, Object> list(int pageNo, int pageSize, String column,String keyword) throws Exception {Map<String, Object> map = new HashMap<String, Object>();map.put("allNews", newsdao.findAll(pageNo, pageSize, keyword, column));map.put("allCount", newsdao.getAllCount(keyword, column));return map;}public void setNewsdao(INewsDAO newsdao) {this.newsdao = newsdao;}public List<NewsType> insertPre() throws Exception {return typedao.findAll();}public void setTypedao(INewsTypeDAO typedao) {this.typedao = typedao;}}
分别写配置文件:
首先,在applicationContext-service中加入Service的配置:
<span style="white-space:pre"></span><bean id="newsServiceImpl" class="org.liky.ssh.back.service.impl.NewsServiceImpl"><property name="newsdao"><ref bean="newsDAOImpl" /></property><property name="typedao"><ref bean="newsTypeDAOImpl" /></property></bean>
然后,在applicationContext-transaction中加入AOP部分的三个<bean>,这三个bean文件在ssh框架中基本上是固定不变的。
<span style="white-space:pre"></span><bean id="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager"><property name="sessionFactory"><ref bean="sessionFactory" /></property></bean><bean id="transactionInterceptor"class="org.springframework.transaction.interceptor.TransactionInterceptor"><property name="transactionManager"><ref bean="transactionManager" /></property><!-- 配置事务处理的方法和方式--><property name="transactionAttributes"><props><!--表示所有方法都要关闭连接,并进行事务处理.PROPAGATION_REQUIRED:如果之前有事务,则将当前操作合并到之前的事务中,如果之前没有事务,则开始一个新的事务。PROPAGATION_REQUIRED_NEW:无论之前是否有事务,都开始一个新的事务。PROPAGATION_REQUIRED_NEVER:不使用事务处理,使用自动提交方式。--><prop key="*">PROPAGATION_REQUIRED</prop></props></property></bean><beanclass="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"><property name="beanNames"><list><value>*ServiceImpl</value></list></property><property name="interceptorNames"><list><value>transactionInterceptor</value></list></property></bean>

、完成Action

这里所有的set/get方法省略:所有的private属性,都需要get/set.
import java.io.File;import java.util.List;import java.util.Map;import org.apache.struts2.ServletActionContext;import org.liky.ssh.back.service.INewsService;import org.liky.ssh.pojo.News;import org.liky.ssh.pojo.NewsType;import org.liky.ssh.util.FileUtils;import org.liky.ssh.util.LogUtils;import com.opensymphony.xwork2.ActionSupport;public class NewsAction extends ActionSupport {private List<NewsType> allType;private INewsService service;private News news;private File photo;private String photoFileName;private String message;private String url;private int pageNo = 1;private int pageSize = 5;private String keyword = "";private String column = "title";private List<News> allNews;private int count;public String updatePre() throws Exception {Map<String, Object> map = service.updatePre(news.getId());allType = (List<NewsType>) map.get("allType");news = (News) map.get("news");return "update";}public String update() throws Exception {if (photo != null && photo.length() > 0) {// 传了新文件, 删除原有文件String filePath = ServletActionContext.getServletContext().getRealPath("/upload")+ "/";FileUtils.dropFile(filePath, news.getPhoto());// 传新的String fileName = FileUtils.saveFile(photo, filePath, photoFileName);news.setPhoto(fileName);}service.update(news);LogUtils.addInfo("修改结束...." + news.getId());message = "修改成功";url = "pages/back/news_list.action";return "forward";}public String delete() throws Exception {service.delete(news.getId());String filePath = ServletActionContext.getServletContext().getRealPath("/upload")+ "/";FileUtils.dropFile(filePath, news.getPhoto());LogUtils.addInfo("删除结束...." + news.getId());message = "删除成功";url = "pages/back/news_list.action";return "forward";}public String list() throws Exception {Map<String, Object> map = service.list(pageNo, pageSize, column,keyword);allNews = (List<News>) map.get("allNews");count = (Integer) map.get("allCount");return "list";}public String insert() throws Exception {// 取得要保存的真实路径String savePath = ServletActionContext.getServletContext().getRealPath("/upload")+ "/";String fileName = FileUtils.saveFile(photo, savePath, photoFileName);news.setPhoto(fileName);service.insert(news);LogUtils.addInfo("新闻添加完成: " + news.getId() + " --> 添加人是: zhangsan");message = "添加成功";url = "index.jsp";return "forward";}public String insertPre() throws Exception {allType = service.insertPre();return "insert";}

六、公共类FIleUtils,处理图片的上传的:

package org.liky.ssh.util;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.util.UUID;public class FileUtils {/** * 保存文件功能 *  * @param orgFile *            要保存的文件 * @param savePath *            保存的位置(真实路径) * @param fileName *            原文件名(为了取得扩展名) * @return 生成的文件名 * @throws Exception */public static String saveFile(File orgFile, String savePath,String orgFileName) throws Exception {String fileName = UUID.randomUUID().toString();String extName = orgFileName.substring(orgFileName.lastIndexOf("."));FileOutputStream os = new FileOutputStream(new File(savePath + fileName+ extName));FileInputStream is = new FileInputStream(orgFile);byte[] data = new byte[1024];int length = 0;try {while ((length = is.read(data)) != -1) {os.write(data, 0, length);}} catch (Exception e) {e.printStackTrace();} finally {is.close();os.close();}return fileName + extName;}public static void dropFile(String filePath, String fileName) {File file = new File(filePath + fileName);if (file.exists()) {file.delete();}}}

、页面的编辑:

先完成struts的配置操作:
<struts><package name="back" namespace="/pages/back" extends="my-default"><action name="news_*" class="newsAction" method="{1}"><result name="insert">/pages/back/news/news_insert.jsp</result><result name="list">/pages/back/news/news_list.jsp</result><result name="update">/pages/back/news/news_update.jsp</result><interceptor-ref name="fileUpload"><param name="maximumSize">700000</param><param name="allowedExtensions">png,jpg,bmp,gif</param></interceptor-ref><interceptor-ref name="defaultStack"></interceptor-ref></action></package></struts>    
news_list.jsp:
<span style="color: rgb(51, 51, 51); white-space: pre; "></span><span style="color:#333333;"><body><center><table border="1" width="80%"><tr><td>编号</td><td>标题</td><td>内容</td><td>所属分类</td><td>发布日期</td><td>图片</td><td>操作</td></tr><s:if test="allNews != null && allNews.size() > 0"><s:iterator value="allNews" ><tr><td>${id }</td><td>${title }</td><td>${content }</td><td>${newsType.tname}</td><td>${pubDate }</td><td><img src="upload/${photo==null?'nophoto.png':photo}" width="100" height="75"/></td><td><a href="pages/back/news_updatePre.action?news.id=${id}">修改</a><a href="pages/back/news_delete.action?news.id=${id}&news.photo=${photo}"onclick="return window.confirm('确定要删除该数据吗?');">删除</a></td></tr></s:iterator></s:if></table></span><span style="color: rgb(51, 51, 51); white-space: pre; "></span><span style="color:#cc0000;">//下面的时分页的组件插入操作,这在我之前的博文中介绍过:</span><span style="color:#333333;"><jsp:include page="/split_page_plugin.jsp"><jsp:param value="${pageNo}" name="pageNo" /><jsp:param value="${pageSize}" name="pageSize" /><jsp:param value="${column}" name="column" /><jsp:param value="${keyword}" name="keyword" /><jsp:param value="${count}" name="count" /><jsp:param value="pages/back/news_list.action" name="URL" /><jsp:param value="title:标题|content:内容" name="columnData" /><jsp:param value="1" name="pageStyle" /></jsp:include></center></body></span>
news_insert.jsp:
<span style="white-space:pre"></span><body><center><s:form action="news_insert.action" method="post" namespace="/pages/back" enctype="multipart/form-data">新闻标题: <s:textfield name="news.title"></s:textfield> <br/>新闻内容: <s:textfield name="news.content"></s:textfield> <br/>发布日期: <s:textfield name="news.pubDate"></s:textfield> <br/>新闻类型: <s:select list="allType" name="news.newsType.tid" listKey="tid" listValue="tname"></s:select><br/>新闻照片: <s:file name="photo"></s:file><br/><s:submit value="添加"></s:submit></s:form></center></body>
news_update.jsp:
<span style="white-space:pre"></span><body><center><s:form action="news_update.action" method="post" namespace="/pages/back" enctype="multipart/form-data">新闻标题: <s:textfield name="news.title"></s:textfield> <br/>新闻内容: <s:textfield name="news.content"></s:textfield> <br/>发布日期: <s:textfield name="news.pubDate"></s:textfield> <br/>新闻类型: <s:select list="allType" name="news.newsType.tid" listKey="tid" listValue="tname"></s:select><br/>新闻照片: <s:file name="photo"></s:file><br/>原照片: <img src="upload/${news.photo==null?'nophoto.png':news.photo }"/> <br/><s:if test="news.photo != null"><s:hidden name="news.photo"></s:hidden></s:if><s:hidden name="news.id"></s:hidden><s:submit value="添加"></s:submit></s:form></center></body>

上面的页面的代码是部分的,仅供参照。



1 0