JavaWeb 之 SSH 框架整合

SSH 框架整合


SSH 框架整合的环境准备


SSH 三大框架需要的 jar包

Struts2 框架

struts-2.3.24\apps\struts2-blank\WEB-INF\lib\*.jar————Struts2 需要的所有 jar 包
struts2-spring-plugin-2.3.24.jar————Struts2 整合 Spring 的插件包

Hibernate 框架

hibernate-release-5.0.7.Final\lib\required\*.jar————Hibernate 框架需要的 jar 包
slf4j-api-1.6.1.jar————日志接口
slf4j-log4j12-1.7.2.jar————日志实现
mysql-connector-java-5.1.7-bin.jar————MySQL 的驱动包

Spring 框架

IoC 核心包(6个)
AOP 核心包(4个)
JDBC 模板和事务核心包(2个)
Spring 整合 JUnit 测试包
Spring 整合 Hibernate 核心包
Spring 整合 Struts2 核心包

SSH 三大框架需要的配置文件

Struts2 框架

  • web.xml 中配置核心的过滤器
1
2
3
4
5
6
7
8
9
10
<!--配置 Struts2 框架核心的过滤器-->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
  • src 目录下创建 struts.xml,用来配置 Action

Hibernate 框架

  • src 目录创建 hibernate.cfg.xml 配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<hibernate-configuration>
<session-factory>
<!-- 必须配置 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///ssh01</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">541638</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

<!-- 可选配置 -->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>

<!-- 配置C3P0的连接池 -->
<property name="connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property>

<!-- 映射配置文件 -->
<mapping resource="com/renkaigis/domain/Customer.hbm.xml"/>
</session-factory>
</hibernate-configuration>
  • JavaBean 所在的包下编写 映射的配置文件JavaBean类名.hbm.xml

Spring 框架

  • web.xml 配置整合 WEB 的监听器
1
2
3
4
5
6
7
8
<!--配置 Spring 框架整合 WEB 的监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
  • src 目录下创建 applicationContext.xml

  • src 目录下加入 log4j.proerties


Spring 框架整合 Struts2 框架


表单访问 Action

  • 导入 CRM 项目的 UI 页面,找到添加客户的页面,修改 form 表单,访问 Action。

编写 CustomerAction 接收请求,在 struts.xml 中完成 Action 的配置

1
2
3
4
5
<!--先配置包结构-->
<package name="crm" extends="struts-default" namespace="/">
<!--配置客户的 Action-->
<action name="customer_*" class="com.renkaigis.web.action.CustomerAction" method="{1}"/>
</package>

模型驱动封装数据

编写好客户的 JavaBean,在 Action 中使用模型驱动来封装数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 客户的控制层
*/
public class CustomerAction extends ActionSupport implements ModelDriven<Customer> {
// 不要忘记自己手动 new
private Customer customer = new Customer();
@Override
public Customer getModel() {
return customer;
}

/**
* 保存客户的方法
*
* @return
*/
public String add() {
System.out.println("WEB 层:保存客户…");
System.out.println(customer);
return NONE;
}
}

在 Action 中获取到 service(开发不会使用,因为麻烦)

可以通过 WebApplicationContextUtils.getWebApplicationContext(ServletActionContext.getServletContext()); 来获取,但是这种方式编写代码太麻烦了!

Spring 整合 Struts2 框架的第一种方式(Action 由 Struts2 框架来创建)

  • 因为导入的 struts2-spring-plugin-2.3.24.jar 包自带一个配置文件 struts-plugin.xml ,该配置文件中有如下代码
1
<constant name="struts.objectFactory" value="spring" />

开启一个常量,如果该常量开启,那么下面的常量就可以使用

  • struts.objectFactory.spring.autoWire = name,该常量是可以让 Action 的类来自动装配 Bean 对象!

  • CustomerService.java

    1
    2
    3
    4
    5
    6
    // 提供 service 的成员属性,提供 set 方法
    private CustomerService customerService;

    public void setCustomerService(CustomerService customerService) {
    this.customerService = customerService;
    }

Spring 整合 Struts2 框架的第二种方式(Action 由 Spring 框架来创建)(强烈推荐)

  • 把具体的 Action 类配置到 applicatonContext.xml 的配置文件中,但是注意 struts.xml 需要做修改:

  • applicationContext.xml

    1
    2
    3
    4
    5
    6
    7
    8
    <!--配置客户模块-->
    <!--强调:配置 Aciton,必须是多例的-->
    <bean id="customerAction" class="com.renkaigis.web.action.CustomerAction" scope="prototype">
    <property name="customerService" ref="customerService"/>
    </bean>

    <bean id="customerService" class="com.renkaigis.service.CustomerServiceImpl">
    </bean>
  • struts.xml 中的修改,把全路径修改成 ID 值

    1
    2
    3
    4
    <package name="crm" extends="struts-default" namespace="/">
    <!--配置客户的 Action,如果 Action 是由 Spring 框架来管理,class 标签只需要去编写 id 值就ok了-->
    <action name="customer_*" class="customerAction" method="{1}"/>
    </package>
  • 第二种方式需要有两个注意的地方

    Spring 框架默认生成 CustomerAction 是单例的,而 Struts2 框架是多例的。所以需要配置 scope="prototype"
    CustomerService 现在必须自己手动注入了。


Spring 框架整合 Hibernate 框架


Spring 框架整合 Hibernate 框架(有配置文件)

(带有 hibernate.cfg.xml 的配置文件。强调:不能加绑定当前线程的配置

编写 CustomerDaoImpl 的代码,加入配置并且在 CustomerServiceImpl 中完成注入

CustomerDaoImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 持久层
*/
public class CustomerDaoImpl implements CustomerDao {
/**
* 保存客户
*
* @param customer
*/
@Override
public void save(Customer customer) {
System.out.println("持久层:保存客户…");
}
}

CustomerServiceImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 客户的业务层
*/
public class CustomerServiceImpl implements CustomerService {
private CustomerDao customerDao;
public void setCustomerDao(CustomerDao customerDao) {
this.customerDao = customerDao;
}

/**
* 保存客户
*
* @param customer
*/
@Override
public void save(Customer customer) {
System.out.println("业务层:保存客户…");
customerDao.save(customer);
}
}

实现步骤:Action 调用 ServiceService 调用 Dao

编写映射的配置文件

Customer.hbm.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<hibernate-mapping>
<class name="com.renkaigis.domain.Customer" table="cst_customer">
<id name="cust_id" column="cust_id">
<generator class="native"/>
</id>
<property name="cust_name" column="cust_name"/>
<property name="cust_user_id" column="cust_user_id"/>
<property name="cust_create_id" column="cust_create_id"/>
<property name="cust_source" column="cust_source"/>
<property name="cust_industry" column="cust_industry"/>
<property name="cust_level" column="cust_level"/>
<property name="cust_linkman" column="cust_linkman"/>
<property name="cust_phone" column="cust_phone"/>
<property name="cust_mobile" column="cust_mobile"/>
</class>
</hibernate-mapping>

hibernate.cfg.xml 的配置文件中引入映射的配置文件

1
2
<!-- 映射配置文件 -->
<mapping resource="com/renkaigis/domain/Customer.hbm.xml"/>

applicationContext.xml 中配置加载 hibernate.cfg.xml

1
2
3
4
<!--编写 Bean,名称都是固定的,加载 hibernate.cfg.xml 配置文件-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml"/>
</bean>

Dao 继承 HibernateDaoSupport 的工具类

CustomerDaoImpl 中想完成数据的添加,Spring 框架提供了一个 HibernateDaoSupport 的工具类,以后 DAO 都可以继承该类!

CustomerDaoImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 持久层
*/
public class CustomerDaoImpl extends HibernateDaoSupport implements CustomerDao {
/**
* 保存客户
*
* @param customer
*/
@Override
public void save(Customer customer) {
System.out.println("持久层:保存客户…");
// 把数据保存到数据库
this.getHibernateTemplate().save(customer);
}
}

applicationContext.xml

1
2
3
4
<!--以后开发:Dao 都需要继承 HibernateDaoSupport,注入 sessionFactory-->
<bean id="customerDao" class="com.renkaigis.dao.CustomerDaoImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>

开启事务的配置

  • 先配置事务管理器,注意现在使用的是 Hibernate 框架,所以需要使用 Hibernate 框架的事务管理器
1
2
3
4
<!--配置平台事务管理器-->
<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
  • 开启注解事务
1
2
<!--开启事务的注解-->
<tx:annotation-driven transaction-manager="transactionManager"/>
  • Service 类中添加事务注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 客户的业务层
*/
@Transactional
public class CustomerServiceImpl implements CustomerService {
private CustomerDao customerDao;
public void setCustomerDao(CustomerDao customerDao) {
this.customerDao = customerDao;
}

/**
* 保存客户
* @param customer
*/
@Override
public void save(Customer customer) {
System.out.println("业务层:保存客户…");
customerDao.save(customer);
}
}

Spring 框架整合 Hibernate 框架(无配置文件)

(不带有 hibernate.cfg.xml 的配置文件)

整合

要不带有 hibernate.cfg.xml 的配置文件,则需要将 hibernate.cfg.xml 中的配置移植到 applicationContext.xml 中。具体操作如下:

Hibernate 配置文件中的配置

  • 数据库连接基本参数(4 大参数)
  • Hibernate 相关的属性
  • 连接池
  • 映射文件

开始进行配置

  • 先配置连接池相关的信息
1
2
3
4
5
6
7
<!--配置 C3P0 连接池-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///ssh01"/>
<property name="user" value="root"/>
<property name="password" value="541638"/>
</bean>
  • 修改 LocalSessionFactoryBean 的属性配置,因为已经没有了 hibernate.cfg.xml 配置文件,所以需要修改该配置,注入连接池:

  • 继续在 LocalSessionFactoryBean 中配置,使用 hibernateProperties 属性继续来配置其他的属性,注意值是 properties 属性文件:

applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!--LocalSessionFactoryBean 加载配置文件-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<!--加载连接池-->
<property name="dataSource" ref="dataSource"/>
<!--加载方言,加载可选项-->
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<!--加载映射配置文件-->
<property name="mappingResources">
<list>
<value>com/renkaigis/domain/Customer.hbm.xml</value>
</list>
</property>
</bean>

延迟加载问题

no session 异常

使用延迟加载的时候,在 WEB 层查询对象的时候程序会抛出异常!

  • 原因是延迟加载还没有发生 SQL 语句,在业务层 session 对象就已经销毁了,所以查询到的 JavaBean 对象已经变成了托管态对象!

  • 注意:一定要先删除 javassist-3.11.0.GA.jar 包(jar包冲突了)

解决方法

解决办法非常简单,Spring 框架提供了一个过滤器,让 session 对象在 WEB 层就创建,在 WEB 层销毁。只需要配置该过滤器即可。

  • 但是:要注意需要在 struts2 的核心过滤器之前进行配置:
1
2
3
4
5
6
7
8
9
<!-- 解决延迟加载的问题 -->
<filter>
<filter-name>OpenSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>OpenSessionInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

终极版 SSH 整合


配置文件

web.xml

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
30
31
32
33
34
35
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">

<!--配置 Spring 框架整合 WEB 的监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>

<!-- 解决延迟加载的问题 -->
<filter>
<filter-name>OpenSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>OpenSessionInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<!--配置 Struts2 框架核心的过滤器-->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

struts.xml

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
<package name="crm" extends="struts-default" namespace="/">
<!--配置客户的 Action-->
<action name="customer_*" class="customerAction" method="{1}"/>
</package>
</struts>

application.xml

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<?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:///ssh01"/>
<property name="user" value="root"/>
<property name="password" value="541638"/>
</bean>

<!--LocalSessionFactoryBean 加载配置文件-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<!--加载连接池-->
<property name="dataSource" ref="dataSource"/>
<!--加载方言,加载可选项-->
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<!--加载映射配置文件-->
<property name="mappingResources">
<list>
<value>com/renkaigis/domain/Customer.hbm.xml</value>
</list>
</property>
</bean>

<!--先配置平台事务管理器-->
<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>

<!--开启事务的注解-->
<tx:annotation-driven transaction-manager="transactionManager"/>

<!--配置客户模块-->
<!--强调:配置 Aciton,必须是多例的-->
<bean id="customerAction" class="com.renkaigis.web.action.CustomerAction" scope="prototype">
<property name="customerService" ref="customerService"/>
</bean>
<bean id="customerService" class="com.renkaigis.service.CustomerServiceImpl">
<property name="customerDao" ref="customerDao"/>
</bean>
<!--以后开发:Dao 都需要继承 HibernateDaoSupport,注入 sessionFactory-->
<bean id="customerDao" class="com.renkaigis.dao.CustomerDaoImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
</beans>

log4j.properties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c\:mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### set log levels - for more verbose logging change 'info' to 'debug' ###

log4j.rootLogger=info, stdout

WEB 项目

控制层

CustomerAction.java ,继承 ActionSupport 类,使用 模型驱动 封装数据(记得手动 new,手动实例化 JavaBean)。

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
30
31
32
33
34
35
36
37
package com.renkaigis.web.action;

import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.renkaigis.domain.Customer;
import com.renkaigis.service.CustomerService;

/**
* 客户的控制层
*/
public class CustomerAction extends ActionSupport implements ModelDriven<Customer> {
// 不要忘记自己手动 new
private Customer customer = new Customer();

@Override
public Customer getModel() {
return customer;
}

// 提供 service 的成员属性,提供 set 方法
private CustomerService customerService;
public void setCustomerService(CustomerService customerService) {
this.customerService = customerService;
}

/**
* 保存客户的方法
*
* @return
*/
public String add() {
System.out.println("WEB 层:保存客户…");
customerService.save(customer);
return NONE;
}
}

业务层

CustomerServiceImpl.java,添加事务注解,处理业务逻辑,调用持久层。

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
30
31
32
package com.renkaigis.service;

import com.renkaigis.dao.CustomerDao;
import com.renkaigis.domain.Customer;
import org.springframework.transaction.annotation.Transactional;

/**
* 客户的业务层
*/
@Transactional
public class CustomerServiceImpl implements CustomerService {
private CustomerDao customerDao;
public void setCustomerDao(CustomerDao customerDao) {
this.customerDao = customerDao;
}

/**
* 保存客户
*
* @param customer
*/
@Override
public void save(Customer customer) {
System.out.println("业务层:保存客户…");
customerDao.save(customer);
}

@Override
public void update(Customer customer) {
customerDao.update(customer);
}
}

持久层

CustomerDaoImpl.java,继承 HibernateDaoSupport 类,使用 Hibernate 模板类实现 Java 类与数据库之间的转换和访问。

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
package com.renkaigis.dao;

import com.renkaigis.domain.Customer;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;

/**
* 持久层
*/
public class CustomerDaoImpl extends HibernateDaoSupport implements CustomerDao {
/**
* 保存客户
* @param customer
*/
@Override
public void save(Customer customer) {
System.out.println("持久层:保存客户…");
// 把数据保存到数据库
this.getHibernateTemplate().save(customer);
}

@Override
public void update(Customer customer) {
this.getHibernateTemplate().update(customer);
}
}