1、什么是 SpringMVC ?
在介紹什么是 SpringMVC 之前,我們先看看 Spring 的基本架構。如下圖:
我們可以看到,在 Spring 的基本架構中,紅色圈起來的 Spring Web MVC ,也就是本系列的主角 SpringMVC,它是屬於Spring基本架構里面的一個組成部分,屬於SpringFrameWork的后續產品,已經融合在Spring Web Flow里面,所以我們在后期和 Spring 進行整合的時候,幾乎不需要別的什么配置。
SpringMVC 是類似於 Struts2 的一個 MVC 框架,在實際開發中,接收瀏覽器的請求響應,對數據進行處理,然后返回頁面進行顯示,但是上手難度卻比 Struts2 簡單多了。而且由於 Struts2 所暴露出來的安全問題,SpringMVC 已經成為了大多數企業優先選擇的框架。
那么多的不說,我們直接通過一個實例來看看 SpringMVC 的魔力。
2、創建 web 工程,並導入相應的 jar 包。
這里我們加入了 Spring 3.2 的所有 jar 包,正好也佐證了上面所說的 SpringMVC 是 Spring 架構的一部分,注意:一定要包括紅色橢圓圈起來的 spring-webmvc-3.2.0.RELEASE.jar
3、新建 SpringMVC 全局配置文件
在 src 目錄下新建 springmvc.xml 文件,並添加如下代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<?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:mvc=
"http://www.springframework.org/schema/mvc"
xmlns:context=
"http://www.springframework.org/schema/context"
xmlns:aop=
"http://www.springframework.org/schema/aop"
xmlns:tx=
"http://www.springframework.org/schema/tx"
xsi:schemaLocation="http:
//www.springframework.org/schema/beans
http:
//www.springframework.org/schema/beans/spring-beans-4.2.xsd
http:
//www.springframework.org/schema/mvc
http:
//www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
http:
//www.springframework.org/schema/context
http:
//www.springframework.org/schema/context/spring-context.xsd
http:
//www.springframework.org/schema/aop
http:
//www.springframework.org/schema/aop/spring-aop-4.2.xsd
http:
//www.springframework.org/schema/tx
http:
//www.springframework.org/schema/tx/spring-tx.xsd">
</beans>
|
4、在 web.xml 文件中配置前端過濾器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<?xml version=
"1.0"
encoding=
"UTF-8"
?>
<web-app xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xmlns=
"http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http:
//java.sun.com/xml/ns/javaee
http:
//java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>SpringMVC_01</display-name>
<!-- 配置前端控制器DispatcherServlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-
class
>org.springframework.web.servlet.DispatcherServlet</servlet-
class
>
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- 對應上一步創建全局配置文件的文件名以及目錄 -->
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.
do
</url-pattern>
</servlet-mapping>
</web-app>
|
5、編寫處理器 Handler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package
com.ys.controller;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
import
org.springframework.web.servlet.ModelAndView;
import
org.springframework.web.servlet.mvc.Controller;
public
class
HelloController
implements
Controller{
@Override
public
ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response)
throws
Exception {
ModelAndView modelView =
new
ModelAndView();
//類似於 request.setAttribute()
modelView.addObject(
"name"
,
"張三"
);
modelView.setViewName(
"/WEB-INF/view/index.jsp"
);
return
modelView;
}
}
|
6、在 springmvc.xml 文件中配置 Handler,處理器映射器,處理器適配器,以及視圖解析器
在 springmvc.xml 文件中添加如下代碼:
1
2
3
4
5
6
7
8
9
10
11
|
<!-- 配置Handler -->
<bean name=
"/hello.do"
class
=
"com.ys.controller.HelloController"
/>
<!-- 配置處理器映射器
將bean的name作為url進行查找,需要在配置Handler時指定bean name(就是url)-->
<bean
class
=
"org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"
/>
<!-- 配置處理器適配器,所有適配器都得實現 HandlerAdapter接口 -->
<bean
class
=
"org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"
/>
<!-- 配置視圖解析器
進行jsp解析,默認使用jstl標簽,classpath下得有jstl的包-->
<bean
class
=
"org.springframework.web.servlet.view.InternalResourceViewResolver"
/>
|
7、在 /WEB-INF/view 目錄下創建 index.jsp 文件
1
2
3
4
5
6
7
8
9
10
11
12
|
<%@ page language=
"java"
contentType=
"text/html; charset=UTF-8"
pageEncoding=
"UTF-8"
%>
<!DOCTYPE html PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd"
>
<html>
<head>
<meta http-equiv=
"Content-Type"
content=
"text/html; charset=UTF-8"
>
<title>Insert title here</title>
</head>
<body>
hello:${name}
</body>
</html>
|
8、在瀏覽器輸入 http://localhost:8080/SpringMVC_01/hello.do
1、SpringMVC 詳細介紹
通過入門實例,我們大概知道 SpringMVC 的作用,那么它到底是什么呢?
Spring Web MVC是一種基於Java的實現了Web MVC設計模式的請求驅動類型的輕量級Web框架,即使用了MVC架構模式的思想,將web層進行職責解耦,基於請求驅動指的就是使用請求-響應模型,框架的目的就是幫助我們簡化開發,Spring Web MVC也是要簡化我們日常Web開發的。
與之相反的是基於組件的、事件驅動的Web框架,如Tapestry、JSF等,在此就不介紹了。
Spring Web MVC也是服務到工作者模式的實現,但進行可優化。前端控制器是DispatcherServlet;應用控制器其實拆為處理器映射器(Handler Mapping)進行處理器管理和視圖解析器(View Resolver)進行視圖管理;頁面控制器/動作/處理器為Controller接口(僅包含ModelAndView handleRequest(request, response) 方法)的實現(也可以是任何的POJO類);支持本地化(Locale)解析、主題(Theme)解析及文件上傳等;提供了非常靈活的數據驗證、格式化和數據綁定機制;提供了強大的約定大於配置(慣例優先原則)的契約式編程支持。
2、SpringMVC 處理請求流程
第一步:用戶發送請求到前端控制器(DispatcherServlet)。
第二步:前端控制器請求 HandlerMapping 查找 Handler,可以根據 xml 配置、注解進行查找。
第三步: 處理器映射器 HandlerMapping 向前端控制器返回 Handler
第四步:前端控制器調用處理器適配器去執行 Handler
第五步:處理器適配器執行 Handler
第六步:Handler 執行完成后給適配器返回 ModelAndView
第七步:處理器適配器向前端控制器返回 ModelAndView
ModelAndView 是SpringMVC 框架的一個底層對象,包括 Model 和 View
第八步:前端控制器請求試圖解析器去進行視圖解析
根據邏輯視圖名來解析真正的視圖。
第九步:試圖解析器向前端控制器返回 view
第十步:前端控制器進行視圖渲染
就是將模型數據(在 ModelAndView 對象中)填充到 request 域
第十一步:前端控制器向用戶響應結果
下面我們對上面出現的一些組件進行解釋:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
1、前端控制器DispatcherServlet(不需要程序員開發)。
作用:接收請求,響應結果,相當於轉發器,中央處理器。有了DispatcherServlet減少了其它組件之間的耦合度。
2、處理器映射器HandlerMapping(不需要程序員開發)。
作用:根據請求的url查找Handler。
3、處理器適配器HandlerAdapter(不需要程序員開發)。
作用:按照特定規則(HandlerAdapter要求的規則)去執行Handler。
4、處理器Handler(需要程序員開發)。
注意:編寫Handler時按照HandlerAdapter的要求去做,這樣適配器才可以去正確執行Handler
5、視圖解析器ViewResolver(不需要程序員開發)。
作用:進行視圖解析,根據邏輯視圖名解析成真正的視圖(view)
6、視圖View(需要程序員開發jsp)。
注意:View是一個接口,實現類支持不同的View類型(jsp、freemarker、pdf…)
ps:不需要程序員開發的,需要程序員自己做一下配置即可。
|
可以總結出:需要我們開發的工作只有處理器 Handler 的編寫以及視圖比如JSP頁面的編寫。可能你還對諸如前端控制器、處理器映射器等等名詞不太理解,那么接下來我們對其進行詳細的介紹。
3、配置前端控制器
在 web.xml 文件中進行如下配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
<?
xml
version="1.0" encoding="UTF-8"?>
<
web-app
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<
display-name
>SpringMVC_01</
display-name
>
<!-- 配置前端控制器DispatcherServlet -->
<
servlet
>
<
servlet-name
>springmvc</
servlet-name
>
<
servlet-class
>org.springframework.web.servlet.DispatcherServlet</
servlet-class
>
<!--springmvc.xml 是自己創建的SpringMVC全局配置文件,用contextConfigLocation作為參數名來加載
如果不配置 contextConfigLocation,那么默認加載的是/WEB-INF/servlet名稱-servlet.xml,在這里也就是 springmvc-servlet.xml
-->
<
init-param
>
<
param-name
>contextConfigLocation</
param-name
>
<
param-value
>classpath:springmvc.xml</
param-value
>
</
init-param
>
</
servlet
>
<
servlet-mapping
>
<
servlet-name
>springmvc</
servlet-name
>
<!--第一種配置:*.do,還可以寫*.action等等,表示以.do結尾的或者以.action結尾的URL都由前端控制器DispatcherServlet來解析
第二種配置:/,所有訪問的 URL 都由DispatcherServlet來解析,但是這里最好配置靜態文件不由DispatcherServlet來解析
錯誤配置:/*,注意這里是不能這樣配置的,應為如果這樣寫,最后轉發到 jsp 頁面的時候,仍然會由DispatcherServlet進行解析,
而這時候會找不到對應的Handler,從而報錯!!!
-->
<
url-pattern
>*.do</
url-pattern
>
</
servlet-mapping
>
</
web-app
>
|
4、配置處理器適配器
在 springmvc.xml 文件中配置。用來約束我們所需要編碼的 Handler類。
第一種配置:編寫 Handler 時必須要實現 Controller
1
2
|
<!-- 配置處理器適配器,所有適配器都得實現 HandlerAdapter接口 -->
<
bean
class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
|
我們可以查看源碼:
第二種配置:編寫 Handler 時必須要實現 HttpRequestHandler
1
2
|
<!-- 配置處理器適配器第二種方法,所有適配器都得實現 HandlerAdapter接口 ,這樣配置所有Handler都得實現 HttpRequestHandler接口-->
<
bean
class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter" />
|
5、編寫 Handler
在 springmvc.xml 文件中配置。通俗來講,就是請求的 URL 到我們這里所編寫的 Handler 類的某個方法進行一些業務邏輯處理。
我們在上面講解了兩個處理器適配器來約束 Handler,那么我們就通過上面兩種配置分別編寫兩個 Handler
第一種:實現Controller 接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package com.ys.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
public class HelloController implements Controller{
@Override
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
ModelAndView modelView = new ModelAndView();
//類似於 request.setAttribute()
modelView.addObject("name","張三");
modelView.setViewName("/WEB-INF/view/index.jsp");
return modelView;
}
}
|
第二種:實現 HttpRequestHandler 接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
package com.ys.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.HttpRequestHandler;
public class HelloController2 implements HttpRequestHandler{
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setAttribute("name", "張三");
request.getRequestDispatcher("/WEB-INF/view/index.jsp").forward(request, response);
}
}
|
總結:通常我們使用第一種方式來編寫 Handler ,但是第二種沒有返回值,我們可以通過 response 修改相應內容,比如返回 json 數據。
1
2
3
|
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("json字符串");
|
所以具體使用哪一種根據實際情況來判斷。
5、配置處理器映射器
在 springmvc.xml 文件中配置。通俗來講就是請求的 URL 怎么能被 SpringMVC 識別,從而去執行我們上一步所編寫好的 Handler
第一種方法:
1
2
3
4
5
6
|
<!-- 配置Handler -->
<
bean
name="/hello.do" class="com.ys.controller.HelloController2" />
<!-- 配置處理器映射器
將bean的name作為url進行查找,需要在配置Handler時指定bean name(就是url)-->
<
bean
class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
|
這樣配置的話,那么請求的 URL,必須為 http://localhost:8080/項目名/hello.do
第二種方法:
1
2
3
4
5
6
7
8
9
10
11
12
|
<!-- 配置Handler -->
<
bean
id="hello1" class="com.ys.controller.HelloController" />
<
bean
id="hello2" class="com.ys.controller.HelloController" />
<!-- 第二種方法:簡單URL配置處理器映射器 -->
<
bean
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<
property
name="mappings">
<
props
>
<
prop
key="/hello1.do">hello1</
prop
>
<
prop
key="/hello2.do">hello2</
prop
>
</
props
>
</
property
>
</
bean
>
|
這種配置請求的 URL可以為 http://localhost:8080/項目名/hello1.do,或者http://localhost:8080/項目名/hello2.do
總結:上面兩種處理器映射器配置可以並存,前端控制器會正確的去判斷 url 用哪個 Handler 去處理。
6、配置視圖解析器
第一種配置:
1
2
3
|
<!-- 配置視圖解析器
進行jsp解析,默認使用jstl標簽,classpath下得有jstl的包-->
<
bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver" />
|
如果這樣配,那么在 Handler 中返回的必須是路徑+jsp頁面名稱+".jsp"
第二種配置:
1
2
3
4
5
6
7
|
<!--配置視圖解析器 -->
<
bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 返回視圖頁面的前綴 -->
<
property
name="prefix" value="/WEB-INF/view"></
property
>
<!-- 返回頁面的后綴 -->
<
property
name="suffix" value=".jsp"></
property
>
</
bean
>
|
如果這樣配,那么在 Handler 中只需要返回在 view 文件夾下的jsp 頁面名就可以了。
7、DispatcherServlet.properties
上面我們講解了各種配置,可能有人會問這么多配置,萬一少配置了一樣,那不就不能運行了,那我們能不能不配置呢?答案是肯定的,SpringMVC 給我們提供了一個 DispatcherServlet.properties 文件。系統會首先加載這里面的配置,如果我們沒有配置,那么就默認使用這個文件的配置;如果我們配置了,那么就優先使用我們手動配置的。
在 SpringMVC 運行之前,會首先加載 DispatcherServlet.properties 文件里面的內容,那么我們來看看這里面都是什么。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
|
我們可以從上面得出,如果我們不手動進行各種配置,那么也有會默認的
①、處理器適配器默認:org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
②、處理器映射器默認:org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
③、視圖解析器默認:org.springframework.web.servlet.view.InternalResourceViewResolver
前兩篇博客我們講解了基於XML 的入門實例,以及SpringMVC運行的詳細流程。但是我們發現基於 XML 的配置還是比較麻煩的,而且,每個 Handler 類只能有一個方法,在實際開發中肯定是不可能這樣來進行開發的。那么這篇博客我們就講解實際開發中用的最多的基於注解配置的SpringMVC配置。
本篇博客源碼下載鏈接:http://pan.baidu.com/s/1dESLgv3 密碼:vkuy
項目結構為:
1、在 web.xml 文件中配置前端處理器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
<?
xml
version="1.0" encoding="UTF-8"?>
<
web-app
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<
display-name
>SpringMVC_01</
display-name
>
<!-- 配置前端控制器DispatcherServlet -->
<
servlet
>
<
servlet-name
>springmvc</
servlet-name
>
<
servlet-class
>org.springframework.web.servlet.DispatcherServlet</
servlet-class
>
<!--springmvc.xml 是自己創建的SpringMVC全局配置文件,用contextConfigLocation作為參數名來加載
如果不配置 contextConfigLocation,那么默認加載的是/WEB-INF/servlet名稱-servlet.xml,在這里也就是 springmvc-servlet.xml
-->
<
init-param
>
<
param-name
>contextConfigLocation</
param-name
>
<
param-value
>classpath:springmvc.xml</
param-value
>
</
init-param
>
</
servlet
>
<
servlet-mapping
>
<
servlet-name
>springmvc</
servlet-name
>
<!--第一種配置:*.do,還可以寫*.action等等,表示以.do結尾的或者以.action結尾的URL都由前端控制器DispatcherServlet來解析
第二種配置:/,所有訪問的 URL 都由DispatcherServlet來解析,但是這里最好配置靜態文件不由DispatcherServlet來解析
錯誤配置:/*,注意這里是不能這樣配置的,應為如果這樣寫,最后轉發到 jsp 頁面的時候,仍然會由DispatcherServlet進行解析,
而這時候會找不到對應的Handler,從而報錯!!!
-->
<
url-pattern
>/</
url-pattern
>
</
servlet-mapping
>
</
web-app
>
|
2、在 springmvc.xml 文件中配置處理器映射器,處理器適配器,視圖解析器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
<?
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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--注解處理器映射器 -->
<
bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></
bean
>
<!--注解處理器適配器 -->
<
bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></
bean
>
<!--使用mvc:annotation-driven可以代替上面的映射器和適配器
這里面會默認加載很多參數綁定方法,比如json轉換解析器就默認加載,所以優先使用下面的配置
-->
<!-- <mvc:annotation-driven></mvc:annotation-driven> -->
<!--單個配置Handler -->
<!-- <bean class="com.ys.controller.HelloController"></bean> -->
<!--批量配置Handler,指定掃描的包全稱 -->
<
context:component-scan
base-package="com.ys.controller"></
context:component-scan
>
<!--配置視圖解析器 -->
<
bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 返回視圖頁面的前綴 -->
<
property
name="prefix" value="/WEB-INF/view/"></
property
>
<!-- 返回頁面的后綴 -->
<
property
name="suffix" value=".jsp"></
property
>
</
bean
>
</
beans
>
|
3、編寫 Handler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package com.ys.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
//使用@Controller注解表示這個類是一個Handler
@Controller
public class HelloController {
//@RequestMapping注解括號里面的表示訪問的URL
@RequestMapping("hello")
public ModelAndView hello(){
ModelAndView modelView = new ModelAndView();
//類似於 request.setAttribute()
modelView.addObject("name","張三");
//配置返回的視圖名,由於我們在springmvc.xml中配置了前綴和后綴,這里直接寫視圖名就好
modelView.setViewName("index");
//modelView.setViewName("/WEB-INF/view/index.jsp");
return modelView;
}
}
|
注意@Controller注解和@RequestMapping注解的用法
4、編寫 視圖 index.jsp
1
2
3
4
5
6
7
8
9
10
11
12
|
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!
DOCTYPE
html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<
html
>
<
head
>
<
meta
http-equiv="Content-Type" content="text/html; charset=UTF-8">
<
title
>Insert title here</
title
>
</
head
>
<
body
>
hello:${name}
</
body
>
</
html
>
|
1、Spring mvc介紹
SpringMVC框架是以請求為驅動,圍繞Servlet設計,將請求發給控制器,然后通過模型對象,分派器來展示請求結果視圖。其中核心類是DispatcherServlet,它是一個Servlet,頂層是實現的Servlet接口。
2、SpringMVC使用
需要在web.xml中配置DispatcherServlet。並且需要配置spring監聽器ContextLoaderListener
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 如果不設置init-param標簽,則必須在/WEB-INF/下創建xxx-servlet.xml文件,其中xxx是servlet-name中配置的名稱。 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
3、SpringMVC運行原理
如圖所示:
流程說明:
(1)客戶端(瀏覽器)發送請求,直接請求到DispatcherServlet。
(2)DispatcherServlet根據請求信息調用HandlerMapping,解析請求對應的Handler。
(3)解析到對應的Handler后,開始由HandlerAdapter適配器處理。
(4)HandlerAdapter會根據Handler來調用真正的處理器開處理請求,並處理相應的業務邏輯。
(5)處理器處理完業務后,會返回一個ModelAndView對象,Model是返回的數據對象,View是個邏輯上的View。
(6)ViewResolver會根據邏輯View查找實際的View。
(7)DispaterServlet把返回的Model傳給View。
(8)通過View返回給請求者(瀏覽器)
4、DispatcherServlet詳細解析
首先看下源碼:
package org.springframework.web.servlet;
@SuppressWarnings("serial")
public class DispatcherServlet extends FrameworkServlet {
public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";
public static final String THEME_RESOLVER_BEAN_NAME = "themeResolver";
public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";
public static final String HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter";
public static final String HANDLER_EXCEPTION_RESOLVER_BEAN_NAME = "handlerExceptionResolver";
public static final String REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME = "viewNameTranslator";
public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver";
public static final String FLASH_MAP_MANAGER_BEAN_NAME = "flashMapManager";
public static final String WEB_APPLICATION_CONTEXT_ATTRIBUTE = DispatcherServlet.class.getName() + ".CONTEXT";
public static final String LOCALE_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".LOCALE_RESOLVER";
public static final String THEME_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_RESOLVER";
public static final String THEME_SOURCE_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_SOURCE";
public static final String INPUT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".INPUT_FLASH_MAP";
public static final String OUTPUT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".OUTPUT_FLASH_MAP";
public static final String FLASH_MAP_MANAGER_ATTRIBUTE = DispatcherServlet.class.getName() + ".FLASH_MAP_MANAGER";
public static final String EXCEPTION_ATTRIBUTE = DispatcherServlet.class.getName() + ".EXCEPTION";
public static final String PAGE_NOT_FOUND_LOG_CATEGORY = "org.springframework.web.servlet.PageNotFound";
private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
protected static final Log pageNotFoundLogger = LogFactory.getLog(PAGE_NOT_FOUND_LOG_CATEGORY);
private static final Properties defaultStrategies;
static {
try {
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());
}
}
/** Detect all HandlerMappings or just expect "handlerMapping" bean? */
private boolean detectAllHandlerMappings = true;
/** Detect all HandlerAdapters or just expect "handlerAdapter" bean? */
private boolean detectAllHandlerAdapters = true;
/** Detect all HandlerExceptionResolvers or just expect "handlerExceptionResolver" bean? */
private boolean detectAllHandlerExceptionResolvers = true;
/** Detect all ViewResolvers or just expect "viewResolver" bean? */
private boolean detectAllViewResolvers = true;
/** Throw a NoHandlerFoundException if no Handler was found to process this request? **/
private boolean throwExceptionIfNoHandlerFound = false;
/** Perform cleanup of request attributes after include request? */
private boolean cleanupAfterInclude = true;
/** MultipartResolver used by this servlet */
private MultipartResolver multipartResolver;
/** LocaleResolver used by this servlet */
private LocaleResolver localeResolver;
/** ThemeResolver used by this servlet */
private ThemeResolver themeResolver;
/** List of HandlerMappings used by this servlet */
private List<HandlerMapping> handlerMappings;
/** List of HandlerAdapters used by this servlet */
private List<HandlerAdapter> handlerAdapters;
/** List of HandlerExceptionResolvers used by this servlet */
private List<HandlerExceptionResolver> handlerExceptionResolvers;
/** RequestToViewNameTranslator used by this servlet */
private RequestToViewNameTranslator viewNameTranslator;
private FlashMapManager flashMapManager;
/** List of ViewResolvers used by this servlet */
private List<ViewResolver> viewResolvers;
public DispatcherServlet() {
super();
}
public DispatcherServlet(WebApplicationContext webApplicationContext) {
super(webApplicationContext);
}
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
}
DispatcherServlet類中的屬性beans:
HandlerMapping:用於handlers映射請求和一系列的對於攔截器的前處理和后處理,大部分用@Controller注解。
HandlerAdapter:幫助DispatcherServlet處理映射請求處理程序的適配器,而不用考慮實際調用的是 哪個處理程序。
HandlerExceptionResolver:處理映射異常。
ViewResolver:根據實際配置解析實際的View類型。
LocaleResolver:解決客戶正在使用的區域設置以及可能的時區,以便能夠提供國際化視野。
ThemeResolver:解決Web應用程序可以使用的主題,例如提供個性化布局。
MultipartResolver:解析多部分請求,以支持從HTML表單上傳文件。
FlashMapManager:存儲並檢索可用於將一個請求屬性傳遞到另一個請求的input和output的FlashMap,通常用於重定向。
在Web MVC框架中,每個DispatcherServlet都擁自己的WebApplicationContext,它繼承了ApplicationContext。WebApplicationContext包含了其上下文和Servlet實例之間共享的所有的基礎框架beans。
HandlerMapping:
HandlerMapping接口處理請求的映射
HandlerMapping接口的實現類:
SimpleUrlHandlerMapping類通過配置文件把URL映射到Controller類。
DefaultAnnotationHandlerMapping類通過注解把URL映射到Controller類。
HandlerAdapter:
HandlerAdapter接口-處理請求映射
AnnotationMethodHandlerAdapter:通過注解,把請求URL映射到Controller類的方法上。
HandlerExceptionResolver:
HandlerExceptionResolver接口-異常處理接口
SimpleMappingExceptionResolver通過配置文件進行異常處理。
AnnotationMethodHandlerExceptionResolver:通過注解進行異常處理。
ViewResolver:
ViewResolver接口解析View視圖。
UrlBasedViewResolver類 通過配置文件,把一個視圖名交給到一個View來處理。
SpringMVC 注解詳解
spring mvc 中有很多的注解,每個注解都有自己的功能,下面我們就對spring mvc中的注解一一作出介紹。關於spring的注解還沒有總結,請等待后續blog更新。
@controller
org.springframework.stereotype.Controller注解類型用於指示當前類是一個控制器。 Spring使用掃描機制查找應用程序中所有基於注解的控制器類,分發器會掃描使用該注解類的方法,並檢測方法是否使用了@RequestMapping注解,只用使用了@RequestMapping注解的方法才能用來處理請求。
為了保證spring能找到控制器,需要完成兩件事情:
- 在spring mvc的配置文件的頭文件中引入spring-context。
- 在spring mvc 的配置文件中使用context:component-scan/,該元素的功能是啟動包掃描功能,以便注冊有@Controller、@Service、@Repository、@Component等注解的類成為spring的bean。
<context:component-scan base-package = "com.chris.controller"/>
@RequestMapping
該注解類型指示spring用哪一個類或方法來處理請求動作,可以用於類或方法。
@Controller // RequestMapping可以用來注釋一個控制器類,此時,所有方法都將映射為相對於類級別的請求, // 表示該控制器處理所有的請求都被映射到 user屬性所指示的路徑下 @RequestMapping(value="/user") public class UserController{ // 映射請求 user/register @RequestMapping(value="/register",method=RequestMethod.GET) public String registerForm() { // 跳轉到注冊頁面 return "registerForm"; } // 映射請求 user/login @RequestMapping("/login") public String login( Model model) { return "loginForm"; } }
@RequestMapping可以指定一些屬性
- value:用來映射一個請求和一個方法,是其默認屬性,如果在使用@RequestMapping時只有這個屬性,則可以省略關鍵字value.
- method:該屬性用來指定該方法僅僅處理哪些HTTP請求的處理方式,例如GET、POST。
- consumes:用來指定處理請求提交內容的類型。
- produces:用來指定返回的內容類型,返回的內容類型必須是request請求頭(Accept)中包含的類型。
- params:指明request中必須包含哪些參數時,才讓該方法處理。例如下面的代碼指明方法只處理其中名為"myParam",值為"myValue"的請求。
@RequestMapping(value="/hello", method = RequestMethod.POST, params = "myParam = myValue")
- headers 指明request中必須包含某些header值,才能讓該方法處理請求,例如
@RequestMapping(value="/hello", method = RequestMethod.POST, header = "bolgID = http://www.cnblogs.com/arax/")
在使用@RequestMapping指定的方法中,如果要訪問HttpServletRequest或HttpSession,可以將其直接作為參數,Spring會將對象傳遞給方法。
@RequestMapping("/hello") public String login(HttpSession session) { return "hello"; }
@RequestParam
該注解將指定的請求參數賦值給方法中的形參。
@RequestMapping("/hello") { public String login( @RequestParam("loginName") String loginName, @RequestParam("password") String password ) { return "login"; } }
在執行上面函數時,springmvc 會將Request中的loginName,password從參數中取出來賦值給函數的形參。
@RequestParam中的屬性如下:
- name:綁定參數在Request中的名稱。
- value:name屬性的別名。
- required:參數是否必須綁定。
- defaultValue:如果沒有傳遞參數而使用的默認值。
@RequestParam(value="loginname",required=true,defaultValue="admin")
@PathVariable
@PathVariable只支持一個屬性value,類型為String,表示綁定的名稱,如果省略則表示綁定同名參數。
@RequestMapping("path/{userId}") public String login(@PathVariable Integer userId) { return "login"; }
加入請求url為http://localhost:8080/path/3,則上述函數在執行時會自動將userId值映射為3。
@RequestHeader
將請求頭信息區書記映射到處理方法上。其主要有如下屬性
- name:指定請求頭綁定的名稱。
- value:name屬性的別名。
- required:參數是否必須綁定。
- defaultValue:如果沒有傳遞參數而使用的默認值。
和@PathVariable的屬性相同。下面給出用法實例
@RequestMapping("/hello") { public String login( @RequestHeader("User-Agent") String userAgent, @RequestHeader(value="Accept") String[] accepts ) { return "login"; } }
@CookieValue
將請求的Cookie書記映射到功能處理方法參數上。其支持的屬性如下:
- name:指定請求頭綁定的名稱。
- value:name屬性的別名。
- required:參數是否必須綁定。
- defaultValue:如果沒有傳遞參數而使用的默認值。
用法和@RequestParam相同,這里不再贅述。
@SessionAttribute
該注解允許我們有選擇的將指定Model
中的哪些屬性轉存到HttpSession對象中。其只能聲明在類上。他包含3個屬性。
使用如下
@Controller // 將Model中的屬性名為user的放入HttpSession對象當中 @SessionAttributes("user") public class SessionAttributesController{ @RequestMapping(value="/{formName}") public String loginForm(@PathVariable String formName){ // 動態跳轉頁面 return formName; } @RequestMapping(value="/login") public String login( @RequestParam("loginname") String loginname, @RequestParam("password") String password, Model model ) { User user = new User(); user.setLoginname(loginname); user.setPassword(password); user.setUsername("admin"); model.addAttribute("user",user); return "welcome"; } }
@ModelAttribute
@ModelAttribute只有一個屬性value,類型為String,表示綁定數據類型的名稱。其使用方法以及表現形式比較多變,容我娓娓道來。@ModelAttribute主要用來修飾方法,被其修飾的方法會在Controller中每個方法執行前被執行,因此在一個Controller類要映射多個URL時,要謹慎使用。
我個人理解被@ModelAttribute修飾的方法,是在執行映射方法前對Model的預處理。
注解返回具體類的方法
@Controller public class ModelAttribute1Controller{ // 使用@ModelAttribute注釋的value屬性, // 來指定model屬性的名稱,model屬性對象就是方法的返回值 @ModelAttribute("loginname") public String userModel( @RequestParam("loginname") String loginname){ return loginname; } @RequestMapping(value="/login1") public String login() { return "result1"; } }
userModel會先於login執行,並在Model中以loginname為屬性名稱,userModel返回值為屬性值,在Model中放入了一個屬性。
注解無返回值的方法
@Controller public class ModelAttribute2Controller{ // model屬性名稱和model屬性對象由model.addAttribute()實現, // 前提是要在方法中加入一個Model類型的參數。 // 注意:當URL或者post中不包含對應的參數時,程序會拋出異常。 @ModelAttribute public void userModel( @RequestParam("loginname") String loginname, @RequestParam("password") String password, Model model){ model.addAttribute("loginname", loginname); model.addAttribute("password", password); } @RequestMapping(value="/login2") public String login() { return "result2"; } }
在這個例子中userModel先於login執行,相當於將一段對model的預處理邏輯單獨放到一個函數中。
注解返回具體類的方法
@Controller public class ModelAttribute3Controller{ // model屬性的名稱沒有指定,它由返回類型隱含表示, // 如這個方法返回User類型,那么這個model屬性的名稱是user。 // 這個例子中model屬性名稱由返回對象類型隱含表示, // model屬性對象就是方法的返回值。它不需要指定特定的參數。 @ModelAttribute public User userModel3( @RequestParam("loginname") String loginname, @RequestParam("password") String password){ return new UserUpperCase(loginname, password); } @RequestMapping(value="/login3") public String login3() { return "result3"; } }
例子中@ModelAttribue沒有參數,修飾的函數的返回值為User的對象,這時會以類名的首字母小寫為屬性名,返回值為屬性值,在Model中放入一個屬性。
@ModelAttribute和@RequestMapping同時注解同一個方法
@Controller public class ModelAttribute4Controller{ // 這時這個方法的返回值並不是表示一個視圖名稱,而是model屬性的值, //視圖名稱是@RequestMapping的value值。 // Model屬性名稱由@ModelAttribute(value="")指定,相當於在request中封裝了 //username(key)=admin(value)。 @RequestMapping(value="/login") @ModelAttribute(value="username") public String login() { return "admin"; } }
此時login方法的返回值不在是一個視圖的名稱,而是model屬性的值,視圖的名稱仍然是@RequestMapping的value值"/login"。處理結束后頁面繼續跳轉到login.jsp。
注釋一個方法的參數
@Controller public class ModelAttribute5Controller{ @RequestMapping(value="/login") public String login(@ModelAttribute("user") User user) { user.setUsername("管理員"); return "result"; } }