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

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


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>

	<bean
		class="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}"
									οnclick="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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值