实验六Hibernate 的体系结构——登录用户信息的增删改查

一、基础实验——Hibernate 常用API

实验内容及步骤

新建项目

1635126000453.png
image.png

搭建项目框架

新建数据库

  1. create table customer
  2. (
  3. customerID int not null
  4. primary key,
  5. Account varchar(20) null,
  6. Password varchar(20) null,
  7. Name varchar(20) null,
  8. Sex tinyint null,
  9. Birthday date null,
  10. Phone varchar(20) null,
  11. Email varchar(100) null,
  12. Address varchar(200) null,
  13. Zipcode varchar(10) null,
  14. Fax varchar(20) null
  15. );
  16. INSERT INTO hibernatedb.customer (customerID, Account, Password, Name, Sex, Birthday, Phone, Email, Address, Zipcode, Fax) VALUES (1, 'zjut', 'Zjut', null, null, null, null, null, null, null, null);
  17. INSERT INTO hibernatedb.customer (customerID, Account, Password, Name, Sex, Birthday, Phone, Email, Address, Zipcode, Fax) VALUES (2, 'admin', 'Admin', null, null, null, null, null, null, null, null);
  18. INSERT INTO hibernatedb.customer (customerID, Account, Password, Name, Sex, Birthday, Phone, Email, Address, Zipcode, Fax) VALUES (3, 'temp', 'Temp', null, null, null, null, null, null, null, null);

在maven中导入如下:

  1. <dependency>
  2. <groupId>org.hibernate</groupId>
  3. <artifactId>hibernate-core</artifactId>
  4. <version>5.4.32.Final</version>
  5. </dependency>
  6. <!-- mysql驱动包-->
  7. <dependency>
  8. <groupId>mysql</groupId>
  9. <artifactId>mysql-connector-java</artifactId>
  10. <version>8.0.26</version>
  11. </dependency>
  12. <dependency>
  13. <groupId>org.apache.struts</groupId>
  14. <artifactId>struts2-core</artifactId>
  15. <version>2.3.15</version>
  16. </dependency>
  17. <dependency>
  18. <groupId>commons-logging</groupId>
  19. <artifactId>commons-logging</artifactId>
  20. <version>1.2</version>
  21. </dependency>
  22. <dependency>
  23. <groupId>org.projectlombok</groupId>
  24. <artifactId>lombok</artifactId>
  25. <version>RELEASE</version>
  26. <scope>compile</scope>
  27. </dependency>
  28. <dependency>
  29. <groupId>org.apache.struts</groupId>
  30. <artifactId>struts2-dojo-plugin</artifactId>
  31. <version>2.3.15</version>
  32. </dependency>

新建目录

1635127197810.png1635127171703.png
项目总体框架如图
image.png

新建Hibernate 相关文件

在/recourse 中新建配置文件hibernate.cfg.xml,具体代码可参照“实验五Hibernate 基础应用”中基础实验里的hibernate.cfg.xml;

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!DOCTYPE hibernate-configuration PUBLIC
  3. "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
  4. "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
  5. <hibernate-configuration>
  6. <session-factory name="HibernateSessionFactory">
  7. <property name="hibernate.connection.driver_class">
  8. com.mysql.jdbc.Driver</property>
  9. <property name="hibernate.connection.url">
  10. jdbc:mysql://localhost:3306/hibernatedb</property>
  11. <property name="hibernate.connection.username">
  12. zhangkun</property>
  13. <property name="hibernate.connection.password">
  14. zhangkun
  15. </property>
  16. <property name="hibernate.dialect">
  17. org.hibernate.dialect.MySQLDialect</property>
  18. </session-factory>
  19. </hibernate-configuration>

在hibernate-prj2 中新建cn.edu.zjut.po 包, 并在其中创建持久化类Customer.java 以及Hibernate 映射文件Customer.hbm.xml,具体代码可参照“实验五Hibernate 基础应用”中基础实验里的内容;

  1. @Data
  2. public class Customer implements java.io.Serializable{
  3. private int customerId;
  4. private String account; private String password;
  5. private String name; private Boolean sex;
  6. private Date birthday; private String phone;
  7. private String email; private String address;
  8. private String zipcode; private String fax;
  9. }
  1. <?xml version="1.0"?>
  2. <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD
  3. 3.0//EN"
  4. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
  5. <hibernate-mapping>
  6. <class name="cn.edu.zjut.po.Customer" table="customer"
  7. catalog="hibernatedb">
  8. <id name="customerId" type="int">
  9. <column name="customerID" />
  10. <generator class="increment" />
  11. </id>
  12. <property name="account" type="string">
  13. <column name="account" length="20" unique="true" />
  14. </property>
  15. <property name="password" type="string">
  16. <column name="password" length="20" />
  17. </property>
  18. <property name="name" type="string">
  19. <column name="name" length="20" />
  20. </property>
  21. <property name="sex" type="java.lang.Boolean">
  22. <column name="sex" />
  23. </property>
  24. <property name="birthday" type="date">
  25. <column name="birthday" length="10" />
  26. </property>
  27. <property name="phone" type="string">
  28. <column name="phone" length="20" />
  29. </property>
  30. <property name="email" type="string">
  31. <column name="email" length="100" />
  32. </property>
  33. <property name="address" type="string">
  34. <column name="address" length="200" />
  35. </property>
  36. <property name="zipcode" type="string">
  37. <column name="zipcode" length="10" />
  38. </property>
  39. <property name="fax" type="string">
  40. <column name="fax" length="20" />
  41. </property>
  42. </class>
  43. </hibernate-mapping>

修改配置文件hibernate.cfg.xml,增加Customer.hbm.xml 映射文件的声明;

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!DOCTYPE hibernate-configuration PUBLIC
  3. "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
  4. "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
  5. <hibernate-configuration>
  6. <session-factory name="HibernateSessionFactory">
  7. ......
  8. <mapping resource="/Customer.hbm.xml" />
  9. </session-factory>
  10. </hibernate-configuration>

新建Struts相关文件

在hibernate-prj2 中新建cn.edu.zjut.dao 包,并在其中创建DAO 操作辅助类HibernateUtil.java,用于生成Configuration 对象和SessionFactory 对象,具体代码如下:

  1. package cn.edu.zjut.dao;
  2. import lombok.Data;
  3. import org.hibernate.HibernateException;
  4. import org.hibernate.Session;
  5. import org.hibernate.cfg.Configuration;
  6. @Data
  7. public class HibernateUtil {
  8. private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
  9. private static final ThreadLocal<Session>
  10. threadLocal = new ThreadLocal<Session>();
  11. private static Configuration configuration = new Configuration();
  12. private static org.hibernate.SessionFactory sessionFactory;
  13. private static String configFile = CONFIG_FILE_LOCATION;
  14. static {
  15. try {
  16. configuration.configure(configFile);
  17. sessionFactory = configuration.buildSessionFactory();
  18. } catch (Exception e) {
  19. System.err.println("%%%% Error Creating SessionFactory %%%%");
  20. e.printStackTrace();
  21. }
  22. }
  23. private HibernateUtil() { }
  24. public static org.hibernate.SessionFactory getSessionFactory() {
  25. return sessionFactory;
  26. }
  27. public static void rebuildSessionFactory() {
  28. try {
  29. configuration.configure(configFile);
  30. sessionFactory = configuration.buildSessionFactory();
  31. } catch (Exception e) {
  32. System.err.println("%%%% Error Creating SessionFactory %%%%");
  33. e.printStackTrace();
  34. }
  35. }
  36. }

完善辅助类HibernateUtil.java,在其中添加代码用于“获取Session 对象”和“关闭Session 对象”,代码片段如下:

  1. public class HibernateUtil {
  2. // ...
  3. public static Session getSession() throws HibernateException {
  4. Session session = (Session) threadLocal.get();
  5. if (session == null || !session.isOpen()) {
  6. if (sessionFactory == null) {
  7. rebuildSessionFactory();
  8. }session = (sessionFactory != null)?sessionFactory.openSession(): null;
  9. threadLocal.set(session);
  10. }
  11. return session;
  12. }
  13. public static void closeSession() throws HibernateException {
  14. Session session = (Session) threadLocal.get();
  15. threadLocal.set(null);
  16. if (session != null) {
  17. session.close();
  18. }
  19. }
  20. }

在hibernate-prj2 的cn.edu.zjut.dao 包中创建BaseHibernateDAO.java,作为数据库操作基础类,具体代码如下:

  1. public class BaseHibernateDAO {
  2. public Session getSession() {
  3. return HibernateUtil.getSession();
  4. }
  5. }

在hibernate-prj2 的cn.edu.zjut.dao 包中创建CustomerDAO.java,继承数据库操作基础类BaseHibernateDAO.java,实现Customer 增删改查操作,代码片段如下:

  1. package cn.edu.zjut.dao;
  2. import cn.edu.zjut.po.Customer;
  3. import org.apache.commons.logging.Log;
  4. import org.apache.commons.logging.LogFactory;
  5. import org.hibernate.query.Query;
  6. import java.util.List;
  7. public class CustomerDAO extends BaseHibernateDAO{
  8. private Log log = LogFactory.getLog(CustomerDAO.class);
  9. public List findByHql(String hql) {
  10. log.debug("finding Customer instance by hql");
  11. try {
  12. String queryString = hql;
  13. Query queryObject = getSession().createQuery(queryString);
  14. return queryObject.list();
  15. } catch (RuntimeException re) {
  16. log.error("find by hql failed", re);
  17. throw re;
  18. }
  19. }
  20. public void save(Customer instance) {
  21. log.debug("saving Customer instance");
  22. try {
  23. getSession().save(instance);
  24. log.debug("save successful");
  25. } catch (RuntimeException re) {
  26. log.error("save failed", re);
  27. throw re;
  28. }
  29. }
  30. public void update(Customer instance) {
  31. log.debug("updating Customer instance");
  32. try {
  33. getSession().update(instance);
  34. log.debug("update successful");
  35. } catch (RuntimeException re) {
  36. log.error("update failed", re);
  37. throw re;
  38. }
  39. }
  40. public void delete(Customer instance) {
  41. log.debug("deleting Customer instance");
  42. try {
  43. getSession().delete(instance);
  44. log.debug("delete successful");
  45. } catch (RuntimeException re) {
  46. log.error("delete failed", re);
  47. throw re;
  48. }
  49. }
  50. }

在hibernate-prj2 中新建cn.edu.zjut.service 包, 并在其中创建UserService.java,用于实现登录、注册、个人信息修改和删除逻辑,代码片段如下:

  1. package cn.edu.zjut.service;
  2. import cn.edu.zjut.dao.CustomerDAO;
  3. import cn.edu.zjut.po.Customer;
  4. import com.opensymphony.xwork2.ActionContext;
  5. import lombok.Data;
  6. import org.hibernate.Transaction;
  7. import java.util.List;
  8. import java.util.Map;
  9. @Data
  10. public class UserService {
  11. private Map<String, Object> request, session;
  12. public boolean login(Customer loginUser) {
  13. ActionContext ctx= ActionContext.getContext();
  14. session=(Map) ctx.getSession();
  15. request=(Map) ctx.get("request");
  16. String account = loginUser.getAccount();
  17. String password = loginUser.getPassword();
  18. String hql = "from Customer as user where account='" + account
  19. + "' and password='" + password + "'";
  20. CustomerDAO dao = new CustomerDAO();
  21. List list = dao.findByHql(hql);
  22. dao.getSession().close();
  23. if (list.isEmpty()) {
  24. return false;
  25. } else{
  26. session.put("user", account);
  27. request.put("tip", "登录成功!");
  28. loginUser=(Customer)list.get(0);
  29. request.put("loginUser", loginUser);
  30. return true;
  31. }
  32. }
  33. public boolean register(Customer loginUser) {
  34. ActionContext ctx= ActionContext.getContext();
  35. session=(Map) ctx.getSession();
  36. request=(Map) ctx.get("request");
  37. CustomerDAO dao = new CustomerDAO();
  38. Transaction tran = null;
  39. try {
  40. tran = dao.getSession().beginTransaction();
  41. dao.save(loginUser);
  42. tran.commit();
  43. session.put("user",loginUser);
  44. request.put("tip", "注册成功");
  45. return true;
  46. } catch (Exception e) {
  47. if(tran != null) {
  48. tran.rollback();
  49. }
  50. return false;
  51. } finally {
  52. dao.getSession().close();
  53. }
  54. }
  55. public boolean update(Customer loginUser) {
  56. ActionContext ctx= ActionContext.getContext();
  57. session=(Map) ctx.getSession();
  58. request=(Map) ctx.get("request");
  59. CustomerDAO dao = new CustomerDAO();
  60. Transaction tran = null;
  61. try {
  62. tran = dao.getSession().beginTransaction();
  63. dao.update(loginUser);
  64. tran.commit();
  65. session.put("user",loginUser);
  66. request.put("tip", "个人信息更新成功");
  67. return true;
  68. } catch (Exception e) {
  69. if(tran != null) {
  70. tran.rollback();
  71. }
  72. return false;
  73. } finally {
  74. dao.getSession().close();
  75. }
  76. }
  77. public boolean delete(Customer loginUser) {
  78. ActionContext ctx= ActionContext.getContext();
  79. session=(Map) ctx.getSession();
  80. request=(Map) ctx.get("request");
  81. CustomerDAO dao = new CustomerDAO();
  82. Transaction tran = null;
  83. try {
  84. tran = dao.getSession().beginTransaction();
  85. dao.delete(loginUser);
  86. tran.commit();
  87. session.remove("user");
  88. request.put("tip", "删除个人信息成功,请重新登录!");
  89. return true;
  90. } catch (Exception e) {
  91. if(tran != null) {
  92. tran.rollback();
  93. }
  94. return false;
  95. } finally {
  96. dao.getSession().close();
  97. }
  98. }
  99. }

在hibernate-prj2 中新建cn.edu.zjut.action 包,并在其中创建UserAction.java,代码片段如下:

  1. package cn.edu.zjut.action;
  2. import cn.edu.zjut.po.Customer;
  3. import cn.edu.zjut.service.UserService;
  4. import lombok.Data;
  5. @Data
  6. public class UserAction {
  7. private Customer loginUser;
  8. //省略getters/setters 方法
  9. public String login() {
  10. UserService userServ = new UserService();
  11. if (userServ.login(loginUser)) {
  12. return "loginsuccess";
  13. }
  14. else {
  15. return "loginfail";
  16. }
  17. }
  18. public String register() {
  19. UserService userServ = new UserService();
  20. if (userServ.register(loginUser)) {
  21. return "registersuccess";
  22. }
  23. else {
  24. return "registerfail";
  25. }
  26. }
  27. public String update() {
  28. UserService userServ = new UserService();
  29. if (userServ.update(loginUser)) {
  30. return "updatesuccess";
  31. }
  32. else {
  33. return "updatefail";
  34. }
  35. }
  36. public String delete() {
  37. UserService userServ = new UserService();
  38. if (userServ.delete(loginUser)) {
  39. return "deletesuccess";
  40. }
  41. else {
  42. return "deletefail";
  43. }
  44. }
  45. }

新建视图页面

在hibernate-prj2 中新建login.jsp 页面,作为用户登录视图,代码片段如下:

  1. <body>
  2. <s:property value="#request.tip"/>
  3. <p>
  4. <s:form action="Userlogin" method="post">
  5. <s:textfield name="loginUser.account" label="请输入用户名"/>
  6. <s:password name="loginUser.password" label="请输入密码"/>
  7. <s:submit value="登录"/>
  8. </s:form>
  9. </body>

在hibernate-prj2 中新建loginSuccess.jsp 页面,作为登录成功视图,并能在该页面中修改个人信息或删除个人信息,代码片段如下:

  1. <body>
  2. <s:property value="#request.tip"/><p>
  3. 修改个人信息<p>
  4. <s:form action="Userupdate" method="post">
  5. <s:hidden name="loginUser.customerId"
  6. value="%{#request.loginUser.customerId}"/>
  7. <s:textfield name="loginUser.account" label="用户名不能修改"
  8. value="%{#request.loginUser.account}" readonly="true"/>
  9. <s:textfield type="password" name="loginUser.password"
  10. label="修改密码" value="%{#request.loginUser.password}"/>
  11. <!-- 省略其它表单域-->
  12. <s:submit value="修改"/>
  13. </s:form>
  14. <s:form action="Userdelete" method="post">
  15. <s:hidden name="loginUser.customerId"
  16. value="%{#request.loginUser.customerId}"/>
  17. <s:submit value="删除"/>
  18. </s:form>
  19. </body>

在hibernate-prj2 中新建register.jsp 页面,作为用户注册视图(可参考“实验二Struts 基础应用”中提高实验里的页面代码,并根据数据库表customer设计页面内容);

  1. <%@ taglib prefix="s" uri="/struts-tags" %>
  2. <%@ taglib prefix="sx" uri="/struts-dojo-tags" %>
  3. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  4. <html>
  5. <head>
  6. <title>Title</title>
  7. <sx:head/>
  8. </head>
  9. <body>
  10. <s:form action="register" method="post">
  11. <s:textfield name="loginUser.account" label="请输入用户名"/>
  12. <s:textfield name="loginUser.name" label="请输入用户名"/>
  13. <s:password name="loginUser.password" label="请输入密码"/>
  14. <%-- <s:password name="loginUser.repassword" label="请再次输入密码"/>--%>
  15. <s:radio name="loginUser.sex" list="#{1 : '男', 0 : '女'}" label
  16. ="请输入性别"/>
  17. <sx:datetimepicker name="loginUser.birthday" displayFormat
  18. ="yyyy-MM-dd" label="请输入生日"/>
  19. <s:textfield name="loginUser.phone" label="请输入电话"/>
  20. <s:textfield name="loginUser.email" label="请输入邮箱"/>
  21. <s:textfield name="loginUser.address" label="请输入联系地址"/>
  22. <s:textfield name="loginUser.zipcode" label="请输入邮政编码"/>
  23. <s:textfield name="loginUser.fax" label="请输入传真号码"/>
  24. <s:submit value="注册"/>
  25. <s:reset value="重置"/>
  26. </s:form>
  27. </body>
  28. </html>

在hibernate-prj2 中新建registerSuccess.jsp 页面,作为注册成功的视图(代码略);

  1. <body>
  2. 注册成功
  3. </body>

在hibernate-prj2 中新建CURDFail.jsp 页面,作为“修改个人信息和删除个人信息”操作失败的视图(代码略);

  1. <body>
  2. 修改个人信息和删除个人信息失败
  3. </body>

配置struts.xml

在hibernate-prj2 的src 目录中创建struts.xml 文件,用于配置Action 并设置页面导航,使得:登录成功时转向loginSuccess.jsp 页面,失败时转向login.jsp重新登录;注册成功时转向registerSuccess.jsp 页面,失败时转向register.jsp重新注册;修改个人信息成功时转向loginSuccess.jsp 页面,失败时转向CURDFail.jsp 页面;删除个人信息成功时转向login.jsp 页面重新登录,失败时转向CURDFail.jsp 页面;

  1. <struts>
  2. <package name="strutsBean" extends="struts-default" namespace="/">
  3. <action name="Userlogin" class="cn.edu.zjut.action.UserAction" method="login">
  4. <result name="loginsuccess">/loginSuccess.jsp</result>
  5. <result name="loginfail">/login.jsp</result>
  6. </action>
  7. <action name="register" class="cn.edu.zjut.action.UserAction" method="register">
  8. <result name="registersuccess">/registerSuccess.jsp</result>
  9. <result name="registerfail">/register.jsp</result>
  10. </action>
  11. <action name="Userupdate" class="cn.edu.zjut.action.UserAction" method="update">
  12. <result name="updatesuccess">/loginSuccess.jsp</result>
  13. <result name="updatefail">/CURDFail.jsp</result>
  14. </action>
  15. <action name="Userdelete" class="cn.edu.zjut.action.UserAction" method="delete">
  16. <result name="deletesuccess">/login.jsp</result>
  17. <result name="deletefail">/CURDFail.jsp</result>
  18. </action>
  19. </package>
  20. </struts>

配置web.xml

编辑Web 应用的web.xml 文件,增加Struts2 核心Filter 的配置;

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
  5. http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  6. <display-name>Archetype Created Web Application</display-name>
  7. <welcome-file-list>
  8. <welcome-file>/register.jsp</welcome-file>
  9. </welcome-file-list>
  10. <!-- 定义Struts2 的核心Filter -->
  11. <filter>
  12. <filter-name>struts2</filter-name>
  13. <filter-class>
  14. org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
  15. </filter-class>
  16. </filter>
  17. <!-- 让Struts2 的核心Filter 拦截所有请求-->
  18. <filter-mapping>
  19. <filter-name>struts2</filter-name>
  20. <url-pattern>/*</url-pattern>
  21. </filter-mapping>
  22. </web-app>

配置Tomcat服务器

依次点击如下
1633963852797.png
1633963873809.png
1633963913095.png
1633963931717.png
此处的工件名称应为hibernate-prj2:war exploded
至此部署完毕,点击启动即可
1633963994148.png

查看效果

数据库Customer表内容如下:
image.png
打开链接http://localhost:8080/hibernate_prj2_war_exploded/login.jsp
登录页面如图
image.png
点击登录
image.png
修改密码为zhangkun
image.png
再次查看数据库
image.png
可以看到后面的信息全部为空,密码已被修改,customerID并未被修改
点击删除
image.png
查看数据库
image.png
可见该用户信息已被删除
点击链接http://localhost:8080/hibernate_prj2_war_exploded/register.jsp
查看注册页面
image.png
点击注册
image.png
查看数据库效果
image.png

实验总结

  1. 运行结果截图;
  2. 结合实验过程,查找相关资料,总结利用Hibernate 基本API 载入配置文件、建立数据库连接并进行数据库操作的基本步骤;
  3. 结合实验过程,查找相关资料,总结Session 中的主要方法,及其与数据库操作的对应关系;
  4. 根据实验步骤8、9,总结Service 和DAO 之间的调用关系,思考事务操作相关代码所处的位置,并记录下来;
  5. 根据实验步骤12,思考表单域中value 值的写法,总结显示value 值的实现方法并记录下来;
  6. 碰到的问题及解决方案或思考;
  7. 实验收获及总结。

    二、提高实验——HQL 语言

    实验内容及步骤

    数据库搭建

    ```sql create table item ( ISBN varchar(20) not null
    1. primary key,
    title varchar(30) null, cost float null, description varchar(100) null, image blob null );

INSERT INTO hibernatedb.item (ISBN, title, cost, description, image) VALUES (‘978-7-121-12345-1’, ‘JAVAEE技术 实验指导教程’, 19.95, ‘WEB程序设计知识回顾、轻量级JAVAEE 应用框架、企业级EJB组件编程技术、 JAVAEE综合应用开发’, 0xEFBBBF); INSERT INTO hibernatedb.item (ISBN, title, cost, description, image) VALUES (‘978-7-121-12345-2’, ‘JAVAEE技术’, 29.95, ‘Struts框架、Hibernate框架、Spring框架、 会话Bean、实体Bean、消息驱动Bean’, null);

  1. <a name="cMnmY"></a>
  2. #### 配置hibernate
  3. 在hibernate-pr2 的cn.edu.zjut.po 包中创建持久化类Item.java 以及Hibernate映射文件Item.hbm.xml,具体代码可参照“实验五Hibernate 基础应用”中提高实验里的内容;
  4. ```java
  5. @Data
  6. public class Item {
  7. private String itemID;
  8. private String title;
  9. private String description;
  10. private float cost;
  11. private Blob image;
  12. }

修改hibernate-prj2 的Hibernate 配置文件hibernate.cfg.xml,增加Item.hbm.xml映射文件的声明;

  1. <?xml version="1.0"?>
  2. <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD
  3. 3.0//EN"
  4. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
  5. <hibernate-mapping>
  6. <class name="cn.edu.zjut.po.Item" table="item"
  7. catalog="hibernatedb">
  8. <property name="itemID" type="string">
  9. <column name="ISBN" length="20" />
  10. </property>
  11. <property name="title" type="string">
  12. <column name="title" length="30" />
  13. </property>
  14. <property name="description" type="string">
  15. <column name="description" length="100" />
  16. </property>
  17. <property name="cost" type="float">
  18. <column name="cost" />
  19. </property>
  20. <property name="image" type="java.sql.Blob">
  21. <column name="image" />
  22. </property>
  23. </class>
  24. </hibernate-mapping>

配置Struts相关文件

在hibernate-prj2 的cn.edu.zjut.dao 包中创建数据库操作类ItemDAO.java,继承数据库操作基础类BaseHibernateDAO.java,具体代码如下:

  1. public class ItemDAO extends BaseHibernateDAO{
  2. private static final Log log = LogFactory.getLog(ItemDAO.class);
  3. public List findByHql(String hql) {
  4. log.debug("finding Item instance by hql");
  5. try {
  6. String queryString = hql;
  7. Query queryObject = getSession().createQuery(queryString);
  8. return queryObject.list();
  9. } catch (RuntimeException re) {
  10. log.error("find by hql failed", re);
  11. throw re;
  12. }
  13. }
  14. }

在hibernate-prj2 的cn.edu.zjut.service 包中创建ItemService.java,使用from子句实现最简单的查询,获取所有商品信息,具体代码如下:

  1. public class ItemService {
  2. private List items = new ArrayList();
  3. public List findByHql() {
  4. ItemDAO dao = new ItemDAO();
  5. String hql = "from cn.edu.zjut.po.Item";
  6. List list = dao.findByHql(hql);
  7. dao.getSession().close();
  8. return list;
  9. }
  10. }

在hibernate-prj2 的cn.edu.zjut.action 包中创建ItemAction.java,并在其中定义findItems()方法用于调用“获取商品信息”逻辑,代码片段如下:

  1. @Data
  2. public class ItemAction {
  3. private List items;
  4. //省略getters/setters 方法
  5. public String findItems() {
  6. ItemService itemServ = new ItemService();
  7. items=itemServ.findByHql();
  8. System.out.println("Item Action executed!");
  9. return "success";
  10. }
  11. }

搭建视图页面

在hibernate-prj2 中新建itemList.jsp 页面,作为显示商品信息的视图,代码片段如下:

  1. <body>
  2. <center>商品列表</center>
  3. <table border=1>
  4. <tr>
  5. <th>编号</th>
  6. <th>书名</th>
  7. <th>说明</th>
  8. <th>单价</th>
  9. </tr>
  10. <s:iterator value="items" >
  11. <tr>
  12. <td><s:property value="itemID"/></td>
  13. <td><s:property value="title"/></td>
  14. <td><s:property value="description"/></td>
  15. <td><s:property value="cost"/></td>
  16. </tr>
  17. </s:iterator>
  18. </table>
  19. </body>

修改hibernate-prj2 的loginSuccess.jsp 页面,在视图中增加超链接,用于查看商品信息,代码片段如下:

  1. <a href="./findItems">查看商品信息</a>

修改struts.xml

修改hibernate-prj2 的struts.xml 文件,增加ItemAction 的配置并设置页面导航;

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE struts PUBLIC
  3. "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
  4. "http://struts.apache.org/dtds/struts-2.3.dtd">
  5. <struts>
  6. <package name="strutsBean" extends="struts-default" namespace="/">
  7. ......
  8. <action name="findItems" class="cn.edu.zjut.action.ItemAction" method="findItems">
  9. <result name="success">/itemList.jsp</result>
  10. </action>
  11. </package>
  12. </struts>

查看效果

image.png

hql语句替换1

修改ItemService.java,将hql 语句替换成“from Item”,省略包名,直接通过类名查询,代码片段如下:

  1. public class ItemService {
  2. private List items = new ArrayList();
  3. public List findByHql() {
  4. ItemDAO dao = new ItemDAO();
  5. String hql = "from Item";
  6. List list = dao.findByHql(hql);
  7. dao.getSession().close();
  8. return list;
  9. }
  10. }

效果如图
image.png

hql语句替换2

修改ItemService.java 中的hql 语句,使用as 为类取名,以便在其它地方使用,代码片段如下:

  1. // ...
  2. String hql = "from Item as item";
  3. // ...

效果如图image.png

hql语句替换3

修改ItemService.java 中的hql 语句,使用select 子句查询商品名称,代码片段如下:

  1. String hql = "select item.title from Item as item";

由于select 子句只返回title 属性,则返回结果将直接封装到该元素类型的集合中,即封装到List集合中,因此需要修改itemList.jsp 页面,显示商品名称,代码片段如下:

  1. <table border=1>
  2. <tr> <th>书名</th> </tr>
  3. <s:iterator value="items" id="object">
  4. <tr>
  5. <td><s:property value="object"/></td>
  6. </tr>
  7. </s:iterator>
  8. </table>

效果如图
image.png

hql语句替换4

修改ItemService.java 中的hql 语句,使用select 子句查询商品名称和商品价格,代码片段如下:

  1. String hql = "select item.title, item.cost from Item as item";

若select 子句返回多个属性,则返回结果将封装到List集合中,因此需要修改itemList.jsp 页面,显示商品名称和商品价格,代码片段如下:

  1. <table border=1>
  2. <tr> <th>书名</th> <th>单价</th> </tr>
  3. <s:iterator value="items" id="object">
  4. <tr>
  5. <td><s:property value="#object[0]"/></td>
  6. <td><s:property value="#object[1]"/></td>
  7. </tr>
  8. </s:iterator>
  9. </table>

image.png

hql语句替换—-聚集函数

修改ItemService.java 中的hql 语句,使用select 子句查询商品最高价格,代码片段如下:

  1. String hql = "select max(item.cost) from Item as item";

修改jsp页面

  1. <table border=1>
  2. <tr> <th>最高价格</th></tr>
  3. <s:iterator value="items" id="object">
  4. <tr>
  5. <td><s:property value="#object"/></td>
  6. </tr>
  7. </s:iterator>
  8. </table>

效果显示如下
image.png

hql语句替换—-where 子句

修改ItemService.java 中的hql 语句,使用select 子句查询商品最高价格,代码片段如下:

  1. String hql = "from Item where title like 'JAVAEE技术'";

修改jsp页面

  1. <table border=1>
  2. <tr>
  3. <th>编号</th>
  4. <th>书名</th>
  5. <th>说明</th>
  6. <th>单价</th>
  7. </tr>
  8. <s:iterator value="items" >
  9. <tr>
  10. <td><s:property value="itemID"/></td>
  11. <td><s:property value="title"/></td>
  12. <td><s:property value="description"/></td>
  13. <td><s:property value="cost"/></td>
  14. </tr>
  15. </s:iterator>
  16. </table>

效果显示如下
image.png

hql语句替换—-order by 子句

修改ItemService.java 中的hql 语句,使用order by 子句降序查询商品价格,代码片段如下:

  1. String hql = "from Item order by cost desc";

效果显示如下
image.png

hql语句替换—-子查询

实验修改ItemService.java 中的hql 语句,使用select 子查询来查询高于平均价格的商品,代码片段如下:

  1. String hql = "from Item where cost > (select avg(cost) from Item)";

效果显示如下
image.png

总结

  1. 运行结果截图;
  2. 查找相关资料,完成实验步骤22,并记录运行结果;
  3. 结合实验过程,查找相关资料,总结HQL 的常用语句及语法规则;
  4. 碰到的问题及解决方案或思考;
  5. 实验收获及总结。

    三、扩展实验——深入Hibernate 配置文件

    实验内容及步骤

    增加配置属性助于调试

    修改hibernate-prj2 的Hibernate 配置文件hibernate.cfg.xml,增加配置属性,使得能在控制台输出Hibernate 生成的格式良好的SQL 语句,并在其中添加有助于调试的注释,代码片段如下:

    1. <hibernate-configuration>
    2. <session-factory name="HibernateSessionFactory">
    3. ……
    4. <property name="hibernate.show_sql">true</property>
    5. <property name="hibernate.format_sql">true</property>
    6. <property name="hibernate.use_sql_comments">true</property>
    7. </session-factory>
    8. </hibernate-configuration>

    登录输出如下
    image.png

    增加C3P0 连接池的配置属性

    修改hibernate.cfg.xml,增加C3P0 连接池的配置属性,代码片段如下:

    1. <hibernate-configuration>
    2. <session-factory name="HibernateSessionFactory">
    3. ……
    4. <property name="hibernate.c3p0.max_size">20</property>
    5. <property name="hibernate.c3p0.min_size">1</property>
    6. <property name="hibernate.c3p0.timeout">1800</property>
    7. <property name="hibernate.c3p0.max_statements">50</property>
    8. <property name="hibernate.connection.provider_class">
    9. org.hibernate.c3p0.internal.C3P0ConnectionProvider</property>
    10. </session-factory>
    11. </hibernate-configuration>

    添加maven

    1. <dependency>
    2. <groupId>org.hibernate</groupId>
    3. <artifactId>hibernate-c3p0</artifactId>
    4. <version>5.3.4.Final</version>
    5. </dependency>

    查看效果如下
    image.png

    使用类代码代替hibernate.cfg.xml配置

    删除hibernate-prj2 的Hibernate 配置文件hibernate.cfg.xml;
    修改cn.edu.zjut.dao 包中的HibernateUtil.java , 通过编程方式创建Configuration 对象,代码片段如下:

    1. private static Configuration configuration = new Configuration();
    2. // ...
    3. static {
    4. try {
    5. configuration
    6. .setProperty("hibernate.connection.driver_class",
    7. "com.mysql.jdbc.Driver")
    8. .setProperty("hibernate.connection.url",
    9. "jdbc:mysql://localhost:3306/hibernatedb")
    10. .setProperty("hibernate.connection.username", "zhangkun")
    11. .setProperty("hibernate.connection.password", "zhangkun")
    12. .setProperty("hibernate.dialect",
    13. "org.hibernate.dialect.MySQL8Dialect")
    14. .addResource("/Customer.hbm.xml")
    15. .addResource("/Item.hbm.xml");
    16. sessionFactory = configuration.buildSessionFactory();
    17. } catch (Exception e) {
    18. System.err.println("%%%% Error Creating SessionFactory %%%%");
    19. e.printStackTrace();
    20. }
    21. }

    运行结果:可正常登录

    自动建立数据库表

    在MySQL 的hibernatedb 数据库中删除customer 数据表;
    修改HibernateUtil.java,通过编程方式添加hibernate.hbm2ddl.auto 配置属性,使得能根据映射文件自动建立数据库表,代码片段如下:

    1. public class HibernateUtil {
    2. private static Configuration configuration = new Configuration();
    3. ……
    4. static {
    5. try {
    6. ……
    7. configuration
    8. .setProperty("hibernate.dialect",
    9. "org.hibernate.dialect.MySQL8Dialect")
    10. .setProperty("hibernate.hbm2ddl.auto", "create-drop");
    11. }
    12. catch (Exception e) { …… }
    13. }
    14. }

    先注册后登陆可以通过,数据库中有实际表生成

    实验总结

  6. 运行结果截图;

  7. 结合实验过程,查找相关资料,写出实验步骤1、3 中所使用的配置属性的作用,并记录下来;
  8. 根据实验步骤9,查找相关资料,写出“hibernate.hbm2ddl.auto”配置属性及其取值的作用;
  9. 根据实验步骤6,查找相关资料,总结通过编程方式创建Configuration 实例或设置配置属性的基本步骤,思考在实际应用中如何将Hibernate 配置文件设置配置属性与编程方式设置配置属性相结合,并记录下来;
  10. 碰到的问题及解决方案或思考;

    1. 自动生成表问题:首先是需要注意字段值必须匹配,其次需要注意导入的mysql配置版本必须正确,解决方案如下:

      1. hibernate.cfg.xml添加新的配置项(注意MySQL8Dialect中间有个8)
        1. <property name="hibernate.dialect">
        2. org.hibernate.dialect.MySQL8Dialect</property>
    2. c3p0一直不能被引入应用中,解决方法如下

      1. 导入maven:

        1. <dependency>
        2. <groupId>org.hibernate</groupId>
        3. <artifactId>hibernate-c3p0</artifactId>
        4. <version>5.3.4.Final</version>
        5. </dependency>
      2. hibernate.cfg.xml添加新的配置项

        1. <property name="hibernate.connection.provider_class">
        2. org.hibernate.c3p0.internal.C3P0ConnectionProvider</property>
  11. 实验收获及总结。