spring_mvc

什么是springmvc

  • springmvc是spring框架的一个模块,springmvc和spring无需通过中间整合层进行整合。
  • springmvc是一个基于mvc的web框架。
    图片丢失

springmvc框架

图片丢失

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

组件:

  1. 前端控制器DispatcherServlet(不需要程序员开发)
    作用接收请求,响应结果,相当于转发器,中央处理器。
    有了DispatcherServlet减少了其它组件之间的耦合度。

  2. 处理器映射器HandlerMapping(不需要程序员开发)
    作用:根据请求的url查找Handler

  3. 处理器适配器HandlerAdapter
    作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler

  4. 处理器Handler(需要程序员开发)
    注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler

  5. 视图解析器View resolver(不需要程序员开发)
    作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)

  6. 视图View(需要程序员开发jsp)
    View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf…)

前端控制器(DispatcherServlet):接收请求,响应结果,相当于电脑的CPU。
处理器映射器(HandlerMapping):根据URL去查找处理器
处理器(Handler):(需要程序员去写代码处理逻辑的)
处理器适配器(HandlerAdapter):会把处理器包装成适配器,这样就可以支持多种类型的处理器,类比笔记本的适配器(适配器模式的应用)
视图解析器(ViewResovler):进行视图解析,多返回的字符串,进行处理,可以解析成对应的页面

Hello World

需求

  • spring mvc+mybatis(商品订单管理)。
  • 商品列表查询

### 依赖

  • spring所有的jar包(一定包括spring-webmvc-3.2.0.RELEASE.jar)
  • mybatis以及数据库相关的jar
  • jstl.jar

配置前端控制器

在web.xml中配置前端控制器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<web-app>
<!-- springmvc前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- contextConfigLocation配置springmvc加载的配置文件(配置处理器映射器、适配器等等) 如果不配置contextConfigLocation,默认加载的是/WEB-INF/servlet名称-serlvet.xml(springmvc-servlet.xml) -->
<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>
<!-- 第一种:*.action,访问以.action结尾 由DispatcherServlet进行解析
第二种:/,所以访问的地址都由DispatcherServlet进行解析,对于静态文件的解析需要配置不让DispatcherServlet进行解析
使用此种方式可以实现 RESTful风格的url
第三种:/*,这样配置不对,使用这种配置,最终要转发到一个jsp页面时, 仍然会由DispatcherServlet解析jsp地址,不能根据jsp页面找到handler,会报错。 -->
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>

  • load-on-startup:表示servlet随服务启动;
  • url-pattern:*.action的请交给DispatcherServlet处理。
  • contextConfigLocation:指定springmvc配置的加载位置,如果不指定则默认加载WEB-INF/[DispatcherServlet 的Servlet 名字]-servlet.xml。

配置处理器适配器

在classpath的springmvc.xml中配置处理器适配器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<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-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">

<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
</beans>

  • 适配器都继承HandlerAdapter
  • 适配器中有一个supports方法是判断这个适配器是执行哪个接口的handle

开发Handler(处理request)

  • 需要实现 controller接口,才能由org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter适配器执行。
  • cn.xwmdream.ssm.controller.ItemsController1
    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
    public class ItemsController1 implements Controller{

    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) 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 联想笔记本电脑!");

    Items items_2 = new Items();
    items_2.setName("苹果手机");
    items_2.setPrice(5000f);
    items_2.setDetail("iphone6苹果手机!");

    itemsList.add(items_1);
    itemsList.add(items_2);

    //返回ModelAndView
    ModelAndView modelAndView = new ModelAndView();
    //相当 于request的setAttribut,在jsp页面中通过itemsList取数据
    modelAndView.addObject("itemsList", itemsList);
    //指定视图
    modelAndView.setViewName("/WEB-INF/jsp/item/itemsList.jsp");
    return modelAndView;
    }
    }

视图编写

  • 使用了jstl解析器,一定要引入这个jar包
  • /WEB-INF/jsp/item/itemsList.jsp

    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
    45
    46
    <%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
    <!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>查询商品列表</title>
    </head>
    <body>
    <form
    action="${pageContext.request.contextPath }/item/queryItem.action"
    method="post">
    查询条件:
    <table width="100%" border=1>
    <tr>
    <td><input type="submit" value="查询" /></td>
    </tr>
    </table>
    商品列表:
    <table width="100%" border=1>
    <tr>
    <td>商品名称</td>
    <td>商品价格</td>
    <td>生产日期</td>
    <td>商品描述</td>
    <td>操作</td>
    </tr>
    <c:forEach items="${itemsList }" var="item">
    <tr>
    <td>${item.name }</td>
    <td>${item.price }</td>
    <td><fmt:formatDate value="${item.createtime}"
    pattern="yyyy-MM-dd HH:mm:ss" /></td>
    <td>${item.detail }</td>

    <td><a
    href="${pageContext.request.contextPath }/item/editItem.action?id=${item.id}">修改</a></td>

    </tr>
    </c:forEach>
    </table>
    </form>
    </body>
    </html>
  • 一个foreach遍历传入的itemsList

配置Handler

将编写Handler在spring容器加载
springmvc.xml

1
2
<!-- 配置Handler -->
<bean name="/queryItems_test.action" class="cn.xwmdream.ssm.controller.ItemsController1" />

配置处理器映射器

在classpath下的springmvc.xml中配置处理器映射器

1
2
3
4
<!-- 处理器映射器 将bean的name作为url进行查找 ,需要在配置Handler时指定beanname(就是url)
所有的映射器都实现 HandlerMapping接口。
-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />

  • 此时handler需要配置路径
    1
    2
    <!-- 配置Handler -->
    <bean name="/queryItems_test.action" class="cn.xwmdream.ssm.controller.ItemsController1" />

配置视图解析器

在classpath下的springmvc.xml中配置视图解析器

需要配置解析jsp的视图解析器。

1
2
3
4
5
<!-- 视图解析器
解析jsp解析,默认使用jstl标签,classpath下的得有jstl的包
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
</bean>

运行

非注解的处理器映射器和适配器

非注解的处理器映射器

BeanNameUrlHandlerMapping

  • 这个映射器是通过handler的name设置映射路径,所以handler的bean需要配置name属性(见hello world)

SimpleUrlHandlerMapping

1
2
3
4
5
6
7
8
9
10
<!--简单url映射  -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<!-- 对itemsController1进行url映射,url是/queryItems1.action -->
<prop key="/queryItems1.action">itemsController1Id</prop>
<prop key="/queryItems2.action">itemsController1Id</prop>
</props>
</property>
</bean>
  • 这个映射器是通过参数的方式配置路径,值是handler的id,所以handler需要配置id
1
2
<!-- 配置Handler -->
<bean id="itemsController1Id" class="cn.xwmdream.ssm.controller.ItemsController1" />
  • 多个映射器可以并存,前端控制器判断url能让哪些映射器映射,就让正确的映射器处理。

非注解的处理器适配器

SimpleControllerHandlerAdapter

  • 配置适配器

    1
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
  • 要求编写的Handler实现 Controller接口(见hello world)

HttpRequestHandlerAdapter

  • 配置适配器

    1
    <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter" />
  • 要求编写的Handler实现 HttpRequestHandler接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    @Override
    public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //调用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 联想笔记本电脑!");

    Items items_2 = new Items();
    items_2.setName("苹果手机");
    items_2.setPrice(5000f);
    items_2.setDetail("iphone6苹果手机!");

    itemsList.add(items_1);
    itemsList.add(items_2);
    //转发数据
    request.setAttribute("itemsList",itemsList);
    request.getRequestDispatcher("/WEB-INF/jsp/item/itemsList.jsp").forward(request,response);
    }
  • 使用此方法可以通过修改response,设置响应的数据格式,比如响应json数据(通过getWriter,类似servlet)

    1
    2
    3
    response.setCharacterEncoding("utf-8");
    response.setContentType("application/json;charset=utf-8");
    response.getWriter().write("json串");

DispatcherSerlvet.properties

  • 如果不在springmvc.xml中配置处理映射器、适配器、视图解析器等组件,使用默认加载的。
  • 默认加载的文件
    图片丢失
  • 这里面配置了多个映射器适配器视图解析器等组件,如果项目中没有指定会对应不同版本加载不同的默认组件

注解的处理器映射器和适配器

默认映射器

在spring3.1之前使用org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping注解映射器。
在spring3.1之后使用org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping注解映射器。

默认适配器

在spring3.1之前使用org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter注解适配器。
在spring3.1之后使用org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter注解适配器。

配置注解映射器和适配器

1
2
3
4
<!--注解映射器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />
<!--注解适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" />
  • 当然也可以换一种方式加载
    1
    2
    3
    4
    5
    6
    <!-- 使用 mvc:annotation-driven代替上边注解映射器和注解适配器配置
    mvc:annotation-driven默认加载很多的参数绑定方法,
    比如json转换解析器就默认加载了,如果使用mvc:annotation-driven不用配置上边的RequestMappingHandlerMapping和RequestMappingHandlerAdapter
    实际开发时使用mvc:annotation-driven
    -->
    <mvc:annotation-driven></mvc:annotation-driven>

开发注解Handler

  • cn.xwmdream.ssm.controller.ItemsController1
    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
    //使用Controller标识 它是一个控制器
    @Controller
    public class ItemsController1 {
    // 商品查询列表
    // @RequestMapping实现 对queryItems方法和url进行映射,一个方法对应一个url
    // 一般建议将url和方法写成一样
    @RequestMapping("/queryItems")
    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 联想笔记本电脑!");

    Items items_2 = new Items();
    items_2.setName("苹果手机");
    items_2.setPrice(5000f);
    items_2.setDetail("iphone6苹果手机!");

    itemsList.add(items_1);
    itemsList.add(items_2);

    // 返回ModelAndView
    ModelAndView modelAndView = new ModelAndView();
    // 相当 于request的setAttribut,在jsp页面中通过itemsList取数据
    modelAndView.addObject("itemsList", itemsList);

    // 指定视图
    modelAndView.setViewName("/WEB-INF/jsp/item/itemsList.jsp");
    return modelAndView;
    }
    }

加载注解handler

1
2
3
4
5
6
7
8
<!-- 对于注解的Handler可以单个配置
实际开发中建议使用组件扫描
-->
<!-- <bean class="cn.itcast.ssm.controller.ItemsController3" /> -->
<!-- 可以扫描controller、service、...
这里让扫描controller,指定controller的包
-->
<context:component-scan base-package="cn.xwmdream.ssm.controller"></context:component-scan>

调试

访问:http://localhost:8080/TestSpringMvc/queryItems.action

  • 记得后面的.action

视图解析器

1
2
3
4
5
6
7
8
9
10
<!-- 视图解析器
解析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>
  • 可以配置前缀和后缀,比如要访问/WEB-INF/jsp/item/itemsList.jsp时候,只需要指定item/itemsList即可

源码分析(了解)

通过前端控制器源码分析springmvc的执行过程。

  1. 前端控制器接收请求
    调用doDiapatch

  2. 前端控制器调用处理器映射器查找 Handler

  3. 调用处理器适配器执行Handler,得到执行结果ModelAndView

  4. 视图渲染,将model数据填充到request域。
    视图解析,得到view:
    调用view的渲染方法,将model数据填充到request域