這是對前一個spring小例子的解析
接上篇:http://www.cnblogs.com/xuejupo/p/5236448.html
首先應該明白,一個web項目,web.xml是入口。
然後下麵來分析上篇博客中出現的web.xml:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <!-- 區分項目名稱,防止預設重名 --> <context-param> <param-name>webAppRootKey</param-name> <param-value>maven.cainiao.root</param-value> </context-param> <!-- Spring的log4j監聽器 --> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener> <!-- 字元集 過濾器 --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- Spring view分發器 --> <servlet> <servlet-name>dispatcher_cainiao</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/dispatcher_cainiao.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher_cainiao</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
首先是context-param參數,說context-param之前,應該有個概念:
web.xml的載入過程是context-param -> listener -> fileter -> servlet。
context-param屬性在xml文件里是最先被載入的,但是只有他是然並卵的,他必須配合別的java類一起使用。context-param差不多就相當於一個web項目的內置map,key和value都是String,context-param的載入只是為這個map賦值,相當於配置參 數,讓之後的監聽或者過濾器等能夠使用context-param中配置好的參數。
舉個例子,我的web伺服器是jboss,在context-param中配置參數
<context-param> <param-name>webAppRootKey</param-name> <param-value>maven.cainiao.root</param-value> </context-param>
後,jboss在載入這個項目的時候這個項目的別名就是maven.cainiao.root。這時候,如果在jboss中有別的項目也叫這個名字,那麼jboss就會報錯。
再比如說,如果要設定日誌監聽,就要在context-param中配置log4jConfigLocation參數,log監聽器Log4jConfigListener會在載入的時候自動監聽log4jConfigLocation參數對應的值下的文件;再比如,ContextLoaderListener監聽器負責將contextConfigLocation參數路徑下的xml文件載入。
當然,也可以自己做監聽或者過濾器,然後在web.xml中通過context-param配置過濾的參數(通過ServletConfig.getInitParameter(key))。
然後就是org.springframework.web.util.Log4jConfigListener,這是一個spring的log4j監聽器。實際上我們不實用這個監聽也是可以的,但是使用它有幾個好處:
首先如果不用他,那麼log的配置文件log4j.properties必須寫在classpath下,而用它的話,你就可以很方便得管理log4j.properties的位置了。
其次,這個監聽中有個方法會每隔60秒掃描log4j配置文件,這樣修改log4j配置文件就可以不用重啟服務了。
再然後,字元過濾器CharacterEncodingFilter,可以看到filter-mapping中的url-pattern是/*,他負責將/*(也就是全部路徑)下的所有請求,強制轉換為UTF-8編碼的形式,這樣如果在編寫頁面的時候也用utf-8
編碼,就可以防止亂碼的產生了。
最後就是跟我們打交道最多的servlet了。首先看servlet-mapping,這裡有個url-pattern,這裡匹配url里輸入的,比如說上面的web.xml中這裡是/,那麼,所有的http://localhost:8080/test/*的url都會被這個名字叫做dispatcher_cainiao的servlet解析。servlet-mapping下的servlet-name對應servlet下的servlet-name,根據name找到具體的servlet(servlet-mapping是servlet的入口,感覺更像是介面,負責servlet的入口url和對應具體的servlet實現類);而這個servlet-class,就是具體的servlet實現類了。當然,我們可以寫自己的實現類,這樣url就會請求到我們自己的servlet里(現在已經很少有這種寫法了),還可以交給spring托管,比如實現類寫org.springframework.web.servlet.DispatcherServlet,這是spring框架中的一個流程式控制制器,負責分發url。init-param表示將初始化他的配置參數,如上面的配置中,這個分發器使用的配置文件路徑為:/WEB-INF/dispatcher_cainiao.xml,load-on-startup表示他在web容易啟動的時候會自載入(這個很重要,不加這個你的url就找不到可以分發的servlet了)。
再來看分發器使用的xml配置文件:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> <mvc:annotation-driven /> <!-- <mvc:default-servlet-handler/> --> <context:component-scan base-package="controller" /> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/views/" /> <property name="suffix" value=".jsp" /> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> </bean> </beans>
首先,mvc:annotation-driven是一種簡寫模式,表示自動載入DefaultAnnotationHandlerMapping與AnnotationMethodHandlerAdapter 兩個bean,是spring MVC為@Controllers分發請求所必須的。context:component-scan是spring中的自動掃描機制,負責掃描包以下所有類中包含的所有spring註解。
然後,就是註冊一個bean了:InternalResourceViewResolver,視圖解析類,就是將servlet中的返回解析到prefix對應參數文件夾下的suffix對應的尾碼文件。
他需要配合控制類使用:
package controller; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import com.cainiaojava.beans.User; /** * DispatcherController: * @author xuejupo [email protected] * * create in 2016-3-1 下午3:35:13 * */ @Controller @RequestMapping("demo") public class DispatcherController { @RequestMapping(method=RequestMethod.GET) public String printWelcome(ModelMap model) { User user = new User(); user.setInfo("哈哈,我是唯一的用戶!"); user.setUserName("我是老大!"); user.setPasswd("不告訴你!"); model.addAttribute("str0121", "我去,成功了呀!!!"); model.addAttribute("info","當前用戶信息為:"); model.addAttribute("user", user); System.out.println("index.jsp"); return "index"; } }
@Controller表示這是一個控制器,@RequestMapping("demo")表示他接收尾碼為demo的url(比如http://localhost:8080/test/demo),@RequestMapping(method=RequestMethod.GET)表示請求方式是get的話進這個方法,ModelMap是spring內置的ui控制類,可以將值傳到前端。 return "index",和前邊說的suffix參數的值,合組成index.jsp,所以這個servlet會將請求返回到頁面index.jsp中。
總結一下:
首先載入web.xml,web.xml中首先載入context-param,他們沒什麼實際意義,只是一個上下文。然後載入監聽,上面的web.xml配置了log監聽器,所以載入Log4jConfigListener文件(配置log監聽器,應該要在context-param中配置log4jConfigLocation參數,我是犯懶,還沒配日誌。。),然後,載入字元過濾器CharacterEncodingFilter,再然後自上而下載入servlet(本文只有一個servlet,不存在先後順序問題),載入DispatcherServlet分發器,這時候就要載入分發器的配置文件dispatcher_cainiao.xml了。在dispatcher_cainiao.xml中,因為 寫了mvc:annotation-driven,所以載入DefaultAnnotationHandlerMapping與AnnotationMethodHandlerAdapter兩個bean,然後掃描包controller,處理包controller下的所有文件包含的註解,然後配置視圖解析類InternalResourceViewResolver,再然後web項目啟動完畢。
當我們請求http://localhost:8080/test/demo的時候,首先根據http://localhost:8080/test找到這個項目,然後根據/demo,在servlet-mapping中的url-pattern中查找對應的項,找到一個dispatcher_cainiao,然後根據註解@RequestMapping("demo")找到文件DispatcherController,然後進入相應的方法處理,最後返回的時候根據return值index和配置文件中的InternalResourceViewResolver視圖管理,找到jsp文件/views/index.jsp,最後就是渲染jsp文件了。
ps:
首先,web項目的唯一入口是web.xml(不知道是不是有其他入口,我是菜鳥,如果有其他入口希望大神留言指正),其他的xml文件都是在web.xml文件中註冊過的,或者是在servlet或者監聽器中被載入的,而監聽也是在web.xml中註冊的,所以所有的配置文件,都能從web.xml通過一定的路徑走到。學spring框架一定要知道他的大概流程是什麼。所以初學spring,建議找一張白紙,好好畫一畫他的流程走向是什麼,很有幫助的。
歡迎轉載,但請標明出處:http://www.cnblogs.com/xuejupo/p/5252009.html, 也歡迎跟我討論。