SpringMVC札记(一)----从入门程序到小探原理

最近工作上重新接触一些和SpringMVC有关的内容,之前接触的时候没有形成自己的笔记,最近来偿还之前欠下的技术债。

1. 入门程序

1.1. 创建Spring MVC项目

在开发工具IDEA中,创建基于Maven的Spring MVC项目,创建的时候我们基于以下archetype(Maven 的41种骨架功能介绍)。

注意:此骨架生成的代码中,JSP的版本比较低不支持el表达式,需要生成后手动进行修改。

1.2. 加入相关依赖

在POM文件中,只需导入spring-webmvc

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

导入该依赖之后,其会自动导入其他所需的依赖,间接引入的依赖,如下图所示:

1.3. 配置程序拦截入口

和Java中其他MVC框架一样,SpringMVC所有的请求都会经过一个前端控制器Servlet,这个Servlet就是SpringMVC框架的统一入口,所以需要对其进行配置

<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:当值为0或者大于0时,表示容器在应用启动时就加载并初始化这个servlet,当值小于0或者没有指定时,则表示容器在该servlet被选择时才会去加载。另外,它的值只表示优先级而非启动延迟时间。

url-pattern:/ 表示默认的URL映射,当request匹配不到其他Servlet时,会默认进入此Servlet,包括静态资源请求。注意:/*配置来表示拦截所有请求是错误的

contextConfigLocation:指定springmvc配置的加载位置,如果不指定则默认加载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"/>

一般实际开发过程中,不会单独配置HandlerAdapter和HandlerMapping。而是使用mvc:annotation-driven,它会自动加入HandlerAdapter和HandlerMapping的配置。

1.5. 开发处理器Controller

处理器是需要程序员自己开发的,先来思考这么一个问题,SpringMVC框架是如何识别你写出来的Controller呢? SpringMVC要求处理器需实现org.springframework.web.servlet.mvc.Controller接口。而我们在实际开发一般只在开发的处理器类上添加@Controller注解即可。

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

    @RequestMapping("/list")
    public ModelAndView queryItems()throws Exception{
        
        //调用service查找 数据库,查询商品列表,这里使用静态数据模拟
        List<Items> itemsList = new ArrayList<Items>();
        //向list中填充静态数据
        
        Items items_1 = new Items();
        items_1.setName("联想笔记本");
        items_1.setPrice(6000f);
        items_1.setDetail("ThinkPad T430 联想笔记本电脑!");
        itemsList.add(items_1);
        
        //返回ModelAndView
        ModelAndView modelAndView =  new ModelAndView();
        //相当 于request的setAttribut,在jsp页面中通过itemsList取数据
        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标签库,所以classpath中必须包含jstl的相关jar 包;
prefix 和suffix:查找视图页面的前缀和后缀,最终视图的址为:
前缀+逻辑视图名+后缀,逻辑视图名需要在controller中返回ModelAndView指定,比如逻辑视图名为hello,则最终返回的jsp视图地址 “WEB-INF/jsp/hello.jsp”

到目前为止,springmvc完整的配置文件内容如下

<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默认加载很多的参数绑定方法, 比如json转换解析器就默认加载了。
    如果使用mvc:annotation-driven不用单独配置RequestMappingHandlerMapping和RequestMappingHandlerAdapter -->
    <mvc:annotation-driven></mvc:annotation-driven>

    <!-- 视图解析器 解析jsp解析,默认使用jstl标签,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. 开发页面

根据视图解析器的配置,在/WEB-INF/jsp/目录下添加对应的页面文件。

1.8. 测试

任何时候都需要谨记测试代码很重要!那么SpringMVC的代码如何进行测试呢?我们可以借助MockMvc来进行测试。

@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 ) //请求数据的格式是URL
                //.param( "userId","22" )    //URL中的参数
        ).andExpect(status().isOk())  //返回的状态是200
                .andDo(print())  //打印出请求和相应的内容
                .andReturn().getResponse().getContentAsString(); //将相应的数据转换为字符串
        System.out.println(response);
    }

}

完整的代码请参考:SpringMVC入门程序

2. SpringMVC原理小探

2.1 SpringMVC运行流程

1、 用户发送请求至前端控制器DispatcherServlet
2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、 DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
5、 执行处理器(Controller,也叫后端控制器)。
6、 Controller执行完成返回ModelAndView
7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器
9、 ViewReslover解析后返回具体View
10、 DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。
11、 DispatcherServlet响应用户

2.2. SpringMVC中的常见组件

  • DispatcherServlet:前端控制器

DispatcherServlet是SpringMVC程序的入口。用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,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的默认配置在DispatcherServlet.properties(和DispatcherServlet类在一个包下)中,而且是当Spring配置文件中没有指定配置时使用的默认策略:


  • HandlerMapping:处理器映射器

HandlerMapping负责根据用户请求找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
有如下几种常见的HandlerMapping

  1. BeanNameUrlHandlerMapping:根据请求的url与容器中定义的bean的name进行匹配,从而从spring容器中找到bean实例。。
  2. SimpleUrlHandlerMapping:BeanNameUrlHandlerMapping的增强版,可以映射一个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注解,根据相关配置,绑定URL到一个Handler。

RequestMappingHandlerMapping是开发中最常用的HandlerMapping。


  • Handler:处理器

Handler就是Controller,它是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。

由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler。


  • HandlAdapter:处理器适配器

SpringMVC最终是通过HandlerAdapter来调用实际的Controller方法的。通过扩展适配器可以对更多类型的处理器进行执行。常用的有如下几个:

  1. SimpleControllerHandlerAdapter:处理实现了org.springframework.web.servlet.mvc. Controller接口的Controller。
  2. AnnotationMethodHandlerAdapter:从spring3.1版本开始,废除使用,推荐使用RequestHandlerAdapter来代替注解形式的处理器适配。
  3. RequestHandlerAdapter:处理类型为HandlerMethod的Handler(使用@RequestMapping注解的方法就是一种HandlerMethod)。
  4. HttpRequestHandlerAdapter:所有实现了org.springframework.web.HttpRequestHandler接口的Controller通过此适配器进行适配和执行。

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


  • ViewResolver:视图解析器

View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。 springmvc框架提供了很多的View视图类型,包括:jstlView、freemarkerView、pdfView等。

一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。


  • HandlerExceptionResolver:异常处理器

我们可以实现自己的处理器在全局层面拦截Handler抛出的Exception,再做进一步的处理。SpringMVC自带了以下几个异常处理器:

  1. SimpleMappingExceptionResolver:可以将不同的异常映射到不同的JSP页面。
  2. ExceptionHandlerExceptionResolver:解析使用了@ExceptionHandler注解的方法来处理异常。
  3. ResponseStatusExceptionResolver:处理@ResponseStatus注解的异常。
  4. DefaultHandlerExceptionResolver:默认的处理器,包括不支持的method、不支持的mediaType等。


  • HandlerInterceptor:Hanler拦截器

请求路径上的拦截器,需要自己实现这个接口以拦截请求,做一些对Handler的前置和后置的处理工作。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容

  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架,建立于...
    Hsinwong阅读 22,366评论 1 92
  • 额(⊙o⊙)…继续记笔记。。。看看SpringMVC从入门到放弃之第一章Web MVC简介一个在实验室的时候就是这...
    键盘瞎阅读 2,091评论 2 10
  • 对于java中的思考的方向,1必须要看前端的页面,对于前端的页面基本的逻辑,如果能理解最好,不理解也要知道几点。 ...
    神尤鲁道夫阅读 806评论 0 0
  • 阳光照进白色的病房中,给房间内添加了一丝温暖,收音机小声的播放着,我打开相册,与半躺在病床上的奶奶一起笑谈着、回忆...
    cllx阅读 574评论 2 16
  • 你仰望星空 赞那遥不可及的美 我低头看蚂蚁 感叹大地上那疲于奔命的劳累
    袁建民_1968阅读 352评论 2 17