零基础学Struts
上QQ阅读APP看书,第一时间看更新

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,并定义处理结果与视图资源之间的关系,代码如下所示。

        <! -- 定义showAllAction,其实现类为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;
              //各属性的settergetter方法
              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,并定义处理结果与视图资源之间的关系,代码如下所示。

        <! -- 定义addAction,其实现类为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,并定义处理结果与视图资源之间的关系,代码如下所示。

        <! -- 定义deleteAction,其实现类为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;
              //各属性的settergetter方法
              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,并定义处理结果与视图资源之间的关系,代码如下所示。

        <! -- 定义updateAction,其实现类为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开发的过程,但是有些地方还不够完善。如没有进行输入校验,以及对产品进行增加、删除和更新操作时的错误提示。