SpringMVC札記(一)----從入門程序到小探原理

最近工作上重新接觸一些和SpringMVC有關(guān)的內(nèi)容,之前接觸的時候沒有形成自己的筆記,最近來償還之前欠下的技術(shù)債。

1. 入門程序

1.1. 創(chuàng)建Spring MVC項(xiàng)目

在開發(fā)工具IDEA中,創(chuàng)建基于Maven的Spring MVC項(xiàng)目,創(chuàng)建的時候我們基于以下archetype(Maven 的41種骨架功能介紹)。

注意:此骨架生成的代碼中,JSP的版本比較低不支持el表達(dá)式,需要生成后手動進(jìn)行修改。

1.2. 加入相關(guān)依賴

在POM文件中,只需導(dǎo)入spring-webmvc。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>4.3.20.RELEASE</version>
</dependency>

導(dǎo)入該依賴之后,其會自動導(dǎo)入其他所需的依賴,間接引入的依賴,如下圖所示:

1.3. 配置程序攔截入口

和Java中其他MVC框架一樣,SpringMVC所有的請求都會經(jīng)過一個前端控制器Servlet,這個Servlet就是SpringMVC框架的統(tǒng)一入口,所以需要對其進(jìn)行配置

<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>
  <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
  <servlet-name>springmvc</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

load-on-startup:當(dāng)值為0或者大于0時,表示容器在應(yīng)用啟動時就加載并初始化這個servlet,當(dāng)值小于0或者沒有指定時,則表示容器在該servlet被選擇時才會去加載。另外,它的值只表示優(yōu)先級而非啟動延遲時間。

url-pattern:/ 表示默認(rèn)的URL映射,當(dāng)request匹配不到其他Servlet時,會默認(rèn)進(jìn)入此Servlet,包括靜態(tài)資源請求。注意:/*配置來表示攔截所有請求是錯誤的。

contextConfigLocation:指定springmvc配置的加載位置,如果不指定則默認(rèn)加載WEB-INF/[DispatcherServlet 的Servlet 名字]-servlet.xml。

1.4. 配置HandlerAdapter和HandlerMapping

在springmvc.xml文件中加入以下配置:

<!--處理器適配器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<!--處理器映射器-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

一般實(shí)際開發(fā)過程中,不會單獨(dú)配置HandlerAdapter和HandlerMapping。而是使用mvc:annotation-driven,它會自動加入HandlerAdapter和HandlerMapping的配置。

1.5. 開發(fā)處理器Controller

處理器是需要程序員自己開發(fā)的,先來思考這么一個問題,SpringMVC框架是如何識別你寫出來的Controller呢? SpringMVC要求處理器需實(shí)現(xiàn)org.springframework.web.servlet.mvc.Controller接口。而我們在實(shí)際開發(fā)一般只在開發(fā)的處理器類上添加@Controller注解即可。

@Controller
@RequestMapping("/item")
public class ItemsController {

    @RequestMapping("/list")
    public ModelAndView queryItems()throws Exception{
        
        //調(diào)用service查找 數(shù)據(jù)庫,查詢商品列表,這里使用靜態(tài)數(shù)據(jù)模擬
        List<Items> itemsList = new ArrayList<Items>();
        //向list中填充靜態(tài)數(shù)據(jù)
        
        Items items_1 = new Items();
        items_1.setName("聯(lián)想筆記本");
        items_1.setPrice(6000f);
        items_1.setDetail("ThinkPad T430 聯(lián)想筆記本電腦!");
        itemsList.add(items_1);
        
        //返回ModelAndView
        ModelAndView modelAndView =  new ModelAndView();
        //相當(dāng) 于request的setAttribut,在jsp頁面中通過itemsList取數(shù)據(jù)
        modelAndView.addObject("itemsList", itemsList);
        modelAndView.setViewName("items/itemsList");
        
        return modelAndView;
    }
}

1.6. 配置視圖解析器

在springmvc的配置文件中,加入如下配置:

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
  <property name="prefix" value="/WEB-INF/jsp/"/>
  <property name="suffix" value=".jsp"/>
</bean>

InternalResourceViewResolver:支持JSP視圖解析
viewClass:JstlView表示JSP模板頁面需要使用JSTL標(biāo)簽庫,所以classpath中必須包含jstl的相關(guān)jar 包;
prefix 和suffix:查找視圖頁面的前綴和后綴,最終視圖的址為:
前綴+邏輯視圖名+后綴,邏輯視圖名需要在controller中返回ModelAndView指定,比如邏輯視圖名為hello,則最終返回的jsp視圖地址 “WEB-INF/jsp/hello.jsp”

到目前為止,springmvc完整的配置文件內(nèi)容如下

<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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.3.20.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-4.3.20.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.3.20.xsd">

    <!-- 可以掃描controller、service、... 這里讓掃描controller,指定controller的包 -->
    <context:component-scan base-package="cn.zgc.mvc.controller"></context:component-scan>

    <!-- mvc:annotation-driven默認(rèn)加載很多的參數(shù)綁定方法, 比如json轉(zhuǎn)換解析器就默認(rèn)加載了。
    如果使用mvc:annotation-driven不用單獨(dú)配置RequestMappingHandlerMapping和RequestMappingHandlerAdapter -->
    <mvc:annotation-driven></mvc:annotation-driven>

    <!-- 視圖解析器 解析jsp解析,默認(rèn)使用jstl標(biāo)簽,classpath下的得有jstl的包 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 配置jsp路徑的前綴 -->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!-- 配置jsp路徑的后綴 -->
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

1.7. 開發(fā)頁面

根據(jù)視圖解析器的配置,在/WEB-INF/jsp/目錄下添加對應(yīng)的頁面文件。

1.8. 測試

任何時候都需要謹(jǐn)記測試代碼很重要!那么SpringMVC的代碼如何進(jìn)行測試呢?我們可以借助MockMvc來進(jìn)行測試。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:testSpringmvc.xml")
@WebAppConfiguration
public class ItemsControllerTest {
    protected MockMvc mockMvc;

    @Autowired
    protected WebApplicationContext wac;
    @Before()
    public void setup() {
        mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();  //初始化MockMvc對象
    }

    @Test
    public void queryItems() throws Exception {

        String response = mockMvc.perform(
                get("/item/list")   //請求的url,請求的方法是get
                .contentType( MediaType.APPLICATION_FORM_URLENCODED ) //請求數(shù)據(jù)的格式是URL
                //.param( "userId","22" )    //URL中的參數(shù)
        ).andExpect(status().isOk())  //返回的狀態(tài)是200
                .andDo(print())  //打印出請求和相應(yīng)的內(nèi)容
                .andReturn().getResponse().getContentAsString(); //將相應(yīng)的數(shù)據(jù)轉(zhuǎn)換為字符串
        System.out.println(response);
    }

}

完整的代碼請參考:SpringMVC入門程序

2. SpringMVC原理小探

2.1 SpringMVC運(yùn)行流程

1、 用戶發(fā)送請求至前端控制器DispatcherServlet
2、 DispatcherServlet收到請求調(diào)用HandlerMapping處理器映射器。
3、 處理器映射器根據(jù)請求url找到具體的處理器,生成處理器對象及處理器攔截器(如果有則生成)一并返回給DispatcherServlet。
4、 DispatcherServlet通過HandlerAdapter處理器適配器調(diào)用處理器
5、 執(zhí)行處理器(Controller,也叫后端控制器)。
6、 Controller執(zhí)行完成返回ModelAndView
7、 HandlerAdapter將controller執(zhí)行結(jié)果ModelAndView返回給DispatcherServlet
8、 DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器
9、 ViewReslover解析后返回具體View
10、 DispatcherServlet對View進(jìn)行渲染視圖(即將模型數(shù)據(jù)填充至視圖中)。
11、 DispatcherServlet響應(yīng)用戶

2.2. SpringMVC中的常見組件

  • DispatcherServlet:前端控制器

DispatcherServlet是SpringMVC程序的入口。用戶請求到達(dá)前端控制器,它就相當(dāng)于mvc模式中的c,dispatcherServlet是整個流程控制的中心,由它調(diào)用其它組件處理用戶的請求,dispatcherServlet的存在降低了組件之間的耦合性。

DispatcherServlet在加載的過程中,會初始化其他組件。

    protected void onRefresh(ApplicationContext context) {
        this.initStrategies(context);
    }

    protected void initStrategies(ApplicationContext context) {
        this.initMultipartResolver(context);
        this.initLocaleResolver(context);
        this.initThemeResolver(context);
        this.initHandlerMappings(context);
        this.initHandlerAdapters(context);
        this.initHandlerExceptionResolvers(context);
        this.initRequestToViewNameTranslator(context);
        this.initViewResolvers(context);
        this.initFlashMapManager(context);
    }

DispatcherServlet的默認(rèn)配置在DispatcherServlet.properties(和DispatcherServlet類在一個包下)中,而且是當(dāng)Spring配置文件中沒有指定配置時使用的默認(rèn)策略:


  • HandlerMapping:處理器映射器

HandlerMapping負(fù)責(zé)根據(jù)用戶請求找到Handler即處理器,springmvc提供了不同的映射器實(shí)現(xiàn)不同的映射方式,例如:配置文件方式,實(shí)現(xiàn)接口方式,注解方式等。
有如下幾種常見的HandlerMapping

  1. BeanNameUrlHandlerMapping:根據(jù)請求的url與容器中定義的bean的name進(jìn)行匹配,從而從spring容器中找到bean實(shí)例。。
  2. SimpleUrlHandlerMapping:BeanNameUrlHandlerMapping的增強(qiáng)版,可以映射一個url到一個Handler的id。
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
  <property name="mappings">
    <props>
      <prop key="/url1">controller的bean id</prop>
      <prop key="/url2">controller的bean id</prop>
    </props>
  </property>
</bean>
  1. DefaultAnnotationHandlerMapping:從spring3.1版本開始,廢除使用。
  2. RequestMappingHandlerMapping:掃描RequestMapping注解,根據(jù)相關(guān)配置,綁定URL到一個Handler。

RequestMappingHandlerMapping是開發(fā)中最常用的HandlerMapping。


  • Handler:處理器

Handler就是Controller,它是繼DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler對具體的用戶請求進(jìn)行處理。

由于Handler涉及到具體的用戶業(yè)務(wù)請求,所以一般情況需要程序員根據(jù)業(yè)務(wù)需求開發(fā)Handler。


  • HandlAdapter:處理器適配器

SpringMVC最終是通過HandlerAdapter來調(diào)用實(shí)際的Controller方法的。通過擴(kuò)展適配器可以對更多類型的處理器進(jìn)行執(zhí)行。常用的有如下幾個:

  1. SimpleControllerHandlerAdapter:處理實(shí)現(xiàn)了org.springframework.web.servlet.mvc. Controller接口的Controller。
  2. AnnotationMethodHandlerAdapter:從spring3.1版本開始,廢除使用,推薦使用RequestHandlerAdapter來代替注解形式的處理器適配。
  3. RequestHandlerAdapter:處理類型為HandlerMethod的Handler(使用@RequestMapping注解的方法就是一種HandlerMethod)。
  4. HttpRequestHandlerAdapter:所有實(shí)現(xiàn)了org.springframework.web.HttpRequestHandler接口的Controller通過此適配器進(jìn)行適配和執(zhí)行。

springmvc使用<mvc:annotation-driven>自動加載RequestMappingHandlerMapping和RequestMappingHandlerAdapter,可用在springmvc.xml配置文件中使用<mvc:annotation-driven>替代注解處理器和適配器的配置。


  • ViewResolver:視圖解析器

View Resolver負(fù)責(zé)將處理結(jié)果生成View視圖,View Resolver首先根據(jù)邏輯視圖名解析成物理視圖名即具體的頁面地址,再生成View視圖對象,最后對View進(jìn)行渲染將處理結(jié)果通過頁面展示給用戶。 springmvc框架提供了很多的View視圖類型,包括:jstlView、freemarkerView、pdfView等。

一般情況下需要通過頁面標(biāo)簽或頁面模版技術(shù)將模型數(shù)據(jù)通過頁面展示給用戶,需要由程序員根據(jù)業(yè)務(wù)需求開發(fā)具體的頁面。


  • HandlerExceptionResolver:異常處理器

我們可以實(shí)現(xiàn)自己的處理器在全局層面攔截Handler拋出的Exception,再做進(jìn)一步的處理。SpringMVC自帶了以下幾個異常處理器:

  1. SimpleMappingExceptionResolver:可以將不同的異常映射到不同的JSP頁面。
  2. ExceptionHandlerExceptionResolver:解析使用了@ExceptionHandler注解的方法來處理異常。
  3. ResponseStatusExceptionResolver:處理@ResponseStatus注解的異常。
  4. DefaultHandlerExceptionResolver:默認(rèn)的處理器,包括不支持的method、不支持的mediaType等。


  • HandlerInterceptor:Hanler攔截器

請求路徑上的攔截器,需要自己實(shí)現(xiàn)這個接口以攔截請求,做一些對Handler的前置和后置的處理工作。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架,建立于...
    Hsinwong閱讀 22,943評論 1 92
  • 額(⊙o⊙)…繼續(xù)記筆記。。??纯碨pringMVC從入門到放棄之第一章Web MVC簡介一個在實(shí)驗(yàn)室的時候就是這...
    鍵盤瞎閱讀 2,172評論 2 10
  • 對于java中的思考的方向,1必須要看前端的頁面,對于前端的頁面基本的邏輯,如果能理解最好,不理解也要知道幾點(diǎn)。 ...
    神尤魯?shù)婪?/span>閱讀 901評論 0 0
  • 陽光照進(jìn)白色的病房中,給房間內(nèi)添加了一絲溫暖,收音機(jī)小聲的播放著,我打開相冊,與半躺在病床上的奶奶一起笑談著、回憶...
    cllx閱讀 605評論 2 16
  • 你仰望星空 贊那遙不可及的美 我低頭看螞蟻 感嘆大地上那疲于奔命的勞累
    袁建民_1968閱讀 394評論 2 17

友情鏈接更多精彩內(nèi)容