SpringMVC

第一章 SpringMVC介绍

1.1 JavaEE经典三层架构

  • 表现层(Web层)

整个表现层负责接收客户端请求并响应结果给客户端。(Http请求)

具体说来,表现层=View视图层+Controller控制层。Controller层负责接收请求、转发请求给Service层、跳转视图页面

servlet—>Struts(过滤器)—>SpringMVC

  • 业务层(Service层)

负责业务逻辑处理,和项目需求息息相关(比如转账业务)。

Spring—>SpringBoot(全注解)

主要涉及逻辑 : 异常处理 参数处理 声明式事务AOP

  • 持久层(Dao层)

和数据库交互,对数据表进行增删改查

JDBC—> JdbcTemplate —> DButils —>MyBatis—>Spring Data JPA

主流:SSM —> 潮流:SSS(Spring全家桶)

1.2 MVC模式

M即Model模型,V即View视图,C即Controller控制器。

  1. Model的广义和狭义之说
  2. 广义:Model = Service +Dao层,由这两层来产生数据模型

狭义:Model 就是数据模型本身,就是Controller和View之间传递的数据,在这种说法下,MVC又可归为Web层。

MVC模式,是JavaEE经典三层中的Web层开发模式

1.3 SpringMVC概述

  • SpringMVC是什么
    • SpringMVC是一个轻量级的Web表现层框架,用来写Controller接收请求跳转页面的,它是Spring框架的一部分。
    • SpringMVC是对Servlet的封装和增强,简化了servlet的操作。它已经超越了Struts,成为目前最优秀的表现层框架。
  • SpringMVC能做什么
    • 接收请求
    • 跳转页面
    • 会话控制
    • 过滤拦截
    • 异步交互
    • 文件上传
    • 文件下载
    • 数据校验
    • 类型转换
  • 什么时候使用SpringMVC?
    • 当你觉得servlet繁琐的时

1.4 SpringMVC的优势

SpringMVC 是 Spring 为表述层开发提供的一整套完备的解决方案。在表述层框架历经 Strust、WebWork、Strust2 等诸多产品的历代更迭之后,目前业界普遍选择了 SpringMVC 作为 Java EE 项目表述层开发的首选方案。之所以能做到这一点,是因为 SpringMVC 具备如下显著优势:

  • Spring 家族原生产品,与 IOC 容器等基础设施无缝对接
  • 表述层各细分领域需要解决的问题全方位覆盖,提供全面解决方案
  • 内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可
  • 性能卓著,尤其适合现代大型、超大型互联网项目要求
  • 操作特简单,性能特别高,灵活性特别强

第二章 SpringMVC快速入门案例

1.1 SpringMVC的处理流程

之前:request请求到servlet,一个项目中有很多servlet,不同serlvet处理不同的事情,好比很多年前装修,业主需要直接把需求告知水工、电工、木工等。现在我们直接把需求告知包工头,包工头具体分发任务给下面的小弟(水工、电工、木工),我们不需要直接和其他人交涉。

前端控制器就类似于上面的包工头,不干具体的活,只负责接收请求,分发请求,反馈结果

SpringMVC全局只需要一个servlet。

1.jpg

1.2 案例需求

浏览器输入url发起请求,该url请求被SpringMVC框架拦截处理,把后台服务器的当前时间输出到jsp页面显示

入门案例实现分析

  • jsp页面(显示当前系统时间)
  • 前端控制器dispatcherServlet在web.xml中配置
  • 写Handler获取当前系统时间(这里的Handler就是Controller)
  • @Controller标识处理类,并配置扫描

springmvc.xml配置

 <!--包扫描-->
 <context:component-scan base-package="com.atguigu"/>
 <!--自动注册最优最合适的处理器适配器和处理器映射器-->
 <mvc:annotation-driven/>

<!--配置视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
</bean>

HelloController类

@Controller
public class HelloController {
    //请求映射,浏览器的请求地址
    @RequestMapping("sayHello")
    //ModelAndWiew模型和视图对象
    public ModelAndView sayHello(ModelAndView modelAndView){
        //键值对存储request域对象
        modelAndView.addObject("now",new Date());
        //要转发的页面
        modelAndView.setViewName("result");
        return modelAndView;
    }
}

web.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1" metadata-complete="true">
  <!--配置前端控制器,接收客户端的所有请求地址为do的-->
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--Servlet初始化参数,加载SpringMVC配置文件-->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
  </servlet>

  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>
</web-app>

1.3 SpringMVC架构流程

2.jpg

第一步:用户发送请求至前端控制器DispatcherServlet

第二步:DispatcherServlet收到请求调用HandlerMapping处理器映射器

第三步:处理器映射器根据请求Url找到具体的Handler(后端控制器),生成处理器对象及处理器拦截器(如果有则生成)一并返回DispatcherServlet

第四步:DispatcherServlet调用HandlerAdapter处理器适配器去调用Handler

第五步:处理器适配器执行Handler

第六步:Handler执行完成给处理器适配器返回ModelAndView

第七步:处理器适配器向前端控制器返回 ModelAndView,ModelAndView 是SpringMVC 框架的一个底层对象,包括 Model 和 View

第八步:前端控制器请求视图解析器去进行视图解析

根据逻辑视图名来解析真正的视图。

第九步:视图解析器向前端控制器返回View

第十步:前端控制器进行视图渲染

就是将模型数据(在 ModelAndView 对象中)填充到 request 域

第十一步:前端控制器向用户响应结果

组件说明

  • DispatcherServlet:前端控制器

    接收用户请求,响应结果,相当于中央处理器,DispatcherServlet是整个流程控制的中心,由它调用其它组件完成用户请求的处理。DispatcherServlet的存在降低了组件之间的耦合性。
    
  • HandlerMapping:处理器映射器理解为一个Map

    HandlerMapping负责根据用户请求的Url找到Handler即处理器,SpringMVC提供了不同的映射器来实现不同的映射方式,例如:实现接口方式,注解方式等。
    
  • Handler:处理器

    在SpringMVC当中有两层意思:Controller或者Controller当中的方法
    
    Handler相对于前端控制器DispatcherServlet来说是后端控制器,执行具体业务处理的,它在        DispatcherServlet的控制下处理用户的具体请求。
    
  • HandlAdapter:处理器适配器

    不同的接口类型转换成usb,体现了万物归一的思想
    

通过HandlerAdapter对Handler处理器进行执行,这是适配器模式的应用。

  • ViewResolver:视图解析器

    ViewResolver进行视图解析,首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象。
    
  • View:视图

SpringMVC框架提供了很多的View视图类型的支持,包括:jsp、html等。

注意:在SpringMVC的各个组件中,处理器映射器、处理器适配器、视图解析器称为SpringMVC的三大组件。

需要我们开发的组件有handler、view

1.4配置 mvc:annotation-driven

处理器映射器、处理器适配器我们在入门程序没有配置,也可以用,因为SprigMVC默认会给我们加载对应器,但是默认加载的器的版本Spring3.x之后已经不推荐使用了,推荐使用更好的。

我们使用很简单配置一个标签即可,SpringMVC会自动注册最合适的处理器映射器、处理器适配器.

第三章 RequestMapping注解

从注解名称上我们可以看到,@RequestMapping注解的作用就是将请求的 URL 地址和处理请求的方式关联起来,建立映射关系。

SpringMVC 接收到指定的请求,就会来找到在映射关系中对应的方法来处理这个请求。

@RequestMapping注解的属性 value,数据类型是String[],可以同时配置多个请求地址

1.1 精确匹配模式

在@RequestMapping注解指定 URL 地址时,不使用任何通配符,按照请求地方进行精确匹配。

<a href="sayHello">HelloWorld</a><br/>
@RequestMapping("/sayHello")

1.2 模糊匹配模式

在@RequestMapping注解指定 URL 地址时,通过使用通配符,匹配多个类似的地址。

<h3>测试@RequestMapping注解匹配方式</h3>
<a href="/fruit/apple">@RequestMapping模糊匹配[apple]</a><br/>
<a href="/fruit/orange">@RequestMapping模糊匹配[orange]</a><br/>
<a href="/fruit/banana}">@RequestMapping模糊匹配[banana]</a><br/>
@RequestMapping("/fruit/*")

1.3 注解作用域类上

添加到类上面(分类管理,限定类中方法访问的前缀)

<h3>测试@RequestMapping注解标记在类上</h3>
<a href="/user/login">用户登录</a><br/>
<a href="/user/register">用户注册</a><br/>
<a href="/user/logout">用户退出</a><br/>
@RequestMapping("useer")
public class User{
    @RequestMapping("login")
    public ModelAndWiew login(ModelAndWiew modelAndWiew){
        return null;
    }
    @RequestMapping("register")
    public ModelAndWiew register(ModelAndWiew modelAndWiew){
        return null;
    }
    @RequestMapping("logout")
    public ModelAndWiew logout(ModelAndWiew modelAndWiew){
        return null;
    }
}

1.4 注解的属性method

method的属性的数据类型是RequestMethod枚举类型的数组,该枚举中定义了8个静态常量。

HTTP 协议定义了八种请求方式,在 SpringMVC 中封装到了下面这个枚举类:

public enum RequestMethod {
    GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
}

前面代码中,只要求请求地址匹配即可,现在附加了请求方式后,还要求请求方式也必须匹配才可以。

<h3>测试@RequestMapping注解限定请求方式</h3>
<a href="/emp}">同地址GET请求</a><br/>
<form action="/emp" method="post">
    <button type="submit">同地址POST请求</button>
</form>
<br/>
  • 处理 GET 请求:
@RequestMapping(value = "/emp", method = RequestMethod.GET)
public ModelAndWiew empGet(ModelAndWiew modelAndWiew) {
    return modelAndWiew;
}
  • 处理 POST 请求:
@RequestMapping(value = "/emp", method = RequestMethod.POST)
public ModelAndWiew empPost(ModelAndWiew modelAndWiew) { 
    return modelAndWiew;
}

@RequestMapper注解中,不写属性method的,那么可以接收任何请求方式!

原版 进阶版
@RequestMapping(value
= “/emp”,
method = RequestMethod.GET)
@GetMapping(“/emp”)
@RequestMapping(value
= “/emp”,
method = RequestMethod.POST)
@PostMapping(“/emp”)

除了 @GetMapping、@PostMapping 还有下面几个类似的注解:

第四章 请求参数绑定

1.1 默认支持ServletAPI

可以将原生HttpServletRequest和HttpServetResponse接口作为参数,传递到handler的方法中

@RequestMapping("servlet")
public ModelAndView servletParam(HttpServletRequest request,      HttpServletResponse response,ModelAndView modelAndView){
    String name = request.getParameter("name");
    System.out.println("name = " + name);
    return modelAndView;
}

1.2 一键一值方式

绑定简单数据类型参数,只需要直接形参声明

注意:形参的参数名和传递的参数名保持一致,建议使用包装类型

<form method="post" action="/paramsName.do">
    <input type="text" name="username">
    <input type="text" name="password">
    <input type="submit">
</form>
@RequestMapping("paramsName")
public ModelAndView paramsName(String username,String password,ModelAndView modelAndView){
    System.out.println("username = " + username);
    System.out.println("password = " + password);
    return modelAndView;
}
  • 请求参数乱码问题,需要配置过滤器
 <filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>utf-8</param-value>
    </init-param>
  </filter>

  <filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

1.3 RequestParam注解

当形参和传递的参数名称不一致时使用RequestParam进行手动映射,类似于Mybatis当中国的resultMap的作用。

<form method="post" action="/paramsName.do">
    <input type="text" name="user">
    <input type="text" name="password">
    <input type="submit">
</form>
@RequestMapping("paramsName")
public ModelAndView paramsName(@RequestParam("user") String username, String password, ModelAndView modelAndView){
    System.out.println("username = " + username);
    System.out.println("password = " + password);
    return modelAndView;
}

1.4 一键多值参数

<form action="/paramsList.do" method="post">
    请选择你最喜欢的球队:
    <input type="checkbox" name="team" value="Brazil"/>巴西
    <input type="checkbox" name="team" value="German"/>德国
    <input type="checkbox" name="team" value="French"/>法国
    <input type="checkbox" name="team" value="Holland"/>荷兰
    <input type="checkbox" name="team" value="Italian"/>意大利
    <input type="checkbox" name="team" value="China"/>中国
    <br/>
    <input type="submit" value="保存"/>
</form>
@RequestMapping("paramsList")
public ModelAndView paramsList( @RequestParam("team") List<String> teamList, ModelAndView modelAndView){
    System.out.println(teamList);
    return modelAndView;
}

1.5 请求参数绑定pojo对象

  • 直接形参声明pojo即可接收
  • 要求:传递的参数名必须和pojo属性名对应
<form method="post" action="/paramsPojo.do">
    <input type="text" name="username">
    <input type="text" name="password">
    <input type="submit">
</form>
@RequestMapping("paramsPojo")
public ModelAndView paramsPojo(User user,ModelAndView modelAndView){
    System.out.println(user);
    return modelAndView;
}

1.6 请求参数绑定pojo对象的包装对象

  • 重点在于传参参数的命名
  • pojo包装对象首先就是一个普通的pojo,就应该按照上面绑定pojo的要求来,然后进一步处理,传参时参数名,首先应该定位到包装对象的属性名,如果不能确定数据,通过属性.的方式进一步锁定即可
<form method="post" action="/paramsPojoVo.do">
    <input type="text" name="user.username">
    <input type="text" name="user.password">
    <input type="submit">
</form>
@RequestMapping("paramsPojoVo")
public ModelAndView paramsPojoVo(QueryVo queryVo, ModelAndView modelAndView){
    System.out.println(queryVo);
    return modelAndView;
}

1.7 绑定List集合包装pojo对象

    <form action="/paramsPojoVoList.do" method="post">
        <table>
            <tr>
                <td>用户名</td>
                <td>密码</td>
            </tr>

            <tr>
                <td>
                    <input type="text" name="userList[0].username">
                </td>
                <td>
                    <input type="text" name="userList[0].password">
                </td>
            </tr>

            <tr>
                <td>
                    <input type="text" name="userList[1].username">
                </td>
                <td>
                    <input type="text" name="userList[1].password">
                </td>

            </tr>

            <tr>
                <td>
                    <input type="text" name="userList[2].username">
                </td>
                <td>
                    <input type="text" name="userList[2].password">
                </td>
            </tr>
        </table>
        <input type="submit">
    </form>
    @RequestMapping("paramsPojoVoList")
    public ModelAndView paramsPojoVoList(QueryVo queryVo,ModelAndView modelAndView){
        System.out.println("queryVo = " + queryVo);
        return modelAndView;
    }

1.8 绑定Map集合包装pojo对象

<form action="/paramsPojoVoMap.do" method="post">
            <table>
                <tr>
                    <td>用户名</td>
                    <td>密码</td>
                </tr>

                <tr>
                <td>
                    <input type="text" name="userMap['k1'].username">
                </td>
                <td>
                    <input type="text" name="userMap['k1'].password">
                </td>
            </tr>

            <tr>
                <td>
                    <input type="text" name="userMap['k2'].username">
                </td>
                <td>
                    <input type="text" name="userMap['k2'].password">
                </td>
            </tr>

            <tr>
                <td>
                    <input type="text" name="userMap['k3'].username">
                </td>
                <td>
                    <input type="text" name="userMap['k3'].password">
                </td>
            </tr>
            </table>
            <input type="submit">
        </form>
    @RequestMapping("paramsPojoVoMap")
    public ModelAndView paramsPojoVoMap(QueryVo queryVo,ModelAndView modelAndView){
        System.out.println("queryVo = " + queryVo);
        return modelAndView;
    }

1.9 RequestHeader注解

  • 获取请求头信息
  • 属性value,属性值为请求头的键名
@RequestMapping("sendParamsHeader")
    public ModelAndView sendParamsHeader(@RequestHeader("user-Agent") String header, ModelAndView modelAndView){
        System.out.println(header);
        return modelAndView;
    }

2.0 CookieValue注解

  • 获取浏览器携带的Cookie
  • 属性value,属性值是Cookie的键名
@RequestMapping("paramsCookie")
public ModelAndView sendParamsCookie(@CookieValue("JSESSIONID") String sessionId, ModelAndView modelAndView){
    System.out.println(sessionId);
    return modelAndView;
}