大三学期渐末,事情也挺多的,上周就开始着手整合SSH框架,到现在才真正的完成,过程中碰到了许多小问题(小问题大折腾,哭脸.jpg)。本着善始善终的原则,最终把它给完成了。

本篇文章就在:

win7 64位,eclipse最新版(2017.9),Spring4.3.13,Hibernate5.0.1,Struts2.3.34 环境下,整合SSH。在下一篇文章,我们也来使用Maven来整合一下(毕竟学了就要用嘛,哈哈)。

首先先介绍一下jar包:

以上是我使用完整的jar包清单,我们分别导入了三个框架所需要的jar包,在导jar包的时候需要注意以下几点:

  • jar包冲突:struts2的javassist和Hibernate的javassist有冲突,我们选择最新的版本的(根据你的自身情况选择)。
  • log4j,log4j-api,log4jcore,slf4j-api,slf4j-log4j12的的冲突,我们依旧看情况选择最新版本。
  • c3p0jar包,我们选择最新的(框架之间有重复的记得删除重复)。
  • Spring整合struts2需要导入Spring-web和struts2-spring-plugin jar包,不要丢掉。
  • 数据库jar驱动jar包,根据自身使用的数据库进行选择
  • 因为我这里使用Spring对事务的管理,所以还要导入事务的jar包,spring -jdbc的jar包,spring-orm,Aspectj的jar包。

以上都是我们需要特别注意的,否则整合的过程中会给你带来不小的麻烦

jar包就介绍差不多了,那我们就来开始吧:

首先看一下我的目录结构:

项目大体可以分为三层,视图层,service层,DAO层,因为我们这里没有什么业务,单纯的是调用DAO,所以可能service层和DAO层之间的区别不是很明显。

其实三个框架的整合,就是将Hibernate的session创建交给Spring,将Struts2的Action交给Spring。

(一)在Hibernate中,我们自己通过以下的一系列操作获取session:

		 //加载配置文件
Configuration config = new Configuration().configure();
//根据配置文件创建会话工厂
SessionFactory factory = config.buildSessionFactory();
//根据会话工厂创建会话
Session session = factory.getCurrentSession();
//创建一个事物对象
Transaction tx = session.beginTransaction();
//new 一个学生对象
Student student = new Student("小三",19,99);
//将对象持久化到数据表中
session.save(student);
//提交事务
tx.commit();
//关闭会话
session.close();
//关闭工厂
factory.close();

同样为了解耦,在项目中,我们不再自己手动的来获取session了,而是通过Spring来帮我们创建,并且service层中需要DAO,DAO需要session,也是Spring进行注入。

(二)在Struts2中,我们通过自己在Struts2的主配置文件中指定对应请求的Action的全限定类名,Struts2和Spring整合则是将Action的创建交给了Spring,由Spring来管理Action对象。

接下来我们就这两个方面分别整合Spring和Hibernate,Spring和Struts2,最后在Struts2 Action的execute方法中调用service,对业务进行操作。

下面为了代码的可读性,博主不会将代码分块分析,很重要的将会指出,大多数的过程说明将在注释中给出:


整合Spring和Hibernate:

先给出我们的基本代码:

//DAO接口:
public interface StudentDao {
void insert(Student student);
void delete(Student student);
void update(Student student);
List<Student> selectAllStudents();
boolean selectStudentByIdAndName(String name,int age);
}
//DAO的实现类,里面注入了SessionFactory对象,利用这个我们可以获取session

public class StudentDaoImpl implements StudentDao{
//这里的sessionFactory由Spring进行注入
private SessionFactory sessionFactory;
//所以这里需要setter方法,这里的getter方法顺带添上,如果以后需要获取sessionFactory的话可以调用
public SessionFactory getSessionFactory() {
return sessionFactory;
}
//依赖注入,需要setter方法
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
} @Override
public void insert(Student student) {
sessionFactory.getCurrentSession().save(student);
} @Override
public void delete(Student student) {
sessionFactory.getCurrentSession().delete(student);
} @Override
public void update(Student student) {
sessionFactory.getCurrentSession().update(student);
} @Override
public List<Student> selectAllStudents() {
String hql = "from Student";
return sessionFactory.getCurrentSession().createQuery(hql).list();
} //通过name和age来判别学生是否存在
@Override
public boolean selectStudentByIdAndName(String name, int age) {
String hql = "from Student where name=? and age=?";
boolean flag = false;
if(sessionFactory.getCurrentSession().createQuery(hql).setString(0, name).setInteger(1, age).uniqueResult()!=null) {
flag = true;
}
return flag;
}
}

上面的DAO,我们获取session不再使用原始的方法了,而是使用Spring注入的方式为我们程序获取session,具体的SessionFactory配置,将在后面的Spring配置文件给出。


接下来我们看Service:

//service接口
public interface StudentService {
void add(Student student);
void remove(Student student);
void modify(Student student);
List<Student> findAllStudents();
boolean findByNameAndAge(String name,int age);
}

//service实现类
public class StudentServiceImpl implements StudentService {
//这里的Dao对象是由Spring注入,下面要有setter方法
private StudentDao studentdao;
public StudentDao getStudentdao() {
return studentdao;
}
public void setStudentdao(StudentDao studentdao) {
this.studentdao = studentdao;
}
@Override
public void add(Student student) {
studentdao.insert(student);
} @Override
public void remove(Student student) {
studentdao.delete(student); } @Override
public void modify(Student student) {
studentdao.update(student); } @Override
public List<Student> findAllStudents() {
return studentdao.selectAllStudents();
}
@Override
public boolean findByNameAndAge(String name, int age) {
return studentdao.selectStudentByIdAndName(name, age);
} }

接着便是我们Spring的配置文件(下面的配置文件是完整的配置文件,即整合ssh的完整配置文件,其实也就是在整合Hibernate的基础上注册了Action类的bean):

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 注册c3p0数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<!--处理中文乱码问题-->
<property name="jdbcUrl" value="jdbc:mysql:///test?useUnicode=true&amp;characterEncoding=utf8"/>
<property name="user" value="root"/>
<property name="password" value="123"/>
<!-- ?useUnicode=true&amp;characterEncoding=utf8 -->
</bean> <!-- 注册sessionFactory -->
<bean id="MysessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!--不要缺少classpath,否则在整合Struts2时候会找不到映射文件-->
<property name="mappingDirectoryLocations" value="classpath:com/testSpring/Entity"/> <property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.current_session_context_class">org.springframework.orm.hibernate5.SpringSessionContext</prop>
</props>
</property>
</bean> <!-- 注册studentDao -->
<bean id="StudentDao" class="com.testSpring.Dao.StudentDaoImpl">
<property name="sessionFactory" ref="MysessionFactory"></property>
</bean> <!-- 注册studentService -->
<bean id="studentservice" class="com.testSpring.Service.StudentServiceImpl">
<property name="studentdao" ref="StudentDao"/>
</bean> <!-- 将Action交由Spring来管理 ref里面的studentservice引用的是上面的bean,这个是多例的,因为每个请求对应一个Action,不能多个用户共用一个Action-->
<bean id="RegisterAction" class="com.testSpring.Action.RegisterAction" scope="prototype">
<property name="studentservice" ref="studentservice"/>
</bean> <!-- 注册事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="MysessionFactory"/>
</bean> <!-- 注册事务通知 -->
<tx:advice id="myAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add" isolation="DEFAULT" propagation="REQUIRED"/>
<tx:method name="remove" isolation="DEFAULT" propagation="REQUIRED" />
<tx:method name="modify" isolation="DEFAULT" propagation="REQUIRED" />
<tx:method name="findAllStudents" isolation="DEFAULT" propagation="REQUIRED" read-only="true"/>
<tx:method name="findByNameAndAge" isolation="DEFAULT" propagation="REQUIRED" read-only="true"/>
</tx:attributes>
</tx:advice> <!-- aop配置切入点 -->
<aop:config>
<aop:pointcut expression="execution(* *..Service.*.*(..))" id="myPointCut"/>
<aop:advisor advice-ref="myAdvice" pointcut-ref="myPointCut"/>
</aop:config>
</beans>

整合Hibernate,

我们需要注册SessionFactory,

class为org.springframework.orm.hibernate5.LocalSessionFactoryBean,位于我们Spring orm包下,对于不同版本的Hibernate,我们应该选用不同的整合class。

上面的Spring主配置文件中用<property name="hibernateProperties">属性来替代了我们导入Hibernate的主配置文件,当然我们也可以直接导入Hibernate的主配置文件,不过为了简洁,我们这样比较方便。

关于配置文件后面对事务的管理,我们这里就不多说了,我的前几篇文章都有详细的介绍,有兴趣的同学可以去看看:

http://blog.csdn.net/qq_39266910/article/details/78826171


如果做到上面的这些,我们便可以进行测试了:

//测试类
public class Test01 {
private StudentService service; @Before
public void before() {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
service = (StudentService)ac.getBean("studentservice");
} @Test
public void test01() {
service.add(new Student("中文",18));
System.out.println("Success");
} @Test
public void test02() {
Student student = new Student();
student.setId(1);
service.remove(student);
} @Test
public void test03() {
Student student = new Student("张三",25);
student.setId(10);
service.modify(student);
} @Test
public void test06() {
System.out.println(service.findAllStudents());
} @Test
public void test07() {
System.out.println(service.findByNameAndAge("中", 18));
}
}

以上就是Spring整合Hibernate的全过程,接下来我们来整合Struts2:


Spring整合Struts2

首先是Struts2的主配置文件:

<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd"> <struts>
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
<constant name="struts.devMode" value="true" /> <package name="default" namespace="/" extends="struts-default" >
<!--下面的全限定类名可以改为RegisterAction,当我们在Spring中注册当前Action类的bean-->
<action name="register" class="com.testSpring.Action.RegisterAction">
<result name="success">/welcome.jsp</result>
<result name="error">/error.jsp</result>
</action>
</package>
</struts>

接着是对应的Action:

public class RegisterAction extends ActionSupport{
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
private int age;
//Spring会为我们自动注入service,但是这个属性名要和Spring主配置文件里面注册的studentservice的id保持一致。
//或者将Action交由Spring管理,在Spring配置Action的bean,为bean注入service,如果这样,我们在struts2主配置文件的class就不必写成Action的全限定类名,而是Spring中注册的id。
private StudentService studentservice;
public RegisterAction() {
super();
} public RegisterAction(String name, int age) {
super();
this.name = name;
this.age = age;
} // 注入Service,我们需要保留set方法
public void setStudentservice(StudentService studentservice) {
this.studentservice = studentservice;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String execute() {
System.out.println(studentservice);
System.out.println(name);
System.out.println(age);
studentservice.add(new Student(name,age));
return SUCCESS;
}
}

以上是模拟完成一个注册功能,view层发送一个请求,包含姓名和年龄,后台负责接收,并调用service层进行处理,service层调用DAO,DAO调用SessionFactory获取session,最终达到对数据库的操作。

如果仅仅这样你是不是忘了些什么?

①我们需要在web.xml中添加Struts2的核心过滤器。

②设置一个监听器,监听当web容器创建的时候,即创建我们的Spring容器,这样我们不再需要自己加载Spring的主配置文件。

③设置web容器全局参数,自定义Spring主配置文件的位置和命名

具体的看web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <!-- 自定义Spring主配置文件的位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param> <!-- 使用ContextLoaderListener初始化Spring容器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener> <!-- 定义Struts 2的FilterDispathcer的Filter -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<!-- FilterDispatcher用来初始化Struts 2并且处理所有的WEB请求。 -->
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping> <welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

我们一并给出jsp页面(success和error页面就不写了,一个形式):

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>register</title>
</head>
<body>
<form action="register" method="post">
姓名<input type="text" name="name"><br>
年龄<input type="text" name="age"><br>
<input type="submit" value="注册">
</form>
</body>
</html>

接下来我们进行测试:

点击后,跳转到:

最后看看数据库:


以上的ssh整合大体上是没有什么问题的,但是碰上延时加载的话会出现一些意想不到的事情,在讲Hibernate的session的时候,我们说过session有两种获取的方式,一个是getCurrentSession,另一个是openSession,它们两个获取的session的区别是,getSession获得的session必须要在事务中执行,也就说没有事务是不能获取session的,当我们使用session.load进行查询的时候,这就是一个延时加载,执行加载方法的时候会产生一个代理,这个代理是一个空代理,只有当我们真正需要这个代理的详细数据的时候,才会真正的进行查询,但是当它真正的查询的时候,已经没有了事务(因为我们这里的事务是通过Spring整合AspectJ,通过AOP的方式实现添加事务的),所以这个时候也就没有了session,所以当再执行详情查询的时候就会报错(no session)。

所以我们需要在web.xml中添加一个过滤器,来获取session,这个过滤器的名字叫做OpenSessionInViewFilter,添上这个过滤器后,当我们进行延时加载的话,就不会再出现no session的情况了!

在OpenSessionInViewFilter的源码中,获取session是利用的SessionFactory,也就是我们自己在Spring的注册的SessionFactory,且在里面,这个类有一个默认的SessionFactory名字就叫做sessionFactory:

注意:添加这个过滤器,一定要在Struts2的核心过滤器之前!

具体原因是:Struts2的核心过滤器中,当有Action请求的时候,会执行executeAction方法,即执行Action,不会有chain.doFilter(执行下一个过滤器),有源码有真相:

这里的mapping就是对应的action请求。

下面是openSessionInViewFilter的具体配置方法,初始化参数是为了自定义我们的sessionFactory的bean id,因为openSessionInViewFilter里面有setter方法,可以为之前设置好的默认值进行修改。


总结:当代码都写出来了,觉得很简单,但是这过程中一直小bug不断(当然大多数都是由自己的粗心造成的),其实三个框架之间的真核无非就是将所有关于类的创建管理交由Spring,由Spring来为需要的注入所需要的bean,不再需要手动的创建一个个的类,使得各个层级之间耦合度降低,即使一层代码出现了问题不需要修改另一层的代码,便于我们项目的维护和更新,也便于出现问题能够即使定位出错的位置。


以上是自己的心得体会,代码均由博主亲自验证,可以运行,文章方便博主以后查阅,也供大家参考,如有错误不吝赐教!

SSH框架完全整合的更多相关文章

  1. maven项目ssh框架的整合

    1.环境 eclipse版本:Eclipse Mars2 4.5jdk版本:1.8maven版本:apache-maven 3.3.9zhnegs这是主要的开发工具版本,ssh的各种jar包版本就不列 ...

  2. 吴裕雄--天生自然JAVA SPRING框架开发学习笔记:测试SSH框架分层整合及验证事务是否有效

    测试框架分层的整合 HibernateTemplate 和 HibernateDaoSupport,这两个类是 Spring 为整合 Hibernate3 提供的两个工具类. HibernateTem ...

  3. 简化SSH框架的整合

    一.开发环境: (1)    OS:Windows 7 (2)    DB:MySql 5.1.6 (3)    JDK:1.8.0_17 (4)    Server:Apache Tomcat 8. ...

  4. ssh框架 基本整合

    struts的基本配置 <struts> <constant name="struts.devModel" value="true" /> ...

  5. Struts2+Spring+Hibernate实现员工管理增删改查功能(一)之ssh框架整合

    前言        转载请标明出处:http://www.cnblogs.com/smfx1314/p/7795837.html 本项目是我写的一个练习,目的是回顾ssh框架的整合以及使用.项目介绍: ...

  6. Spring框架的第四天(整合ssh框架)

    ## Spring框架的第四天 ## ---------- **课程回顾:Spring框架第三天** 1. AOP注解方式 * 编写切面类(包含通知和切入点) * 开启自动代理 2. JDBC模板技术 ...

  7. SSH框架的基本整合

    SSH框架的基本整合 AOP注解方式 编写切面类(包括通知和切入点) 开启自己主动代理 JDBC模板技术 Spring提供模板技术,数据库的操作 以后编写DAO层,都能够继承JdbcDaoSuppor ...

  8. J2EE SSH框架整合教程

    本文仅作为学习和研究的参考,与实际项目使用技术有所不同,由于作者水平有限,错误疏漏在所难免,请各位看官批评指教. 项目的源代码放在:https://github.com/Frank-Pei/SSHIn ...

  9. Eclipse下面的Maven管理的SSH框架整合(Struts,Spring,Hibernate)

    搭建的环境:eclispe下面的maven web项目 Struts:    2.5.10 Spring:    4.3.8 Hibernate:   5.1.7 .Final MySQL:   5. ...

随机推荐

  1. 《Linux命令行与shell脚本编程大全》第十四章 处理用户输入

    有时还会需要脚本能够与使用者交互.bash shell提供了一些不同的方法来从用户处获得数据, 包括命令行参数,命令行选项,以及直接从键盘读取输入的能力. 14.1 命令行参数 就是添加在命令后的数据 ...

  2. JavaEE中的MVC(五)定制Struts——Action跳转JSP

    在JavaEE中的MVC(三)中,我在Servlet中引入了命令模式的使用,采用Xml配置的方式,实现了一个Servlet调用多个不同的Action类,但是还不能实现页面地跳转,这一篇博客从之前的代码 ...

  3. hadoop2.5的伪分布式安装配置

    一.windows环境下安装 根据博主写的一次性安装成功了: http://blog.csdn.net/antgan/article/details/52067441 二.linux环境下(cento ...

  4. C语言之猜数游戏

    #include<stdio.h>#include<stdlib.h>#include<time.h>int main(){ srand(time(0)); int ...

  5. Code Kata:超级偶数数列 javascript实现

    超级偶数(SuperEven)是指每一位都是偶数的正整数,例如: 0,2,4,6,8,20,22,24,26,28,40,...,88,200,202,... 要求写一个函数,输入项数n,返回数列第n ...

  6. 算法提高 9-3摩尔斯电码 map

    算法提高 9-3摩尔斯电码 时间限制:1.0s   内存限制:256.0MB     问题描述 摩尔斯电码破译.类似于乔林教材第213页的例6.5,要求输入摩尔斯码,返回英文.请不要使用"z ...

  7. HDU1075-What Are You Talking About

    What Are You Talking About Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/204800 K ...

  8. CCF-201403-3-命令行选项

    问题描述 试题编号: 201403-3 试题名称: 命令行选项 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 请你写一个命令行分析程序,用以分析给定的命令行里包含哪些选项.每 ...

  9. OAuth 2.0(网转)

    (一)背景知识 OAuth 2.0很可能是下一代的"用户验证和授权"标准,目前在国内还没有很靠谱的技术资料.为了弘扬"开放精神",让业内的人更容易理解" ...

  10. otter双A同步配置

    otter双A配置 最近做跨国服务器的数据同步,用了阿里的otter开源框架,遇到了不少问题,写一下文档为以后做参考. 第一步: 下载所需的文件 :otter,zookeeper,aria2 otte ...