深刻理解java:4. 框架編程

瞭解 Servlet 和 Filtercss

Servlet(即servlet-api.jar) 是 J2EE 最重要的一部分,有了 Servlet 你就是 J2EE 了,J2EE 的其餘方面的內容擇需採用。html

而 Servlet 規範你須要掌握的就是 servlet 和 filter 這兩項技術。java

絕大多數框架不是基於 servlet 就是基於 filter,若是它要在 Servlet 容器上運行,就永遠也脫離不開這個模型。linux

Servlet容器,大一點就是應用服務器,推薦 Tomcat 、或者 Jetty 這些輕量級的產品。web

SpringMVC的入口是servlet:servlet是一種運行服務器端的java應用程序,具備獨立於平臺和協議的特性,而且能夠動態的生成web頁面,它工做在客戶端請求與服務器響應的中間層。
Struts2的入口是filter:filter是一個能夠複用的代碼片斷,能夠用來轉換HTTP請求、響應和頭信息。Filter不像Servlet,它不能產生一個請求或者響應,它只是修改對某一資源的請求,或者修改從某一的響應。filter可以在一個請求到達servlet以前預處理用戶請求,也能夠在離開servlet時處理http響應。spring

 

爲何 Servlet 規範會有兩個包,javax.servlet 和 javax.servlet.http ?sql

早先設計該規範的人認爲 Servlet 是一種服務模型,不必定是依賴某種網絡協議之上,所以就抽象出了一個 javax.servlet ,同時再提供一個基於 HTTP 協議上的接口擴展。數據庫

可是從實際運行這麼多年來看,彷佛沒有發現有在其餘協議上實現的 Servlet 技術。apache

javax.servlet 和 javax.servlet.http 這兩個包總共加起來也不過是三十四個接口和類。你須要經過 J2EE 的 JavaDoc 文檔 熟知每一個類和接口的具體意思。編程

特別是下面幾個接口必須熟知每一個方法的意思和用途:

  • HttpServlet
  • ServetConfig
  • ServletContext
  • Filter
  • FilterConfig
  • FilterChain
  • RequestDispatcher
  • HttpServletRequest
  • HttpServletResponse
  • HttpSession
  • 一些 Listenser 類

再次強調 HttpServletRequestHttpServletResponse 這兩個接口更應該是爛熟於心。

由於 Web 開發是離不開 HTTP 協議的,而 Servlet 規範其實就是對 HTTP 協議作面向對象的封裝,HTTP協議中的請求和響應就是對應了 HttpServletRequest 和 HttpServletResponse 這兩個接口。

你能夠經過 HttpServletRequest 來獲取全部請求相關的信息,包括 URI、Cookie、Header、請求參數等等,別無它路。

所以當你使用某個框架時,你想獲取HTTP請求的相關信息,只要拿到 HttpServletRequest 實例便可。

 

再談談 Session

HTTP 協議裏是沒有關於 Session 會話的定義,Session 是各類編程語言根據 HTTP 協議的無狀態這種特色而產生的。

其實現無非就是服務器端的一個哈希表,哈希表的Key就是傳遞給瀏覽器的名爲 jsessionid 的 Cookie 值。

當須要將某個值保存到 session 時,容器會執行以下幾步:

a. 獲取 jsessionid 值,沒有的話就生成一個,也就是 request.getSession() 這個方法
b. 拿到的 HttpSession 對象實例就至關於一個哈希表,你能夠往哈希表裏存放數據(setAttribute)
c. 你也能夠經過 getAttribute 來獲取某個值

而這個名爲 jsessionid 的 Cookie 在瀏覽器關閉時會自動刪除。

把 Cookie 的 MaxAge 值設爲 -1 就能達到瀏覽器關閉自動刪除的效果。

 

關於 JSP

任何一個 JSP 頁面在執行的時候都會編譯成一個 Servlet 類文件,

若是是 Tomcat 的話,這些生成的 java 文件會放置在 {TOMCAT}/work 目錄下對應項目的子目錄中。

在 servlet 中有一個包 javax.servlet.jsp 是跟 JSP 相關的一些接口規範定義。

JSP 比 Servlet 方便的地方在於可直接修改當即生效,不像 Servlet 修改後必須重啓容器才能生效。

所以 JSP 適合用來作視圖,而 Servlet 則適合作控制層。

 

struts不過是對servlet、filter的封裝而已,

hibernate也不過是對jdbc的封裝而已。

框架解決的是解耦的問題,複用的問題,分工的問題。

 

SSI框架總結

專一於控制層的Struts2

專一於業務邏輯方面的spring框架

專一於持久層的 iBatis

Struts2主要來源於webwork框架,在數據傳遞方面,Struts2提供了更增強大OGNL標籤功能,使其可以經過在action中定義變量來直接與jsp頁面中的數據進行相互傳值,省去了Struts1中的formbean。

Spring功能很是的強大,好比它的控制反轉/依賴注入機制,省去了咱們本身書寫工廠模式的工做;Spring對AOP支持使咱們在用戶權限控制、事務處理方面節省了不少工做量;

iBatis則是一種輕量級的ORM框架,與Hibernate相比,iBatis提供了半自動化對象關係 映射的實現,開發人員須要編寫具體的sql語句,提供了更大的自由空間,爲sql語句優化提供了便利。

下面這張圖就是咱們所用到的這三種框架的結合體,下面對其做以簡單介紹。

 


在控制層,利用Strtus2標籤功能,在Action中直接與jsp頁面上的數據進行交互。

在調用業務邏輯層應用時,Struts2提供了對Sping的支持。

開發人員須要完成對struts.xml的配置工做和對各個Action類的編寫。

 

在業務邏輯層,利用Spring框架的依賴注入實現對業務邏輯類和DAO類的實例託管;

在事務處理方面,利用Spring提供的面向切面的事務處理功能,使對數據的事務控制脫離於數據訪問接口實現;

在對象關係映射方面,利用Spring對數據庫鏈接池的託管和對iBatis框架的支持。

開發人員須要完成對數據源的配置、對不一樣模塊所對應的Application*.xml文件的配置,以及對業務邏輯接口的定義和業務邏輯實現的編寫。

 

在持久層,利用iBatis提供的半自動化對象關係映射的實現,開發人員須要編寫具體的sql語句,爲系統設計提供了更大的自由空間。

另外,開發人員須要完成對SqlMapConfig.xml和*SqlMap.xml的配置,以及對DAO接口的定義和DAO接口的實現。

 

在各層之間進行交換的過程當中,利用數據傳輸類進行數據的傳遞和交互。其中,數據傳輸類與數據庫表一一對應。

SSI框架可以下降咱們代碼的耦合度,加強了代碼的健壯性和可重用性,加快了開發速度,

可是也有一些不足之處,好比因爲三種框架的配置文件較多,也給咱們帶來了一些不便,特別是對於較小的應用來講更是如此。

 

SSI開發過程:

一:首先引入struts2 spring ibatis 各自的jar包 在此就不一一羅列了。

二:添加配置文件

   咱們首先從web.xml文件提及

   web.xml加載過程:
   1 啓動WEB項目的時候,容器(如:Tomcat)會讀他的配置文件web.xml讀兩個節點
         <context-param></context-param>和<listener></listener>
    2 緊接着,容器建立一個ServletContext(上下文) 這個WEB項目全部部分都將共享這個上下文
    3 容器將<context-param></context-param>轉化爲鍵值對並交給ServletContext
    4 容器建立<listener></listener>中的類的實例,即建立監聽
    5 在監聽中會有contextInitialized(ServletContextEvent args)初始化方法,在這個方法中得到:
              ServletContext = ServletContextEvent.getServletContext();  
              context-param的 = ServletContext.getInitParameter("context-param的");

     web.xml節點加載順序
     節點的加載順序與它們在web.xml文件中的前後順序無關。即不會由於filter寫在listener的前面而會先加載filter。

     最終得出的結論是:listener->filter->servlet
     同時還存在着這樣一種配置節點:context-param,它用於向 ServletContext 提供鍵值對,即應用程序上下文信息。

     咱們的 listener, filter 等在初始化時會用到這些上下文 的信息,那麼context-param 配置節是否是應該寫在 listener 配置節前呢?實際上 context-param 配置節可寫在任意位置,所以真正的加載順序爲:
     context-param -> listener -> filter -> servlet

    加載spring
     <listener> 
             <listener-class> 
               org.springframework.web.context.ContextLoaderListener  
            </listener-class> 
       </listener>
     最終結論:

     web.xml 的加載順序是:[context-param -> listener -> filter -> servlet -> spring] ,而同類型節點之間的實際程序調用的時候的順序是根據對應的 mapping 的順序進行調  用的。

    打開web.xml文件,根據實際須要添加以下內容

<!--上下文參數用於log4j以及spring中使用-->
<context-param>
    <param-name>webAppRootKey</param-name>
    <param-value>/WEB-INF/log4j.properties</param-value>
</context-param>

<!--應用程序上下文參數,指定spring配置文件位置-->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/beans.xml</param-value>
</context-param> 

<listener>
    <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>

<!--監聽器 用於初始化spring框架-->
<listener>
     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

 
在這說說SSI整合時的一些配置文件:

 1,contextConfigLocation:Spring容器啓動時須要加載Spring的配置文件。默認是/WEB-INF目錄下的applicationContext.xml文件

   固然也能夠放在classpath下,能夠包括多個spring配置文件,這就得依靠contextConfigLocation

<!-- 加載spring的配置文件 若是文件名爲applicationContext.xml而且是在WEB-INF目錄下 則無需此配置 -->
    <context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/beans.xml</param-value>
    </context-param> 

若是web.xml中沒有配置context-param,spring的配置就像如上這段代碼示例一下,自動去WEB-INF目錄下尋找applicationContext.xml。此時,若是你修改applicationContext.xml的名稱,或者移除它,再啓動服務器,你會獲得以下異常信息:

1.nested exception is java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/applicationContext.xml]  

這證明了其默認配置。默認配置狀況下spring只會去WEB-INF目錄下尋找配置文件,而不會去classpath下尋找。
若是咱們不想將配置文件放在WEB-INF目錄下呢?開發中常常在src下面建立一個config目錄,用於存放配置文件。此時,對應的param-value改成:classpath:config/applicationContext.xml。
必定要加上classpath,這告訴spring去class目錄下的config目錄下面尋找配置文件。

2,如何啓動Spring容器

兩種方法,一種以listener啓動  一種以load-on-startup Servlet。

<!-- 配置spring監聽器 -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

 

第二種

<servlet>
 <servlet-name>context</servlet-name>
 <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
 <load-on-startup>1</load-on-startup>
</servlet>


 

 

 3,整合Struts2

        <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>


4,Spring整合ibatis配置文件

       <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
		<property name="configLocation"> 
			<value>classpath:SqlMapConfig.xml</value>
		</property>
	</bean>

5,Struts.xml

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

constant配置struts的常量(也可在struts.properties)文件中配置,將struts的對象工廠託由spring管理。

SSM框架總結

SpringMVC能夠徹底替代Struts,配合註解的方式,編程很是快捷,並且經過restful風格定義url,讓地址看起來很是優雅。
另外,MyBatis也能夠替換hibernate,正由於MyBatis的半自動特色,咱們程序猿能夠徹底掌控SQL,這會讓有數據庫經驗的程序猿能開發出高效率的SQL語句,並且XML配置管理起來也很是方便。

  1. SpringMVC:它用於web層,至關於controller(等價於傳統的servlet和struts的action),用來處理用戶請求。舉個例子,用戶在地址欄輸入http://網站域名/login,那麼springmvc就會攔截到這個請求,而且調用controller層中相應的方法,(中間可能包含驗證用戶名和密碼的業務邏輯,以及查詢數據庫操做,但這些都不是springmvc的職責),最終把結果返回給用戶,而且返回相應的頁面(固然也能夠只返回json/xml等格式數據)。springmvc就是作前面和後面過程的活,與用戶打交道!!

  2. spring:太強大了,以致於我沒法用一個詞或一句話來歸納它。但與咱們平時開發接觸最多的估計就是IOC容器,它能夠裝載bean,有了這個機制,咱們就不用在每次使用這個類的時候爲它初始化,不多看到關鍵字new。另外spring的aop,事務管理等等都是咱們常常用到的。

  3. MyBatis:若是你問我它跟鼎鼎大名的Hibernate有什麼區別?我只想說,他更符合個人需求。第一,它能自由控制sql,這會讓有數據庫經驗的人編寫的代碼能搞提高數據庫訪問的效率。第二,它可使用xml的方式來組織管理咱們的sql,由於通常程序出錯不少狀況下是sql出錯,別人接手代碼後能快速找到出錯地方,甚至能夠優化原來寫的sql。

SpringMVC與Struts2區別與比較總結

一、Struts2是類級別的攔截, 一個類對應一個request上下文,SpringMVC是方法級別的攔截,一個方法對應一個request上下文,而方法同時又跟一個url對應,因此說從架構自己上SpringMVC就容易實現restful url,而struts2的架構實現起來要費勁,由於Struts2中Action的一個方法能夠對應一個url,而其類屬性卻被全部方法共享,這也就沒法用註解或其餘方式標識其所屬方法了。

二、由上邊緣由,SpringMVC的方法之間基本上獨立的,獨享request response數據,請求數據經過參數獲取,處理結果經過ModelMap交回給框架,方法之間不共享變量,而Struts2搞的就比較亂,雖然方法之間也是獨立的,但其全部Action變量是共享的,這不會影響程序運行,卻給咱們編碼 讀程序時帶來麻煩,每次來了請求就建立一個Action,一個Action對象對應一個request上下文。
三、因爲Struts2須要針對每一個request進行封裝,把request,session等servlet生命週期的變量封裝成一個Map,供給每一個Action使用,並保證線程安全,因此在原則上,是比較耗費內存的。

四、 攔截器實現機制上,Struts2有以本身的interceptor機制,SpringMVC用的是獨立的AOP方式,這樣致使Struts2的配置文件量仍是比SpringMVC大。

五、SpringMVC的入口是servlet,而Struts2是filter(這裏要指出,filter和servlet是不一樣的。之前認爲filter是servlet的一種特殊),這就致使了兩者的機制不一樣,這裏就牽涉到servlet和filter的區別了。

六、SpringMVC集成了Ajax,使用很是方便,只需一個註解@ResponseBody就能夠實現,而後直接返回響應文本便可,而Struts2攔截器集成了Ajax,在Action中處理時通常必須安裝插件或者本身寫代碼集成進去,使用起來也相對不方便。

七、SpringMVC驗證支持JSR303,處理起來相對更加靈活方便,而Struts2驗證比較繁瑣,感受太煩亂。

八、spring MVC和Spring是無縫的。從這個項目的管理和安全上也比Struts2高(固然Struts2也能夠經過不一樣的目錄結構和相關配置作到SpringMVC同樣的效果,可是須要xml配置的地方很多)。

九、 設計思想上,Struts2更加符合OOP的編程思想, SpringMVC就比較謹慎,在servlet上擴展。

十、SpringMVC開發效率和性能高於Struts2。
十一、SpringMVC能夠認爲已經100%零配置。

mybatis和ibatis區別

ibatis本是apache的一個開源項目,2010年這個項目由apache software foundation 遷移到了google code,而且更名爲mybatis。

一、Mybatis實現了接口綁定,使用更加方便。
在ibatis2.x中咱們須要在DAO的實現類中指定具體對應哪一個xml映射文件,
而Mybatis實現了DAO接口與xml映射文件的綁定,自動爲咱們生成接口的具體實現,使用時不須要經過SqlMapClient去指定namespace 和 sql statement id, 只須要在 sql map config 文件中指定接口的 namespace, 而且sql statement id 和 接口的名字意義對應,而後調用對一個接口便可。
注意:
雖然Mybatis支持在接口中直接使用annotation的配置方式來簡化配置,
不過強烈建議仍然使用xml配置的方式。畢竟annotation的配置方式功能有限且代碼入侵性太強。使用xml配置方式才能體現出Mybatis的優點所在
二、對象關係映射的改進,效率更高
相信不少在使用ibatis2.x的朋友並無經過ibatis的xml映射文件來實現對象間的關係映射。其實也確實沒有必要那麼作,由於ibatis2.x採用的是「嵌套查詢」的方式將對象之間的關係經過查詢語句的直接拼裝來實現,其效果和在DAO或Service中自行封裝是同樣的。
不過這種方式存在「N+1查詢問題」。
歸納地講,N+1查詢問題能夠是這樣引發的:
? 你執行了一個單獨的SQL語句來獲取結果列表(就是+1)。
? 對返回的每條記錄,你執行了一個查詢語句來爲每一個加載細節(就是N)。
這個問題會致使成百上千的SQL語句被執行。這一般不是指望的。

而在Mybatis中,除了兼容ibatis2.x中的「嵌套查詢」方式外,還提供了直接「嵌套結果」的方式,其效果至關於直接經過一句sql將查詢出的dto對象自動封裝成所需的對象。
具體實現方法請自行參考Mybatis官方使用手冊,不在此累述.

不過實際上這一改進所帶來的好處也是頗有限的。由於這一方式在使用分頁的時候並不起做用,或者說嵌套對象的結果集是不容許進行分頁的。這一點在Mybatis框架中已經作出了明確的限制(org.apache.ibatis.executor.resultset.NestedResultSetHandler裏34行),而實際項目中須要分頁的狀況又特別多……
仔細一想,一對多映射確實不能經過配置文件來分頁,由於這時查詢出的記錄數並不等於實際返回對象的size,不過一對一映射爲何也不容許就不太明白了。多是由於一對一是一對多的特例,而在設計框架的時候並無考慮去處理或是難於處理這一特例吧。
三、MyBatis採用功能強大的基於OGNL的表達式來消除其餘元素。
熟悉struts2的人應該對OGNL表達式不會感到陌生,
MyBatis採用OGNL表達式簡化了配置文件的複雜性,使用起來更簡潔。
補充:比較遺憾的是,Mybatis的分頁繼續沿用ibatis2.x的邏輯分頁方式,依賴於JDBC的規範。大數據量時會出現性能問題,要想實現物理分頁還得本身想辦法改了。

SSM開發過程:

第一步:先在spring文件夾裏新建spring-dao.xml文件,由於spring的配置太多,咱們這裏分三層,分別是dao service web。

    1. 讀入數據庫鏈接相關參數(jdbc.properties
    2. 配置數據鏈接池
      1. 配置鏈接屬性,能夠不讀配置項文件直接在這裏寫死
      2. 配置c3p0,只配了幾個經常使用的
    3. 配置SqlSessionFactory對象(mybatis-config.xml
    4. 掃描dao層接口,動態實現dao接口,也就是說不須要daoImpl,sql和參數都寫在xml文件上

第二步:接下來到service層了。在spring文件夾裏新建spring-service.xml文件。

  1. 掃描service包全部註解 @Service
  2. 配置事務管理器,把事務管理交由spring來完成
  3. 配置基於註解的聲明式事務,能夠直接在方法上@Transaction

第三步:配置web層,在spring文件夾裏新建spring-web.xml文件。

  1. 開啓SpringMVC註解模式,可使用@RequestMapping,@PathVariable,@ResponseBody等
  2. 對靜態資源處理,如js,css,jpg等
  3. 配置jsp 顯示ViewResolver,例如在controller中某個方法返回一個string類型的」login」,實際上會返回」/WEB-INF/login.jsp」
  4. 掃描web層 @Controller

第四步:最後就是修改web.xml文件了,它在webappWEB-INF下。

web.xml

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1" metadata-complete="true"> <!-- 若是是用mvn命令生成的xml,須要修改servlet版本爲3.1 --> <!-- 配置DispatcherServlet --> <servlet> <servlet-name>seckill-dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 配置springMVC須要加載的配置文件 spring-dao.xml,spring-service.xml,spring-web.xml Mybatis - > spring -> springmvc --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/spring-*.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>seckill-dispatcher</servlet-name> <!-- 默認匹配全部的請求 --> <url-pattern>/</url-pattern> </servlet-mapping> </web-app> 

第五步:Java後臺邏輯代碼。

相關文章
相關標籤/搜索