Struts2+Hibernate3+Spring2的简单小例子

    今天这个例子主要是为了学习Hibernate,之前已经对Struts有了了解,因此加上Struts的控制,另外稍微加上了一点点Spring&Struts的使用。

    使用工具:eclipse for J2EE,Tomcat6.0,JDK1.6,SQLServer2000。

    此例子重点在于使用Hibernate的对数据库表的增删改查功能,以及分页的实现。

    使用数据库:Pubs,复制其中的表titles为newtitles以供使用,复制表的代码为:

    use pubs

    select * into newtitles from titles;

    alter table newtitles add primary key(title_id);

 

    首先建立工程取名SSH2_Example(当然工程名任意起),然后环境配置,将所有要用到的jar包复制进工程lib里,关于jar包的引用就不多说了,这是个大问题,也是个应该没啥问题的问题,so...

 

    工程下新建包,com.hp.db,这个包里我们放HibernateSessionFactory这个类,也是Hibernate的关键类,其功能就是提供数据库的连接,是个Session,相当于JDBC里的Connection,还可以提供事务的共通代码,代码如下:

package com.hp.db; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; public class HibernateSessionFactory { /** Hibernate的配置文件的位置 **/ private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml"; /** 设置本地线程变量,使多线程开发时保证线程的安全,Session和Transaction **/ private static final ThreadLocal threadLocal = new ThreadLocal(); private static final ThreadLocal threadtrans = new ThreadLocal(); /** configuration */ private static Configuration configuration = new Configuration(); /** 定义Hibernate的Session类工厂 **/ private static org.hibernate.SessionFactory sessionFactory; /** 定义config要指定的文件目录 **/ private static String configFile = CONFIG_FILE_LOCATION; /** Default Constructor **/ private HibernateSessionFactory() { } /** getSession():get one connection **/ public static Session getSession() throws HibernateException { // 通过本地线程变量来获取Session Session session = (Session) threadLocal.get(); // 因为ThreadLocal未initialvalue()初始化,则值为null,第一次 if (session == null || !session.isOpen()) { // 如果Session为空或者未打开连接则先通过类工厂重建Session即Connection,或者打开Session if (sessionFactory == null) { rebuildSessionFactory(); } //openSession()--创建一个session //getCurrentSession()--得到当前的session //区别在于openSession()必须手动关闭session session = (sessionFactory != null) ? sessionFactory.openSession() : null; threadLocal.set(session); } return session; } /** 类工厂创建类 **/ public static void rebuildSessionFactory() { try { // config文件找到需要调用的文件 configuration.configure(configFile); // Session创建(Hibernate内部类完成) sessionFactory = configuration.buildSessionFactory(); } catch (Exception e) { // 若创建不成功,则控制台输出提示 System.err.println("%%%% Error Creating SessionFactory %%%%"); e.printStackTrace(); } } /** Close the connection */ public static void closeSession() throws HibernateException { Session session = (Session) threadLocal.get(); threadLocal.set(null); if (session != null) { session.close(); } } /** SessionFactory的属性get() */ public static org.hibernate.SessionFactory getSessionFactory() { return sessionFactory; } /** SessionFactory的属性set() */ public static void setConfigFile(String configFile) { HibernateSessionFactory.configFile = configFile; sessionFactory = null; } /** configuration的属性get(),set()无,常量已经指定值 */ public static Configuration getConfiguration() { return configuration; } /** 事务开始 **/ public static void beginTransaction() { Transaction ts = (Transaction) threadtrans.get(); try { if (ts == null) { ts = getSession().beginTransaction(); threadtrans.set(ts); } } catch (HibernateException e) { e.printStackTrace(); } } /** 事务提交 **/ public static void commitTransaction() { Transaction ts = (Transaction) threadtrans.get(); try { if (ts != null && !ts.wasCommitted() && !ts.wasRolledBack()) { ts.commit(); threadtrans.set(null); } } catch (HibernateException e) { rollbackTransaction(); e.printStackTrace(); } } /** 事务回滚 **/ public static void rollbackTransaction() { Transaction ts = (Transaction) threadtrans.get(); try { if (ts != null && !ts.wasCommitted() && !ts.wasRolledBack()) { ts.rollback(); threadtrans.set(null); } } catch (HibernateException e) { e.printStackTrace(); } } }

    可以看到,HibernateSessionFactory类还需要一个Hibernate的配置文件,来共通完成对数据库的连接,配置文件名:hibernate.cfg.xml,放在src目录下,内容如下:

    org.hibernate.dialect.SQLServerDialect True sqlserver org.hibernate.connection.ProxoolConnectionProvider proxool.xml

    hibernate.cfg.xml中我们使用了连接池的技术,也需要个配置文件,文件名:proxool.xml,也同样放到src目录下,代码如下:

sqlserver jdbc:jtds:sqlserver://localhost:1433;databasename=pubs net.sourceforge.jtds.jdbc.Driver 10

    在hibernate.cfg.xml中我们看到有个Java类到数据库表的映射文件,,这个是配置数据库里的表对应程序中的POJO类的配置文件,新建个包,com.hp.voo,用来放需要用到的POJO类,首先就是数据表的映射类,类名:Newtitles,代码如下:

package com.hp.voo; import java.util.Date; /** * 同表名的映射类 * 数据类型都选用了对象类型,而没有使用基本数据类型,原因是属性和字段对应,只有对象才能 * 表示空值的概念,即数据库中的NULL。 * 另外,该对象实现了java.io.Serializable接口,表示这个对象能够进行串行化操作,例如保 * 存到硬盘、数据库或网络传输。 * */ public class Newtitles implements java.io.Serializable { private String titleId; private String title; private String type; private String pubId; private Double price; private Double advance; private Integer royalty; private Integer ytdSales; private String notes; private Date pubdate; /** Default constructor */ public Newtitles() { } /** Minimal constructor */ public Newtitles(String titleId, String title, String type, Date pubdate) { this.titleId = titleId; this.title = title; this.type = type; this.pubdate = pubdate; } /** Full constructor */ public Newtitles(String titleId, String title, String type, String pubId, Double price, Double advance, Integer royalty, Integer ytdSales, String notes, Date pubdate) { this.titleId = titleId; this.title = title; this.type = type; this.pubId = pubId; this.price = price; this.advance = advance; this.royalty = royalty; this.ytdSales = ytdSales; this.notes = notes; this.pubdate = pubdate; } public String getTitleId() { return titleId; } public void setTitleId(String titleId) { this.titleId = titleId; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getPubId() { return pubId; } public void setPubId(String pubId) { this.pubId = pubId; } public Double getPrice() { return price; } public void setPrice(Double price) { this.price = price; } public Double getAdvance() { return advance; } public void setAdvance(Double advance) { this.advance = advance; } public Integer getRoyalty() { return royalty; } public void setRoyalty(Integer royalty) { this.royalty = royalty; } public Integer getYtdSales() { return ytdSales; } public void setYtdSales(Integer ytdSales) { this.ytdSales = ytdSales; } public String getNotes() { return notes; } public void setNotes(String notes) { this.notes = notes; } public Date getPubdate() { return pubdate; } public void setPubdate(Date pubdate) { this.pubdate = pubdate; } }

    Newtitles.hbm.xml也放在com.hp.voo包中,代码如下:

    同时,com.hp.voo包中,我们需要放入一个分页显示的POJO类,类中属性为分页所需的各种属性,譬如当前页码,总记录数,当前页的数据等等,类名:PageBean,代码如下:

package com.hp.voo; import java.util.ArrayList; import java.util.List; public class PageBean { private int allcount; //总记录数 private int allpage; //总页数 private int pagecode; //页码 private int pagesize; //每页记录数 private List data = new ArrayList(); //当前页数据 public int getAllcount() { return allcount; } public void setAllcount(int allcount) { this.allcount = allcount; } public int getAllpage() { return allcount % pagesize == 0 ? allcount / pagesize : allcount / pagesize + 1; } public List getData() { return data; } public void setData(List data) { this.data = data; } public int getPagecode() { return pagecode; } public void setPagecode(int pagecode) { this.pagecode = pagecode; } public int getPagesize() { return pagesize; } public void setPagesize(int pagesize) { this.pagesize = pagesize; } }

    然后新建包,com.hp.base,这个包中将存放所有增删改查以及分页的基础方法,通过用泛型的方式,使其成为任何业务Bean都可以使用的通用增删改查的基础类,为了实现面向接口编程,我们这个包里放入一个接口,和一个实现类,接口名:IGenericDao,代码如下:

package com.hp.base; import java.io.Serializable; import java.util.List; import com.hp.voo.PageBean; /** * DAO=Data Access Object(数据访问对象) DAO模式接口,定义DAO的CRUD操作的抽象方法,用泛型实现通用的DAO实现 * */ public interface IGenericDao { // 增 public T create(T entity); // 删 public void delete(ID id); // 改 public T update(T entity); // 查找所有记录 public List findAll(); // 按ID查找 public T findById(ID id); // 查找对象 public List findByHQL(String hql, Object[] params); // 分页显示 public PageBean findByPage(String hql, int pagecode, int pagesize, Object[] params); // 批量更新 public void bulkUpdate(String hql, Object[] params); }

    实现类类名:GenericHibernateDao,代码如下:

package com.hp.base; import java.io.Serializable; import java.lang.reflect.ParameterizedType; import java.util.ArrayList; import java.util.List; import org.hibernate.Criteria; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.criterion.Criterion; import com.hp.db.HibernateSessionFactory; import com.hp.voo.PageBean; /** * DAO=Data Access Object(数据访问对象) DAO模式方法,定义DAO的CRUD操作的实现方法,用泛型实现通用的DAO实现 * */ public class GenericHibernateDao implements IGenericDao { // 持久化类 private Class persistentClass; public Class getPersistentClass() { return persistentClass; } // 开始事务 @SuppressWarnings("unchecked") public GenericHibernateDao() { this.persistentClass = (Class) ((ParameterizedType) getClass() .getGenericSuperclass()).getActualTypeArguments()[0]; HibernateSessionFactory.beginTransaction(); } // 增加 public T create(T entity) { Session session = HibernateSessionFactory.getSession(); session.save(entity); return entity; }; // 删除 public void delete(ID id) { Session session = HibernateSessionFactory.getSession(); session.delete(findById(id)); }; // 修改 public T update(T entity) { Session session = HibernateSessionFactory.getSession(); session.update(entity); return entity; } // 查找所有记录 public List findAll() { return findByCreteria(new ArrayList()); }; // 内部使用条件查询方法 @SuppressWarnings("unchecked") public List findByCreteria(List criterion) { Criteria crit = HibernateSessionFactory.getSession().createCriteria( getPersistentClass()); for (Criterion c : criterion) { crit.add(c); } return crit.list(); } // 按主键查询 @SuppressWarnings("unchecked") public T findById(ID id) { Session session = HibernateSessionFactory.getSession(); T entity = (T) session.load(persistentClass, id); return entity; }; // 按HQL查询 @SuppressWarnings("unchecked")// 执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型。 public List findByHQL(String hql, Object[] params) { Session session = HibernateSessionFactory.getSession(); Query q = session.createQuery(hql); for (int i = 0; i < params.length; i++) q.setParameter(i, params[i]); return q.list(); }; // 分页查询 @SuppressWarnings("unchecked") public PageBean findByPage(String hql, int pagecode, int pagesize, Object[] params) { Session session = HibernateSessionFactory.getSession(); PageBean pb = new PageBean(); Query q = session.createQuery(hql); for (int i = 0; i < params.length; i++) q.setParameter(i, params[i]); q.setMaxResults(pagesize); q.setFirstResult((pagecode - 1) * pagesize); pb.setData(q.list()); q = session.createQuery("select count(*) " + hql.substring(hql.toLowerCase().indexOf("from"))); for (int i = 0; i < params.length; i++) q.setParameter(i, params[i]); pb.setAllcount(Integer.parseInt(q.uniqueResult().toString())); pb.setPagecode(pagecode); pb.setPagesize(pagesize); return pb; }; // 批量更新 public void bulkUpdate(String hql, Object[] params) { Session session = HibernateSessionFactory.getSession(); HibernateSessionFactory.beginTransaction(); Query q = session.createQuery(hql); for (int i = 0; i < params.length; i++) q.setParameter(i, params[i]); q.executeUpdate(); }; }

    下面再建个包,com.hp.dao,此包为业务类包,即我们要做的所有业务,同样用接口和实现类的方式来写,同时要继承刚才com.hp.base包中的基础接口和类,dao包下接口名为ITitlesDao,代码如下:

package com.hp.dao; import java.util.List; import com.hp.voo.Newtitles; import com.hp.voo.PageBean; /** * 定义业务用到的DAO方法接口,继承了基础CRUD的业务接口 * */ public interface ITitlesDao extends com.hp.base.IGenericDao { //实现分页的方法 public PageBean selectTitlesByPage(int pagecode, int pagesize); }

    实现类的类名为TitlesDaoImp,代码如下:

package com.hp.dao; import com.hp.base.GenericHibernateDao; import com.hp.voo.Newtitles; import com.hp.voo.PageBean; /** * 定义业务用到的DAO方法,继承了基础CRUD的业务方法 * */ public class TitlesDaoImp extends GenericHibernateDao implements ITitlesDao { // 实现分页的方法 public PageBean selectTitlesByPage(int pagecode, int pagesize) { return this.findByPage("select a from Newtitles as a", pagecode, pagesize, new Object[] {}); }; }

    接下来新建包,com.hp.actions,我们在这里放入我们的业务action,类名CrudAction,代码如下:

package com.hp.actions; import com.hp.dao.ITitlesDao; import com.hp.dao.TitlesDaoImp; import com.hp.voo.Newtitles; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.ModelDriven; @SuppressWarnings("serial") public class CrudAction extends ActionSupport implements ModelDriven { //实例化POJO private Newtitles titles = new Newtitles(); //DAO实现接口创建新业务实例 private ITitlesDao td = new TitlesDaoImp(); private int pagecode = 1; public int getPagecode() { return pagecode; } public void setPagecode(int pagecode) { this.pagecode = pagecode; } //获得POJO(页面同名) public Newtitles getModel() { return titles; } //返回分页数据 public String bypage() throws Exception { ActionContext.getContext().put("tlist", td.selectTitlesByPage(pagecode, 5)); return SUCCESS; } //添加新数据 public String create() throws Exception { td.create(titles); return bypage(); } //删除 public String delete() throws Exception { td.delete(titles.getTitleId()); return bypage(); } //更新 public String update() throws Exception { td.update(titles); return bypage(); } //更新页面 public String preupdate() throws Exception { Newtitles t = td.findById(titles.getTitleId()); titles.setTitle(t.getTitle()); titles.setPrice(t.getPrice()); titles.setType(t.getType()); titles.setPubdate(t.getPubdate()); return "input"; } //添加页面 public String precreate() throws Exception { return "input"; } }

    继续新建个包,com.hp.filters,此包下放入所有的过滤器,我们主要是为了让页面提交时事务能自动提交然后关闭Session,所以使用它,过滤器名:SessionFilter2,代码如下:

package com.hp.filters; 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.HttpServlet; import com.hp.db.HibernateSessionFactory; public class SessionFilter2 extends HttpServlet implements Filter { public SessionFilter2() { // TODO Auto-generated constructor stub } public void destroy() { // TODO Auto-generated method stub } public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException { try { arg2.doFilter(arg0, arg1); HibernateSessionFactory.commitTransaction(); } catch (Exception e) { HibernateSessionFactory.rollbackTransaction(); } finally { HibernateSessionFactory.closeSession(); } } public void init(FilterConfig fConfig) throws ServletException { // TODO Auto-generated method stub } }

    src下的包都建完了,最后一项需要写struts.xml文件,目录也是src下,代码如下:

/TitlesList.jsp /AddTitles.jsp

    注意,里面多了一句使用Spring实例Action的命令,而且class="crudBySpring"一句如果不用Spring的话,需要写的是Action的路径,现在使用了Spring的话,只需要定义个名字跟Spring里的配置文件里的某个名字相同,会自动去找到Spring里同名的属性里的Action的路径,我们看到Spring的作用其实就是截了一下Action的创建的过程。

    下面是spring的配置文件,文件名:applicationContext.xml,目录在WEB-INF下,代码如下:

    最后就差页面和web.xml文件了,代码如下:

    index.jsp:

    <%@ page language="java" contentType="text/html; charset=windows-31j" pageEncoding="windows-31j"%>

Loading...

    TitlesList.jsp:

<%@ page language="java" contentType="text/html; charset=windows-31j" pageEncoding="windows-31j"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> Insert title here

Select the book

Book IDBook NMTypePriceDateDo something
${title.titleId} ${title.title} ${title.type} ${p} ${d}Delete  Update
${i} ${i}   Count:${tlist.allcount};${tlist.pagecode}/${tlist.allpage};

    AddTitles.jsp:

<%@ page language="java" contentType="text/html; charset=windows-31j" pageEncoding="windows-31j"%> <%@ taglib uri="/struts-tags" prefix="s" %> Insert title here

Add Boooks






    web.xml:

struts2 org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter SessionFilter2 com.hp.filters.SessionFilter2 SessionFilter2 /* struts2 /* org.springframework.web.context.ContextLoaderListener

搞定收工。。。

   

   

你可能感兴趣的:(SSH2学习笔记)