spring的使用-ssh整合

Posted liuxuelin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring的使用-ssh整合相关的知识,希望对你有一定的参考价值。

ssh整合-xml方式:

1.需要记住的三个jar包:

       spring-web-4.2.4.RELEASE.jar           ---保证项目启动时就实例化spring配置的对象(通过一个servletContext监听器ContextLoaderListener实现),保证整个项目只有一个工厂。

       struts2-spring-plugin-2.3.24.jar ---解决了struts2和spring的整合问题,将struts2中的action交给spring创建

       spring-orm-4.2.4.RELEASE .jar          ---解决hibernate和spring的整合,将sessionfactory交给spring创建(通过一个FactoryBean接口实现类实现),并且hibernate的事务也由spring事务管理器管理

2.FactoryBean接口      //对象工厂,可以存入对象。这个接口中的方法有getObject(); getObjectType(); ...这两个方法获取对象和对象class

       如果让一个类实现这个接口,然后将这个类交给spring管理(在applicationContext.xml中配置这个bean),如:

              <bean id="car" class="...CarFactoryBean"></bean>

              那么在获取bean对象时:

              a. 如果通过applicationContext对象调用getBean();获取:

                            ac.getBean("car");

                     此时,底层发现CarFactoryBean实现了FactoryBean接口,就会调用其中getObject();方法获取到这个类中的对象

              b. 如果通过ac.getBean(Car.class);这种方式获取bean:

                     那么,会调用CarFactoryBean中的getObjectType();如果发现这个方法返回的是Car.class,则会接下来调用getObject()获取对象;

      

       注意:

              @autowire           //这种方式是在spring容器中找到Car或其实现类实现注入的,相当于调用ac.getBean(Car.class);获取,因此使用FactoryBean获取时要重写getObjectType();

              private Car car;                  

      

3.spring的hibernate整合,配置文件             //原理:通过factoryBean方式让spring来管理sessionFactory

       方式一:LocalSessionFactoryBean注入configLocation方式        //LocalSessionFactoryBean实现了FactoryBean和initialize

             

                     <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">

                            <property name="configLocation" value="classpath:hibernate.cfg.xml"></property>         //这个属性传入的是hibernate配置文件类路径

                     </bean>

 

              原理:   1. 实例化LocalSessionFactoryBean时会注入configLocation,

                            2. 由于LocalSessionFactoryBean底层实现了initialize,会调用初始化方法,根据配置文件路径加载和解析hibernate.cfg.xml配置文件,并创建SessionFactory对象

                            3. 在获取sessionFactory时会调用getObject();方法获取

                           

              缺点:依然需要hibernate.cfg.xml文件

             

       方式二:配置LocalSessionFactoryBean,注入hibernate.cfg.xml中的连接池、属性等           //不再需要hibernate.cfg.xml文件

      

              <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">    //配置LocalSessionFactoryBean

                     <property name="dataSource" ref="dataSource"></property>   //需要注入连接池

                     <property name="hibernateProperties">                                    //注入其他属性,hibernateProperties底层为properties集合

                            <value>

                                   hibernate.show_sql=true

                                   hibernate.format_sql=true

                                   hibernate.dialect=org.hibernate.dialect.mysqlDialect

                                   hibernate.hbm2ddl.auto=update

                            </value>

                     </property>

                    

                     <property name="hibernateProperties">        //也可通过这种方式注入其他属性

                            <props>

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

                            </props>

                     <property>

                    

                     <property name="mappingDirectoryLocations" value="classpath:cn/itheima/domain"></property>      //配置映射文件(xxx.hbm.xml)路径,四种方式

                     <property name="mappingLocations" value="classpath:cn/itheima/domain/User.hbm.xml"></property>

                     <property name="mappingResources" value="cn/itheima/domain/User.hbm.xml"></property>

                     <property name="mappingJarLocations"></property>

              </bean>

             

4.spring的hibernate整合,Dao的操作:

       让Dao继承HibernateDaoSupport,只需要注入SessionFactory就可以获得HibernateTemplate      //这里的HibernateDaoSupport类似于JdbcDaoSurport,封装了HibernateTemplate

              <bean id="userDao" class="cn.itheima.dao.UserDaoImpl">

                     <property name="sessionFactory" ref="sessionFactory"/>    //dao中注入sessionFactory

              </bean>

 

       使用hibernateTemplate实现增删改查    //底层通过session实现,得到的是getCurrentSession();    事务默认为只读

              this.getHibernateTemplate().save(user)                                 //底层调用session.save(user)

              this.getHibernateTemplate().update(user)                      //底层调用session.update(user)

              this.getHibernateTemplate().del(user)                            //底层调用session.del(user)

              this.getHibernateTemplate().get(User.class,id)                //底层调用session.get(User.class,id)

              this.getHibernateTemplate().find("hql",arg1,arg2...) //底层调用session.createQrery("hql").serParameter(...).list();

             

       原理:

              配置文件加载时创建userDao,同时注入sessionFactory,sessionFactory注入时,会直接创建HibernateTemplate对象

              因此,userDao可以直接调用父类的getHibernateTemplate()来获取HibernateTemplate实现增删改查

              增删改查的实现在底层均通过hibernate中的session对象实现。为getCurrentSession();得到与线程绑定的session

             

              注意:未添加事务时有默认事务,且事务的默认为readonly,即默认只能查,不能增删改。

             

       总结:spring整合hibernate主要包括两个方面:

              1)将sessionFactory交给spring管理 //两种方式,均由spring来加载配置文件,创建sessionFactoryBean

              2)dao层使用hibernateTemplate实现增删改查    //dao继承HibernateDaoSupport,注入sessionFactory实现

      

5.spring的hibernate整合,事务管理:

       采用HibernateTransactionManager事务管理器,注入sessionFactory,其他操作(配置通知切面,<tx:advice> <aop:config>)同day3中的spring自身事务的操作:

              <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">

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

              </bean>

             

       总结:基于spring自身提供的事务管理模式,只是采用的事务管理器不同

      

6.Spring整合struts2框架  //必须导入jar包struts2-spring-plugin-2.3.24.jar,这个jar包改变了创建Action的方式

       原理:

              struts2框架配置文件加载顺序

              a.    default.properties

              b.    struts-default.xml

              c.     struts -plugin.xm        

              在导入的jar包中有一个plugin的配置文件,加载时会覆盖struts2中的一个常量struts.objectFactory为spring

              struts2框架默认通过ObjectFactory创建对象,由于上述常量值的改变。bean的创建由spring对象工厂SpringObjectFactory来管理

             

                     SpringObjectFactory创建对象主要方法:

                     public Object buildBean(String beanName, Map<String, Object> extraContext, boolean injectInternal) throws Exception {

                            Object o;

                            //这个beanName是struts2框架传入的,对应struts.xml中的class属性

                            //把beanName作为id判断Spring容器是否有这个id对应的bean

                            if (appContext.containsBean(beanName)) {

                               //如果找到了就直接从Spring容器获取

                              o = appContext.getBean(beanName);

                            } else {

                              //如果没有从Spring容器找到该id对应bean,

                              //就把beanName作为全类名通过反射创建对象并且注入属性

                              Class beanClazz = getClassInstance(beanName);

                              o = buildBean(beanClazz, extraContext);

                            }

                             return o;

                     }

              总结:struts2-spring-plugin-2.3.24.jar改变了struts中action的创建方式,将action创建交给spring管理

 

       方式一:基于spring管理action :伪类名     //在applicationContext.xml文件中来声明action

              1. 在applicationContext中配置action:

                   <bean id="userAction" class="cn.itheima.action.UserAction" scope="prototype">       //此处必须设置scope的属性为prototype,否则每次请求获取到的是同一个action

                            <property name="userService" ref="userService"/> //service的注入,必须在action中提供对应的set方法

                     </bean>

                    

              2. 在struts.xml中配置,将class 值修改为伪类名

                     <package name="default" extends="struts-default">

                            <action name="user_add" class="userAction" method="add">    //此处class不再是全类名,而是对应了applicationContext中的id

                                   <result name="...">...</result>

                            </action>    

                     </package>

                    

              原理:

                     当请求发出时,spring会根据class 的值,在applicationContext.xml中查找是否有对应的id,有则直接从applicationContext容器中获取对象

                    

       方式二:自动注入service

              struts.xml中的class 直接用全类名,只需要在action中提供service的set方法

                            <action name="user_add" class="cn.itheima.action.UserAction" method="add">   //此处class是全类名

                                   <result name="...">...</result>

                            </action>           

                           

                            public void UserAction extends ActionSupport{

                                   private IUserService userService;

                                  

                                   public void setUserService(IUserService us){     //会根据set方法的名称在applicationContext.xml中查找对应的id(userService),并注入bean

                                          this.userService=us;

                                   }

                            }

                           

              struts.objectFactory.spring.autoWire常量的配置:

             

                     <constant name="struts.objectFactory.spring.autoWire" value="type"/>    //默认值为name

                    

                     默认情况下,根据action中的set方法名称,查找applicationContext.xml对应id并实现属性注入,

                     常量值修改为type后,会根据set方法的参数类型,在applicationContext.xml中根据这个类型查找其实现类对象并注入属性

             

              原理:

                     与伪类名方式执行流程相同,会根据class属性的值,在applicationContext.xml中查找是否有对应的id,此时,找不到对应的id,会根据这个全类名创建对象,并将对象放入spring容器,

                     同时,根据类中的set方法注入对应的属性

                    

       总结:   本质上是将action交给spring管理,两种方式

             

  补充:

    <context:component-scan>和<context:annotation-config>的区别:

           <context:component-scan>      //注解扫描,做了两件事,扫描注解,创建对象放入spring容器中,让注解生效

           <context:annotation-config>    //使注解生效,与注解扫描的区别?

 

 

ssh整合,注解的使用

1.实体类的注解:

       1)实体类注解配置:

              @Entity

              @Table(name="t_user")

              public class User {

                     @Id

                     @GeneratedValue(strategy=GenerationType.IDENTITY)

                     private int id;

                     private String name;

                     private int age;

                    

       2)applicationContext.xml中实体类的引入:

              <property name="packagesToScan" value="cn.itheima.domain"></property> //与之前引入hbm.xml文件不同,在sessionFactory中注入packagesToScan,指定实体类所在的包

             

2.dao的注解配置:

       applicationContext.xml中开启注解扫描:

            <context:component-scan base-package="cn.itheima"></context:component-scan>

      

       dao的注解配置:

              @Repository

              public class UserDaoImpl extends HibernateDaoSupport implements IUserDAO {

                    

                     @Autowired

                     public void setSf(SessionFactory sf){          //将sessionFactory注入父类,前提:applicationContext.xml中配置LocalSessionFactoryBean

                            super.setSessionFactory(sf);

                     }

             

3.service的注解配置,事务的添加

       1)service注解配置:

              @Service              //注解方式配置UserServiceImpl

              public class UserServiceImpl implements IUserService{

                    

                     @Autowired         //注入dao

                     private IUserDAO userDao;

 

       2)事务管理的实现:

              A.applicationContext.xml:

                     <bean id="tm" class="org.springframework.orm.hibernate5.HibernateTransactionManager">   //配置事务管理器

                            <property name="sessionFactory" ref="sessionFactory"></property> //要注入sessionFactory

                     </bean>

                    

                     <tx:annotation-driven transaction-manager="tm"/>            //配置注解驱动,需要传入事务管理器

              B.类上或方法上加事务管理注解:

                     @Transactional

                     public class UserServiceImpl implements IUserService{

             

4.action的注解配置: //采用的是全类名方式完成整合

       只需要在配置好struts中的配置的基础上,在private IUserService userService;加上@Autowired即可

              @ParentPackage("struts-default")

              public class UserAction extends ActionSupport implements ModelDriven<User>{

                    

                     private User user=new User();

                    

                     @Autowired         //只需要添加这个注解即可

                     private IUserService userService;

 

                     @Override

                     public User getModel() {

                            return user;

                     }

                    

                     @Action(value="user_add",results={@Result(name="success",location="/success.jsp")})         //在此处其实有一个className属性,相当于配置文件中的class,默认为UserAction全类名

                     public String add(){

                            userService.add(user);

                            return SUCCESS;

                     }

              }

             

       原理:   请求发出时,spring会代替struts2创建action对象(根据xml中的class属性值或者注解中@Action中的className属性),有一下两种方式

                     A.默认的全类名方式: //className属性取默认值

                            由于@Action中的className默认值为UserAction全类名,因此spring会根据这个全类名,创建UserAction对象并交给spring容器管理,同时根据类型注入userService。

                            因此在spring容器中必须有userService对象存在,即在applicationContext中必须配置这个对象

                           

                     B.让程序以伪类名方式创建: //麻烦,不建议使用    //设置className属性

                            1)设置@Action中的className属性为userAction。此时,会根据这个名称,在applicationContext中获取对象,因此需手动将userAction交给spring容器管理:

                            2)在UserAction类上配置注解,实现action由spring创建并管理:

                                   @Component      //默认的id为userAction

                                   @Scope("prototype")          //必须配置这个属性

                                   public class UserAction extends ActionSupport implements ModelDriven<User>{         

             

5.no session 的问题:配置一个filter

       问题产生的原因:默认情况下,session是在dao层通过getCurrentSession();获取到,这个session在service层事务关闭时会自动关闭。

                                   当在dao层进行延迟查询时,不会马上从数据库查询数据。当要使用这些数据时,会再action层获取,此时会使用到session,由于session在service已经关闭,会出现no session异常

      

       <filter>         //必须放在struts2过滤器之前

              <filter-name>openSessionInView</filter-name>

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

       </filter>

       <filter-mapping>

              <filter-name>openSessionInView</filter-name>

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

       </filter-mapping>

      

       原理:

              请求发出时,会先被这个过滤器拦截,在这个过滤器中,会从spring容器中获取到sessionFactory,并调用openSession()获取session这个session会被放到sessionHolder中,被dao拿到。

              这个过滤器走完后会执行struts2过滤器,以及action。service,dao层的操作,此时在service层执行完,事务提交时不会再关闭session,而是再action执行完后由过滤器关闭session

             

       如果请求为action请求,struts2过滤器不会放行,因此必须把openSessionInView过滤器放在struts2过滤器之前

             

             

             

             

       //sturts 会拦截url,不会拦截uri(指定某个网络资源)                   

             

             

             

             

             

             

             

             

              

以上是关于spring的使用-ssh整合的主要内容,如果未能解决你的问题,请参考以下文章

Spring第四天——SSH整合

SSH(struts2+spring+hibernate)三大框架整合

spring 手动整合web项目(SSH)

spring 手动整合web项目(SSH)

spring学习 ———— 整合web项目(SSH)

ssh笔记整合