一、基本使用,獲取提交的參數
後端代碼:
- @RequestMapping("testRequestParam")
- public String filesUpload(@RequestParam String inputStr, HttpServletRequest request) {
- System.out.println(inputStr);
- int inputInt = Integer.valueOf(request.getParameter("inputInt"));
- System.out.println(inputInt);
- // ......省略
- return "index";
- }
前端代碼:
- <form action="/gadget/testRequestParam" method="post">
- 參數inputStr:<input type="text" name="inputStr">
- 參數intputInt:<input type="text" name="inputInt">
- </form>
前端界面:
執行結果:
test1
123
可以看到spring會自動根據參數名字封裝進入,我們可以直接拿這個參數名來用
二、各種異常情況處理
1、可以對傳入參數指定參數名
- @RequestParam String inputStr
- // 下面的對傳入參數指定爲aa,如果前端不傳aa參數名,會報錯
- @RequestParam(value="aa") String inputStr
錯誤信息:
HTTP Status 400 - Required String parameter 'aa' is not present
2、可以通過required=false或者true來要求@RequestParam配置的前端參數是否一定要傳
- // required=false表示不傳的話,會給參數賦值爲null,required=true就是必須要有
- @RequestMapping("testRequestParam")
- public String filesUpload(@RequestParam(value="aa", required=true) String inputStr, HttpServletRequest request)
3、如果用@RequestMapping註解的參數是int基本類型,但是required=false,這時如果不傳參數值會報錯,因爲不傳值,會賦值爲null給int,這個不可以
- @RequestMapping("testRequestParam")
- public String filesUpload(@RequestParam(value="aa", required=true) String inputStr,
- @RequestParam(value="inputInt", required=false) int inputInt
- ,HttpServletRequest request) {
- // ......省略
- return "index";
- }
解決方法:
“Consider declaring it as object wrapper for the corresponding primitive type.”建議使用包裝類型代替基本類型,如使用“Integer”代替“int”
self.location.href;//當前頁面打開URL頁面
window.location.href;//當前頁面打開URL頁面
this
.location.href;//當前頁面打開URL頁面
location.href;// 當前頁面打開URL頁面
parent.location.href;//在父頁面打開新頁面
top.location.href;//在頂層頁面打開新頁面
jQuery(function(){}) 或$(function(){}); 它是$(document).ready() 的簡寫
自SpringMVC4.2之後,RequestParam內部有4個參數:
1、String name
2、String value
3、boolean required
4、String defaultValue
其中name和value分別是對方的別名,即二者沒區別,我個人比較喜歡用name,因爲它的某些特性使得name這個名字更直觀,下面會說到。
先看第一個映射方法的定義:
@RequestMapping("/paramTest0") public @ResponseBody String paramTest(Long id){ String result = ""; result += id; return result; }
①然後我在瀏覽器地址欄上輸入:http://localhost:8080/test/hello/paramTest0
瀏覽器顯示:null
這裏引申出了SpringMVC的一個特性,即當瀏覽器中沒有輸入相應參數和值,那麼SpringMVC不會給id賦值即id值是默認值null,因此參數都最好不要用基礎類型。
②在瀏覽器中輸入:http://localhost:8080/test/hello/paramTest0?userName=zhang&userName=li&id=9&userName=shit
瀏覽器顯示:9
說明瀏覽器中只要有輸入需要的參數即可,而不管是否包含多餘的參數,且沒有規定順序(因爲後臺是可以根據key來獲取值的,而如果是通過QueryString則順序也不影響解析參數)。
③在瀏覽器中輸入:http://localhost:8080/test/hello/paramTest0?id=6
顯示爲:6
這個就不解釋了。
#########################################分隔符##################################################
再看第二個映射方法的定義:
@RequestMapping("/paramTest") public @ResponseBody String paramTest(@RequestParam(name="userName", required = false) String[] userNames, Long id){ String result = ""; if(userNames != null){ for(int i=0;i<userNames.length;i++){ result += userNames[i] + "#"; } } result += id; return result; }
①然後在瀏覽器輸入:http://localhost:8080/test/hello/paramTest?userName=zhang&userName=li&id=5&userName=fuck
顯示爲:zhang#li#fuck#5
由此引申出:首先URL請求的參數部分可以有多對參數的參數名一樣,如上面的userName,且它們中間可以用其它參數隔開(上面用了id=5隔開)而不會影響這幾個參數名一樣的參數值構成“數組”(對於瀏覽器而言它只是URL中的字符串而已是否重複沒半毛錢關係,Tomcat也不會主動將它拼成數組),
相同的參數名的值會被SpringMVC通過request.getQueryString()方法獲取完整的參數然後再將相同key的Entry轉換成數組(應該是SpringMVC判斷參數裏有數組就不用getParameter方法而用getQueryString方法獲取參數),這裏的元素值的順序則是跟在URL請求中的順序是對應的。
然後看我們方法參數裏的是userNames而非userName,但是仍然顯示正確,這是因爲RequestParam的name或value屬性的值userName纔是和
瀏覽器那邊傳過來的參數名對應(個人認爲這是name比value更直觀一點的原因),而它註解的參數userNames就是
此註解"userName"要“賦值”的變量(或說SpringMVC因爲有RequestParam而做了個參數映射將客戶端請求中的參數值映射到相應方法的參數上,即userNames)。
還要注意,一個@RequestParam只能註解一個參數,即後面的Long id上是沒有該註解的。
RequestParam中的required是指這個參數是否客戶端必須提供,defaultValue則是如果沒有提供該參數默認值是什麼(故required=true, defaultValue="xxx"就沒意義了)。
作者:Silentdoer
歡迎任何形式的轉載,但請務必註明出處。
限於本人水平,如果隨筆/文章及代碼有表述不當之處,還請不吝賜教。
①request.getParameter(“username”)等價於${param.username },它們一般用在服務器獲取頁面或客戶端的內容,這些內容都是String的;
②request.getAttribute(“username”)等價於${requestScope.username},一般是從服務器傳遞數據到頁面,在頁面中獲取服務器保存在其中的數據內容。
<%!%>是聲明標籤
<%=%>獲取後臺的變量值,比如後臺一個session["ab"]="ab";前臺<%=session["ab"]%>就能取到值; <%:%>同<%=%>。
<%@ page ... %> | 定義網頁依賴屬性,比如腳本語言、error頁面、緩存需求等等 |
<%@ include ... %> | 包含其他文件 |
<%@ taglib ... %> | 引入標籤庫的定義 |
request | HttpServletRequest類的實例 |
response | HttpServletResponse類的實例 |
out | JspWriter類的實例,用於把結果輸出至網頁上 |
session | HttpSession類的實例 |
application | ServletContext類的實例,與應用上下文有關 |
config | ServletConfig類的實例 |
pageContext | PageContext類的實例,提供對JSP頁面所有對象以及命名空間的訪問 |
page | 類似於Java類中的this關鍵字 |
Exception | Exception類的對象,代表發生錯誤的JSP頁面中對應的異常對象 |
<th>和<td>一樣,也是需要嵌套在<tr>當中的,<tr>嵌套在<table>當中 <table>...</table> 用於定義一個表格開始和結束 <th>...</th> 定義表頭單元格。表格中的文字將以粗體顯示,在表格中也可以不用此標籤,<th>標籤必須放在<tr>標籤內 <tr>...</tr> 定義一行標籤,一組行標籤內可以建立多組由<td>或<th>標籤所定義的單元格 <td>...</td> 定義單元格標籤,一組<td>標籤將將建立一個單元格,<td>標籤必須放在<tr>標籤內
\n 用於字符串的換行
<br/>用於html的換行
JSP 讀取表單數據
getParameter(): 使用 request.getParameter() 方法來獲取表單參數的值。
getParameterValues(): 獲得如checkbox類(名字相同,但值有多個)的數據。 接收數組變量 ,如checkbox類型
getParameterNames():該方法可以取得所有變量的名稱,該方法返回一個Emumeration。
getInputStream():調用此方法來讀取來自客戶端的二進制數據流。
這兩個應該是HTML標記吧?
p是段落標記
b是加粗
@RequestParam A) 常用來處理簡單類型的綁定,通過Request.getParameter() 獲取的String可直接轉換爲簡單類型的情況( 由String到 簡單類型的轉換操作由ConversionService配置的轉換器來完成);因爲使用request.getParameter()方式獲取參數,所以可以處理get 方式中queryString的值,也可以處理post方式中 body data的值。 B)用來處理Content-Type: 爲 application/x-www-form-urlencoded編碼的內容,提交方式GET、POST。(不設置這個屬性,好像這就是默認值) C) 該註解有兩個屬性: value、required; value用來指定要傳入值的id名稱,required用來指示參數是否必須綁定。 在方法參數裏面如是:public @ResponseBody JsonResult getPublishedToposByConnStreamId(@RequestParam(value = "streamId", required = false) String streamId) {} @RequestBody A) GET、POST方式提時, 根據request header Content-Type的值來判斷: application/x-www-form-urlencoded, 可選(即非必須,因爲這種情況的數據@RequestParam, @ModelAttribute也可以處理,當然@RequestBody也能處理); multipart/form-data, 不能處理(次類型多用來上傳文件類型---即使用@RequestBody不能處理這種格式的數據,@RequestParam這個卻是可以處理的。); 其他格式, 必須(其他格式包括application/json, application/xml等。這些格式的數據,必須使用@RequestBody來處理); B) PUT方式提交時, 根據request header Content-Type的值來判斷:(表示沒見過put方式滴,可以無視吧。) application/x-www-form-urlencoded, 必須; multipart/form-data, 不能處理; 其他格式, 必須; 說明:request的body部分的數據編碼格式由header部分的Content-Type指定; 最後 就我的經驗來看: @RequestBody這個一般處理的是在ajax請求中聲明contentType: "application/json; charset=utf-8"時候。也就是json數據或者xml(我沒用過這個,用的是json) @RequestParam這個一般就是在ajax裏面沒有聲明contentType的時候,爲默認的。。。urlencode格式時,用這個。 看我前面幾個截圖就可以看出來。
springMVC @RequestMapping 設置後 會默認將返回字符串拼成 .jsp 地址形式
1、
@responseBody註解的作用是將controller的方法返回的對象通過適當的轉換器轉換爲指定的格式之後,寫入到response對象的body區,通常用來返回JSON數據或者是XML
數據,需要注意的呢,在使用此註解之後不會再走試圖處理器,而是直接將數據寫入到輸入流中,他的效果等同於通過response對象輸出指定格式的數據。
2、
@RequestMapping("/login")@ResponseBody
public User login(User user){
return user;
}
User字段:userName pwd
那麼在前臺接收到的數據爲:'{"userName":"xxx","pwd":"xxx"}'
效果等同於如下代碼:
@RequestMapping("/login")
public void login(User user, HttpServletResponse response){
response.getWriter.write(JSONObject.fromObject(user).toString());
spring是目前最流行的框架。創建java web項目時,我們首先會遇到的配置文件就是web.xml,這是javaweb爲我們封裝的邏輯,不在今天的研究中。下面我們將簡單講講web.xml中的配置。
一、一個空的web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID"> </web-app>
二、標籤介紹
web.xml中比較常見的標籤以及其加載順序爲:
context-param > listener > filter > servlet
1、 <display-name>Archetype Created Web Application</display-name>
display-name 是標識項目的名稱,這個不是很常用,可有可無的,或者說不需要我們去在意的東西。
2、 <context-param>
<context-param> <param-name>webAppRootKey</param-name> <param-value>60000</param-value> </context-param>
context-param 是web.xml首先加載的標籤,其下子標籤有param-name和param-value.
此所設定的參數,在JSP網頁中可以使用下列方法來取得:
${initParam.webAppRootKey}
若在Servlet可以使用下列方法來獲得:
String param_name=getServletContext().getInitParamter(“webAppRootKey”);
3、listener
<listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener>
listenter在項目開始的時候就注入進來,盡在context-param之後,所以正常我們將spring配置在listener 中,這樣方法spring 初始化相關的bean。
4、filter
<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>
filter起到一個過濾的作用,在servlet執行前後,像上面的配置就是在過濾servlet前將編碼轉換UTF-8,filter-mapping 則是將filter和url路徑進行映射。其中init-param則是將初始化需要的參數傳入到filter-class中從而進行初始化。filter和filter-mapping中的name必須是相同的,才能起到映射的作用,而filter-mapping 中的url-pattern則是匹配請求路徑的。上面‘/*'表示過濾所有請求的servlet,如果寫成‘/zxh',則過濾http://localhost:8080/項目名/zxh這個請求。
5、servlet
<servlet> <!-- 配置DispatcherServlet --> <servlet-name>springMvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 指定spring mvc配置文件位置 不指定使用默認情況 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/spring-mvc.xml</param-value> </init-param> <!-- 設置啓動順序 --> <load-on-startup>1</load-on-startup> </servlet> <!-- ServLet 匹配映射 --> <servlet-mapping> <servlet-name>springMvc</servlet-name> <url-pattern>*.zxh</url-pattern> </servlet-mapping>
servlet和filter類似,需要先指定servlet對應的class類,然後將這個類和utl路徑請求地址進行映射。這裏不多說了。
以上就是web.xml文件中出現最多的幾個標籤。其他的比如:
6、歡迎頁
<welcome-file-list> <welcome-file>login.jsp</welcome-file> </welcome-file-list>
7、錯誤頁
<!-- 後臺程序異常錯誤跳轉頁面 --> <error-page> <exception-type>java.lang.Throwable</exception-type> <location>/views/error.jsp</location> </error-page> <!-- 500跳轉頁面--> <error-page> <error-code>500</error-code> <location>/views/500.jsp</location> </error-page> <!-- 404跳轉頁面 --> <error-page> <error-code>404</error-code> <location>/views/404.jsp</location> </error-page>
三、示例
1、spring 框架解決字符串編碼問題:過濾器 CharacterEncodingFilter(filter-name)
2、在web.xml配置監聽器ContextLoaderListener(listener-class)
ContextLoaderListener的作用就是啓動Web容器時,自動裝配ApplicationContext的配置信息。因爲它實現了ServletContextListener這個接口,在web.xml配置這個監聽器,啓動容器時,就會默認執行它實現的方法。
3、部署applicationContext的xml文件:contextConfigLocation(context-param下的param-name)
4、DispatcherServlet是前置控制器,配置在web.xml文件中的。攔截匹配的請求,Servlet攔截匹配規則要自已定義,把攔截下來的請求,依據某某規則分發到目標Controller(我們寫的Action)來處理。
DispatcherServlet(servlet-name、servlet-class、init-param、param-name(contextConfigLocation)、param-value)
在DispatcherServlet的初始化過程中,框架會在web應用的 WEB-INF文件夾下尋找名爲[servlet-name]-servlet.xml 的配置文件,生成文件中定義的bean
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" 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_3_0.xsd"> <!-- 在Spring框架中是如何解決從頁面傳來的字符串的編碼問題的呢? 下面我們來看看Spring框架給我們提供過濾器CharacterEncodingFilter 這個過濾器就是針對於每次瀏覽器請求進行過濾的,然後再其之上添加了父類沒有的功能即處理字符編碼。 其中encoding用來設置編碼格式,forceEncoding用來設置是否理會 request.getCharacterEncoding()方法,設置爲true則強制覆蓋之前的編碼格式。--> <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 時,applicationContext.xml配置文件中並沒有BeanFactory,要想在業務層中的class 文件中直接引用Spring容器管理的bean可通過以下方式--> <!--1、在web.xml配置監聽器ContextLoaderListener--> <!--ContextLoaderListener的作用就是啓動Web容器時,自動裝配ApplicationContext的配置信息。因爲它實現了ServletContextListener這個接口,在web.xml配置這個監聽器,啓動容器時,就會默認執行它實現的方法。 在ContextLoaderListener中關聯了ContextLoader這個類,所以整個加載配置過程由ContextLoader來完成。 它的API說明 第一段說明ContextLoader可以由 ContextLoaderListener和ContextLoaderServlet生成。 如果查看ContextLoaderServlet的API,可以看到它也關聯了ContextLoader這個類而且它實現了HttpServlet這個接口 第二段,ContextLoader創建的是 XmlWebApplicationContext這樣一個類,它實現的接口是WebApplicationContext->ConfigurableWebApplicationContext->ApplicationContext-> BeanFactory這樣一來spring中的所有bean都由這個類來創建 IUploaddatafileManager uploadmanager = (IUploaddatafileManager) ContextLoaderListener.getCurrentWebApplicationContext().getBean("uploadManager"); --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!--2、部署applicationContext的xml文件--> <!--如果在web.xml中不寫任何參數配置信息,默認的路徑是"/WEB-INF/applicationContext.xml, 在WEB-INF目錄下創建的xml文件的名稱必須是applicationContext.xml。 如果是要自定義文件名可以在web.xml里加入contextConfigLocation這個context參數: 在<param-value> </param-value>裏指定相應的xml文件名,如果有多個xml文件,可以寫在一起並以“,”號分隔。 也可以這樣applicationContext-*.xml採用通配符,比如這那個目錄下有applicationContext-ibatis-base.xml, applicationContext-action.xml,applicationContext-ibatis-dao.xml等文件,都會一同被載入。 在ContextLoaderListener中關聯了ContextLoader這個類,所以整個加載配置過程由ContextLoader來完成。--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/applicationContext.xml</param-value> </context-param> <!--如果你的DispatcherServlet攔截"/",爲了實現REST風格,攔截了所有的請求,那麼同時對*.js,*.jpg等靜態文件的訪問也就被攔截了。--> <!--方案一:激活Tomcat的defaultServlet來處理靜態文件--> <!--要寫在DispatcherServlet的前面, 讓 defaultServlet先攔截請求,這樣請求就不會進入Spring了,我想性能是最好的吧。--> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.css</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.swf</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.gif</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.jpg</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.png</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.js</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.xml</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.json</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.map</url-pattern> </servlet-mapping> <!--使用Spring MVC,配置DispatcherServlet是第一步。DispatcherServlet是一個Servlet,,所以可以配置多個DispatcherServlet--> <!--DispatcherServlet是前置控制器,配置在web.xml文件中的。攔截匹配的請求,Servlet攔截匹配規則要自已定義,把攔截下來的請求,依據某某規則分發到目標Controller(我們寫的Action)來處理。--> <servlet> <servlet-name>DispatcherServlet</servlet-name><!--在DispatcherServlet的初始化過程中,框架會在web應用的 WEB-INF文件夾下尋找名爲[servlet-name]-servlet.xml 的配置文件,生成文件中定義的bean。--> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--指明瞭配置文件的文件名,不使用默認配置文件名,而使用dispatcher-servlet.xml配置文件。--> <init-param> <param-name>contextConfigLocation</param-name> <!--其中<param-value>**.xml</param-value> 這裏可以使用多種寫法--> <!--1、不寫,使用默認值:/WEB-INF/<servlet-name>-servlet.xml--> <!--2、<param-value>/WEB-INF/classes/dispatcher-servlet.xml</param-value>--> <!--3、<param-value>classpath*:dispatcher-servlet.xml</param-value>--> <!--4、多個值用逗號分隔--> <param-value>classpath:spring/dispatcher-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup><!--是啓動順序,讓這個Servlet隨Servletp容器一起啓動。--> </servlet> <servlet-mapping> <!--這個Servlet的名字是dispatcher,可以有多個DispatcherServlet,是通過名字來區分的。每一個DispatcherServlet有自己的WebApplicationContext上下文對象。同時保存的ServletContext中和Request對象中.--> <!--ApplicationContext是Spring的核心,Context我們通常解釋爲上下文環境,我想用“容器”來表述它更容易理解一些,ApplicationContext則是“應用的容器”了:P,Spring把Bean放在這個容器中,在需要的時候,用getBean方法取出--> <servlet-name>DispatcherServlet</servlet-name> <!--Servlet攔截匹配規則可以自已定義,當映射爲@RequestMapping("/user/add")時,爲例,攔截哪種URL合適?--> <!--1、攔截*.do、*.htm, 例如:/user/add.do,這是最傳統的方式,最簡單也最實用。不會導致靜態文件(jpg,js,css)被攔截。--> <!--2、攔截/,例如:/user/add,可以實現現在很流行的REST風格。很多互聯網類型的應用很喜歡這種風格的URL。弊端:會導致靜態文件(jpg,js,css)被攔截後不能正常顯示。 --> <url-pattern>/</url-pattern> <!--會攔截URL中帶“/”的請求。--> </servlet-mapping> <welcome-file-list><!--指定歡迎頁面--> <welcome-file>login.html</welcome-file> </welcome-file-list> <error-page> <!--當系統出現404錯誤,跳轉到頁面nopage.html--> <error-code>404</error-code> <location>/nopage.html</location> </error-page> <error-page> <!--當系統出現java.lang.NullPointerException,跳轉到頁面error.html--> <exception-type>java.lang.NullPointerException</exception-type> <location>/error.html</location> </error-page> <session-config><!--會話超時配置,單位分鐘--> <session-timeout>360</session-timeout> </session-config> </web-app>
四、spring加載
通過上面的瞭解,我們可以看出spring核心配置文件就是listener那塊。在監聽之前我們已經通過context-param將spring配置文件傳到上下文中了(application)。下面我們就來看看spring是如何工作的吧
第一步:
點開listener源碼,我們發現他有下面幾個方法。和繼承的關係。我們發現他實現了ContextLoaderListener這個接口,這個接口在參數設置好之後自動執行contextInitialized方法的。
那麼我們來看看contextInitialized方法
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
throw new IllegalStateException(
"Cannot initialize context because there is already a root application context present - " +
"check whether you have multiple ContextLoader* definitions in your web.xml!");
}
Log logger = LogFactory.getLog(ContextLoader.class);
servletContext.log("Initializing Spring root WebApplicationContext");
if (logger.isInfoEnabled()) {
logger.info("Root WebApplicationContext: initialization started");
}
long startTime = System.currentTimeMillis();
try {
// Store context in local instance variable, to guarantee that
// it is available on ServletContext shutdown.
if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent ->
// determine parent for root web application context, if any.
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl == ContextLoader.class.getClassLoader()) {
currentContext = this.context;
}
else if (ccl != null) {
currentContextPerThread.put(ccl, this.context);
}
if (logger.isDebugEnabled()) {
logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
}
if (logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
}
return this.context;
}
catch (RuntimeException ex) {
logger.error("Context initialization failed", ex);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
throw ex;
}
catch (Error err) {
logger.error("Context initialization failed", err);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
throw err;
}
}
仔細研究官方解釋,就是在這裏初始化application,這裏會用到contextClass+contextConfigLocation兩個參數,如果contextClass在context-param提供了,我們就會根據這一個class去初始化application,很顯然我們正常配置都沒有配這個,而是配置了後者,配置了後者就會去根據contextConfigLocation中提供的配置文件去解析然後創建相關的bean和application操作,這個方法的最後會執行configureAndRefreshWebApplicationContext方法。這個方法就是在根據contextConfigLocation提供的配置文件中創建相關的bean。
五、springMVC 加載
springMVC其實和spring是一樣的,但是他不用再程序開始時訪問
<servlet> <!-- 配置DispatcherServlet --> <servlet-name>springMvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 指定spring mvc配置文件位置 不指定使用默認情況 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/spring-mvc.xml</param-value> </init-param> <!-- 設置啓動順序 --> <load-on-startup>1</load-on-startup> </servlet> <!-- ServLet 匹配映射 --> <servlet-mapping> <servlet-name>springMvc</servlet-name> <url-pattern>*.zxh</url-pattern> </servlet-mapping>
看DispatcherServlet源碼中對contextConfigLocation參數的解釋
上面明確指出我們這個參數給XmlWebApplicationContext類的,我們在進入XmlWebApplicationContext類看看究竟。
這樣我們很容易理解爲什麼springmvc默認的配置文件會在WEB-INF/application.xml中的吧。
在dispatcherservlet中有一個初始化方法,這裏就初始化配置中一些東西,比如說文件上傳適配器的配置等等。
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
總結
spring+springmvc在配置中主要就是上面的兩個配置,當然spring的強大不是我們一兩天能夠研究來的,我上面只是簡單的研究討論了一下。
spring與mybatis三種整合方法
1、採用MapperScannerConfigurer,它將會查找類路徑下的映射器並自動將它們創建成MapperFactoryBean。
spring-mybatis.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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!-- 自動掃描 --> <context:component-scan base-package="com.hua.saf" /> <!-- 引入配置文件 --> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:jdbc.properties" /> </bean> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> <!-- 初始化連接大小 --> <property name="initialSize" value="${initialSize}" /> <!-- 連接池最大數量 --> <property name="maxActive" value="${maxActive}" /> <!-- 連接池最大空閒 --> <property name="maxIdle" value="${maxIdle}" /> <!-- 連接池最小空閒 --> <property name="minIdle" value="${minIdle}" /> <!-- 獲取連接最大等待時間 --> <property name="maxWait" value="${maxWait}" /> </bean> <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- 自動掃描mapping.xml文件,**表示迭代查找 --> <property name="mapperLocations" value="classpath:com/hua/saf/**/*.xml" /> </bean> <!-- DAO接口所在包名,Spring會自動查找其下的類 ,包下的類需要使用@MapperScan註解,否則容器注入會失敗 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.hua.saf.*" /> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /> </bean> <!-- (事務管理)transaction manager, use JtaTransactionManager for global tx --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> </beans>
UserMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- 爲這個mapper指定一個唯一的namespace,namespace的值習慣上設置成包名+sql映射文件名,這樣就能夠保證namespace的值是唯一的 例如namespace="me.gacl.mapping.userMapper"就是me.gacl.mapping(包名)+userMapper(userMapper.xml文件去除後綴) --> <mapper namespace="com.hua.saf.dao.UserDao"> <!-- 在select標籤中編寫查詢的SQL語句, 設置select標籤的id屬性爲getUser,id屬性值必須是唯一的,不能夠重複, 使用parameterType屬性指明查詢時使用的參數類型,resultType屬性指明查詢返回的結果集類型 resultType="com.hua.saf.User"就表示將查詢結果封裝成一個User類的對象返回,User類就是t_user表所對應的實體類 --> <!-- 根據id查詢得到一個user對象--> <select id="getUser" parameterType="int" resultType="com.hua.saf.pojo.User"> select * from t_user where id=#{id} </select> </mapper>
dao類:
/** * 這裏的@MapperScan就是上面所講的Mapper掃描器中所需要的配置,會自動生成代理對象。 * 注意,接口中的方法名稱要和對應的MyBatis映射文件中的語句的id值一樣,因爲生成的 * 動態代理,會根據這個匹配相應的Sql語句執行。另外就是方法的參數和返回值也需要注 * 意。接口中的方法如何定義,對應的MyBatis映射文件就應該進行相應的定義。 * 最後,標註中的userDao是用來作爲Spring的Bean的id(或name)進行使用的,方便我 * 們在Service層進行注入使用。 */ @MapperScan public interface UserDao { //此處的方法名必須和mapper中的映射文件中的id同名 //回去映射文件中通過com.hua.saf.dao.UserDao.getUser,即this.getClass().getName()+".getUser" public User getUser(int id); }
service類:
@Service("userService") public class UserServiceImpl implements IUserService { @Resource private UserDao userDao; public User getUser(int id) { return userDao.getUser(id); } }
2、採用接口org.apache.ibatis.session.SqlSession的實現類org.mybatis.spring.SqlSessionTemplate。
mybatis中, sessionFactory可由SqlSessionFactoryBuilder.來創建。MyBatis-Spring 中,使用了SqlSessionFactoryBean來替代。SqlSessionFactoryBean有一個必須屬性dataSource,另外其還有一個通用屬性configLocation(用來指定mybatis的xml配置文件路徑)。
spring-mybatis.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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!-- 自動掃描 --> <context:component-scan base-package="com.hua.saf" /> <!-- 引入配置文件 --> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:jdbc.properties" /> </bean> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> <!-- 初始化連接大小 --> <property name="initialSize" value="${initialSize}" /> <!-- 連接池最大數量 --> <property name="maxActive" value="${maxActive}" /> <!-- 連接池最大空閒 --> <property name="maxIdle" value="${maxIdle}" /> <!-- 連接池最小空閒 --> <property name="minIdle" value="${minIdle}" /> <!-- 獲取連接最大等待時間 --> <property name="maxWait" value="${maxWait}" /> </bean> <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="configLocation" value="classpath:sqlMapConfig.xml"/> <!-- 自動掃描mapping.xml文件,**表示迭代查找,也可在sqlMapConfig.xml中單獨指定xml文件--> <property name="mapperLocations" value="classpath:com/hua/saf/**/*.xml" /> </bean> <!-- mybatis spring sqlSessionTemplate,使用時直接讓spring注入即可 --> <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg> </bean> <!-- (事務管理)transaction manager, use JtaTransactionManager for global tx --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> </beans>
sqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <typeAliases> <typeAlias type="com.hua.saf.pojo.User" alias="User" /> </typeAliases> </configuration>
User.java
public class User { private int id; private String username; private String password; private int age; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
UserDao.java
@Repository public class UserDao{ @Resource private SqlSessionTemplate sqlSessionTemplate; public User getUser(int id) { return sqlSessionTemplate.selectOne(this.getClass().getName() + ".getUser", 1); } }
UserService.java
@Service public class UserService{ @Resource private UserDao userDao; public User getUser(int id) { return userDao.getUser(id); } }
3、採用抽象類org.mybatis.spring.support.SqlSessionDaoSupport提供SqlSession。
spring-mybatis.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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!-- 自動掃描 --> <context:component-scan base-package="com.hua.saf" /> <!-- 引入配置文件 --> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:jdbc.properties" /> </bean> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> <!-- 初始化連接大小 --> <property name="initialSize" value="${initialSize}" /> <!-- 連接池最大數量 --> <property name="maxActive" value="${maxActive}" /> <!-- 連接池最大空閒 --> <property name="maxIdle" value="${maxIdle}" /> <!-- 連接池最小空閒 --> <property name="minIdle" value="${minIdle}" /> <!-- 獲取連接最大等待時間 --> <property name="maxWait" value="${maxWait}" /> </bean> <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="configLocation" value="classpath:sqlMapConfig.xml"/> <!-- 自動掃描mapping.xml文件,**表示迭代查找,也可在sqlMapConfig.xml中單獨指定xml文件--> <property name="mapperLocations" value="classpath:com/hua/saf/**/*.xml" /> </bean> <!-- (事務管理)transaction manager, use JtaTransactionManager for global tx --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> </beans>
sqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <typeAliases> <typeAlias type="com.hua.saf.pojo.User" alias="User" /> </typeAliases> </configuration>
User.java
public class User { private int id; private String username; private String password; private int age; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
UserDao.java
@Repository public class UserDao extends SqlSessionDaoSupport{ public User getUser(int id) { return this.getSqlSession().selectOne(this.getClass().getName() + ".getUser", 1); } //使用SqlSessionDaoSupport必須注意,此處源碼1.1.1中有自動注入,1.2中取消了自動注入,需要手工注入,侵入性強 //也可在spring-mybatis.xml中如下配置,但是這種有多少個dao就要配置到少個,多個dao就很麻煩。 //<bean id="userDao" class="com.hua.saf.dao.UserDao"> // <property name="sqlSessionFactory" ref="sqlSessionFactory"/> //</bean> @Resource public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) { // TODO Auto-generated method stub super.setSqlSessionFactory(sqlSessionFactory); } }
UserService.java
@Service public class UserService{ @Resource private UserDao userDao; public User getUserss(int id) { return userDao.getUser(1); } }