13.3 Struts 2整合Hibernate开发
为了降低Struts 2和Hibernate框架之间的耦合度,一般不会在Struts 2的Action中调用Hibernate的API。而是通过使用DAO组件并结合Struts 2以及Hibernate框架从而将Struts 2与Hibernate以低耦合度的方式进行整合。
13.3.1 整合策略
在整合Struts 2和Hibernate开发之前,首先必须清楚分层的思想。一个好的应用一般都采用多层设计。下面采用的是4层架构,如图13.8所示。其中最上一层为表现层,该层主要负责和用户进行交互,并通过调用业务逻辑层代码实现判断等操作。第二层为业务逻辑层,该层专注于实现业务逻辑功能,通过调用持久层代码来操作数据库。第三层为持久化层,该层专注于持久化操作,而不用涉及业务逻辑。第四层为数据库层,即为使用的数据库。
这里的表现层使用Struts 2框架来实现,而持久层使用DAO结合Hibernate框架来实现。下面通过一个产品管理示例来演示整合策略。
图13.8 应用分层
13.3.2 持久层设计
首先新建Hibernate配置文件以及持久化类和映射文件。这部分内容同前面的示例代码完全相同。
新建ProductDao接口,该接口中包含5个方法,分别用来进行添加产品、删除产品、更新产品、查询所有产品、按ID查询产品操作,代码如下所示。
package net.hncu.dao; import java.util.List; import net.hncu.po.Product; public interface ProductDao { //添加产品 public void save(Product p); //删除产品 public void delete(String id); //更新产品 public void update(Product p); //查询所有产品 public List queryAll(); //按id查询产品 public Product queryByID(String id); }
新建ProductDaoImpl类,该类实现ProductDao接口。在该类中添加相应方法的具体操作,代码如下所示。
package net.hncu.dao; import java.util.Iterator; import java.util.List; import net.hncu.po.Product; import net.hncu.util.HibernateUtil; import org.hibernate.Query; import org.hibernate.Session; public class ProductDaoImpl implements ProductDao{ //添加产品 public void save(Product p) { //创建Session Session session = HibernateUtil.getSession(); //开启事务 session.beginTransaction(); //保存数据 session.save(p); //事务提交 session.getTransaction().commit(); //关闭session HibernateUtil.closeSession(session); } //删除产品 public void delete(String id) { //创建Session Session session = HibernateUtil.getSession(); //开启事务 session.beginTransaction(); // 使用HQL查询 String hql = "DELETE Product WHERE id=? "; Query q = session.createQuery(hql); q.setString(0, id); q.executeUpdate(); //事务提交 session.getTransaction().commit(); //关闭session HibernateUtil.closeSession(session); } //更新产品 public void update(Product p) { //创建Session Session session = HibernateUtil.getSession(); //开启事务 session.beginTransaction(); //保存数据 session.update(p); //事务提交 session.getTransaction().commit(); //关闭session HibernateUtil.closeSession(session); } //查询所有产品 public List queryAll() { // 创建Session Session session = HibernateUtil.getSession(); // 使用HQL查询 String hql = "FROM Product as pro"; // 通过Query方法查询 Query q = session.createQuery(hql); //查询结果保存到list中 List list = q.list(); //关闭session HibernateUtil.closeSession(session); return list; } //按id查询产品 public Product queryByID(String id) { // 创建Session Session session = HibernateUtil.getSession(); // 使用HQL查询 String hql = "FROM Product as pro WHERE pro.id=? "; // 通过Query方法查询 Query q = session.createQuery(hql); q.setString(0, id); //查询结果保存到list中 List list = q.list(); Product p = null; //遍历是否存在该id的产品,如果存在则进行输出 Iterator iter = list.iterator(); if(iter.hasNext()) { p = (Product) iter.next(); } //关闭session HibernateUtil.closeSession(session); return p; } }
新建DAO工厂类,通过调用该类的getDaoInstance()方法能返回一个ProductDaoImpl实例,代码如下所示。
package net.hncu.factory; import net.hncu.dao.ProductDao; import net.hncu.dao.ProductDaoImpl; public class DaoFactory { public static ProductDao getDaoInstance(){ return new ProductDaoImpl(); } }
13.3.3 业务逻辑组件
新建业务逻辑组件接口,该接口中定义了添加产品、删除产品、更新产品、查询所有产品、按ID查询产品5个方法,代码如下所示。
package net.hncu.service; import java.util.List; import net.hncu.po.Product; public interface ProductService { //添加产品 public void addProduct(Product p); //删除产品 public void deleteProduct(String id); //更新产品 public void updateProduct(Product p); //查询所有产品 public List queryAllProduct(); //按id查询产品 public Product queryProductByID(String id); }
新建业务逻辑组件实现类,该类实现业务逻辑组件接口。业务逻辑组件通过调用DAO组件从而实现业务逻辑操作,代码如下所示。
package net.hncu.service; import java.util.List; import net.hncu.dao.ProductDao; import net.hncu.factory.DaoFactory; import net.hncu.po.Product; public class ProductServiceImpl implements ProductService { // 添加产品 public void addProduct(Product p) { //从DAO工厂取得DAO实现类实例 ProductDao dao = DaoFactory.getDaoInstance(); //判断是否存在相同ID的产品 if (dao.queryByID(p.getId()) == null) { //如果不存在,而调用DAO实现类进行保存 dao.save(p); } else { //否则提示错误信息 System.out.println("id已经存在"); } } // 删除产品 public void deleteProduct(String id) { //从DAO工厂取得DAO实现类实例 ProductDao dao = DaoFactory.getDaoInstance(); //判断是否存在相同ID的产品 if (dao.queryByID(id) ! = null) { //如果存在,而调用DAO实现类进行删除 dao.delete(id); } else { //否则提示错误信息 System.out.println("id不存在"); } } // 更新产品 public void updateProduct(Product p) { //从DAO工厂取得DAO实现类实例 ProductDao dao = DaoFactory.getDaoInstance(); //判断是否存在相同ID的产品 if (dao.queryByID(p.getId()) ! = null) { //如果存在,而调用DAO实现类进行更新 dao.update(p); } else { //否则提示错误信息 System.out.println("id不存在"); } } // 查询所有产品 public List queryAllProduct() { //从DAO工厂取得DAO实现类实例 ProductDao dao = DaoFactory.getDaoInstance(); //调用DAO实现类进行查询 return dao.queryAll(); } // 按id查询产品 public Product queryProductByID(String id) { //从DAO工厂取得DAO实现类实例 ProductDao dao = DaoFactory.getDaoInstance(); //调用DAO实现类进行查询 return dao.queryByID(id); } }
新建业务逻辑组件工厂类,通过调用该类的getServiceInstance ()方法能返回一个业务逻辑组件实现类实例,代码如下所示。
package net.hncu.factory; import net.hncu.service.ProductService; import net.hncu.service.ProductServiceImpl; public class ServiceFactory { public static ProductService getServiceInstance(){ return new ProductServiceImpl(); } }
13.3.4 查询所有产品
新建业务控制器ShowAllP,在该Action中通过业务逻辑组件工厂获得业务逻辑组件,并通过调用业务逻辑组件获得所有的商品,最后将产品集合储存在request范围中,代码如下所示。
package net.hncu.action; import java.util.List; import org.apache.struts2.ServletActionContext; import net.hncu.factory.ServiceFactory; import net.hncu.service.ProductService; import com.opensymphony.xwork2.ActionSupport; public class ShowAllAction extends ActionSupport{ public String execute() throws Exception { //通过业务逻辑组件工厂获得业务逻辑组件 ProductService ps = ServiceFactory.getServiceInstance(); //通过调用业务逻辑组件获得所有的产品 List all = ps.queryAllProduct(); //将所有产品List储存在request范围中 ServletActionContext.getRequest().setAttribute("all", all); return SUCCESS; } }
新建产品显示页。使用iterator标签遍历产品集合,并使用property标签进行输出,代码如下所示。
<%@page contentType="text/html; charset=gb2312"%> <%@taglib prefix="s" uri="/struts-tags"%> <html> <head> <title>产品列表</title> </head> <body> <center> <h2>产品列表</h2> <table border="1"> <tr> <td>产品ID</td> <td>产品名称</td> <td>产品价格</td> <td>是否删除</td> <td>是否更新</td> </tr> <s:iterator value="#request.all" id="product"> <tr> <td><s:property value="#product.id"/></td> <td><s:property value="#product.name"/></td> <td><s:property value="#product.price"/></td> <td><a href="delete.action? id=<s:property value=' #product.id' />"> 删除</a></td> <td><a href="update.jsp? id=<s:property value=' #product.id' />">更新</a></td> </tr> </s:iterator> </table> <a href="add.jsp">添加产品</a> </center> </body> </html>
在“struts.xml”文件中配置ShowAllAction,并定义处理结果与视图资源之间的关系,代码如下所示。
<! -- 定义showAll的Action,其实现类为net.hncu.action.ShowAllAction --> <action name="showAll" class="net.hncu.action.ShowAllAction"> <! -- 定义处理结果与视图资源之间的关系--> <result name="success">/showAll.jsp</result> </action>
打开浏览器,运行showAll.action,在页面中显示所有的产品,如图13.9所示。
图13.9 产品列表页
13.3.5 添加产品
新建产品添加页,页面中包含3个表单,分别用来输入产品ID、产品名以及产品价格。该表单提交到add.action进行处理,代码如下所示。
<%@page contentType="text/html; charset=gb2312"%> <%@taglib prefix="s" uri="/struts-tags"%> <html> <head> <title>添加产品</title> </head> <body> <center> <h2>添加产品</h2> <s:form action="add"> <s:textfield label="产品ID" name="id"></s:textfield> <s:textfield label="产品名" name="name"></s:textfield> <s:textfield label="产品价格" name="price"></s:textfield> <s:submit value="提交"></s:submit> <s:reset value="重置"></s:reset> </s:form> </center> </body> </html>
新建业务控制器AddAction,该Action接受产品添加页传递的参数,并将接受的参数设置到Product实例中,然后调用业务逻辑组件保存该产品,代码如下所示。
package net.hncu.action; import net.hncu.factory.ServiceFactory; import net.hncu.po.Product; import net.hncu.service.ProductService; import com.opensymphony.xwork2.ActionSupport; public class AddAction extends ActionSupport{ //产品ID private String id; //产品名 private String name; //产品价格 private double price; //各属性的setter和getter方法 public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public String execute() throws Exception { //通过业务逻辑组件工厂获得业务逻辑组件 ProductService ps = ServiceFactory.getServiceInstance(); //将接受的参数设置到Product实例中 Product p = new Product(); p.setId(id); p.setName(name); p.setPrice(price); //调用业务逻辑组件保存该产品 ps.addProduct(p); return SUCCESS; } }
在“struts.xml”文件中配置addAction,并定义处理结果与视图资源之间的关系,代码如下所示。
<! -- 定义add的Action,其实现类为net.hncu.action.AddAction--> <action name="add" class="net.hncu.action.AddAction"> <! -- 定义处理结果与视图资源之间的关系--> <result name="success" type="redirect">show.action </result> </action>
单击“添加产品”链接,页面跳转到产品添加页,如图13.10所示。
填写好相应的产品信息,单击“提交”按钮。产品添加完成后,页面将跳转回产品列表页,如图13.11所示。
图13.10 产品添加页
13.3.6 删除产品
图13.11 产品添加成功
新建业务控制器DeleteAction,该Action接受ID参数,通过调用业务逻辑组件删除该ID产品,代码如下所示。
package net.hncu.action; import net.hncu.factory.ServiceFactory; import net.hncu.service.ProductService; import com.opensymphony.xwork2.ActionSupport; public class DeleteAction extends ActionSupport{ //产品ID private String id; public String getId() { return id; } public void setId(String id) { this.id = id; } public String execute() throws Exception { //通过业务逻辑组件工厂获得业务逻辑组件 ProductService ps = ServiceFactory.getServiceInstance(); //通过调用业务逻辑组件删除该ID产品 ps.deleteProduct(id); return SUCCESS; } }
在“struts.xml”文件中配置deleteAction,并定义处理结果与视图资源之间的关系,代码如下所示。
<! -- 定义delete的Action,其实现类为net.hncu.action.DeleteAction --> <action name="delete" class="net.hncu.action.DeleteAction"> <! -- 定义处理结果与视图资源之间的关系--> <result name="success" type="redirect">showAll.action </result> </action>
当单击产品列表中相应产品中的删除链接,就可以删除相应产品。产品删除完成后,页面将跳转回产品列表页,如图13.12所示。
图13.12 产品删除成功
13.3.7 更新产品
新建产品更新页,页面中包含3个表单,分别用来输入产品ID、产品名以及产品价格。该表单提交到update.action进行处理,代码如下所示。
<%@page contentType="text/html; charset=gb2312"%> <%@taglib prefix="s" uri="/struts-tags"%> <html> <head> <title>更新产品</title> </head> <body> <center> <h2>更新产品</h2> <s:form action="update"> <s:set name="id" value="#parameters.id[0]"></s:set> <s:textfield label="产品ID" name="id"></s:textfield> <s:textfield label="产品名" name="name"></s:textfield> <s:textfield label="产品价格" name="price"></s:textfield> <s:submit value="更新"></s:submit> <s:reset value="重置"></s:reset> </s:form> </center> </body> </html>
新建业务控制器UpdateAction,该Action接受产品更新页传递的参数,并将接受的参数设置到Product实例中,然后调用业务逻辑组件更新该产品,代码如下所示。
package net.hncu.action; import net.hncu.factory.ServiceFactory; import net.hncu.po.Product; import net.hncu.service.ProductService; import com.opensymphony.xwork2.ActionSupport; public class UpdateAction extends ActionSupport{ //产品ID private String id; //产品名 private String name; //产品价格 private double price; //各属性的setter和getter方法 public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public String execute() throws Exception { //通过业务逻辑组件工厂获得业务逻辑组件 ProductService ps = ServiceFactory.getServiceInstance(); //将接受的参数设置到Product实例中 Product p = new Product(); p.setId(id); p.setName(name); p.setPrice(price); //调用业务逻辑组件保存该产品 ps.updateProduct(p); return SUCCESS; } }
在“struts.xml”文件中配置UpdateAction,并定义处理结果与视图资源之间的关系,代码如下所示。
<! -- 定义update的Action,其实现类为net.hncu.action.UpdateAction --> <action name="update" class="net.hncu.action.UpdateAction"> <! -- 定义处理结果与视图资源之间的关系--> <result name="success" type="redirect">showAll.action</result> </action>
单击需要更新产品的更新链接,页面跳转到产品更新页,如图13.13所示。
填写好相应的产品信息,单击“更新”按钮。产品添加完成后,页面将跳转回产品列表页,如图13.14所示。
图13.13 产品更新页
图13.14 产品更新成功
程序成功地完成了Struts 2整合Hibernate开发的过程,但是有些地方还不够完善。如没有进行输入校验,以及对产品进行增加、删除和更新操作时的错误提示。