1. 程式人生 > >spring的使用-ssh整合

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(指定某個網路資源)