最近老师带一个网上商城的SSH项目,自己想把项目的过程记录下来。一希望自己能将做项目中的一些BUG的解决方法分享给大家,二来可以帮助那些期末做课设的同学。本项目的SSH是指Spring4+Struts2+Hibernate5,项目中需要的jar包我会放在本章的百度网盘链接中。如果后续还需要添加jar包我会在需要添加的地方加以说明并会附上百度网盘链接。
开发环境说明
- 网上商城项目SSH项目开发环境,部分辅助软件不做陈述。- MySQL 5
- Eclipse EE
- Java 1.8
- Tomcat 9.0
 
下载需要的jar
- 我已经将将搭建环境的jar包进行了初步的整理,先把文件下载下来。 - SSH整合Jar百度网盘地址 - 1 - https://pan.baidu.com/s/1Fv0JBF7p7DEqVjBKSCF9Eg 
- 下载解压后的文件应该如下图所示,红框文件夹里的jar应该有49个。 -SSH%E6%A1%86%E6%9E%B6%E6%95%B4%E5%90%88-1_1.png) 
 
搭建Spring4环境
- 在Eclipse里创建Dynamic Web Project项目。 - 项目名我这里起为SshTest。Tomcat 9.0也在这里设置,web.xml的版本设置为3.1。第一个页面设置完成后不要直接点Finish,请点Next。具体设置如下图。-SSH%E6%A1%86%E6%9E%B6%E6%95%B4%E5%90%88-1_2.png) 
- 点击Next两次到下图这个界面把Generate web.xml deploayment descriptor勾选上,然后再点击Finish。-SSH%E6%A1%86%E6%9E%B6%E6%95%B4%E5%90%88-1_3.png) 
 
- 项目名我这里起为SshTest。Tomcat 9.0也在这里设置,web.xml的版本设置为3.1。第一个页面设置完成后不要直接点Finish,请点Next。具体设置如下图。
- 将“全部的jar包”中49个jar包复制到项目/WebContent/WEB-INF/lib文件中。然后将bin所有jar添加项目依赖中。 
- 在Java Resources下的src中创建beans.xml,内容如下所示。 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11- <?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:aop="http://www.springframework.org/schema/aop"
 xmlns:context="http://www.springframework.org/schema/context" 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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
 <context:annotation-config />
 <bean id="date" class="java.util.Date" />
 </beans>
- 配置spring监听器和log4j2监听器,编辑/WebContent/WEB-INF/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- <?xml version="1.0" encoding="UTF-8"?> 
 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
 <display-name>SshTest</display-name>
 <!-- 1、添加log4j监听器,log4j监听器要放在前面 -->
 <context-param>
 <param-name>log4jConfiguration</param-name>
 <param-value>/WEB-INF/classes/log4j2.xml</param-value>
 </context-param>
 <!-- log4j监听器配置结束,在Servlet3.0以上且Tomcat7.0以上的版本中,log4j不需要额外的配置了 -->
 <!-- 2、添加spring监听器 -->
 <context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>classpath:beans.xml</param-value>
 </context-param>
 <listener>
 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
 <!-- spring监听器配置结束 -->
 <welcome-file-list>
 <welcome-file>index.html</welcome-file>
 <welcome-file>index.htm</welcome-file>
 <welcome-file>index.jsp</welcome-file>
 <welcome-file>default.html</welcome-file>
 <welcome-file>default.htm</welcome-file>
 <welcome-file>default.jsp</welcome-file>
 </welcome-file-list>
 </web-app>
- 在Java Resources下的src中创建log4j2.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- <?xml version="1.0" encoding="UTF-8"?> 
 <!DOCTYPE xml>
 <Configuration status="off" monitorInterval="1800">
 <properties>
 <property name="LOG_HOME">/opt/logs/Test/log4j2Demo/logs</property>
 <property name="ERROR_LOG_FILE_NAME">error</property>
 </properties>
 <Appenders>
 <Console name="Console" target="SYSTEM_OUT">
 <PatternLayout pattern="%d %-5p (%F:%L) - %m%n" />
 </Console>
 <RollingRandomAccessFile name="ErrorLog"
 fileName="${LOG_HOME}/${ERROR_LOG_FILE_NAME}.log"
 filePattern="${LOG_HOME}/${ERROR_LOG_FILE_NAME}.log.%d{yyyy-MM-dd}.gz">
 <PatternLayout
 pattern="%d %-5p (%F:%L) - %m%n"/>
 <Policies>
 <TimeBasedTriggeringPolicy/>
 <SizeBasedTriggeringPolicy size="100 MB"/>
 </Policies>
 <DefaultRolloverStrategy max="20"/>
 </RollingRandomAccessFile>
 </Appenders>
 <Loggers>
 <!-- 3rdparty Loggers -->
 <logger name="org.springframework.core" level="info">
 </logger>
 <logger name="org.springframework.beans" level="info">
 </logger>
 <logger name="org.springframework.context" level="info">
 </logger>
 <logger name="org.springframework.web" level="info">
 </logger>
 <logger name="com.hafiz.www.controller" level="error" includeLocation="true" additivity="false">
 <appender-ref ref="ErrorLog"/>
 <appender-ref ref="Console"/>
 </logger>
 <root level="info" includeLocation="true">
 <appender-ref ref="Console"/>
 </root>
 </Loggers>
 </Configuration>
- 创建cn.hncj.test包,并在包中创建Test类。 - Test.java中写入的内容如下。 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16- package cn.hncj.test; 
 import java.util.Date;
 import org.junit.runner.RunWith;
 import javax.annotation.Resource;
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 @RunWith(SpringJUnit4ClassRunner.class)
 @ContextConfiguration(locations="classpath:beans.xml")
 public class Test {
 @Resource
 private Date date;
 @org.junit.Test//测试spring的IOC环境
 public void spingioc(){
 System.out.println(date);
 }
 }
- 在Test.java中鼠标右键Run As>Junit Test,如果控制台显示当前时间则说明spring环境配置成功。 -SSH%E6%A1%86%E6%9E%B6%E6%95%B4%E5%90%88-1_4.png)  
 
搭建Hibernate环境
- 在Mysql中创建shop数据库,在shop中创建category数据表。 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22- /*如果存在shop数据库则删除shop数据库 */ 
 DROP DATABASE
 IF EXISTS shop;
 /*创建shop数据库并设置编码方式为utf-8*/
 CREATE DATABASE shop DEFAULT CHARACTER
 SET utf8;
 /*创建shop数据库*/
 USE shop;
 /*如果存在category数据表则删除category数据表 */
 DROP TABLE
 IF EXISTS category;
 /*创建category数据表*/
 CREATE TABLE category (
 /* 类别编号,自动增长 */
 id INT NOT NULL auto_increment,
 /* 类别名称 */
 type VARCHAR (20),
 /* 类别是否为热点类别,热点类别才有可能显示在首页*/
 hot bool DEFAULT FALSE,
 /* 设置类别编号为主键*/
 PRIMARY KEY (id)
 );- category数据表格式如下。id type hot 1 music 1 
 
- category数据表格式如下。
- 创建xml映射文件 - 在Java Resources下的src中创建hibernate.cfg.xml,特别注意的是代码块中的A和B。hibernate.cfg.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<?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 元素用于配置Hibernate中的属性 键:值 -->
 <!-- hibernate.connection.driver_class : 连接数据库的驱动 -->
 <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
 <!-- hibernate.connection.username : 连接数据库的用户名 -->
 <property name="hibernate.connection.username">root</property>
 <!-- hibernate.connection.password : 连接数据库的密码 -->
 <property name="hibernate.connection.password">123456</property>
 <!-- A 下边的hibernate.connection.url是连接数据库的地址,路径,我这里的是本地路径,账号为root,密码是123456 -->
 <property name="hibernate.connection.url">jdbc:mysql:///shop?useUnicode=true&characterEncoding=utf-8</property>
 <!-- ====================以上配置和Spring整合后可以删除================================ -->
 <!-- 操作数据库时,会 向控制台打印sql语句 -->
 <property name="show_sql">true</property>
 <!--============================================================================ -->
 <!-- 打印sql语句前,会将sql语句先格式化 -->
 <property name="format_sql">true</property>
 <!--============================================================================ -->
 <!-- hbm2ddl.auto: 生成表结构的策略配置 update(最常用的取值): 如果当前数据库中不存在表结构,那么自动创建表结构. 如果存在表结构,并且表结构与实体一致,那么不做修改 如果存在表结构,并且表结构与实体不一致,那么会修改表结构.会保留原有列. create(很少):无论是否存在表结构.每次启动Hibernate都会重新创建表结构.(数据会丢失)
 create-drop(极少): 无论是否存在表结构.每次启动Hibernate都会重新创建表结构.每次Hibernate运行结束时,删除表结构.
 validate(很少):不会自动创建表结构.也不会自动维护表结构.Hibernate只校验表结构. 如果表结构不一致将会抛出异常. -->
 <property name="hbm2ddl.auto">update</property>
 <!--============================================================================ -->
 <!-- 数据库方言配置 -->
 <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
 <!--============================================================================ -->
 <!-- 事务自动提交 -->
 <property name="hibernate.connection.autocommit">true</property>
 <!-- B 这是引入ORM的映射文件将下文你创建的实体类的路径替换掉resourcez中的字符串 -->
 <mapping resource="cn/hncj/entity/Category.hbm.xml" />
 </session-factory>
 </hibernate-configuration>
 
- 在Java Resources下的src中创建hibernate.cfg.xml,特别注意的是代码块中的A和B。hibernate.cfg.xml内容如下所示。
- 创建cn.hncj.entity包,并在包中创建Category类,写入的内容如下。 - 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- package cn.hncj.entity; 
 public class Category {
 private Integer id;
 private String type;
 private Boolean hot;
 public Category() {
 }
 public Category(String type, Boolean hot) {
 super();
 this.type = type;
 this.hot = hot;
 }
 public Category(Integer id, String type, Boolean hot) {
 super();
 this.id = id;
 this.type = type;
 this.hot = hot;
 }
 @Override
 public String toString() {
 return "Category [id=" + id + ", type=" + type + ", hot=" + hot + "]";
 }
 public Integer getId() {
 return this.id;
 }
 public void setId(Integer id) {
 this.id = id;
 }
 public String getType() {
 return this.type;
 }
 public void setType(String type) {
 this.type = type;
 }
 public Boolean getHot() {
 return this.hot;
 }
 public void setHot(Boolean hot) {
 this.hot = hot;
 }
 }
- 在cn.hncj.entity包中创建Category.hbm.xml文件,写入的内容如下。 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17- <?xml version="1.0"?> 
 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 <hibernate-mapping>
 <class name="cn.hncj.entity.Category" table="category">
 <id name="id" type="java.lang.Integer">
 <column name="id" />
 <generator class="native" />
 </id>
 <property name="type" type="java.lang.String">
 <column name="type" />
 </property>
 <property name="hot" type="java.lang.Boolean">
 <column name="hot" />
 </property>
 </class>
 </hibernate-mapping>
- 创建cn.hncj.util包,并在包中创建HibernateSessionFactory类,写入的内容如下。 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15- package cn.hncj.util; 
 import org.hibernate.Session;
 import org.hibernate.SessionFactory;
 import org.hibernate.cfg.Configuration;
 public class HibernateSessionFactory {
 private static final Configuration config;
 private static final SessionFactory factory;
 static {
 config = new Configuration().configure();
 factory = config.buildSessionFactory();
 }
 public static Session getSession() {
 return factory.openSession();
 }
 }
- 创建cn.hncj.service包,并在包中创建CategoryService接口类,写入的内容如下。 - 1 
 2
 3
 4
 5- package cn.hncj.service; 
 import cn.hncj.entity.Category;
 public interface CategoryService {
 public void save(Category category); //用来测试Hibernate环境
 }
- 在cn.hncj.service包中创建CategoryServiceImpl接口实现类用来实现CategoryService接口类未实现的方法,写入的内容如下。 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24- package cn.hncj.service; 
 import org.hibernate.Session;
 import cn.hncj.entity.Category;
 import cn.hncj.util.HibernateSessionFactory;
 public class CategoryServiceImpl implements CategoryService{
 @Override
 public void save(Category category) {
 // 通过刚刚生成的sessionFactory获取session
 Session session = HibernateSessionFactory.getSession();
 try {
 // 手动事务
 session.getTransaction().begin();
 // 执行业务逻辑
 session.save(category);
 // 手动提交
 session.getTransaction().commit();
 } catch (Exception e) {
 session.getTransaction().rollback();
 throw new RuntimeException(e);
 } finally {
 session.close();
 }
 }
 }
- 重新编写cn.hncj.test包中的Test.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- package cn.hncj.test; 
 import java.util.Date;
 import org.junit.runner.RunWith;
 import javax.annotation.Resource;
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 import cn.hncj.entity.Category;
 import cn.hncj.service.CategoryService;
 import cn.hncj.service.CategoryServiceImpl;
 @RunWith(SpringJUnit4ClassRunner.class)
 @ContextConfiguration(locations="classpath:beans.xml")
 public class Test {
 @Resource
 private Date date;
 @org.junit.Test//测试spring的IOC环境
 public void spingioc(){
 System.out.println(date);
 }
 @org.junit.Test//测试Hibernate的开发环境,因为没有整合,可以直接new
 public void hihernate() {
 CategoryService categoryService = new CategoryServiceImpl();
 Category category = new Category("mantype", true);
 categoryService.save(category);
 }
 }- 在Test.java中鼠标右键Run As>Junit Test,如果控制台显示如下则说明hibernate环境可能配置成功。-SSH%E6%A1%86%E6%9E%B6%E6%95%B4%E5%90%88-1_5.png) 
- 如果shop数据库category数据表中插入下边的数据,则hibernate环境配置成功。id type hot 1 mantype 1 
 
- 在Test.java中鼠标右键Run As>Junit Test,如果控制台显示如下则说明hibernate环境可能配置成功。
整合Spring4和Hibernate5
- 在Java Resources下的src中创建jdbc.properties,将数据库的链接信息单独提取出来便于后期优化,内容如下所示。 - 1 
 2
 3
 4- jdbc.driverClassName=com.mysql.jdbc.Driver 
 jdbc.url = jdbc:mysql://***.**.**.**:3306/shop?useSSL=false
 jdbc.username = ****
 jdbc.password = ******
- 整合spring和hibernate需要在beans.xml添加配置如下。 - 配置数据源dataSource - 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- <context:property-placeholder location="classpath:jdbc.properties" /> 
 <!-- 配置数据源 -->
 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
 destroy-method="close">
 <property name="driverClass">
 <value>${jdbc.driverClassName}</value>
 </property>
 <property name="jdbcUrl">
 <value>${jdbc.url}</value>
 </property>
 <property name="user">
 <value>${jdbc.username}</value>
 </property>
 <property name="password">
 <value>${jdbc.password}</value>
 </property>
 <!--连接池中保留的最小连接数。 -->
 <property name="minPoolSize">
 <value>5</value>
 </property>
 <!--连接池中保留的最大连接数。Default: 15 -->
 <property name="maxPoolSize">
 <value>30</value>
 </property>
 <!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->
 <property name="initialPoolSize">
 <value>10</value>
 </property>
 <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
 <property name="maxIdleTime">
 <value>60</value>
 </property>
 <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
 <property name="acquireIncrement">
 <value>5</value>
 </property>
 <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。
 如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0 -->
 <property name="maxStatements">
 <value>0</value>
 </property>
 <!--每60秒检查所有连接池中的空闲连接。Default: 0 -->
 <property name="idleConnectionTestPeriod">
 <value>60</value>
 </property>
 <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
 <property name="acquireRetryAttempts">
 <value>30</value>
 </property>
 <!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效 保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试
 获取连接失败后该数据源将申明已断开并永久关闭。Default: false -->
 <property name="breakAfterAcquireFailure">
 <value>true</value>
 </property>
 <!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的 时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable
 等方法来提升连接测试的性能。Default: false -->
 <property name="testConnectionOnCheckout">
 <value>false</value>
 </property>
 </bean>
- 在beans.xml配置数据源dataSource后,需要将hibernate.cfg.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- <?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>
 <!-- 操作数据库时,会 向控制台打印sql语句 -->
 <property name="show_sql">true</property>
 <!--============================================================================ -->
 <!-- 打印sql语句前,会将sql语句先格式化 -->
 <property name="format_sql">true</property>
 <!--============================================================================ -->
 <!-- hbm2ddl.auto: 生成表结构的策略配置 update(最常用的取值): 如果当前数据库中不存在表结构,那么自动创建表结构.
 如果存在表结构,并且表结构与实体一致,那么不做修改 如果存在表结构,并且表结构与实体不一致,那么会修改表结构.会保留原有列. create(很少):无论是否存在表结构.每次启动Hibernate都会重新创建表结构.(数据会丢失)
 create-drop(极少): 无论是否存在表结构.每次启动Hibernate都会重新创建表结构.每次Hibernate运行结束时,删除表结构.
 validate(很少):不会自动创建表结构.也不会自动维护表结构.Hibernate只校验表结构. 如果表结构不一致将会抛出异常. -->
 <property name="hbm2ddl.auto">update</property>
 <!--============================================================================ -->
 <!-- 数据库方言配置 -->
 <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
 <!--============================================================================ -->
 <!-- 事务自动提交 -->
 <property name="hibernate.connection.autocommit">true</property>
 <!-- B 这是引入ORM的映射文件将下文你创建的实体类的路径替换掉resourcez中的字符串 -->
 <mapping resource="cn/hncj/entity/Category.hbm.xml" />
 </session-factory>
 </hibernate-configuration>
- 配置sessionFactory - 1 
 2
 3
 4
 5- <!-- 配置sessionFactory --> 
 <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
 <property name="dataSource" ref="dataSource" />
 <property name="configLocation" value="classpath:hibernate.cfg.xml" />
 </bean>
- 配置spring的事务管理器 - 1 
 2
 3
 4- <!-- 配置spring事务管理器--> 
 <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
 <property name="sessionFactory" ref="sessionFactory" />
 </bean>
- 配置advice - 1 
 2
 3
 4
 5
 6
 7
 8
 9- <!-- 配置advice(通知) --> 
 <tx:advice id="advice" transaction-manager="transactionManager">
 <tx:attributes>
 <tx:method name="save*" propagation="REQUIRED" />
 <tx:method name="update*" propagation="REQUIRED" />
 <tx:method name="delete*" propagation="REQUIRED" />
 <tx:method name="*" propagation="SUPPORTS" />
 </tx:attributes>
 </tx:advice>
- 配置AOP切面(需要足以的是expression中service的路径,这个需要根据自己在hibernate中写的service路径来写) - 1 
 2
 3
 4
 5
 6
 7
 8- <!-- 配置AOP切面 --> 
 <aop:config>
 <!-- 配置哪些包的类要切入事务 -->
 <aop:pointcut id="pointcut" expression="execution(* cn.hncj.service.*.*(..))" />
 <aop:advisor advice-ref="advice" pointcut-ref="pointcut" />
 <!-- 连接了上面的advice和上面的pointcut -->
 <!-- aop:pointcut要写在aop:advisor上面,否则会报错 -->
 </aop:config>
 
- 由于要测试spring和hibernate的整合需要重写cn.hncj.service包中的CategoryService接口类,写入的内容如下。 - 1 
 2
 3
 4
 5
 6- package cn.hncj.service; 
 import cn.hncj.entity.Category;
 public interface CategoryService {
 public void save(Category category); //用来测试Hibernate环境
 public void update(Category category); //用来测试Spring和Hibernate整合后
 }
- 由于我们重写了cn.hncj.service包中的CategoryService接口类,我们添加的update接口方法需要在CategoryServiceImlp中实现。CategoryServiceImlp.java写入的内容如下。 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23- package cn.hncj.service; 
 import org.hibernate.Session;
 import org.hibernate.SessionFactory;
 import cn.hncj.entity.Category;
 public class CategoryServiceImpl implements CategoryService{
 private SessionFactory sessionFactory;
 // 当需要使用sessoinFactory的时候,Spring会将sessionFactory注入进来
 public void setSessionFactory(SessionFactory sessionFactory) {
 this.sessionFactory = sessionFactory;
 }
 protected Session getSession() {
 // 从当前线程获取session,如果没有则创建一个新的session
 return sessionFactory.getCurrentSession();
 }
 @Override
 public void save(Category category) {
 getSession().save(category);
 }
 @Override
 public void update(Category category) {
 getSession().update(category);
 }
 }
- 在Spring的配置文件beans.xml中配一下这个CategoryService。 - 1 
 2
 3
 4
 5- <!-- 测试spring与hibernate整合结果 --> 
 <bean id="categoryService" class="cn.hncj.service.CategoryServiceImpl">
 <property name="sessionFactory" ref="sessionFactory" />
 <!-- 依赖的sessionFactory用我们之前配好的sessionFactory -->
 </bean>
- 重新Java Resources下的src的beans.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
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102- <?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:aop="http://www.springframework.org/schema/aop"
 xmlns:context="http://www.springframework.org/schema/context" 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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
 <context:annotation-config />
 <bean id="date" class="java.util.Date" />
 <context:property-placeholder location="classpath:jdbc.properties" />
 <!-- 配置数据源 -->
 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
 destroy-method="close">
 <property name="driverClass">
 <value>${jdbc.driverClassName}</value>
 </property>
 <property name="jdbcUrl">
 <value>${jdbc.url}</value>
 </property>
 <property name="user">
 <value>${jdbc.username}</value>
 </property>
 <property name="password">
 <value>${jdbc.password}</value>
 </property>
 <!--连接池中保留的最小连接数。 -->
 <property name="minPoolSize">
 <value>5</value>
 </property>
 <!--连接池中保留的最大连接数。Default: 15 -->
 <property name="maxPoolSize">
 <value>30</value>
 </property>
 <!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->
 <property name="initialPoolSize">
 <value>10</value>
 </property>
 <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
 <property name="maxIdleTime">
 <value>60</value>
 </property>
 <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
 <property name="acquireIncrement">
 <value>5</value>
 </property>
 <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。
 如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0 -->
 <property name="maxStatements">
 <value>0</value>
 </property>
 <!--每60秒检查所有连接池中的空闲连接。Default: 0 -->
 <property name="idleConnectionTestPeriod">
 <value>60</value>
 </property>
 <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
 <property name="acquireRetryAttempts">
 <value>30</value>
 </property>
 <!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效 保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试
 获取连接失败后该数据源将申明已断开并永久关闭。Default: false -->
 <property name="breakAfterAcquireFailure">
 <value>true</value>
 </property>
 <!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的 时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable
 等方法来提升连接测试的性能。Default: false -->
 <property name="testConnectionOnCheckout">
 <value>false</value>
 </property>
 </bean>
 <!-- 配置sessionFactory -->
 <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
 <property name="dataSource" ref="dataSource" />
 <property name="configLocation" value="classpath:hibernate.cfg.xml" />
 </bean>
 <!-- 配置spring事务管理器 -->
 <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
 <property name="sessionFactory" ref="sessionFactory" />
 </bean>
 <!-- 配置advice(通知) -->
 <tx:advice id="advice" transaction-manager="transactionManager">
 <tx:attributes>
 <tx:method name="save*" propagation="REQUIRED" />
 <tx:method name="update*" propagation="REQUIRED" />
 <tx:method name="delete*" propagation="REQUIRED" />
 <tx:method name="*" propagation="SUPPORTS" />
 </tx:attributes>
 </tx:advice>
 <!-- 配置AOP切面 -->
 <aop:config>
 <!-- 配置哪些包的类要切入事务 -->
 <aop:pointcut id="pointcut" expression="execution(* cn.hncj.service.*.*(..))" />
 <aop:advisor advice-ref="advice" pointcut-ref="pointcut" />
 <!-- 连接了上面的advice和上面的pointcut -->
 <!-- aop:pointcut要写在aop:advisor上面,否则会报错 -->
 </aop:config>
 <!-- 测试spring与hibernate整合结果 -->
 <bean id="categoryService" class="cn.hncj.service.CategoryServiceImpl">
 <property name="sessionFactory" ref="sessionFactory" />
 <!-- 依赖的sessionFactory用我们之前配好的sessionFactory -->
 </bean>
 </beans>
- 重新编写cn.hncj.test包中的Test.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- package cn.hncj.test; 
 import java.util.Date;
 import org.junit.runner.RunWith;
 import javax.annotation.Resource;
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 import cn.hncj.entity.Category;
 import cn.hncj.service.CategoryService;
 import cn.hncj.service.CategoryServiceImpl;
 @RunWith(SpringJUnit4ClassRunner.class)
 @ContextConfiguration(locations="classpath:beans.xml")
 public class Test {
 @Resource
 private Date date;
 @org.junit.Test//测试spring的IOC环境
 public void spingioc(){
 System.out.println(date);
 }
 // @org.junit.Test//测试Hibernate的开发环境,因为没有整合,可以直接new
 // public void hihernate() {
 // CategoryService categoryService = new CategoryServiceImpl();
 // Category category = new Category("mantype", true);
 // categoryService.save(category);
 // }
 @Resource
 private CategoryService categoryService;
 @org.junit.Test // 测试Hibernate和Spring整合后
 public void hibernateAndSpring() {
 categoryService.update(new Category(1, "girltype", true)); // categoryService通过Spring从上面注入进来的
 }
 }- 在Test.java中鼠标右键Run As>Junit Test,如果控制台显示如下则说明spring和hibernate整合可能成功。-SSH%E6%A1%86%E6%9E%B6%E6%95%B4%E5%90%88-1_6.png) 
- 如果shop数据库category数据表中插入下边的数据,则说明spring和hibernate整合成功。id type hot 1 girltype 1 
 
- 在Test.java中鼠标右键Run As>Junit Test,如果控制台显示如下则说明spring和hibernate整合可能成功。
搭建Struts2环境并整合Spring4
- 在web.xml文件对Struts2进行配置,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
 36- <?xml version="1.0" encoding="UTF-8"?> 
 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
 <display-name>SshTest</display-name>
 <!-- 1、添加log4j监听器,log4j监听器要放在前面 -->
 <context-param>
 <param-name>log4jConfiguration</param-name>
 <param-value>/WEB-INF/classes/log4j2.xml</param-value>
 </context-param>
 <!-- log4j监听器配置结束,在Servlet3.0以上且Tomcat7.0以上的版本中,log4j不需要额外的配置了 -->
 <!-- 2、添加spring监听器 -->
 <context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>classpath:beans.xml</param-value>
 </context-param>
 <listener>
 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
 <!-- spring监听器配置结束 -->
 <!-- 6、添加Struts2的核心过滤器。注意对应的是2.5.16版本 -->
 <filter>
 <filter-name>struts2</filter-name>
 <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
 </filter>
 <filter-mapping>
 <filter-name>struts2</filter-name>
 <url-pattern>/*</url-pattern>
 </filter-mapping>
 <welcome-file-list>
 <welcome-file>index.html</welcome-file>
 <welcome-file>index.htm</welcome-file>
 <welcome-file>index.jsp</welcome-file>
 <welcome-file>default.html</welcome-file>
 <welcome-file>default.htm</welcome-file>
 <welcome-file>default.jsp</welcome-file>
 </welcome-file-list>
 </web-app>
- 创建cn.hncj.action包,并在包中创建CategoryAction类,写入的内容如下。 - 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- package cn.hncj.action; 
 import com.opensymphony.xwork2.ActionSupport;
 import cn.hncj.entity.Category;
 import cn.hncj.service.CategoryService;
 public class CategoryAction extends ActionSupport{
 private static final long serialVersionUID = 1L;
 private CategoryService categoryService;
 // 设置categoryService是为了很直观的看出与Spring整合前后的不同
 private Category category;
 // 设置一个私有成员变量接收url带过来的参数,注意下面要写好get和set方法
 public void setCategoryService(CategoryService categoryService) {
 this.categoryService = categoryService;
 }
 public String update() {
 System.out.println("----update----");
 System.out.println(categoryService);// 由于已经和Spring整合,所以可以拿到这个categoryService了,打印出来就不是null了
 categoryService.update(category);
 // 新加一条语句,来更新数据库
 return "index";
 }
 public String save() {
 System.out.println("----save----");
 System.out.println(categoryService);// 整合前后输出不同
 categoryService.save(category);
 return "index";
 }
 public Category getCategory() {
 return category;
 }
 public void setCategory(Category category) {
 this.category = category;
 }
 }
- 在Java Resources下的src中创建struts.xml文件,内容如下。 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13- <?xml version="1.0" encoding="UTF-8" ?> 
 <!DOCTYPE struts PUBLIC
 "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
 "http://struts.apache.org/dtds/struts-2.5.dtd">
 <struts>
 <package name="test" namespace="/" extends="struts-default">
 <global-allowed-methods>execute,input,back,cancel,browse,update,save,delete,list,index</global-allowed-methods>
 <!-- class对应的是Spring中配置该Action的id值,因为要交给Spring管理 -->
 <action name="category_*" class="cn.hncj.action.CategoryAction" method="{1}">
 <result name="index">/index.jsp</result>
 </action>
 </package>
 </struts>
- 在beans.xml文件中添加categoryaction配置。 - 1 
 2
 3
 4
 5- <!-- 把CategoryAction和它的依赖交给Spring管理 --> 
 <bean id="categoryAction" class="cn.hncj.action.CategoryAction" scope="prototype">
 <property name="categoryService" ref="categoryService" />
 <!-- 依赖的categoryService用上面和Hibernate整合时配置好的categoryService -->
 </bean>
- 完整的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
 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
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107- <?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:aop="http://www.springframework.org/schema/aop"
 xmlns:context="http://www.springframework.org/schema/context" 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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
 <context:annotation-config />
 <bean id="date" class="java.util.Date" />
 <context:property-placeholder location="classpath:jdbc.properties" />
 <!-- 配置数据源 -->
 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
 destroy-method="close">
 <property name="driverClass">
 <value>${jdbc.driverClassName}</value>
 </property>
 <property name="jdbcUrl">
 <value>${jdbc.url}</value>
 </property>
 <property name="user">
 <value>${jdbc.username}</value>
 </property>
 <property name="password">
 <value>${jdbc.password}</value>
 </property>
 <!--连接池中保留的最小连接数。 -->
 <property name="minPoolSize">
 <value>5</value>
 </property>
 <!--连接池中保留的最大连接数。Default: 15 -->
 <property name="maxPoolSize">
 <value>30</value>
 </property>
 <!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->
 <property name="initialPoolSize">
 <value>10</value>
 </property>
 <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
 <property name="maxIdleTime">
 <value>60</value>
 </property>
 <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
 <property name="acquireIncrement">
 <value>5</value>
 </property>
 <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。
 如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0 -->
 <property name="maxStatements">
 <value>0</value>
 </property>
 <!--每60秒检查所有连接池中的空闲连接。Default: 0 -->
 <property name="idleConnectionTestPeriod">
 <value>60</value>
 </property>
 <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
 <property name="acquireRetryAttempts">
 <value>30</value>
 </property>
 <!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效 保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试
 获取连接失败后该数据源将申明已断开并永久关闭。Default: false -->
 <property name="breakAfterAcquireFailure">
 <value>true</value>
 </property>
 <!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的 时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable
 等方法来提升连接测试的性能。Default: false -->
 <property name="testConnectionOnCheckout">
 <value>false</value>
 </property>
 </bean>
 <!-- 配置sessionFactory -->
 <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
 <property name="dataSource" ref="dataSource" />
 <property name="configLocation" value="classpath:hibernate.cfg.xml" />
 </bean>
 <!-- 配置spring事务管理器 -->
 <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
 <property name="sessionFactory" ref="sessionFactory" />
 </bean>
 <!-- 配置advice(通知) -->
 <tx:advice id="advice" transaction-manager="transactionManager">
 <tx:attributes>
 <tx:method name="save*" propagation="REQUIRED" />
 <tx:method name="update*" propagation="REQUIRED" />
 <tx:method name="delete*" propagation="REQUIRED" />
 <tx:method name="*" propagation="SUPPORTS" />
 </tx:attributes>
 </tx:advice>
 <!-- 配置AOP切面 -->
 <aop:config>
 <!-- 配置哪些包的类要切入事务 -->
 <aop:pointcut id="pointcut" expression="execution(* cn.hncj.service.*.*(..))" />
 <aop:advisor advice-ref="advice" pointcut-ref="pointcut" />
 <!-- 连接了上面的advice和上面的pointcut -->
 <!-- aop:pointcut要写在aop:advisor上面,否则会报错 -->
 </aop:config>
 <!-- 测试spring与hibernate整合结果 -->
 <bean id="categoryService" class="cn.hncj.service.CategoryServiceImpl">
 <property name="sessionFactory" ref="sessionFactory" />
 <!-- 依赖的sessionFactory用我们之前配好的sessionFactory -->
 </bean>
 <!-- 把CategoryAction和它的依赖交给Spring管理 -->
 <bean id="categoryAction" class="cn.hncj.action.CategoryAction" scope="prototype">
 <property name="categoryService" ref="categoryService" />
 <!-- 依赖的categoryService用上面和Hibernate整合时配置好的categoryService -->
 </bean>
 </beans>
- 在WebContent文件夹下创建index.jsp用来测试struts2和Spring4整合的环境。inde.jsp的内容如下。 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13- <%@ 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>Spring和Struts整合测试</title>
 </head>
 <body>
 <a href="category_update.action?category.id=9&category.type=gcl&category.hot=true">访问update</a><br>
 <a href="category_save.action?category.type=gcl&category.hot=true">访问save</a>
 </body>
 </html>
- 在tomcat9.0服务器上运行index.jsp,点击两个链接输出结果如下图所示。并且数据库有数据的更新和添加则struts2和spring4的整合成功了。 
 -SSH%E6%A1%86%E6%9E%B6%E6%95%B4%E5%90%88-1_7.png) - 如果有报错请先检查你的数据库中是否有id=9的数据信息,因为我在index.jsp中设定了category.id=9。
 
提示说明
- 本章的SSH整合项目的目录结构如下图所示。
 -SSH%E6%A1%86%E6%9E%B6%E6%95%B4%E5%90%88-1_8.png) 
- 本章的SSH整合项目我已经上传到百度网盘了,链接放到下边。  1 https://pan.baidu.com/s/12xlczc_sTbVxnmxuJHESpA 
本文作者: Jade
版权声明: 未经授权禁止使用,转载请注明出处!
 
   
        