• spring


    spring的作用及优势


    Spring的作用

    Spring用于整合软件开发中的各种框架,提供组件之间松耦合的平台,目的就是将耦合度降至最低,即解耦。(开源,都是相通的。所有的框架都是基于反射实现的。)

    1. spring用于整合各种框架,简化开发比如DAO层,只要使用spring的一个工具类即可

    2. 解耦,松耦合让类与类之间的联系不大。降低依赖性,换了一个类,不影响整个项目。项目开发过程中,难点不是模块不好开发,功能能否实现,而是怎么整合各个程序员开发的程序代码。类比较多的时候不好管理,spring是将类与类之间的关联降至最低。

    3. 我们在使用Spring框架时,主要是使用Spring容器的两个特性:IoC和AOP

    spring的优势

    1. spring是一个开源框架,开放源代码

    2. spring 为JavaEE应用提供轻量级的解决方案;

    3. spring提倡”最少侵入”;(降低耦合度,换了谁都可以)

    4. spring是一个优秀的MVC框架   

    5. 基于依赖注入的核心机制,基于AOP的声明式事务管理

    spring容器


    概念

    spring框架的核心就是提供了一个容器。该容器类型是BeanFactory或者ApplicationContext(建议用这个类型,它是BeanFactory的子类,功能更多)

    Spring的核心接口:BeanFactory

    该容器具有以下功能:

    a. 容器可以创建和销毁组件对象,等价于原来”工厂”类的作用。

    b. 容器可以采用不同的模式创建对象,如单例模式创建对象

    c. 容器具有IOC机制实现

    d. 容器具有AOP机制实现

    容器实例化

    BeanFactory创建并负责管理Spring bean的上下文的生命周期。BeanFactory接口指明了spring到底干了什么事。

    org.springframework.beans.factory.xml.XmlBeanFactory 是BeanFactory的实现类,在XMLBeanFactory中,以xml结构方式描述对象及对象之间的依赖关系。

    创建BeanFactory实例时,必须提供Spring容器管理bean的详细配置信息,相应的XML文件作为参数传入。

    BeanFactory  factory = new ClassPathXmlApplicationContext(“applicationContext.xml”);

    BeanFactory  factory = new FileSystemXmlApplicationContext(“F:/applicationContext.xml”);

    推荐使用ClassPathXmlApplicationContext方式

    Bean对象

    Bean指代的就是对象,BeanFactory是产生和管理bean的容器。

    a. 产生bean

    b. 控制Bean的产生数量

    c. 控制Bean的产生时间

    d. 控制Bean的生命周期

    Spring通过BeanFactory管理和配置bean ,在Spring里,任何的java对象、java组件bean处理。

    spring环境的搭建

    1. 创建web工程

    2. 导入jar  spring.jar commons-logging.jar     log4j-1.2.15.jar

    3. 导入配置文件  log4j.properties        applicationContext.xml

    实例化Bean对象方式

    a. 用构造器来实例化

    <bean  id=”XXBean”  class=”” />

    b. 使用静态工厂方法实例化

    <bean  id=”XXbean”  class=”XXXfactoryClass”  factory-method=”” />

    c. 使用实例工厂方法实例化

    <bean  id=”XXfactory”  class=”” />
    <bean  id=”XXXbean”  factory-bean=”XXX”  factory-method=”” />

    将一个Bean组件交给Spring容器管理,获取spring容器对象和Bean对象

    案例

    1. 新建web功能

    2. 导入jar包

    3. 创建Bean1对象

    public class Bean1{}

    4. 工厂类

    public class Bean1Factory {
      public Bean1Factory(){
         System.out.println("创建工厂对象");
      }
      //使用静态方法获得对象
       public static Bean1 getBean1(){
         return new Bean1();
      }
      //使用实例方法获得对象
      public Bean1 getBean(){
        return new Bean1();
      }
    }

    5. 添加配置文件applicationContext.xml文件

    <?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:mvc="http://www.springframework.org/schema/mvc"
        xmlns:aop="http://www.springframework.org/schema/aop" 
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd 
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd ">
     
        <!-- 把bean1配置到是pring,让spring管理bean1
             id:该bean的标识,用来区分开每一个bean(类的对象)
             class:指明配置的具体的类,包名+类名,底层利用反射创建对象class.forName()-->
        <bean id="bean1" class="web.test.bean.Bean"></bean>
        <!-- 在spring中调用工厂的静态方法创建对象 -->
        <bean id="bean2" class="web.test.factory.Bean1Factory"    factory-method="getBean1"></bean>
        <!-- 在spring中,调用工厂的实例方法,获得对象 -->
        <!-- 1、先把工厂实例化 -->
        <bean id="factory" class="web.tarena.factory.Bean1Factory"></bean>
        <!-- 2、调用工厂中的实例方法获得对象 -->
        <bean id="bean3" factory-bean="factory"    factory-method="getBean1"></bean>
    </beans>

    5. 测试类

    public class TestSping {
        public void test1() {
            /**
             * ClassPathXmlApplicationContext:用来加载核心配置文件。applicationContext.xml,比较消耗资源,重量级对象,所以应该写成静态的,只加载一次。
             * 重量级对象:功能强大,消耗资源较多,ClassPathXmlApplicationContext和HibernateSessionFactory都是重量级对象
             * BeanFactory接口 Object getBean(String name); name就是指配置文件中的id值 返回结果是Object,spring可以管理任意的对象
             */
            ApplicationContext beanFactory = new ClassPathXmlApplicationContext("applicationContext.xml");
            // 通过构造器创建Bean对象
            Bean bean1 = (Bean)beanFactory.getBean("bean1");
            System.out.println(bean1);
            // 通过工厂的静态方法创建Bean对象
            Bean bean2 = (Bean)beanFactory.getBean("bean2");
            System.out.println(bean2);
            // 通过实例化工厂方法创建Bean对象
            Bean bean3 = (Bean)beanFactory.getBean("bean3");
            System.out.println(bean3);
        }
    
        public void test2() {
            // 单例模式下不同的beanFactory创建出来的Bean对象不是同一个
            BeanFactory beanFactory = new ClassPathXmlApplicationContext("applicationContext.xml");
            System.out.println("---------------------------");
            Bean bean1 = (Bean)beanFactory.getBean("bean1");
            System.out.println(bean1);
            BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");
            Bean bean11 = (Bean)factory.getBean("bean1");
            System.out.println(bean11);
    
        }
    }

    spring容器对Bean组件的管理


    Bean对象的创建模式

    Spring支持singleton(单例)和prototype(原型,非单例)两种模式。Singleton:每次调用getBean()返回同一个对象。prototype:每次调用getBean()返回新的对象。

    默认是singleton模式,可以通过<bean>的scope属性修改为prototype模式。例如:<bean  id=”标识符”  scope=”prototype”  class=”Bean组件类型”  />

    Bean对象的创建时机

    a. singleton模式的Bean组件是在容器实例化时创建的。

    b. prototype模式是在调用getBean()方法时创建。

    c. singleton模式可以使用<bean>元素的lazy-init=”true”属性将对象的创建时机推迟到调用getBean()方法。也可以在<beans>(根元素)中使用default-lazy-init=”true”推迟所有单例Bean组件的创建时机。

    Bean对象的初始化和销毁

    初始化

    1. 可以利用<bean>元素的init-method=”方法名”属性指定初始化方法。

    2. 指定的初始化方法是在构造方法调用后自动执行。若非单例模式,则每创建一个对象,则执行一次初始化方法。

    初始化的三种方式

    1. 写在构造方法中

    2. 写在{}中(代码块);

    2. spring框架中<bean>元素写init-method=”方法名”

    初始化不能用static{},它是类加载调用,比创建对象要早。

    销毁

    1. 可以利用<bean>元素的idestory-method=”方法名”属性执行销毁方法。

    2. 销毁方法是在容器关闭时触发,而且只适用于singleton模式的组件

    //spring容器关闭
    AbstractApplicationContext  ac=new ClassPathXmlApplicationContext();
    ac.getBean(“feeDAO”);
    ac.close();//该方法执行后,Bean对象被销毁

    spring框架的IOC特性


    IOC概念

    IOC,Inverse of Controller被称为控制反转或反向控制,其实真正体现的是”控制转移”。所谓的控制指的是负责对象关系的指定、对象创建、初始化、和销毁等逻辑。

    IOC指的是将控制逻辑交给第三方框架或容器负责(即把Action中的控制逻辑提出来,交给第三方负责),当两个组件发生改变时,只需要修改框架或容器的配置即可。

    控制反转就是应用本身(Action)不负责依赖对象(Dao)的创建及维护,依赖对象的创建及维护是由外部容器(BeanFactory)负责的。这样控制权就由应用转移到了外部容器,控制权的转移就是所谓反转。

    DI概念

    DI,Dependency Injection依赖注入

    依赖注入就是指:在运行期,由外部容器(BeanFactory)动态地将依赖对象(Dao)注入到组件(Action)中。Spring框架采用DI技术实现了IoC控制思想

    Spring提供了两种形式的注入方式:

    ①(常用)setter方式注入:依靠set方法,将组件对象传入(可注入多个对象)

    a. 首先添加属性变量和set方法

    b. 在该组件的<bean>定义中采用下面的描述方式 <property  name=”属性名”  ref=”要注入的Bean对象的id值”></property>

    c. 属性名与set方法名对应,和属性名无关。例如CostAction中有costDao属性,而他的标准set方法名为setCostDAO,那么配置文件中的name就应该写costDAO(去掉set,首字母小写)。name不是看定义的属性名,而是set方法名。

    ②(用的少)构造方法注入:依靠构造方法,将组件对象传入

    a. 在需要注入的组件中,添加带参数的构造方法。

    b. 在该组件<bean>定义中,使用下面格式描述<constructor-arg  index=”参数索引” ref=”要注入的Bean对象的id值” />

    DIIOC的关系

    Spring是具有IoC特性的框架,实现Ioc是由Spring容器完成的,Spring容器通过DI建立起对象之间的关系。可以这样理解:DI是IoC实现的一种手段,IoC的理论通过DI实现。

    案例

    UserDao

    public interface UserDAO {
        public void saveUser(String user);
    }

    UserDAOOracleImpl

    public class UserDAOOracleImpl implements UserDAO{
        public void saveUser(String user) {
            System.out.println("oracle实现");
        }
    }

    UserDAOMysqlImpl

    public class UserDAOMysqlImpl implements UserDAO{
        public void saveUser(String user) {
            System.out.println("mysql实现");
        }    
    }

    UserAction

    public class UserAction {
        private UserDAO userDao;
        //Action依赖DAO,保存数据。把依赖的UserDao写到方法的外面,可以通过set方法注入不同实现的dao对象
        //这样操作不同的数据库的时候,不用对UserAction进行任何的修改或者完全通过配置文件进行配置
        public void saveUser(String username){
            userDao.saveUser();
        }
        //set方式注入
        //public void setUserDao(UserDAO userDao) {
        //     this.userDao = userDao1;
        //}
         //构造方式注入
        public UserAction(UserDAO userDao) {
            this.userDao=userDao;
        }
    }     

    applicationContext.xml

    <beans ...>
        <!-- 把所有的Dao和Action全部配置到spring当中,全部纳入spring的管理 -->
        <bean id="userDaoMySql" class="com.test.dao.impl.UserDaoMySqlImpl"></bean>
        <bean id="userDaoOracle" class="com.test.dao.impl.UserDaoOracleImpl" ></bean>
        <bean id="userAction”  class="com.tarena.web.action.UserAction" >
          <!-- set方式注入 -->
          <!--<property name="userDao1" ref="userDaoOracle"></property>-->
          <!-- 构造器方式注入 -->
          <constructor-arg ref="userDaoDB2"></constructor-arg>
      </bean>
    </beans>

    各种数据类型的注入


    Bean3

    //使用spring创建对象的时候,创建的同时给对象属性赋值
    public class Bean3 {
        private int id;
        private String name;
        private String[] arrayValue;
        private List listValue;
        private Set  setValue;
        private Map mapValue;
        private Properties propValue;
        //get set方法
    }

    appliactionContext.xml

    <beans  ..>
        <bean id="bean3" class="web.tarena.bean.Bean3">
        <!-- set方式注入 -->
        <property name="id" value="12"></property>
        <property name="name" value="liu"></property>
        <property name="arrayValue">
            <list>
                <value>a</value>
                <value>b</value>
                <value>c</value>
            </list>
        </property>
        <property name="listValue">
        <!-- list和数组很相似 -->
        <list>
          <value>list1</value>
          <value>list2</value>
          <value>list3</value>
        </list>
      </property>
      <property name="setValue">
        <set>
          <value>set1</value>
          <value>set2</value>
        </set>
      </property>
      <property name="mapValue">
        <map>
          <entry key="k1" value="v1"></entry>
          <entry key="k2" value="v2"></entry>
        </map>
      </property>
      <property name="propValue">
        <props>
          <prop key="p1">v1</prop>
          <prop key="p2">p2</prop>
        </props>
      </property>
    </bean>
    </beans>       

    AOP概念


    什么是AOP

    AOP,Aspect Oriented Programming被称为面向方面编程。对单个对象(一对一)的解耦用IoC,而当有共通组件,它对应多个其他组件(一对多),则解耦用AOP。如拦截器。这也是为何在程序中大量的用IoC,而AOP却用的很少,因为程序中不可能有很多的共通部分。

    AOP主要解决共通处理和目标组件之间解耦。

    AOP的相关术语

    1. 方面Aspect,指的是封装了共通处理的功能组件。该组件可以作用到某一批目标组件的方法上。方面也可以说是通知的集合。

    2. 通知Advice,用于指定方面组件的目标组件方法之间的作用时机。例如:先执行方面组件再执行目标方法,或先执行目标方法再执行方面组件。

    3. 目标对象Target,要使用Advice操作的方法的对象

    4. 连接点JoinPoint,指的是方面组件和具体的哪一个目标组件的方法有关系。

    5. 切入点Pointcut,用于指定目标组件的表达式。指的是方面组件和哪一批目标组件方法有关系。多个连接点组成的集合就是切入点。

    AutoProxy动态代理

    采用AOP之后,容器返回的对象是代理对象。用户在使用时,由代理对象调用切面组件和目标对象的功能。

    spring支持JDK动态代理和cglib动态代理。JDK动态代理默认提供的,spring以JDK代理为主。cglib动态代理,spring需要依赖第3方cglib-nodep-2.1_3.jar来实现。

    注意spring在默认情况下

    1. 目标对象有接口采用JDK动态代理。比如 FeeDaoImpl implements FeeDAO

    2. 目标对象没有接口采用CGLIB代理。

    修改配置<aop:config proxy-target-class="true"/> proxy-target-class默认是false,表示有接口使用JDK,没有接口使用cglib代理。设置成true,强制都使用cglib代理

    AOP案例

    想让所有的操作进行日志记录,那么按以前的方式就需要给所有Action或DAO中添加日志记录的代码,如果Action或者DAO很多,那么不容易维护。而使用AOP机制,则可以很方便的实现上述功能。

    1. 导入AOP需要的包 aspectjrt.jar  aspectjweaver.jar

    2. 目标对象

    3. 切面类

    //切面类(Aspect)
    public class LoggerBean {
         //这个类下面的方法都是通知。通知(Advice),切面类中的方法就是通知
        public void logger(){
            System.out.println("记录当前的操作");
        }
    }

    4. 配置文件

    <beans ...>
        <!-- 切面类 -->
        <bean id="loggerBean" class="com.test.aop.aspect.LoggerBean"></bean>
        <!-- 目标对象 -->
        <bean id="feeDao" class="com.test.dao.impl.feeDaoImpl"></bean>
        <!-- 配置AOP -->
        <aop:config>
          <!-- 切入点,如何找连接点,pointcut就是一个表达式,用来指向连接点(要操作的方法),within(com.test.dao.impl.*)在这个包下面的所有类和所有方法 -->
           <aop:pointcut expression="within(com.tarena.dao.impl.*)" id="feeDaoPoint"/>
           <!-- 切面,id切面的标识, -->
           <aop:aspect id="loggerAspect" ref="loggerBean">
                  <!-- 通知前,就是在调用连接点之前调用方法logger,切入点feeDaoPoint所对应的路径com.test.dao.impl.*,即impl包下所有的方法在执行前都用logger方法 -->
                  <aop:before method="logger" pointcut-ref="feeDaoPoint"/>
           </aop:aspect>
       </aop:config>
    </beans>

    通知类型和切入点


    通知类型

    通知决定方面组件和目标组件作用的关系。主要有以下几种类型通知

    a. 前置通知 <aop:before/>,方面组件在目标方法之前执行

    b. 后置通知<aop:after-returning/>,方面组件在目标方法之后执行,目标方法没有抛出异常才执行方面组件

    c. 最终通知<aop:after>,方面组件在目标方法之后执行,目标方法有没有异常都会执行方面组件。

    d. 异常通知<aop:after-throwing>,方面组件在目标方法抛出异常后执行。

    e. 环绕通知<aop:around>,方面组件在目标方法之前和之后执行。环绕通知等价于前置+后置通知

    try{
        //前置通知
        //执行目标方法
        //后置通知
    } catch(){
        //异常通知
    }fially{
        //最终通知
    }

    切入点

    切入点用于指定目标组件和方法,Spring提供了多种表达式写法

    方法限定表达式

    指定哪些方法启用了方面组件

    ①execution(修饰符?  返回类型 方法名(参数列表) throws  异常?)

    ②示例

    execution(public * *(..)):匹配容器中所有修饰符是public(不写则无要求的),返回类型、方法名,参数列表也不要求的方法。

    execution(* set*(..)):匹配容器中,方法以set开头的所有方法

    execution(* org.test.CostDAO.*(..)):匹配CostDAO类中的所有方法。

    execution(* org.test.dao.*.*(..)):匹配dao包下所有类所有方法

    execution(* org.test.dao..*.*(..)):匹配dao包及子包中所有类所有方法

    execution(* com.test.dao.impl.feeDaoImpl.save*(..))

    第一个*指的是返回值任意

    第二个*指的是方法名以save开头的任意方法

    第三个..指的是方法的参数任意

    类型限定表达式

    指定哪些类型的组件的所有方法启用方面组件(默认就是所有方法都启用,且只到类型,不到方法)

    ①形式:within(类型)

    ②示例

    within(com.xyz.service.*),匹配service包下的所有类所有方法

    within(com.xyz.service..*),匹配service包及其子包中的所有类所有方法

    within(org.test.dao.CostDAO),匹配CostDAO所有方法

    注意:within(com.xyz.service.*.*)是错误的,只到类名,不到方法名

    Bean名称限定

    按<bean>元素的id值进行匹配。

    ①形式:Bean(id值)

    ②示例

    bean(costDAO),匹配id=costDAO的bean对象

    bean(*DAO),匹配所有id值以DAO结尾的bean对象

    args参数限定表达式

    按方法参数类型限定匹配

    ①形式:args(类型)

    ②示例

    args(java.io.Serializable)匹配方法只有一个参数,并且类型符合Serializable的方法。public void f1(String s)、public void f2(int  i)都能匹配。

    上述表达式可以使用&&、||运算符连接使用

    案例A-环绕通知

    环绕通知与其他通知有点区别,它要求程序员调用目标对象的连接点方法,否则连接点方法不会执行

    案例:通过logger方法显示当前用户操作的目标对象的类型以及目标对象操作的方法 (连接点的方法)

    1. 导入包 aspectjrt.jar  aspectjweaver.jar  cglib.jar

    2. 目标对象

    public interface UserDao {
      void saveUser(String username);
    }
    public class UserDaoImpl implements UserDao{
        //连接点
        public void saveUser(String username) {
            System.out.println("保存操作");
        }
    }

    3. 切面

    public class LoggerBean {
      //利用反射
       //连接点对象ProceedingJoinPoint
      public void logger(ProceedingJoinPoint pjp) throws Throwable{
        //调用目标对象的连接点方法,如果不加这句那么连接点方法不执行
        pjp.proceed();
        //获得当前执行的方法的类型名
        String className=pjp.getTarget().getClass().getName();
         //获得当前执行的方法的名字
        String methodName=pjp.getSignature().getName();
        System.out.println("您正在执行"+className+"类的"+methodName+"方");
      }
    }

    4. 配置

    <beans ...>
        <!-- 切面 -->
        <bean id="loggerBean" class="com.tarena.aop.aspect.LoggerBean"></bean>
        <!-- 目标对象 -->
        <bean id="userDao" class="com.tarena.dao.impl.UserDaoImpl"></bean>
        <!-- 配置AOP -->
        <aop:config>
            <aop:pointcut id="userDaoPointcut"  expression="execution(* com.test.dao..*.*(..))"/>
            <aop:aspect id="loggerAspect" ref="loggerBean">
                <aop:around method="logger" pointcut-ref="userDaoPointcut"/>
            </aop:aspect>
        </aop:config>
    </beans>    

    案例B-异常通知

    目标对象运行产生异常时,把异常信息通过日志方式记录到文件中。在A案例中添加 

    1. log4j.properties

    #--------console-----------
    
    #log4j.rootLogger=warn,myconsole
    #log4j.appender.myconsole=org.apache.log4j.ConsoleAppender
    #log4j.appender.myconsole.layout=org.apache.log4j.SimpleLayout
    
    #--------file-----------
    
    log4j.rootLogger=error,myfile
    log4j.appender.myfile=org.apache.log4j.FileAppender
    log4j.appender.myfile.File=D:\error.htm
    log4j.appender.myfile.layout=org.apache.log4j.HTMLLayout

    2. 添加切面类

    //切面,(截获异常信息)
    public class ExceptionLogger {
        private Log log=LogFactory.getLog(this.getClass());
        //将异常的信息写到文件中,D盘下面的error.html
        public void exceptionLogger(Exception ex){
          //1、获得当前异常的堆栈信息
          StackTraceElement[] els=ex.getStackTrace();
          //2、需要放入第一行的内容els[0] (java.lang.NullPointerException)
           log.error(ex.getClass().getName());
           log.error(els[0]);
        }
    }

    3. 配置信息

    <beans ...>
        <!-- 切面 -->
        <bean id="loggerBean" class="com.tarena.aop.aspect.LoggerBean"></bean>
        <bean id="exceptionLogger" class="com.tarena.aop.aspect.ExceptionLogger"></bean>
        <!-- 目标对象 -->
        <bean id="userDao" class="com.tarena.dao.impl.UserDaoImpl"></bean>
        <!-- 配置AOP -->
        <aop:config>
            <aop:pointcut id="userDaoPointcut" expression="execution(* com.test.dao..*.*(..))"/>
            <aop:aspect id="loggerAspect" ref="loggerBean">
                <aop:around method="logger" pointcut-ref="userDaoPointcut"/>
           </aop:aspect>
           <aop:aspect id="exceptionLoggerAspect" ref="exceptionLogger">
             <!-- throwing:和方法exceptionLogger中的参数名相同。注意一定要把异常抛出来才行,try-catch了不行 -->
             <aop:after-throwing method="exceptionLogger" pointcut-ref="userDaoPointcut" throwing="ex"/>
           </aop:aspect>
      </aop:config>
    </beans>    

    spring注解配置


    注解技术从JDK5.0推出,之后很多框架开始提供注解配置形式。Spring框架从2.5版本开始支持注解配置。

    功能:简化spring的配置文件,把spring的配置文件的信息,放入到各个类当中。

    优点:方便快捷,可以减少spring的配置文件

    缺点:当项目过大的时候,里面可能会有很多个类(比如1000个),在每个类当中加入注解。容易出现错误,而且不易于管理和维护。

    开始是否使用注解,主要看公司的要求以及项目的规模。

    AOP注解(了解)

     @Aspect

     @Before

     @After

     @Around

     @AfterReturning

     @AfterThrowing

     @Pointcut

    案例-使用注解方式

    1. 在配置文件中加入:xmlns:context="http://www.springframework.org/schema/context",content可以直接管理注解

    2. applicationContext.xml文件;

    <beans ...xmlns:context="http://www.springframework.org/schema/context" >
        <!-- 开启AOP注解 ,启动注解-->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
        <!-- 切面 -->
        <bean id="exceptionBean" class="com.tarena.aop.aspect.ExecptionLogger"></bean>
        <bean id="loggerBean" class="com.tarena.aop.aspect.LoggerBean"></bean>
        <!-- 目标对象 -->
        <bean id="userDao" class="com.tarena.dao.impl.UserDaoImpl"></bean>
       <!-- 使用注解后,就没有AOP的配置了 -->
    </beans>

    3. 切面(修改最多的)

    // 使用AOP注解,首先确定切面,然后确定通知
    @Aspect
    public class LoggerBean {
    
        // 只有一个pointcut
        @Around("execution (* com.tarena.dao..*.*(..))")
        public void logger(ProceedingJoinPoint pjp) throws Throwable {
            pjp.proceed();
            String className = pjp.getTarget().getClass().getName();
            String methodName = pjp.getSignature().getName();
            String key = className + "." + methodName;
            String value = PropertiesUtil.getValue(key);
            System.out.println("用户的操作信息是:" + value);
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
            System.out.println("操作的时间是:" + dateFormat.format(new Date()));
        }
    }
    @Aspect
    public class ExecptionLogger {
        @Pointcut("execution (* com.tarena.dao..*.*(..))")
        // 定义一个方法,该方法只起到标记一个id的作用
        public void myPointCutId() {
        }
    
        // 要放两部分信息,pointcut,throwing。pointcut里面不要直接放表达式
        @AfterThrowing(pointcut = "myPointCutId()", throwing = "ex")
        public void exceptionLogger(Exception ex) {
            StackTraceElement[] els = ex.getStackTrace();
            System.out.println(els[0]);
            Logger logger = Logger.getLogger(this.getClass());
            logger.error(ex.getClass().getName());
            logger.error(els[0]);
        }
    }

    4. 目标对象(没有变化)

    public class UserDaoImpl implements UserDao {
        // 连接点
        public void deleteUserById(int id) {
            System.out.println("删除操作");
        }
        public String findUserById(int id) {
            System.out.println("查询操作");
            return null;
        }
        public void saveUser(String uname) {
            System.out.println("保存操作");
            String str = null;
            str.charAt(1);// 抛出异常
        }
        public void updateUser(String user) {
            System.out.println("修改操作");
        }
    }

    web开发中的注解(组件)

    applicationContext.xml文件中有<bean>元素的配置,来生成Bean对象。web开发中的注解用来取消这些配置。简化操作。

       1组件扫描功能

        spring可以按照指定的包路径扫描内部的组件,当发现组件类定义前有相应的注解

        标记,会将该组件纳入spring容器管理中。

        web分为三层,dao是持久层或者是模型层,action或者servlet是控制层。

        @Repository:专门指代Dao层(dao层属于持久层或者模型层)

        @Service:专门指代Service层

        @Controller:专门用来指代控制层(action/servlet)

        @Component:指代任意的一层,切记在web三层中少用,为影响对架构控制。

                     用多了,哪一方是dao,哪一方是service都分不清楚。

        @Resource

        @Autowired

        注意:上述4个注解任意使用也可以,但不符合规范。

              注解只能用在类定义前、方法定义前、成员变量定义前。

        一般面试问的注解都是web开发中的注解,不是指AOP注解。

    3、案例,使用组件注解方式

    1)applicationContext.xml

    <beans ...>

    <!-- 开启AOP注解 ,启动注解-->

    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

    <!-- 启动组件扫描:逐个扫描com.tarena下的类 -->

    <context:component-scan

    base-package="com.tarena"></context:component-scan>

    </beans>

    2)切面

    @Component

    @Aspect

    public class ExecptionLogger {

           @Pointcut("execution (* com.tarena.dao..*.*(..))")

           //定义一个方法,该方法只起到标记一个id的作用

           public void myPointCutId(){}

           //要放两部分信息,pointcut,throwing。pointcut里面不要放表达式

           @AfterThrowing(pointcut="myPointCutId()",throwing="ex")

           public void exceptionLogger(Exception ex){

                 .....

    }

    }

    @Component

    @Aspect

    public class LoggerBean {

      @Around("execution (* com.tarena.dao..*.*(..))")

      public void logger(ProceedingJoinPoint pjp) throws Throwable{

    .....

      } 

    }

     3)目标对象

    @Repository("userDao")//userDao就是Bean对象的id标识

    public class UserDaoImpl implements UserDao {

           public void deleteUserById(int id) {

                  System.out.println("删除操作");

           }

    ....

    }

     4)测试

    public class TestSpring{

           public void test1(){

                  BeanFactory factory=

    new ClassPathXmlApplicationContext("applicationContext.xml");

                  UserDao dao=(UserDao) factory.getBean("userDao");

                  dao.findUserById(1);//测试LoggerBean切面

                  dao.saveUser("");//测试ExceptionLogger切面

           }

    }

    4、web分层,控制层  业务层  DAO

    1)dao层

         public interface UserDao {

                 void saveUser(String uname);

                 ...

    }

    public class UserDaoImpl implements UserDao {

           public void saveUser(String uname) {

                  System.out.println("dao保存操作");

           }

           public void updateUser(String user) {

                  System.out.println("修改操作");

           }

    }

    2)业务层

    根据业务需要1次或者多次的调用Dao层,业务层具体解决问题层。

    业务层依赖于dao层对数据库操作,实现业务需要。

    public interface UserService {

            void saveUser(String uname);

    }

    public class UserServiceImpl implements UserService{

           //调用dao

           private UserDao userDao;//省略get set 方法

           public void saveUser(String uname) {

                  System.out.println("业务:保存");

                  userDao.saveUser(uname);

           }

    }

    3)action层

    省略

    4)applicationContext.xml

    <beans ...>

           <!-- 配置dao -->

           <bean id="userDao" class="com.tarena.dao.impl.UserDaoImpl"></bean>

           <!--配置service -->

           <bean id="userService" class="com.tarena.service.impl.UserServiceImpl">

                  <property name="userDao" ref="userDao"></property>

           </bean>

           <!-- 配置Action(省略) -->

    </beans>

    5)测试

    public void test1(){

           BeanFactory factory=

    new ClassPathXmlApplicationContext("applicationContext.xml");

           UserService service=(UserService) factory.getBean("userService");

           service.saveUser("");

    }

    5、使用注解来维护依赖关系(注入注解)

    要求给UserServiceImple注入UserDao属性。

    Spring不但支持自己定义的@Autowired注解,还支持由JSR-250规范定义的几个注解,

    如:@Resource、 @PostConstruct及@PreDestroy。

    @PostConstruct //等价于设置了init-method=”方法名”属性

    public void myinit(){...}

    @PreDestroy //等价于设置了destroy-method=”方法名”属性

    public void mydestroy{...}

    @Resource

    private UserDao userDao;

    userDao是名字,UserDao是类型

    1)@Resource

       @Resource是J2EE提供的,需导入Package:javax.annotation.Resource;

         javaee1.5不需要额外导入包,javaee1.4需要导入包common-annotations.jar

       @Resource有两个中重要的属性:name和type 。

         Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为

         bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使

         用type属性时则使用 byType自动注入策略。如果既不指定name也不指定type

         属性,这时将通过反射机制使用byName自动注入策略,byName匹配不到后再使

         用byType自动注入策略。

       @Resource装配顺序

        (1). 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进

             行装配,找不到则抛出异常;

        (2). 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不

             到则抛出异常; 

         (3). 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到

             或者找到多个,都会抛出异常;

        (4). 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;

             如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;

    不需要set方法

        //凡是出現注解的地方都不需要set方法

    2)@Autowired

       @Autowired:跟@Resource功能很相似,都是用来维护依赖的关系。

       @Autowired是spring提供的,默认只根据类型匹配注入。如果匹配到多个将报异常。

       可以手动的按照名称匹配。

       @Autowired

       @Qualifier("userDao")

       private UserDao userDao;

    3)@Resource和@Autowired的区别

    a、@Autowired 与@Resource都可以用来装配bean. 都可以写在字段上,或写在

       setter方法上;写在字段上可以不用写set方法

    b、@Autowired 默认按类型装配。

       如果我们想使用名称装配可以结合 @Qualifier注解进行使用;

    c、@Resource(这个注解属于J2EE的),默认安装名称进行装配,名称可以通过

       name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取

       字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。

       当找不到与名称匹配的bean时才按照类型进行装 配。但是需要注意的是,如

       果name属性一旦指定,就只会按照名称进行装配。

      

     d、 推荐使用@Resource注解在字段上,是属于J2EE的,减少了与Spring的耦

         合,这样代码看起就比较优雅 。

         @Resource性能好,如果是@Autowired,会把UserDao接口对应的实现类全部

         遍历一遍  

         企业开发一般都使用@Resource

    4)案例

    DAO层

    接口

    public interface UserDao {

          void saveUser(String uname);

    }

    两个实现类

    @Repository("userDao")//userDao就是Bean对象的id标识

    @Scope("prototype")//单例还是多例

    public class UserDaoImpl implements UserDao {

                  public void saveUser(String uname) {

                         System.out.println("保存操作");

                  }

    }

    @Repository

    public class UserDaoMysqlImpl implements UserDao{

                  public void saveUser(String uname) {

                         ...

    }

    }

    业务层

    接口

    public interface UserService {

                 void saveUser(String uname);

    }

    实现类

    @Service("userService")//userService就相当于<bean>元素中id标识的作用

    public class UserServiceImpl implements UserService{

                  @Resource

                  private UserDao userDao;

                  public void saveUser(String uname) {

                         System.out.println("业务:保存");

                         userDao.saveUser(uname);

                  }

    }

    配置文件

    <beans ..>

           <!-- 开启AOP注解 ,启动注解-->

           <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

        <!-- 启动组件扫描:逐个扫描com.tarena下的类 -->

        <context:component-scan base-package="com.tarena"></context:component-scan>

    </beans>

    测试类

    public void test1(){

                  BeanFactory factory=

    new ClassPathXmlApplicationContext("applicationContext.xml");

                  UserService service=(UserService) factory.getBean("userService");

                  service.saveUser("");

           }

    八、数据连接池

    1、为什么要使用数据连接池?

    获得数据库连接的过程DriverManager.getConnection()是非常消耗系统性能的操作,如

    果过于频繁获得连接,会导致系统性能急剧下降,甚至崩溃。

    一般获得连接会占用85%的时间。一般上线的项目都使用连接池。

    2、连接池原理

    连接池中有很多创建好的连接。请求过来后,申请连接,连接池返回一个连接,用完连

    接以后,释放连接(不是关闭连接),别人可以继续使用这个连接。

    连接池主要做三件事:建立连接(服务器启动,建立一定数量的连接)

                  管理连接      

    释放连接(服务器关闭,连接池也关闭,连接释放)

    连接池原理:复用已经建立好的数据库连接

    hibernate内部默认有一个小连接池。

    3、连接池的使用步骤

    1)建立数据库连接池对象(服务器启动的时候创建)

    2)按照事先设计好的初始化连接数量,创建数据库的连接

    3)对于一个数据库的访问,直接从连接池获取连接

    4)操作数据库

    5)将连接重新放入连接池中

      (3---5,在项目运行中反复的出现)

    6)释放连接池对象

          (服务器关闭,维护期间,释放数据库连接池,释放所有的连接)

    4DBCP连接池

        使用必须要导入两个jar包

    commons-dbcp-1.2.2.jar

    commons-pool.jar

    5、连接池的核心类和核心接口

    1)DataSource接口  javax.sql.DataSource

           DataSource 对象所表示的物理数据源的连接。作为 DriverManager 工具的替代项,

           DataSource 对象是获取连接的首选方法 。

           DataSource有抽象方法getConnection();由实现类覆盖。

           所有连接池的核心都会间接或直接实现该接口。

    2)BasicDataSource类

           org.apache.commons.dbcp.BasicDataSource,实现了DataSource接口

    九、spring整合JDBC

    1、工具类JdbcTemplate

     spring整合Jdbc所用的工具类,里面封装了所有对jdbc的基本操作。

     企业开发中,一般dao操作数据库都是一条sql语句+工具类的一个方法

     Dao层:

     String sql = “”

     jdbcTemplate.方法(sql,参数)

    2、创建JdbcTemplate对象

    class JdbcTemplate {

          带DataSource参数的构造方法来生成对应的JdbcTemplate对象。

      public JdbcTemplate(DataSource dataSource) {

                  setDataSource(dataSource);

                  afterPropertiesSet();

      }

    所以创建JdbcTemplate对象对象需要传入一个DataSource参数

    3dao

    public class CostDaoImpl implements CostDao {

           private JdbcTemplate jdbcTemplate ;

           public void setDataSource(DataSource dataSource){

                  jdbcTemplate =  new JdbcTemplate(dataSource);

           }

    }

    必须注入一个DataSource对象,强调是实现DataSource接口的对象,一般注入的是连

    接池核心类对象,比如BasicDataSource。

    4、JdbcTemplate的常用方法

    update()       增删改

    query()                查询

    queryForObject()

    queryForList()

    queryForLong()

    queryForMap()

    注意:查询对象的操作

    jdbc返回的结果封装到ResultSet对象当中,Dao返回的结果,往往是一个entity对象。

    需要从ResultSet集合转换成entity对象。需要实现spring提供的RowMapper接口。

    或者使用spring的BeanPropertyRowMapper类。

    public class CostMapper implements RowMapper{

           //把rs转化成一个Object对象,不会有任何的问题

           public Object mapRow(ResultSet rs, int rowNum) throws SQLException {

                  Cost cost=new Cost();

                  cost.setId(rs.getInt("ID"));

                  cost.setName(rs.getString("NAME"));  .....

                  return cost;

           }

    }

    public Cost findById(int id) {

    String sql = "select * from cost" + " where id=?";

    CostMapper costMapper = new CostMapper();

    // return (Cost) jdbcTemplate.queryForObject(sql, new Object[]{id},costMapper );

    return (Cost) jdbcTemplate.queryForObject(sql, new Object[] { id },

                                                     new BeanPropertyRowMapper(Cost.class));

    //BeanPropertyRowMapper:实现RowMapper接口的对象

    //不稳定,如果对象的字段为空的时候,容易出现异常

    // 不同的spring版本,返回不同的结果

    }

    5、案例

    1)实体类以及实体类对应的Mapper类

    public class Cost {

           private Integer id;

           private String name;

           private Integer baseDuration;

           private Double baseCost; 

           private Double unitCost;

           private String status;

           private String descr;

           private Date createTime;

           private Date startTime;

           private String costType;

           ....

    }

    public class CostMapper implements RowMapper{

           //把rs转化成一个Object对象,不会有任何的问题

           public Object mapRow(ResultSet rs, int rowNum) throws SQLException {

                  Cost cost=new Cost();

                  cost.setId(rs.getInt("ID"));

                  cost.setName(rs.getString("NAME"));

                  cost.setBaseDuration(rs.getInt("BASE_DURATION"));

                  .....

    return cost;

           }

    }

    2)配置文件applicationContext.xml

    <beans ....>

    <!-- spring整合jdbc -->

    <!---让spring来管理数据连接源对象--->

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">

    <!---基本属性 driverClassName  url  username  password --->

    <property name="driverClassName"

    value="oracle.jdbc.driver.OracleDriver"></property>

           <property name="url"

    value="jdbc:oracle:thin:@172.17.3.6:1521:ora10g"></property>

           <property name="username" value="szsd1307"></property>

           <property name="password" value="szsd1307"></property>

           <!-- initialSize:连接池创建的时候,初始化连接数量,不配置默认是0个

                  maxWait:如果没有连接,最长的等待时间,单位是毫秒数

                  maxActive:连接池在同一时间内分配最大的使用连接数量-->

           <property name="initialSize" value="10"></property>

           <property name="maxWait" value="2000"></property>

           <property name="maxActive" value="50"></property>

    </bean>

    <!-- 该实现DataSource接口的BasicDataSource注入到dao当中

    创建JdbcTemplate对象时,需要传入参数DataSource -->

    <bean id="costDao" class="com.tarena.dao.impl.CostDaoImpl">

           <property name="dataSource" ref="dataSource"></property>

    </bean>

    </beans>

    3)DAO层

    接口

    public interface CostDao {

           void saveCost(Cost cost);

           void deleteCost(Cost cost);

           void updateCost(Cost cost);

           Cost findById(int id);

           List<Cost> findAll();

           long findCount();

           //查询最高(unit_cost,最低unit_cost,平均unit_cost)

           Map findUnitCost();

    }

    实现类

    public class CostDaoImpl implements CostDao{

           private JdbcTemplate jdbcTemplate;

           //通过外界注入参数(数据库连接参数)

           public void setDataSource(DataSource datasource){

                  jdbcTemplate=new JdbcTemplate(datasource);

           }

           public void deleteCost(Cost cost) {

                  String sql="delete from COST_QIN where id=?";

                  jdbcTemplate.update(sql, new Object[]{cost.getId()});

            //第一个参数放sql语句,第二个参数放对象数组,里面放入?对应的值

           }

           public List<Cost> findAll() {

                  String sql="select * from COST_QIN";

                  return jdbcTemplate.query(sql,new CostMapper());

           }

           public Cost findById(int id) {

                  String sql="select * from cost_qin where id=?";

    RowMapper costMapper=new CostMapper();

    return (Cost)jdbcTemplate.queryForObject

    (sql, new Object[]{id}, costMapper);

           }

           public void saveCost(Cost cost) {

                  String sql="insert into COST_QIN(ID,NAME,BASE_DURATION,

      BASE_COST,UNIT_COST,STATUS,DESCR,CREATIME,

      STARTIME,COST_TYPE) " +

                                  "values(COST_SEQ.NEXTVAL,?,?,?,?,?,?,?,?,?) ";

                  jdbcTemplate.update(sql, new Object[]{cost.getName(),cost.getBaseCost(),

    cost.getBaseCost(),cost.getUnitCost(),cost.getStatus(),cost.getDescr(),cost.get

    CreateTime(),cost.getStartTime(),cost.getCostType()});

           }

           public void updateCost(Cost cost) {

                  String sql="update COST_QIN set NAME=?,BASE_DURATION=?,

     BASE_COST=?,UNIT_COST=?,STATUS=?,DESCR=?,

     CREATIME=?,STARTIME=?,COST_TYPE=? WHERE ID=?";

                  jdbcTemplate.update(sql, new Object[]{cost.getName(),cost.getBaseCost(),

    cost.getBaseCost(),cost.getUnitCost(),cost.getStatus(),cost.getDescr(),cost.get

    CreateTime(),cost.getStartTime(),cost.getCostType(),cost.getId()});

           }

           public long findCount() {

                  //sql语句当中,切记尽量少出现"*"

    //一般对于数据的都用long类型

                  String sql="select count(id) from cost_qin";

                  return jdbcTemplate.queryForLong(sql);

           }

           public Map findUnitCost() {

                  String sql="select max(unit_cost),min(unit_cost),avg(unit_cost)

             from cost_qin";

                  return jdbcTemplate.queryForMap(sql);

           }

    }

    4)测试类

          public class TestSpring {

           public void test1(){

                  BeanFactory factory=new

    ClassPathXmlApplicationContext("applicationContext.xml");

                  CostDao  costDao=(CostDao) factory.getBean("costDao");

                  Cost cost=new Cost();

                  cost.setId(168);

                  costDao.deleteCost(cost);

           }

    ....

    6DaoSupport 

    是spring提供专门用来Dao层公共抽象类,spring建议程序员在写Dao层,

    所有的类最好都继承DaoSupport下属子类。

    1)针对jdbc:继承JdbcDaoSupport

    JdbcDaoSupport:内部包含一个JdbcTemplate对象,以简化操作。

           可以通过 getJdbcTemplate()方法获得JdbcTemplate对象

    public abstract class JdbcDaoSupport extends DaoSupport {

           private JdbcTemplate jdbcTemplate;

           public final void setDataSource(DataSource dataSource) {

                  if (this.jdbcTemplate == null || dataSource !=

    this.jdbcTemplate.getDataSource()) {

                         this.jdbcTemplate = createJdbcTemplate(dataSource);

                         initTemplateConfig();

                  }

           }

    public final JdbcTemplate getJdbcTemplate() {

             return this.jdbcTemplate;

    }

    }

       之所以要继承JdbcDaoSupport,主要是因为JdbcDaoSupport类中有一个属性

       JdbcTemplate。不继承也可以,在dao实现类中添加属性JdbcTemplate

    2)针对hibernate:继承HibernateDaoSupport  

       包含一个hibernateTemplate

           spring建议使用hibernate做开发的时候,dao最好继承

           HibernateDaoSupport,以便利用里面工具类hibernateTemplate

    7、修改Dao实现类,采用继承JdbcDaoSupport方式

    public class CostDaoImpl extends JdbcDaoSupport implements CostDao{

    // CostDaoImpl 继承了 JdbcDaoSupport类,

    //相当于CostDaoImpl有了下面的代码

    private JdbcTemplate jdbcTemplate;

           public final void setDataSource(DataSource dataSource) {

                  if (this.jdbcTemplate == null || dataSource !=

    this.jdbcTemplate.getDataSource()) {

                         this.jdbcTemplate = createJdbcTemplate(dataSource);

                         initTemplateConfig();

                  }

           }

    //有了属性JdbcTemplate,创建JdbcTemplate依然要注入DataSource参数。

    //applicationContext.xml配置文件不需要改变

           public void deleteCost(Cost cost) {

                  String sql="delete from COST_QIN where id=?";

                  this.getJdbcTemplate().update(sql, new Object[]{cost.getId()});

    }

           public List<Cost> findAll() {

                  String sql="select * from COST_QIN";

                  return this.getJdbcTemplate().query(sql,new CostMapper());

           }

    .....

           public Map findUnitCost() {

                  String sql="select max(unit_cost),min(unit_cost),avg(unit_cost) from cost_qin";

                  return this.getJdbcTemplate().queryForMap(sql);

           }

    }

    十、spring整合hibernate

    1、spring整合Hibernate步骤

    1)导入hibernate的jar包 hibernate常用的版本是3.2或者3.5

    2)导入hibernate的配置文件

    3)生成对应po类和orm映射文件

    4)导入spring的jar包

    5)导入spring核心配置文件

    2、spring整合hibernate的工具类

    HibernateTemplate类

    封装了spring针对hibernate的方法,简化hibernate的操作。

    该类的构造器

    public HibernateTemplate(SessionFactory sessionFactory) {

             setSessionFactory(sessionFactory);

             afterPropertiesSet();

    }

    说明在创建HIbernateTemplate对象时,需要传入一个Sessionfactory参数。

    public class CostDaoImpl implements CostDao {

           private HibernateTemplate hibernateTemplate;

    //使用spring的DI依赖注入,使用set注入一个SessionFactory

    //让spring管理hibernate的数据源

           public void setSessionFactory(SessionFactory sessionFactory){

    //创建带sessionFactroy的hibernateTemplate对象

                  hibernateTemplate =  new HibernateTemplate(sessionFactory);

           }

    }

    3、注入SessionFactory

    1、创建hibernateTemplate对象时,需要传入一个参数SessionFactory

       SessionFactory代表了hibernate配置文件中的所有信息,sessionfactory只有一份

       1)、数据库的连接信息

       2)、hibernate自身的属性信息

       3)、hibernate映射文件

       注意不是注入DataSource,DataSource只是SessionFactory真的一小部分

    2、使用spring核心配置文件注入SessionFactroy(第一种方式)

       <bean id="sessionFactory"

                        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" >

           <property name="configLocation"  value="classpath:hibernate.cfg.xml"></property>

       </bean>

       <bean id="costDao" class="com.tarena.dao.impl.CostDaoImpl">

                  <property name="sessionFactory" ref="sessionFactory"></property>

       </bean>

       上述配置注入了一个SessionFactory,

       类型为org.springframework.orm.hibernate3.LocalSessionFactoryBean,

       部分源代码:

       public class LocalSessionFactoryBean extends AbstractSessionFactoryBean

    implements BeanClassLoaderAware {

           private Configuration configuration;

    public void setConfigLocation(Resource configLocation) {

                         this.configLocations = new Resource[] {configLocation};

                  }

       }

       LocalSessionFactoryBean类中的属性configuration用来用来加载资源文件,

       这里加载hibernate配置文件。

    3、 问题:LocalSessionFactoryBean类型并不是SessionFactory接口类型

          (即没有实现Sessionfactory接口),如何实现注入的?

          LocalSessionFactoryBean 本身不是一个session factory,但是spring会自动把对这

        个bean的引用替换成LocalSessionFactoryBean 里面的真正的session factory。

       (1)在LocalSessionFactoryBean 中有个字段是存放真正的session factory的:

    LocalSessionFactoryBean 继承了抽象类AbstractSessionFactoryBean

                 抽象类中有:

    public abstract class AbstractSessionFactoryBean

                  implements FactoryBean, InitializingBean, DisposableBean,

    PersistenceExceptionTranslator {

                             private DataSource dataSource;

    private SessionFactory sessionFactory;  

                               public Object getObject(); {  

                           returnthis.sessionFactory;  

              }

    当引用这个LocalSessionFactoryBean 的时候,比如

    applicationContext.getBean("localSessionFactoryBean ")这样,spring返回的不是

    LocalSessionFactoryBean 本身,他会自动调用getObject()这个方法,把真正的

    session factory返回,得到的都是session factory而不是

    LocalSessionFactoryBean 。

    (2)LocalSessionFactoryBean实现了org.springframework.beans.factory.FactoryBean

     接 口, spring在装配的时候, 如果发现实现了factory.FactoryBean接口, 就会

     使用FactoryBean#getObject() 方法返回的对象装配。

     如果你想拿到LocalSessionFactoryBean实例, 在id前面加个'&'就可以了,在你

     的配置文件中BeanFactory.getBean('&sessionFactory')拿到的 就是

     LocalSessionFactoryBean的实例.     

    4、案例

    1)导入hibernate的jar包 hibernate常用的版本是3.2或者3.5

    2)导入hibernate的配置文件

    <hibernate-configuration>

           <session-factory>

                  <!-- 方言,指定Hibernate语句生成的sql类型 -->

                  <property name="dialect">org.hibernate.dialect.OracleDialect</property>

                  <!-- 连接数据库属性 -->

                  <propertyname="connection.url">

    jdbc:oracle:thin:@172.17.3.6:1521:ora10g</property>

                  <property name="connection.username">szsd1307</property>

                  <property name="connection.password">szsd1307</property>

                  <property name="connection.driver_class">

    oracle.jdbc.OracleDriver</property>

                  <!-- 将底层的sql操作显示出来 -->

                  <property name="show_sql">true</property>

                  <property name="format_sql">true</property>

    <!--映射文件->

                  <mapping resource="com/tarena/pojo/Cost.hbm.xml" />

           </session-factory>

    </hibernate-configuration>

    3)生成对应po类和orm映射文件

    public class Cost implements java.io.Serializable {

           private Integer id;

           private String name;

           private Long baseDuration;

           private Double baseCost;

           private Double unitCost;

           private String status;

           private String descr;

           private Date creatime;

           private Date startime;

           private String costType;

           get/set方法

    }

    Cost.hbm.xml 省略

    4)导入spring的jar包

    5)导入spring核心配置文件

    配置文件applicationContext.xml

    <beans ..>

           <!-- 利用spring的工具类加载hibernate的核心配置文件hibernate.cfg.xml -->

           <bean id="sessionFactory"

    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

    <!-- 加载核心配置文件放入sessionfactory属性configLocation中 -->

                  <property name="configLocation"

    value="classpath:hibernate.cfg.xml"></property>

           </bean>

           <!-- 配置CostDao -->

           <bean id="costDao" class="com.tarena.dao.impl.CostDaoImpl">

                  <property name="sessionFactory" ref="sessionFactory"></property>

           </bean>

    </beans>

    6)DAO层(注意事务问题,下节讲)

    public interface CostDao {

           void saveCost(Cost cost);

           void deleteById(int id);

           void updateCost(Cost cost);

           Cost findById(int id);

           List<Cost> findAll();

           //查询总的cost数量

           long findCount();

           List<Cost> findPage(int page,int pageSize);

    }

    第一种方式:添加一个HibernateTemplate类

    public class CostDaoImpl implements CostDao{

           private  HibernateTemplate hibernateTemplate;

           public void setSessionFactory(SessionFactory sessionFactory){

                  hibernateTemplate=new HibernateTemplate(sessionFactory);

           }

           public void saveCost(Cost cost) {

                  //不要使用hql语句,hql语句可以查询,修改,删除就不是不能保存

                  hibernateTemplate.save(cost);

           }

           public void updateCost(Cost cost) {

                  hibernateTemplate.save(cost);

           }

           public Cost findById(int id) {

                  return (Cost) hibernateTemplate.get(Cost.class, id);

           }

           public List<Cost> findAll() {

                  //spring整合hibernate时,查询方法一般使用find方法,find方法返回一

    //般都是list集合,spring没有整合uniqueResult,

                  //如果使用hql查询,使用find,返回永远都是list

                  //这是spring整合hibernate不太成功之一

                  String hql="from Cost";

                  return hibernateTemplate.find(hql);

           }

           public long findCount() {

                  String hql="select count(id) from Cost";

                  //最好先变成string再转成int。不要强转,spring的版本不同,返回可能

    //是Long,Integer类型

                  List list=hibernateTemplate.find(hql);

                  long count=Long.parseLong(list.get(0).toString());

                  return count;

           }

           public List<Cost> findPage(final int page,final int pageSize) {

                  final String  hql="from Cost";

                  //spring整合hibernate的时候,对分页没有很好的支持

                  //必须要使用hibernate中的session来实现分页

                  //使用回调的方式(固定写法,必须记住)

                  return (List<Cost>) hibernateTemplate.execute(new HibernateCallback() {

                         //内部类使用外界的变量的时候,外界变量必须使用final修饰

                         @Override

                         public Object doInHibernate(org.hibernate.Session session)

                                       throws HibernateException, SQLException {

                                int begin=(page-1)*pageSize;

                                returnsession.createQuery(hql)

    .setFirstResult(begin).setMaxResults(pageSize).list();

                         }

                  });

           }

           public void deleteById(int id) {

                  Cost cost=new Cost();

                  cost.setId(id);

                  hibernateTemplate.delete(cost);

                 

           }

    }

    第二种方式:继承HibernateDaoSupport类

    public class CostDaoImpl extends HibernateDaoSupport implements CostDao{

           public void saveCost(Cost cost) {

                  this.getHibernateTemplate().save(cost);

           }

           public void updateCost(Cost cost) {

                  this.getHibernateTemplate().save(cost);

           }

           public Cost findById(int id) {

                  return (Cost)this.getHibernateTemplate().get(Cost.class, id);

           }

           public List<Cost> findAll() {

                  String hql="from Cost";

                  return this.getHibernateTemplate().find(hql);

           }

           public long findCount() {

                  String hql="select count(id) from Cost";

                  List list=this.getHibernateTemplate().find(hql);

                  long count=Long.parseLong(list.get(0).toString());

                  return count;

           }

           public List<Cost> findPage(final int page,final int pageSize) {

                  final String  hql="from Cost";

                 

                  return (List<Cost>) this.getHibernateTemplate().

    execute(new HibernateCallback() {

                         public Object doInHibernate(org.hibernate.Session session)

                                       throws HibernateException, SQLException {

                                int begin=(page-1)*pageSize;

                                return session.createQuery(hql)

    .setFirstResult(begin).setMaxResults(pageSize).list();

                         }

                  });

           }

           public void deleteById(int id) {

                  Cost cost=new Cost();

                  cost.setId(id);

                  this.getHibernateTemplate().delete(cost);

           }           

    }

    5、spring+hibernate如何使用SessionQuery等对象

    (1)方式一

     利用HIbernateDaoSupport提供的getSession方法。

     没用到延迟加载的API,那么用这个方式简单些。但是有延迟加载的API,则会

     出现问题:session关闭早了,页面可能获取不到数据;不关闭,一旦出了方法体

     则关不上了。而多次访问数据库后,就发现没结果,因为连接数用完了。

         Session session = getSession();

     ..............利用session进行一些操作.......

     session.close();//注意:一定要释放

     getHibernateTemplate中的API都有释放操作,所以自己不用再写。

    (2)方式二

     利用HibernateTemplate.execute()方法,以回调函数方式使用。这种方式不用担心

     方式一出现的问题,session的关闭由HibernateTemplate统一管理。

     getHibernateTemplate().execute(

    new HibernateCallBack(Session session){

    public Object doInHibernate()throws HibernateException,SQLException{

    //回调函数中使用session

    }

    }

     );

    6、spring配置SessionFactory的第2中方式(更常用)

    修改applicationContext.xml文件

    将hibernate.cfg.xml文件去掉,把该文件的信息配置到applicationContext.xml文件中。

    添加数据连接池的配置

    <beans ...>

           <!-- 配置SessionFactory的第二种方式(企业项目上线的时候)

                      主要配置的是3部分参数

                1)DataSource(连接池对象)

                2)hibernate属性

                3)orm映射文件 -->

            <!-- 配置DBCP连接池 -->

            <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">

                 <property name="driverClassName"

    value="oracle.jdbc.OracleDriver"></property>

                 <property name="url"

    value="jdbc:oracle:thin:@172.17.3.6:1521:ora10g"></property>

                 <property name="username" value="szsd1307"></property>

                 <property name="password" value="szsd1307"></property>

                 <property name="initialSize" value="10"></property>

            </bean>

            

           <bean id="sessionFactory"

    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

                  <property name="dataSource" ref="dataSource"></property>

                  <property name="hibernateProperties">

                         <props>

                                <prop key="hibernate.dialect">

    org.hibernate.dialect.OracleDialect</prop>

                                <prop key="hibernate.show_sql">true</prop>

                                <prop key="hibernate.format_sql">true</prop>

                         </props>

                  </property>

                  <property name="mappingResources">

                         <list>

                                <value>com/tarena/pojo/Cost.hbm.xml</value>

                         </list>

                  </property>

           </bean>

           <bean id="costDao" class="com.tarena.dao.impl.CostDaoImpl">

                  <property name="sessionFactory" ref="sessionFactory"></property>

           </bean>

    </beans>

    十一、spring事务管理

    JDBC的底层是默认自动提交事务,每次执行JDBC都会在底层默认提交事务。HIbernate底层是默认手动提交事务,需要我们程序员自己去提交事务。

    真实企业开发中:需要我们控制事务的提交,回滚等,比如银行转账,减钱和加钱同时提交事务才可以。

    1、事务的传播特性

    1)事务边界

       比如银行转账,减钱开始前和加钱结束后就是事务边界,共用同一个事务。

    2)事务的传播特性

       事务的传播特性是指连续一次或者多次对数据库的操作,事务的控制。

       指多次对数据进行操作时,如何对事务进行控制就是事务的传播特性。

       对事务进行控制就是指控制什么时候开启,什么时候提交,什么时候回滚。

          (1)propagation_required  数据库操作1 数据库操作2 数据库操作3 ...

       连续两次或者多次操作数据库,都沿用同一个事务。

       如果存在一个事务,则支持当前事务,如果没有事务,则开启一个事务。

       比如:第一次查询没有事务,第二次删除操作,开启事务,第三次是修改操作,

             沿用删除操作开启的事务。

       增删改是required特性,必须要有事务。

      (2)propagation_not_supported

       非事务执行。一般用于查询操作(比如分页查询)

          (3)企业开发中,一般增删改操作配置成required,查询配置成not_supported

    2、事务的隔离级别

       脏数据(永远不要出现):读到没有提交的数据。脏读就是读取没提交的数据

       不可重复读:数据提交到数据库,可以读数据。

                   一条数据被修改的同时,另一个人也在修改该数据。

                   同一时刻,多个人修改同一条数据,读出来的数据和自己修改的数据

       不一样

       幻象读:    整张表数据被修改,又插入一些新数据

                   一个人对所有数据进行修改时,另一个人又插入一些新数据

                   一个人访问所有数据的同时又有人添加了一些新数据

       脏读一定不能出现,不可重复读和幻象读可以出现

       1)read_uncommited

      最低的隔离级别,数据没有提交就能读,能看到

           企业开发一定尽量不要使用

       2)read_commited 

      提交后才能读(不能脏读)

       3)repeatable_read

      在我访问某条数据的时候,别人都不能访问,但可以访问其他数据。

      不会出现不可重复读,会出现幻觉读(指的是整张表中所有的数据)

       4)serializable 

          整张表在同一时刻只有一个人可以访问,访问结束后其他人才可以访问。

          不会出现不可重复读,不会出现幻想读。最昂贵的。

       最最常用的隔离级别是read_commited

       隔离一定要避免脏读(数据位提交,一定不能读取)

       面试问在隔离级别中要避免什么?避免脏读。

    spring管理事务就是管理事务的传播特性和隔离级别

    3、声明式事务(hibernate版本的)

    通过spring配置文件来控制事务

    通过spring配置来管理我们的事务(事务的传播特性和事务的隔离级别)。

       (1)指定事务管理器

           (事务管理器在spring底层来控制事务的对象,开启事务,提交事务,回滚事务等)

    类HibernateTransactionManager中管理事务的方法

    1)doBegin(){ hibTx = session.beginTransaction();} 开启事务

    2)doCommit(){}                                                   提交事务

    3)doRollBack(){}                                                  回滚事务

          <!-- 指定当前的事务管理器 -->

          <bean id="transactionManager"

                 class="org.springframework.orm.hibernate3.HibernateTransactionManager">

                 <!-- 使用HibernateTransactionManager必须注入一个SessionFactory -->

                 <property name="sessionFactory"ref="sessionFactory"></property>

          </bean>

    (2)配置事务特性(方法执行的时候,事务如何控制)

         a)事务的传播特性

               PROPAGATION_REQUIRED :增删改

               PROPAGATION_NOT_SUPPORTED:查询

         b)事务的隔离级别

               READ_COMMITED

     c)配置事务的特性(事务的传播特性和事务的隔离级别)

    <!--

                  transaction-manager指定事务管理器,由transactionManager来管理事务

    DEFAULT指的是当前数据库默认的隔离级别

    mysql必须修改隔离级别,oracle可以不修改,默认是read_commited

    delete*":*匹配后面的任意的名字,比如匹配deleteUser... 其他同理

    -->

           <tx:advice id="txAdvice" transaction-manager="transactionManager">

                  <tx:attributes>

                         <tx:method name="find*" propagation="NOT_SUPPORTED"

    read-only="true" isolation="READ_COMMITTED"/>

                         <tx:method name="save*" propagation="REQUIRED"

    isolation="READ_COMMITTED"/>

                         <tx:method name="delete*" propagation="REQUIRED"

    isolation="READ_COMMITTED"/>

                         <tx:method name="update*" propagation="REQUIRED"

    isolation="READ_COMMITTED"/>

                  </tx:attributes>

           </tx:advice>

    (3)固定的Aop

    <aop:config>

           <aop:pointcut expression="execution(* com.tarena.dao..*.*(..))" id="txPointcut"/>

           <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>

    </aop:config>

    4、applicationContext.xmlhibernate版本)

    将spring整合hibernate的案例添加事务管理

    <beans >

           <bean id="sessionFactory"

    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

                  <property name="configLocation"

    value="classpath:hibernate.cfg.xml"></property>

           </bean>

           <bean id="transactionManager"

    class="org.springframework.orm.hibernate3.HibernateTransactionManager">

                  <property name="sessionFactory" ref="sessionFactory"></property>

           </bean>

           <tx:advice id="txAdvice" transaction-manager="transactionManager">

                  <tx:attributes>

                         <tx:method name="find*" propagation="NOT_SUPPORTED"

    read-only="true" isolation="READ_COMMITTED"/>

                         <tx:method name="save*" propagation="REQUIRED"

     isolation="READ_COMMITTED"/>

                         <tx:method name="delete*" propagation="REQUIRED"

    isolation="READ_COMMITTED"/>

                         <tx:method name="update*" propagation="REQUIRED"

    isolation="READ_COMMITTED"/>

                  </tx:attributes>

           </tx:advice>

           <aop:config>

                  <aop:pointcut expression="execution(* com.tarena.dao..*.*(..))" id="txPointcut"/>

                  <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>

           </aop:config>

           <bean id="costDao" class="com.tarena.dao.impl.CostDaoImpl">

                  <property name="sessionFactory" ref="sessionFactory"></property>

           </bean>

    </beans>

    5、使用注解方式配置事务

    1)applicationContext.xml

    <beans ...>

           <bean id="sessionFactory"

    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

    <property name="configLocation"

    value="classpath:hibernate.cfg.xml"></property>

           </bean>

           <!-- 1、指定当前事务的管理器

                    管理事务 事务开启 提交 回滚 -->

           <bean id="transactionManager"

    class="org.springframework.orm.hibernate3.HibernateTransactionManager">

                  <property name="sessionFactory" ref="sessionFactory"></property>

           </bean>

           <!-- 2、开启事务的注解配置

                transaction-manager:指明让transactionManager管理事务 -->

           <tx:annotation-driven proxy-target-class="true"

    transaction-manager="transactionManager"/>

          

           <bean id="costDao" class="com.tarena.dao.impl.CostDaoImpl">

                  <property name="sessionFactory" ref="sessionFactory"></property>

           </bean>

    </beans>

    2)在业务组件的类定以前或方法中使用@Transactional注解即可

    public class CostDaoImpl extends HibernateDaoSupport implements CostDao{

    @Transactional(isolation=Isolation.READ_COMMITTED,

    propagation=Propagation.REQUIRED)

                  public void saveCost(Cost cost) {

                         .....

                  }

    @Transactional(isolation=Isolation.READ_COMMITTED,

    propagation=Propagation.REQUIRED)

                  public void updateCost(Cost cost) {

                  .....

           }

    @Transactional(isolation=Isolation.READ_COMMITTED,

    propagation=Propagation.REQUIRED)

                  public Cost findById(int id) {

                  ....

                  }

    @Transactional(isolation=Isolation.READ_COMMITTED,

    propagation=Propagation.REQUIRED)

                  public List<Cost> findAll() {

                         ...

                  }

    }

    3)注意事项

    如果将Action当作目标,需要在<tx:annotation-driven>添加 proxy-target-class="true"

    属性,表示不管有没有接口,都采用CGLIB方式生成代理类。

    6、编程式事务管理

    基于Java编程实现事务控制,不推荐使用。

    主要是利用TransactionTemplate的execute()方法,以回调方式将多个操作封装在一个

    事务中。

    7spring针对JDBC的声明式事务

    企业开发中,两层架构事务配置在action上,三层架构配置在service上面。

    applicationContext.xml文件

    <beans ...>

     <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">

          <property name="driverClassName" value="oracle.jdbc.OracleDriver"></property>

          <property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"></property>

          <property name="username"  value="system"></property>

          <property name="password"   value="1234"></property>

          <property name="initialSize"  value="10"></property>

          <property name="maxWait"   value="2000" ></property>

           <property name="maxActive"  value="50"></property>   

     </bean>

    <!-- jdbc声明式事务 -->

    <!-- 指定jdbc中的事务管理器DataSourceTransactionManager-->

    <bean id="transactionManager"

    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

           <property name="dataSource" ref="dataSource"></property>

    </bean>

    <!-- 配置事务的特性(事务传播特性和隔离级别) -->

    <tx:advice id="txadvice"

    transaction-manager="transactionManager">

           <tx:attributes>

                  <tx:method name="find*" propagation="NOT_SUPPORTED" read-only="true"

                                                                  isolation="READ_COMMITTED"/>

                  <tx:method name="save*"  propagation="REQUIRED"

                                                                    isolation="READ_COMMITTED" />

                  <tx:method name="update*" propagation="REQUIRED"

                                                                    isolation="READ_COMMITTED"/>

                  <tx:method name="delete*" propagation="REQUIRED"

     isolation="READ_COMMITTED" />

           </tx:attributes>

    </tx:advice>

    <aop:config>

           <!--事务配置到那个层(Action,dao)是pointcut决定的,

       一般来说如果Action,Dao结构,事务一般配置到Action

       如果是Action,service,dao结构事务一般配置到service      

       切记:事务尽量不要配置到dao层,在web项目中

          -->

          <aop:pointcut  expression="execution (* com.tarena.dao..*.*(..))"  id="curd"/>

         <!-- 针对事务,spring一般使用专用标签advisor,把通知和切入点连接起来-->

         <aop:advisor advice-ref="txadvice"  pointcut-ref="curd"/>

    </aop:config>

    <bean id="costDao"  class="com.tarena.dao.impl.CostDaoImpl">

           <property name="dataSource" ref="dataSource"></property> 

    </bean>

    </beans>

    十二、spring整合struts2

    1struts2 中常量定义

    <constant name="" value=""></constant>

    struts2这个框架,在运行本身配置很多的常量,而这些是应用于一般性的开发,这些常

    量全部都配置在default.properties。

    default.properties文件在struts2-core02.1.8.jar包中 /org/apache/struts2/default.properties

    1)# struts.objectFactory = spring :由spring来提供struts2中

       action对象的创建及维护,默认情况下给注释了。

       struts本身负责创建action对象的类是:StrutsObjectFactory类

    2)struts.i18n.encoding=UTF-8 :struts2默认编码是UTF-8

    3)struts.action.extension=action,,

           提交的请求的后缀,struts默认情况下可以接收以.action和不加任何后缀结尾的请求

    2、修改常量

        1)default.properties该文件中定义的常量的信息,可以随意的进行修改,修改方法

           在struts.xml中

       <constant name="" value=""></constant>重新定义值

       eg:<constant name="struts.action.extension" value="do"></constant>。

           更改为接收以.do为结尾的请求

       2)spring整合struts2,spring管理struts2中的Action对象的创建及维护,

          必须要修改default.properties中配置信息

      导入一个struts2-spring-plugin-2.0.11.2.jar

          有一个配置文件:struts-plugin.xml中

          <constant name="struts.objectFactory" value="spring" />

          修改default.properties中配置信息,由spring来创建并维护struts2中的Action对象

      struts-plugin.xml文件内容

      <struts>

        <bean type="com.opensymphony.xwork2.ObjectFactory" name="spring"

    class="org.apache.struts2.spring.StrutsSpringObjectFactory" />

        指定struts的action对象由spring来创建维护,即StrutsSpringObjectFactory类。

    这样struts请求过来时,Action对象将交给整合包spring容器获取,即struts2不再

    产生Action对象。

        <constant name="struts.objectFactory" value="spring" />

     </struts>

    3struts2中默认继承的包struts-default

    <default-class-ref class="com.opensymphony.xwork2.ActionSupport" />

    默认关联ActionSupport

    <!-- 跳转到新增页面的Action -->

    <action name="toAddCost" >

                  <result name="success">/WEB-INF/cost/addCost.jsp</result>

    </action>

    toAddCost请求------》默认关联ActionSupport------》execute方法,返回值是success

    4spring整合struts2

    1)原理:把struts2中的action对象的创建和维护,全部交给spring 统一的创建和维护。

      必须要导入struts2-spring-plugin-2.0.11.2.jar

      自动修改default.properties中的

      struts.objectFactory = spring,交由spring来维护action对象

    2)什么时候加载spring核心配置?(把spring配置文件中bean全部实例化)

       监听器:

       启动服务器,就去实例化spring中的bean,提交性能

    3)spring 提供加载配置文件的类:

    org.springframework.web.context.ContextLoaderListener

    4) 修改web.xml文件

    5、案例整合资费模块

    1) 首先添加spring,struts2,hibernate的jar包和配置文件

    2) 对po类,修改成符合hibernate操作的po和orm映射文件

    3) 修改spring核心配置文件,用来整合hibernate

    4) 添加spring核心配置文件,用来配置action ,dao

        spring整合框架的配置文件最好单独作为一个配置文件

    5) spring整合struts2

    6) 重写CostDaoImpl(spring整合hibernate)

    7) 重构Action,去掉工厂,使用spring的IOC,提供Action所依赖dao对象

    1)导入包

    2)po类和orm映射文件

    3)applicationContext_hibernate.xml文件

       <beans ...>

    <!-- 配置DataSource -->

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">

                  <property name="driverClassName"

    value="oracle.jdbc.driver.OracleDriver"></property>

                  <property name="url"

    value="jdbc:oracle:thin:@172.17.3.6:1521:ora10g"></property>

                  <property name="username" value="szsd1307"></property>

                  <property name="password" value="szsd1307"></property>

                  <property name="initialSize" value="10"></property>

                  <property name="maxWait" value="2000"></property>

                  <property name="maxActive" value="50"></property>

       </bean>

    <!-- 配置SessionFactory -->

       <bean id="sessionFactory"

    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

                  <property name="dataSource" ref="dataSource"></property>

                  <property name="hibernateProperties">

                         <props>

                                <prop key="hibernate.dialect">

    org.hibernate.dialect.OracleDialect</prop>

                                <prop key="hibernate.show_sql">true</prop>

                                <prop key="hibernate.format_sql">true</prop>

                         </props>

                  </property>

                  <property name="mappingResources">

                         <list>

                                <value>web/netctoss/cost/entity/Cost.hbm.xml</value>

                                <value>web/netctoss/account/entity/Account.hbm.xml</value>

                                ....

                         </list>

                  </property>

       </bean>

    <!-- 指定事务管理器 -->

    <bean id="transactionManager"

    class="org.springframework.orm.hibernate3.HibernateTransactionManager">

                  <property name="sessionFactory" ref="sessionFactory"></property>

    </bean>

    <!-- 配置事务特性 -->

    <tx:advice id="txAdvice" transaction-manager="transactionManager">

                  <tx:attributes>

                         <tx:method name="find*" propagation="NOT_SUPPORTED"

    isolation="READ_COMMITTED" read-only="true"/>

                         <tx:method name="delete*" propagation="REQUIRED"

    isolation="READ_COMMITTED"/>

                         <tx:method name="update*" propagation="REQUIRED"

    isolation="READ_COMMITTED"/>

                         <tx:method name="save*" propagation="REQUIRED"

    isolation="READ_COMMITTED"/>

                         <!-- 添加action中的execute方法,暂时先用required -->

                         <tx:method name="execute" propagation="REQUIRED"

    isolation="READ_COMMITTED"/>

                  </tx:attributes>

    </tx:advice>

    <!-- AOP -->

    <aop:config>

                  <aop:pointcut expression="execution(* web.netctoss.cost.action.*.*(..) )"

    id="costPointcut"/>

                  <aop:pointcut expression="execution(* web.netctoss.account.action.*.*(..) )"

    id="accountPointcut"/>

                  <aop:pointcut expression="execution(* web.netctoss.service.action.*.*(..) )"

    id="servicePointcut"/>

                  <aop:advisor advice-ref="txAdvice" pointcut-ref="costPointcut"/>

                  <aop:advisor advice-ref="txAdvice" pointcut-ref="accountPointcut"/>

                  <aop:advisor advice-ref="txAdvice" pointcut-ref="servicePointcut"/>

    </aop:config>

     </beans>

    4)applicationContext_bean.xml

    <!--资费模块模块 action,dao

       把struts2中的Action,纳入spring的管理,

       struts2中的Action的创建和维护都交给spring统一处理

       还有一个问题,struts2中的action是多例,spring中的bean是单例-->

    <bean id="costDao" class="web.netctoss.cost.dao.impl.CostDAOImpl">

                  <property name="sessionFactory" ref="sessionFactory"></property>

    </bean>

    <bean id="findCostAction" class="web.netctoss.cost.action.FindCostAction"

    scope="prototype">

           <property name="costDao" ref="costDao"></property>

    </bean>

    5)action配置文件

    <package name="cost" namespace="/cost" extends="netctoss">

    <!-- struts中的action对象都是由spring来创建和维护,不用struts2来维护

        每一个action中的class属性的值,指向spring生成的Action对象bean的id -->

           <action name="findCost" class="findCostAction">

                         <interceptor-ref name="netctossStack"></interceptor-ref>

                         <!-- 属性注入 -->

                         <param name="pageSize">3</param>

                         <result name="success">/WEB-INF/cost/cost_list.jsp</result>

           </action>

    6)修改action类

    public class FindCostAction {

           .....输入输出属性

           private CostDAO costDao; 依赖注入dao类

           public String execute(){

                  try {

                         costs=costDao.findByPages(page, pageSize);

                         totalPage=costDao.findTotalPage(pageSize);

                  } catch (Exception e) {

                         e.printStackTrace();

                         return "error";

                  }

                  return "success";

    }

     }

    7)修改dao类

    添加工具类HibernateTemplate类

    8)修改web.xml文件

    <web-app ...>

           <!-- 配置参数 -->

          <context-param>

                 <param-name>contextConfigLocation</param-name>                                                 <param-value>classpath:applicationContext_*.xml</param-value>

          </context-param>

          <!-- 配置监听器,加载spring的核心配置文件 -->

          <listener>

    <listener-class>

    org.springframework.web.context.ContextLoaderListener

    </listener-class>

          </listener>

          <filter>

                  <filter-name>Struts2</filter-name>

                  <filter-class>

                         org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter

                  </filter-class>

           </filter>

           <filter-mapping>

                  <filter-name>Struts2</filter-name>

                  <url-pattern>/*</url-pattern>

           </filter-mapping>

    </web-app>

    十三、Spring MVC

    struts2和webwork是基于过滤器实现的

    struts1和spring是基于servlet实现的

    struts1的Action,servlet,springMVC的Controller是单例的,struts2的Action是多例的

    springMVC流程

    1、客户端发送请求

    2、客户端发送的请求到达控制器,控制器由Servlet(DispacherServlet)实现的,完成请求的转发

    3、该控制器(DispatcherServlet)调用一个用于映射的类HandlerMapping

       该类用于将请求映射到对应的处理器来处理请求

    4、HandlerMapping将请求映射到对应的处理器Controller(相对于Action)

       在Spring当中如果写一些处理器组件,一般实现Controller接口

    5、在Controller中就可以调用一些Service或DAO来进行数据操作

    6、ModelAndView可以存放从Dao中取出的数据,还可以存放响应视图的一些数据

    7、如果想将处理结果返回给用户,那么在Sping框架中还提供了一个视图组件ViewResolver,

       该组件根据Controller返回的标识,找到对应的视图,将响应返回给用户

    案例

    1、新建一个web项目导入jar包

           commons-logging.jar       spring-webmvc.jar        spring.jar

    2、web.xml文件

           <web-app ...>

                 <!-- springMVC首先截获所有.do结尾的请求,都交给DispatcherServlet统一处理

                       DispatcherServlet加载src目录下的spring-mvc.xml配置文件

                       springMVC的controller是单例

                -->

                 <servlet>

                        <servlet-name>springMVC</servlet-name>

                        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

                      <init-param>

                                <param-name>contextConfigLocation</param-name>

                                <param-value>classpath:spring-mvc.xml</param-value>

                         </init-param>

                 </servlet>

                 <servlet-mapping>

                        <servlet-name>springMVC</servlet-name>

                        <url-pattern>*.do</url-pattern>

                 </servlet-mapping>

    </web-app>

    3、login.jsp

    <!-- struts1和springMVC所截获.do结尾的请求

              struts2的请求后缀可以任意修改 -->

           <form action="login.do" method="post">

                  用户名:<input type="text" name="username"><br>

                  密码:<input type="password" name="password"><br>

                  <input type="submit" value="登录">

                  <span style="color:red;">${errormessage }</span>

           </form>

           ok.jsp

    <body>

           ${message }

    </body>

    4、control

       User类

    public class User {

                  //用来保存请求发送的请求数据,

                  //每一个请求都有一个对应的user对象来保存数据

                  private String username;

           private String password;

    get/set方法

    }

    public class LoginControl extends SimpleFormController{

           //核心方法onSubmit,等价于struts2中的execute方法

           //                      servlet中的service(doPost和doGet方法)

          

           //command指代用来保存用户提交请求参数的对象,比如user对象

           @Override

           protected ModelAndView onSubmit(HttpServletRequest request,

                         HttpServletResponse response, Object command, BindException errors)

                         throws Exception {

                  //1.接收请求参数

                  User user = (User) command;

                  //2.判断用户名为liu,密码为123才通过

           if(user!=null&&"liu".equals(user.getUsername())&&

    "123".equals(user.getPassword())){

                         //3.用来保存数据,显示到页面中

                         // ModelAndView表示返回的信息,两部分信息

                         // ModelAndView(跳转页面的名字,要显示到页面中的信息                                                      ModelMap map = new ModelMap();

                         map.put("message", user.getUsername()+"登录成功");

                         return new ModelAndView("ok", map);//

                  }else{

                         ModelMap map = new ModelMap();

                         map.put("errormessage", "登录失败,用户名或者密码错误");

                         return new ModelAndView("login", map);//

                  }

           }

      5、sprin-mvc.xml

    <!-- springMVC分成3个部分

                    第一部分controlBean

                    第二部分映射关系HandleMapping

                    第三部分跳转信息 -->

                   

                 

          <!-- 配置bean信息 -->

           <bean id="loginControl" class="com.tarena.control.LoginControl">

                  <property name="commandClass" value="com.tarena.control.User"></property>

           </bean>

           <!-- 请求和control的对应关系 -->

           <bean id="urlHandlerMapping"

    class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

                  <!-- mappings  请求和对应的处理类映射  -->

                  <property name="mappings">

                         <props>

                                <!-- 有多少个请求就写多少个 -->

                                <prop key="login.do">loginControl</prop>

                         </props>

                  </property>

           </bean>

          

           <!-- 跳转信息 -->

           <bean id="viewResolver"

       class="org.springframework.web.servlet.view.InternalResourceViewResolver">

                  <property name="suffix" value=".jsp"></property><!-- 后缀 -->

                  <property name="prefix" value="/"></property><!-- 前缀 -->

           </bean>

  • 相关阅读:
    closure
    运算符优先级
    css妙用
    BFC (块级格式化上下文)
    display:table-cell 详解
    line-height深入理解
    margin collapse
    探究 CSS 解析原理
    python入门
    spring与线程安全
  • 原文地址:https://www.cnblogs.com/qin-derella/p/6772928.html
Copyright © 2020-2023  润新知