网上商城项目(SSH)-SSH框架整合-1

      最近老师带一个网上商城的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个。


搭建Spring4环境

  • 在Eclipse里创建Dynamic Web Project项目。

    • 项目名我这里起为SshTest。Tomcat 9.0也在这里设置,web.xml的版本设置为3.1。第一个页面设置完成后不要直接点Finish,请点Next。具体设置如下图。
    • 点击Next两次到下图这个界面把Generate web.xml deploayment descriptor勾选上,然后再点击Finish。
  • 将“全部的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环境配置成功。


搭建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
  • 创建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&amp;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>
  • 创建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环境可能配置成功。
    • 如果shop数据库category数据表中插入下边的数据,则hibernate环境配置成功。
      id type hot
      1 mantype 1

整合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整合可能成功。
    • 如果shop数据库category数据表中插入下边的数据,则说明spring和hibernate整合成功。
      id type hot
      1 girltype 1

搭建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的整合成功了。

    • 如果有报错请先检查你的数据库中是否有id=9的数据信息,因为我在index.jsp中设定了category.id=9。

提示说明

  • 本章的SSH整合项目的目录结构如下图所示。
  • 本章的SSH整合项目我已经上传到百度网盘了,链接放到下边。
    1
    https://pan.baidu.com/s/12xlczc_sTbVxnmxuJHESpA

本文作者: Jade
版权声明: 未经授权禁止使用,转载请注明出处!

Jade wechat
扫一扫上面的二维码添加我的QQ哟
各位看官求打赏!