Spring入门(四)— 整合Struts和Hibernate

一、Spring整合Struts

1. 初步整合

只要在项目里面体现spring和 strut即可,不做任何的优化。

  • struts 环境搭建

    1. 创建action
    public class UserAction extends ActionSupport {
        public String save(){
            System.out.println("调用了UserAction的save方法~~!");
        }
    }
    1. 在src下配置struts.xml , 以便struts能根据请求调用具体方法
    <?xml version="1.0" encoding="UTF-8"?>
    <!-- 1. 导入约束 -->
    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">
    <struts>
        <package name="user" namespace="/" extends="struts-default">
            <!-- localhost:8080/项目名/user_save -->
            <action name="user_*" class="com.pri.web.action.UserAction" method="{1}"></action>
        </package>
    </struts>
    1. 在web.xml中配置前端控制器,以便strust抓住请求
      <!-- struts的前端控制器  | 前端控制总栈 -->
      <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>
  • spring 环境搭建
    1. 创建service
    2. 在src下创建applicationContext.xml 并且托管service实现类
    3. 在action里面获取工厂进而调用方法

2. 初步整合的问题

该小节讲述的是: 上面初步整合遗留下来的问题。

问题:

  1. 每次请求都会创建工厂,解析xml

    ? 解决方案: 工具类 | 静态代码块

    1. 工厂创建时机有点晚, 请求到来的时候才创建工厂

      ?解决方案: 让工厂提前 ---- 项目发布| 服务器启动 ----- 使用监听器(ServletContextListener) ----- 不用我们编写监听器 (spring已经写好了。) ---- 配置监听器即可。

3. 进阶整合

该小节讲述的是:把上面初步整合出现的问题给解决了。

该阶段整合的目标就是解决上面出现的两个问题。

 xml里面配置listener
 <!-- 注册spring的监听器 -->
      <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      </listener>

      <!-- 监听器里面会执行工厂的创建,创建工厂需要依赖xml文件,所以我们还得告诉它xml文件在哪里 -->
      <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
      </context-param>
?
代码里面获取工厂
?
    ApplicationContext context =WebApplicationContextUtils.getWebApplicationContext(ServletActionContext.getServletContext());

4. 进阶整合的问题

该小节讲述的是: action和service对接的问题。 已经不是工厂创建这类问题

public class UserAction  extends ActionSupport{
?
    public String save(){
        System.out.println("调用了UserAction的save方法~~·");

        ApplicationContext context =  WebApplicationContextUtils.getWebApplicationContext(ServletActionContext.getServletContext());
        UserService us = (UserService)context.getBean("userService");
        us.save();

        return NONE;
    }
}

分析以上代码:

? 其实action就是让service干活。但是我们想要让service干活,必须经过两个动作:

    1. 先从工具类中获取工厂    2. 从工厂里面拿service对象。 

一个方法还好,如果action里面有多个方法呢? 都得这么写!!

? 以前的解决方案:

? 工具类 | 静态代码块

? 现在学了spring的解决方案:

? action z只有一个目的就是为了得到service。 service已经在spring容器里面了。我要让spring把service主动送过来。 所以这里必须是注入。 要想完成注入,前提是托管action。

? 总结:

? 把action交给spring托管

? 把service注入到action中来。

5. 最终整合

把action的创建工作交给spring来完成。 注意的是: spring创建action的实例必须是多例的。

  • spring配置
<bean id="userAction" class="com.pri.web.action.UserAction" scope="prototype">
        <property name="userService" ref="userService"></property>
</bean>
?
<bean id="userService" class="com.pri.service.impl.UserServiceImpl"></bean>
  • struts.xml的配置
<!-- 为了能够让struts使用到spring创建好的action实例,这里的class不要写全路径了,而是写spring那边托管action的id标识符 -->
<action name="user_*" class="userAction" method="{1}">
</action>

6. 最终整合的背后细节

说一说刚才导入的jar包struts-spring-plugin.jar 它里面的细

  1. struts-spring-plugin.jar 里面有一个struts-plugin.xml , 其中有两行关键的配置
<bean type="com.opensymphony.xwork2.ObjectFactory" name="spring" class="org.apache.struts2.spring.StrutsSpringObjectFactory" />

<!--  Make the Spring object factory the automatic default -->
<constant name="struts.objectFactory" value="spring" />
  1. 在struts的default.properties中也有以下两个配置
### if specified, the default object factory can be overridden here
### Note: short-hand notation is supported in some cases, such as "spring"
###       Alternatively, you can provide a com.opensymphony.xwork2.ObjectFactory subclass name here
# struts.objectFactory = spring
?
### specifies the autoWiring logic when using the SpringObjectFactory.
### valid values are: name, type, auto, and constructor (name is the default)
struts.objectFactory.spring.autoWire = name
  1. 其实struts.xml里面的action ,class属性也可以写全路径,也可以写bean的标识符(id值).

struts 是这么来的, 拿着这个id值去问spring的工厂要对象,如果找不到, 尝试自己创建对象, 也就是把class的属性看成一个类的全路径地址。

<action name="user_*" class="com.pri.web.action.UserAction" method="{1}"></action>

spring的applicationContext.xml里面配置如下,但是struts不用它,而且他是多例的,只用有的之后才会创建

<bean id="userAction" class="com.pri.web.action.UserAction" scope="prototype">
    <property name="userService" ref="userService"></property></bean>

既然都不用人家的实例,选择自己创建,为什么这个action里面也会有service实例,也会调用setXXX方法呢?

原因就是在strust的defautl.properties里面有一行关键的配置 , 它的特点是struts会按照名字去找spring的工厂要对象注入进来。前提条件是struts能找到spring的工厂,也就是说必须要依赖前面提到的struts-spring-plugin-xx.jar

### specifies the autoWiring logic when using the SpringObjectFactory.
### valid values are: name, type, auto, and constructor (name is the default)
struts.objectFactory.spring.autoWire = name

二、Spring整合Hibernate

1. 初步整合

hibernate环境搭建

  1. 持久化类&映射文件
<hibernate-mapping>
      <class name="com.pri.bean.User" table="t_user">
          <id name="uid">
              <generator class="native"></generator>
          </id>

          <property name="username"/>
          <property name="password"/>
       </class>
 </hibernate-mapping>
  1. hibernate核心配置文件
<hibernate-configuration>
    <session-factory>

        <!-- 可以写三部分内容 -->
        <!-- 1. 核心必须 : 告诉hibernate连接什么数据库, 用什么账号 , 什么密码去连接-->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql:///user</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">root</property>

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

        <!-- 3. 映射文件 -->
        <mapping resource="com/pri/bean/User.hbm.xml"/>
    </session-factory>
</hibernate-configuration>

2. 初步整合的问题

  1. 来一次请求就会中一次sessionFactory的创建

    解决方法: 工具类 | 静态代码块

  2. sessionFactory创建时机的问题 .当请求来的之后,才会创建sessionFactory.
解决方法: 提前创建sessionFactory  ----- 项目发布| 服务器启动  ---  需要用到listener , 但是spring不再做出来新的监听器了。
?~~~java
其实spring压根不用再给hibernate做任何的监听器。 struts已经有监听器,它的监听器用于捕获项目发布, 只要捕获到了一定会解析spring的applicationContext.xml文件。所以spring建议hibernate的核心配置文件,就放到applicationContext.xml中来。
?~~~

3. 进阶整合(保留hibernate核心配置文件)

该阶段整合的目标是:在项目启动的时候,创建hibernate的sessionFactory工厂。 需要在applicationContext.xml中配置LocalSessionFactoryBean.

  • applicationContext.xml中配置如下
<!-- 配置该类,spring会创建它的实例,并且里面会包含了解析hibernate核心文件代码以及创建SessionFactory -->
<bean id="sessionFactory"class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
    <!-- 要求指定hibernate核心文件所在位置 -->
     <property name="configLocations">
       <array>
            <value>classpath:hibernate.cfg.xml</value>
        </array>
     </property>
</bean>
...
<bean id="userDao" class="com.pri.dao.impl.UserDaoImpl">
    <property name="sessionFactory" ref="sessionFactory"></property>
</bean>
  • dao层代码如下:
public class UserDaoImpl implements UserDao {
     //声明sessionFactory
     private SessionFactory sessionFactory;
     //让spring注入sessionFactory进来
     public void setSessionFactory(SessionFactory sessionFactory) {
           this.sessionFactory = sessionFactory;
     }

     @Override
     public void save() {
           System.out.println("调用了UserDaoImpl的save方法~~~");
           Session session = sessionFactory.openSession();

           Transaction transaction = session.beginTransaction();

           User user = new User();
           user.setUsername("bb");
           user.setPassword("123");
           session.save(user);

           transaction.commit();
           session.close();
           //sessionFactory.close();
      }
}

4. 进阶整合(去掉hibernate核心配置文件)

该阶段整合的目标是: 删除掉hibernate.cfg.xml,但是它里面的内容还是要有。 把这三部分内容放到spring里面来写。

<!-- 配置该类,spring会创建它的实例,并且里面会包含了解析hibernate核心文件代码以及创建SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
        <!-- 要求指定hibernate核心文件所在位置 -->
        <!-- <property name="configLocations">
                <array>
                    <value>classpath:hibernate.cfg.xml</value>
                </array>
            </property> -->

      <!-- 1. 核心必须配置  连接什么数据库,怎么连数据库-->
      <property name="dataSource" ref="dataSource"></property>

      <!-- 2. 可选配置 -->
      <property name="hibernateProperties">
            <props>
               <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
               <prop key="hibernate.show_sql">true</prop>
               <prop key="hibernate.format_sql">true</prop>
               <prop key="hibernate.hbm2ddl.auto">update</prop>
             </props>
      </property>

      <!-- 3. 映射文件导入 -->
      <property name="mappingResources">
          <array>
               <value>com/pri/bean/User.hbm.xml</value>
           </array>
       </property>
</bean>

5. 进阶整合(细节)

  • 使用连接池
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${driverClass}"></property
    <property name="jdbcUrl" value="${jdbcUrl}"></property
    <property name="user" value="${user}"></property
    <property name="password" value="${password}"></roperty>
</bean>
  • 使用jdbc.properties
  1. jdbc.properties:
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql:///users
user=root
password=root
  1. xml:
<context:property-placeholder location="classpath:jdbc.properties"/>
?
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${driverClass}"></property>
    <property name="jdbcUrl" value="${jdbcUrl}"></property>
    <property name="user" value="${user}"></property>
    <property name="password" value="${password}"></property>
</bean>
  • 多个映射文件的处理
以前的写法:
    <property name="mappingResources">
        <array>
            <value>com/pri/bean/User.hbm.xml</value>
        </array>
    </property>
?
现在的写法:
    <property name="mappingDirectoryLocations" value="classpath:com/pri/bean"/>

6. 最终整合

讲述的是: 使用Hibernate模板 , 简化我们dao层的CRUD操作

  1. 开启事务

一定要开启事务,否则会抛出异常

在applicationContext.xml中开启事务

<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
  1. service层代码
@Transactional
public class UserServiceImpl implements UserService {}
  1. dao层代码
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
     @Override
     public void save() {
         User user = new User();
         user.setUsername("admin");
         user.setPassword("123456");

         getHibernateTemplate().save(user);
     }
}
  1. dao层一定要注入sessionFactory
<bean id="userDao" class="com.pri.dao.impl.UserDaoImpl">
    <property name="sessionFactory" ref="sessionFactory"></property>
</bean>

三、 Hibernate模板

1. hibernate模板的API

  • save方法
@Override
public void save(User user) {
    getHibernateTemplate().save(user);
}
  • upate方法
public void update(User user) {
    getHibernateTemplate().update(user);
}
  • delete方法
public void delete(User user) {
    getHibernateTemplate().delete(user);
}
  • get方法
public User get(Integer id) {
    return getHibernateTemplate().get(User.class, id);
}
  • load方法
public User load(Integer id) {
    return getHibernateTemplate().load(User.class, id);
}
  • 查询总条目数
@Override
public int findCount() {
        String hql = "select count(*) from User";
    //查询的时候,返回总是list, 区别就是list里面放的是什么数据,因为查询总数,回来肯定就是一个数字
        //list.add(500)
        List<Long> list = (List<Long>) getHibernateTemplate().find(hql);
        if(list.size()>0){
            return list.get(0).intValue();
        }
        return 0;
}
  • 使用 HQL 方式查询
    @Override
    public List<User> findByHQL() {

        //hql其实就是sql语句这种写法的hibernate版本。  表名 --- 类名
        String hql = "from User";
        return (List<User>) getHibernateTemplate().find(hql);
    }
  • 使用QBC方式查询
 @Override
 public List<User> findByQBC() {
        //QBC的方式是面向对象编程。 也就是我们再也不能写sql语句, hql语句也写不了。  对象。方法

        //这行离线对象对应的sql语句应该是  select * from user;
        //如果想知道离线对象更详细的用法,以及它的作用。 请看 8号上午上课的11点左右。
        DetachedCriteria criteria = DetachedCriteria.forClass(User.class);
//      criteria.add(Restrictions.like(propertyName, value))
        return (List<User>) getHibernateTemplate().findByCriteria(criteria);
 }

四、HibernateTemplate 懒加载的问题

  • 抛出异常

    could not initialize proxy - no Session

  • 原因

  spring管理这个session,也是放置到Theradlocal里面去的。 只要在业务逻辑层提交了事务,那么session就关闭掉。所以使用懒加载就会有一个问题,无法查询,因为没有了session。 为了解决这个问题,我们需要在web.xml中配置一个过滤器,以便让session的关闭稍微推后、延迟点。  

  事实上spring自己整合了dao层的事务管理,也提供了dao层的模板支持,它为了确保这两者使用的连接对象是同一个,就在底层使用ThreadLocal来存储session连接 ,详情请参看下面的时序图. 虽然该图描述的是jdbc模板的技术,但是hibernate模板的技术也同样适用。

  • 解决办法:

    在web.xml中配置过滤器。这个过滤器会对来访的请求进行过滤,以便知道哪些请求延迟关闭session。

注意: 要在struts的过滤器之前添加 否则无效 ,原因是struts的过滤器抓住请求后,后面不会给配置的这个过滤器了。

<filter>
    <filter-name>OpenSession</filter-name>
    <filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>OpenSession</filter-name>
    <url-pattern>*.action</url-pattern> <!-- 匹配后面带有.action的请求 -->
</filter-mapping>
  1. 有的同学可能会想,为什么这里过滤的是.action呢 ? 直接写/可以不?

    其实也可以,但是/*能够包含的范围更广,也就是不管是什么请求,都会让这个session延迟关闭,这就造成资源的浪费了。

  2. 有的同学可能还会想,我们的action访问,不是会自动带有.action的后缀么?

    其实这是一种错误的想法,我们在页面上的写的时候路径是这样的

    ? localhost:8080/项目/user_save

    人家的那个action的后缀规定,只是说,你在访问action的时候可以带上这个.action,也可以不带,而不是说它会自己带这个.action过来。

原文地址:https://www.cnblogs.com/gdwkong/p/8453166.html

时间: 2024-08-29 22:11:08

Spring入门(四)— 整合Struts和Hibernate的相关文章

Spring入门(四):使用Maven管理Spring项目

让我们先回顾下本系列的前3篇博客: Spring入门(一):创建Spring项目 Spring入门(二):自动化装配bean Spring入门(三):通过JavaConfig装配bean 1.为什么要使用Maven? 之前我们新建的项目,项目所要依赖的第三方jar包都在项目的类路径下(通常为lib目录),如下所示: 使用这种方式,我们无法知道第三方类库的依赖关系,比如导入一个特定的jar包时,可能此jar包还依赖于其他的jar包,其他的jar包又依赖于更多的jar包,这也是我们平常遇到的Clas

spring入门(四) spring mvc返回json结果

前提:已搭建好环境 1.建立Controller 1 package com.ice.controller; 2 3 import com.ice.model.Person; 4 import org.springframework.stereotype.Controller; 5 import org.springframework.web.bind.annotation.RequestMapping; 6 import org.springframework.web.bind.annotat

Spring与Struts2整合VS Spring与Spring MVC整合

Spring与Struts2整合,struts.xml在src目录下 1.在web.xml配置监听器 web.xml <!-- 配置Spring的用于初始化ApplicationContext的监听器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <contex

(转)最新版的SSH框整合(Spring 3.1.1 + Struts 2.3.1.2 + Hibernate 4.1)

最近一直有朋友在问,最新版的Spring.Struts.Hibernate整合老是有问题,昨晚大概看了一下.从Hibernate 4 开始,本身已经很好的实现了数据库事务模块,而Spring也把Hibernate4之后的HibernateDaoSupport去掉了,Spring建议使用官方的HibernateAPI进行操作.这样一来,以前习惯使用HibernateDaoSupport来操作的人来说刚刚开始可能有些不习惯.我根据官方的说明,大概的整合一下,高手可以路过,给刚上路的朋友们. 现在把主

Struts 2 + Hibernate + Spring 整合要点

Struts 2 和 Spring 的功能有重合,因此有必要说明下,整合中分别使用了两种框架的哪些技术. Struts 2 使用功能点: 1.拦截器.一处是对非登录用户购物进行拦截,一处是对文件上传的格式进行拦截.前者的拦截器文件需自己手动编写,后者可直接用 Struts 2 框架封装好的拦截器. 2.数据校验,重写 Validate() 方法.对用户注册信息进行校验. 3.核心控制器 FilterDispatcher,限制只有管理员才能访问后台. Spring 使用功能点: 1.配置 bean

Java新手如何学习Spring、Struts、Hibernate三大框架?(转)

整理知乎大牛答案: 1.入门看文档(blog,书籍等等),深入理解配置文件的含义(Spring.Struts.Hibernate); 2.遇到问题,自己动手解决,如果解决了,为什么这样解决?(凡事总问个为什么) 3.具体到hibernate的入门, 首先还是先要学会数据库, JDBC, 设计模式, 这些都是基础. 我的个人理解:凡事总问为什么,很关键,这是入门也是以后进一步发展的基础. 具体新手学习视频资料可以参考看看网上的视频教程,但理念必须在入门之前建立起来. 如果你是个老师(Java工程师

条理清晰的搭建SSH环境之整合Struts和Spring

上文说到搭建SSH环境所需三大框架的jar包,本篇博客将通过修改配置文件整合Struts和Spring,下篇博客整合Hibernate和Spring即可完成环境搭建. 1.声明bean,新建TestAction.java,需要给类添加注解:@Controller 和 @Scope("prototype"): "使用@Controller注解标识TestAction之后,就表示要把TestAction交给Spring容器管理,在Spring容器中会存在一个名字为"te

关于Struts、hibernate、spring三大框架详解。

struts 控制用的 hibernate 操作数据库的 spring 用解耦的 Struts . spring . Hibernate 在各层的作用 1 ) struts 负责 web 层 . ActionFormBean 接收网页中表单提交的数据,然后通过 Action 进行处理,再 Forward 到对应的网页. 在 struts-config.xml 中定义 <action-mapping>, ActionServlet 会加载. 2 ) spring 负责业务层管理,即 Servic

osgi与流行的框架(spring,struts,hibernate等)的集成

1.与流行的 JAVA B/S体系架构的集成 了解了基于osgi系统设计的基本思想,进一步来研究osgi与流行的框架(spring,struts,hibernate等)的集成,这里首先讲解一下集成原理. l        解决和spring的集成 由于spring的应用占据了大部分的java应用领域,所以解决与spring的集成是osgi必须解决的,spring-dm的推出大大促进了两者的结合,有助于osgi进军企业领域. Spring所带来得好处主要有这么两点: 1.       不需要对外的