SpringMVC是一個基於DispatcherServlet的MVC框架,每一個請求最先訪問的都是DispatcherServlet,DispatcherServlet負責轉發每一個Request請求給相應的Handler,Handler處理以後再返回相應的視圖(View)和模型(Model),返回的視圖和模型都可以不指定,即可以只返回Model或只返回View或都不返回。
DispatcherServlet是繼承自HttpServlet的,既然SpringMVC是基於DispatcherServlet的,那麼我們先來配置一下DispatcherServlet,好讓它能夠管理我們希望它管理的內容。HttpServlet是在web.xml文件中聲明的。
- <servlet>
- <servlet-name>blog</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>blog</servlet-name>
- <url-pattern>*.do</url-pattern>
- </servlet-mapping>
上面聲明瞭一個名爲blog的DispatcherServlet,該Servlet將處理所有以“.do”結尾的請求。在初始化DispatcherServlet的時候,SpringMVC默認會到/WEB-INF目錄下尋找一個叫[servlet-name]-servlet.xml的配置文件,來初始化裏面的bean對象,該文件中對應的bean對象會覆蓋spring配置文件中聲明的同名的bean對象。如上面的就會在/WEB-INF目錄下尋找一個叫blog-servlet.xml的文件;當然也可以在Servlet中聲明配置文件的位置。
- <servlet>
- <servlet-name>blog</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>/WEB-INF/blog-servlet.xml</param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>blog</servlet-name>
- <url-pattern>*.do</url-pattern>
- </servlet-mapping>
DispatcherServlet會利用一些特殊的bean來處理Request請求和生成相應的視圖返回。
關於視圖的返回,Controller只負責傳回來一個值,然後到底返回的是什麼視圖,是由視圖解析器控制的,在jsp中常用的視圖解析器是InternalResourceViewResovler,它會要求一個前綴和一個後綴
- <bean
- class="org.springframework.web.servlet.view.InternalResourceViewResolver">
- <property name="prefix" value="/WEB-INF/" />
- <property name="suffix" value=".jsp" />
- </bean>
在上述視圖解析器中,如果Controller返回的是blog/index,那麼通過視圖解析器解析之後的視圖就是/WEB-INF/blog/index.jsp。
要使用註解的SpringMVC需要在SpringMVC的配置文件中進行聲明,具體方式爲先引入mvc命名空間,然後利用<mvc:annotation-driven />進行聲明。
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
- <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
- 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
- <span style="color: #ff0000; background-color: #00ff00;"> http://www.springframework.org/schema/mvc
- http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"</span>>
- <mvc:annotation-driven />
- </beans>
主要是說說Controller.
一個類使用了@Controller進行標記的都是Controller
- @Controller
- public class BlogController {
- }
有了Controller之後,那麼到底是怎樣請求一個Controller具體的方法的呢,那是通過@RequestMapping來標記的,@RequestMapping可以標記在類上面,也可以標記在方法上,當方法上和類上都標記了@RequestMapping的時候,那麼對應的方法對應的Url就是類上的加方法上的,如下面的index方法,其對應的URL應爲類上的/blog加上index方法上的/index,所以應爲/blog/index,所以當請求/blog/index.do的時候就會訪問BlogController的index方法。
- @Controller
- @RequestMapping("/blog")
- public class BlogController {
- @RequestMapping("/index")
- public String index(Map<String, Object> map) {
- return "blog/index";
- }
- }
在上面的代碼中,如果index方法上沒有RequestMapping註解,而只有BlogController類上有,且該類只有一個方法的時候,直接請求類上的URL就會調用裏面的方法,即直接請求/blog.do的時候就會調用index方法。
在RequestMapping中還可以指定一個屬性method,其主要對應的值有RequestMethod.GET和RequestMethod.POST,利用該屬性可以嚴格的控制某一方法只能被標記的請求路徑對應的請求方法才能訪問,如指定method的值爲GET,則表示只有通過GET方式才能訪問該方法,默認是都可以訪問。
在SpringMVC中常用的註解還有@PathVariable,@RequestParam,@PathVariable標記在方法的參數上,利用它標記的參數可以利用請求路徑傳值,看下面一個例子
- @RequestMapping(value="/comment/{blogId}", method=RequestMethod.POST)
- 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進行返回
- @RequestMapping("/{owner}/index")
- public String userIndex(Map<String, Object> map,@PathVariable String owner, HttpServletRequest request) throws ParserException {
- List<DefCategory> categories = categoryService.find(owner);
- int offset = Util.getOffset(request);
- Pager<Blog> pager = blogService.find(owner, 0, offset, maxResults);
- int totalRecords = pager.getTotalRecords();
- List<Blog> blogs = pager.getData();
- Util.shortBlog(blogs);
- List<Message> messages = messageService.find(owner, 0, 5).getData();
- Util.shortMessage(messages, 20);
- map.put("messages", messages);
- map.put("totalRecords", totalRecords);
- List<BlogStore> stores = storeService.find(owner, 0, 5).getData();
- map.put("maxResults", maxResults);
- map.put("blogs", blogs);
- map.put("totalRecords", totalRecords);
- map.put("owner", userService.find(owner));
- map.put("defCategories", categories);
- map.put("stores", stores);
- return "blog/userIndex";
- }