SpringMVC是一個基于DispatcherServlet的MVC架構,每一個請求最先通路的都是DispatcherServlet,DispatcherServlet負責轉發每一個Request請求給相應的Handler,Handler處理以後再傳回相應的視圖(View)和模型(Model),傳回的視圖和模型都可以不指定,即可以隻傳回Model或隻傳回View或都不傳回。
DispatcherServlet是繼承自HttpServlet的,既然SpringMVC是基于DispatcherServlet的,那麼我們先來配置一下DispatcherServlet,好讓它能夠管理我們希望它管理的内容。HttpServlet是在web.xml檔案中聲明的。
02 | < servlet-name >blog</ servlet-name > |
04 | < servlet-class >org.springframework.web.servlet.DispatcherServlet</ servlet-class > |
05 | < load-on-startup >1</ load-on-startup > |
08 | < servlet-name >blog</ servlet-name > |
10 | < url-pattern >*.do</ url-pattern > |
上面聲明了一個名為blog的DispatcherServlet,該Servlet将處理所有以“.do”結尾的請求。在初始化DispatcherServlet的時候,SpringMVC預設會到/WEB-INF目錄下尋找一個叫[servlet-name]-servlet.xml的配置檔案,來初始化裡面的bean對象,該檔案中對應的bean對象會覆寫spring配置檔案中聲明的同名的bean對象。如上面的就會在/WEB-INF目錄下尋找一個叫blog-servlet.xml的檔案;當然也可以在Servlet中聲明配置檔案的位置。
03 | < servlet-name >blog</ servlet-name > |
04 | < servlet-class >org.springframework.web.servlet.DispatcherServlet</ servlet-class > |
06 | < param-name >contextConfigLocation</ param-name > |
08 | < param-value >/WEB-INF/blog-servlet.xml</ param-value > |
10 | < load-on-startup >1</ load-on-startup > |
14 | < servlet-name >blog</ servlet-name > |
15 | < url-pattern >*.do</ url-pattern > |
DispatcherServlet會利用一些特殊的bean來處理Request請求和生成相應的視圖傳回。
關于視圖的傳回,Controller隻負責傳回來一個值,然後到底傳回的是什麼視圖,是由視圖解析器控制的,在jsp中常用的視圖解析器是InternalResourceViewResovler,它會要求一個字首和一個字尾
2 | class = "org.springframework.web.servlet.view.InternalResourceViewResolver" > |
3 | < property name = "prefix" value = "/WEB-INF/" /> |
4 | < property name = "suffix" value = ".jsp" /> |
在上述視圖解析器中,如果Controller傳回的是blog/index,那麼通過視圖解析器解析之後的視圖就是/WEB-INF/blog/index.jsp。
要使用注解的SpringMVC需要在SpringMVC的配置檔案中進行聲明,具體方式為先引入mvc命名空間,然後利用<mvc:annotation-driven />進行聲明。
01 | < beans xmlns = "http://www.springframework.org/schema/beans" |
02 | xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns:context = "http://www.springframework.org/schema/context" |
03 | <span style = "background-color:#00ff00;" >< span style = "color:#ff0000;" >xmlns:mvc="http://www.springframework.org/schema/mvc"</ span ></ span >
xsi:schemaLocation="http://www.springframework.org/schema/beans |
04 | http://www.springframework.org/schema/beans/spring-beans-3.0.xsd |
05 | http://www.springframework.org/schema/context |
06 | http://www.springframework.org/schema/context/spring-context-3.0.xsd |
07 | < span style = "background-color:#00ff00;color:#ff0000;" >
http://www.springframework.org/schema/mvc |
08 | http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"</ span >> |
10 | < mvc:annotation-driven /> |
主要是說說Controller.
一個類使用了@Controller進行标記的都是Controller
2 | public class BlogController
{ |
有了Controller之後,那麼到底是怎樣請求一個Controller具體的方法的呢,那是通過@RequestMapping來标記的,@RequestMapping可以标記在類上面,也可以标記在方法上,當方法上和類上都标記了@RequestMapping的時候,那麼對應的方法對應的Url就是類上的加方法上的,如下面的index方法,其對應的URL應為類上的/blog加上index方法上的/index,是以應為/blog/index,是以當請求/blog/index.do的時候就會通路BlogController的index方法。
02 | @RequestMapping ( "/blog" ) |
03 | public class BlogController
{ |
06 | @RequestMapping ( "/index" ) |
07 | public String
index(Map<String, Object> map) { |
在上面的代碼中,如果index方法上沒有RequestMapping注解,而隻有BlogController類上有,且該類隻有一個方法的時候,直接請求類上的URL就會調用裡面的方法,即直接請求/blog.do的時候就會調用index方法。
在RequestMapping中還可以指定一個屬性method,其主要對應的值有RequestMethod.GET和RequestMethod.POST,利用該屬性可以嚴格的控制某一方法隻能被标記的請求路徑對應的請求方法才能通路,如指定method的值為GET,則表示隻有通過GET方式才能通路該方法,預設是都可以通路。
在SpringMVC中常用的注解還有@PathVariable,@RequestParam,@PathVariable标記在方法的參數上,利用它标記的參數可以利用請求路徑傳值,看下面一個例子
1 | @RequestMapping (value= "/comment/{blogId}" ,
method=RequestMethod.POST) |
2 | public void comment(Comment
comment, @PathVariable int blogId,
HttpSession session, HttpServletResponse response) throws IOException
{ |
在該例子中,blogId是被@PathVariable标記為請求路徑變量的,如果請求的是/blog/comment/1.do的時候就表示blogId的值為1. 同樣@RequestParam也是用來給參數傳值的,但是它是從頭request的參數裡面取值,相當于request.getParameter("參數名")方法。
在Controller的方法中,如果需要WEB元素HttpServletRequest,HttpServletResponse和HttpSession,隻需要在給方法一個對應的參數,那麼在通路的時候SpringMVC就會自動給其傳值,但是需要注意的是在傳入Session的時候如果是第一次通路系統的時候就調用session會報錯,因為這個時候session還沒有生成。
接下來讨論一下方法的傳回值,主要有一下情況:
- 傳回一個ModelAndView,其中Model是一個Map,裡面存放的是一對對的鍵值對,其可以直接在頁面上使用,View是一個字元串,表示的是某一個View的名稱
- 傳回一個View,也就是一個字元串,這個時候如果需要給頁面傳值,可以給方法一個Map參數,該Map就相當于一個Model,往該Model裡面存入鍵值對就可以在頁面上進行通路了
- 傳回一個Model也就是一個Map,這個時候将解析預設的生成的view name。
- 什麼也不傳回,這個時候可以利用HttpServletResponse進行傳回,也可以直接使用printStream進行傳回
下面是一個簡單的執行個體
01 | @RequestMapping ( "/{owner}/index" ) |
02 | public String
userIndex(Map<String, Object> map, @PathVariable String
owner, HttpServletRequest request) throws ParserException
{ |
03 | List<DefCategory>
categories = categoryService.find(owner); |
04 | int offset
= Util.getOffset(request); |
05 | Pager<Blog>
pager = blogService.find(owner, ,
offset, maxResults); |
06 | int totalRecords
= pager.getTotalRecords(); |
07 | List<Blog>
blogs = pager.getData(); |
08 | Util.shortBlog(blogs); |
10 | List<Message>
messages = messageService.find(owner, , 5 ).getData(); |
11 | Util.shortMessage(messages, 20 ); |
12 | map.put( "messages" ,
messages); |
13 | map.put( "totalRecords" ,
totalRecords); |
14 | List<BlogStore>
stores = storeService.find(owner, , 5 ).getData(); |
15 | map.put( "maxResults" ,
maxResults); |
16 | map.put( "blogs" ,
blogs); |
17 | map.put( "totalRecords" ,
totalRecords); |
18 | map.put( "owner" ,
userService.find(owner)); |
19 | map.put( "defCategories" ,
categories); |
20 | map.put( "stores" ,
stores); |
21 | return "blog/userIndex" ; |