/ JavaEE  

利用Struts+Hibernate构建学生管理系统遇到的一些问题

私以为在学习过程中多一些BUG是有好处的,通过BUG可以学习很多新的东西,以及解决问题方法。当然遇到BUG首先应该仔细看报错信息,然后准确定位问题,不要盲目的百度检索。下面就来记录一下利用Struts+Hibernate构建学生管理系统遇到的一些问题,如果以后出现类似问题,方便查阅。

1. jar包配置问题

本次项目的开发环境为:Struts2.3 + hibernate3.0 + MySQL5.0,由于使用的是Eclipse,并没有使用Maven进行项目构建,所以所有的环境和需要的jar都需要手动配置。项目需要导入需要的核心jar包,包括:hibernate-core包,struts2-core包,mysql驱动包 junit单元测试包。

所需要的jar包,大多可通过百度查的官方下载地址(https://mvnrepository.com/),下载需要的jar,然后导入到项目的WEB-INF目录下的lib目录中。

2. 配置struts环境

配置struts只需要简单的两部:

  1. 修改web.xml, 配置过滤器。这里需要弄清楚struts使用的版本。
  2. 创建struts.xml 并将文件保存在Java Resources 下的src目录下,struts.xml 是用来拦截请求转发至对应Action的,所以要完成Action注册。

下面是一个简单的struts.xml配置例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<!-- Struts xml的配置文件 -->
<!-- 所有匹配*.action的请求都由struts2处理 -->
<constant name="struts.action.extension" value="action,," />
<!-- 是否启用开发模式 -->
<constant name="struts.devMode" value="true" />

<package name="default" extends="struts-default" namespace="/">
<!-- 如果不指定method,那么默认方法是execute-->
<!--name:Action类的名字,具有唯一性,页面上通过name来访问Action类 -->

<action name="test" class="test" method="test">
<!-- 配置结果集 :name属性的值一定要与execute方法的返回值一致-->
<result name="test">test.jsp</result>
</action>
</package>

</struts>

3. hibernate相关配置

创建hibernate.cfg.xml文件,并将文件保存在Java Resources 下的src目录下。配置文件包括两个核心部分:一个是property属性,主要配置的是数据库的链接。另外一个是mapping属性,指定关联的 .hbm.xml文件。

另外指定currentSession()方法所得到的Session由谁来跟踪管理,thread指Session由当前线程来跟踪管理,这是一种事务配置的方式,实质上是只当前session通过当前执行的线程来跟踪和界定。

hibernate还有一个很牛的feature就是可以用HQL,这是完全可以把查询映射到你OO模型的查询语言,我们可以不用过多关注SQL的编写,而更关注于数据和数据、对象和对象之间的关系。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/studentms?useUnicode=true&amp;characterEncoding=utf-8</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 执行操作时是否在控制台打印SQL -->
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<!-- 指定自动生成数据表的策略 -->
<property name="hbm2ddl.auto">update</property>
<!-- 指定currentSession()方法所得到的Session由谁来跟踪管理,thread指Session由当前线程来跟踪管理 -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 指定关联的 .hbm.xml文件 -->
<mapping resource="entity/Students.hbm.xml"/>
<mapping resource="entity/Users.hbm.xml"/>
</session-factory>
</hibernate-configuration>

关于实体和表的映射,需要生成相关.hbm.xml映射文件,用于向Hibernate提供关于将对象持久化到关系数据库中的信息,持久化对象的映射定义可全部存储在同一个映射文件中,也可将每个对象的映射定义存储在独立的文件中。后一种方法较好,因为将大量持久化类的映射定义存储在一个文件中比较麻烦,而且将难以调试和隔离特定类的映射定义错误。

4. 设计接口和实现类

面向接口编程是OOP的设计原则之一,目的是就是降低程序的耦合性,接口定义统一的编程规范,实现类可以根据具体的业务逻辑实现特定的功能,既利于程序的扩展,也利于程序的维护。

在对数据库进行管理时,可以利用Hibernate的 SessionFactroy接口,创建会话工厂对象,它充当数据存储源的代理,并负责创建Session对象。一般情况下,一个项目通常只需要一个SessionFactory就够,然后在其他类中调用其中的方法就OK了。下面就是一个简单的创建会话对象的类方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;


// 会话工厂类,目的获得SessionFactory对象
public class MyHibernateSessionFactory {

private static SessionFactory sessionFactory; //会话工厂属性
// 构造函数保证单例模式
private MyHibernateSessionFactory(){

}
//共有的静态方法,获得会话工厂对象
public static SessionFactory getSessionFactory(){
if(sessionFactory==null){
//创建配置对象
Configuration config = new Configuration().configure();
//创建服务注册对象
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(config.getProperties()).build();
//创建sessionFactory
sessionFactory = config.buildSessionFactory(serviceRegistry);
return sessionFactory;
}else{
return sessionFactory;
}
}
}

利用Hibernate的Query,Transaction和Session可以完成数据库事务的管理操作,Query负责执行各种数据库查询。它可以使用HQL语言或SQL语句两种表达方式。它的返回值一般是List,需要自己转换。Transaction接口负责事务相关的操作,一般在Hibernate的增删改中出现,但是使用Hibernate的人一般使用spring)去管理事务。

这里值得注意的是Hibernate的Session接口, Session可以看作介于数据连接与事务管理一种中间接口,有时也称Session是一个持久层管理器,因为它包含这一些持久层相关的操作,如存储持久对象至数据库,以及从数据库从获得它们。

在Hibernate中,实例化的Session是一个轻量级的类,创建和销毁它都不会占用很多资源,这不同于JSP 应用中的HttpSession,一般情况我们会会HttpSesion 对象称为用户session。

5. 设计Action控制器

在项目中Action承担着一个控制业务调度和管理跳转的功能,Action就像是服务员,顾客点什么菜,菜上给几号桌,都是ta的职责;所以当实现功能后,需要在struts.xml 中进行注册,与JSP的请求相对应,并完成相应的界面调用。

Struts接受的表单数据的方式有几种方式,分别是实体类对象,属性驱动,模型驱动的方式和表达式驱动等,具体采用哪种需要根据具体的业务逻辑来选择,没有最好的,只有最合适的。

可以直接使用Validator(验证器)框架对表单数据进行验证,而不需要用户编写代码去验证,拦截器是在Action提交之前,动态的拦截Action,然后查询配置文件,如果当前的Action配置了拦截器,那么就相应的实例化出拦截器对象,并串联成表,最后一个一个调用拦截器。

拦截器只对Action进行处理,对其余的不进行处理。拦截器可以读取值栈中的东西,就像登录验证时,拦截器可以读取Session的内容。拦截器一次创建可以多次被调用,只要是使用拦截器的Action,Action执行几次,拦截器就同样执行几次。

6. 项目框架

项目中没有使用spring进行解耦,而是将hibernate和struts进行整合,项目也基本上符合MVC的一个设计理念:

Entity对应数据库表的实体类,Dao层是使用hibernate连接数据库、操作数据库(增删改查)定义了一些列操作数据库的接口,Service层:引用对应的Dao数据库操作。在一定程度上Dao层和Service可以写在一起。以上几层综合起来类似于MVC的模型层。

Action层:处理业务调度和管理跳转,引用对应的Service层,结合Struts的配置文件,跳转到指定的页面。起到一个控制层的作用。

最后是JSP表现的视图层,可以通过编写JSP进行请求和数据显示,这里可以使用struts的一些标签,通过用户session读出数据。JSP真的太难写了ORZ…前后端分离是相当有必要的,使用页面模板也是很有必要的。

整个项目的调用流程基本上是:JSP—Action—Service—DAO—Hibernate。整个项目框架的优点是:利用Struts负责Web层,进行请求拦截。利用Hibernate负责持久化层,完成对数据库的crud操作。

7. 问题总结

通过上面的总结,把项目构建的重要步骤和项目的框架流程都进行分析,从零开始,一步步的构建一个完整项目,真的能够学到很多东西。熟能生巧,多看多思多动手,技术能力自然就有增长咯。