专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

Spring MVC学习笔记

内容输出来源:拉勾教育Java高薪训练营

Spring MVC 是 Spring 给我们提供的⼀个⽤于简化 Web 开发的框架。

第一章 Spring MVC应用

1. Spring MVC简介

1.1. MVC体系结构

1.1.1 经典三层架构(代码架构)

我们的开发架构⼀般都是基于两种形式,⼀种是C/S架构,也就是客户端/服务器;另⼀种是B/S架构,也就是浏览器/服务器。在JavaEE开发中,⼏乎全都是基于B/S架构的开发。那么在B/S架构中,系统标准的三层架构包括:表现层业务层持久层

  • 表现层

    也就是web层。负责接收客户端请求,向客户端响应结果。
    表现层分为展示层(view)和控制层(controller):控制层负责接收请求,展示层负责结果的展示。
    表现层依赖于业务层。

  • 业务层

    也就是我们常说的service层。负责业务逻辑处理。
    表现层依赖于业务层,但业务层不依赖于表现层。
    业务层可能会依赖于持久层。

  • 持久层

    也就是我们是常说的dao层。
    负责数据持久化,包括数据层即数据库和数据访问层。
    通俗的讲,持久层就是和数据库交互,对数据库表进⾏增删改查的。

1.1.2 MVC设计模式(代码的组织方式/形式)

MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是⼀ 种⽤于设计创建Web应⽤程序表现层的模式。

  • Mode(模型)

    模型包含业务模型和数据模型,数据模型⽤于封装数据,业务模型⽤于处理业务。

  • View(视图)

    通常指的就是我们的 jsp 或者 html。作⽤⼀般就是展示数据的。通常视图是依据 模型数据创建的。

  • Controller(控制器)

    是应⽤程序中处理⽤户交互的部分。作⽤⼀般就是处理程序逻辑的。

MVC提倡:每⼀层只编写⾃⼰的东⻄,不编写任何其他的代码;分层是为了解耦,解耦是为了维护⽅便和分⼯协作。

1.2. Spring MVC是什么

SpringMVC 全名叫 Spring Web MVC,是⼀种基于Java的实现MVC设计模型的请求驱动类型的轻量级Web框架,属于SpringFrameWork的后续产品。

Spring MVCStruts2都是一个表现层框架,他们都是基于MVC设计模式的,主要负责处理前端的HTTP请求

Spring MVC的本质是对Servlet的封装。

Spring MVC的作用:

    1. 接收请求
    1. 返回响应,跳转页面

79_1.png

2. Spring MVC ⼯作流程

需求:前端浏览器请求url:http://localhost:8080/demo/handle01 ,前端⻚⾯显示后台服务器的时间

    1. 配置DispatcherServlet前端控制器
<!--第一步:配置前端控制器DispatcherServlet-->
  <servlet>
      <servlet-name>springmvc</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      <!--第四步:将xml文件地址告诉Spring MVC(DispatcherServlet)-->
      <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>classpath:springmvc.xml</param-value>
      </init-param>
  </servlet>

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

    <!--
      方式一:带后缀,比如*.action, *.do, *.aaa
      方式二:/ 不包括.jsp
      方式三:/* 拦截所有,包括.jsp
    -->
    <url-pattern>/</url-pattern>
  </servlet-mapping>

    1. 开发处理具体业务逻辑的Handle@Controller@RequestMapping
/**
 * 第二步:开发处理具体业务逻辑的`Handle`
 */
@Controller
@RequestMapping("/demo")
public class DemoController {

    /**
     * url: http:localhost:8080/demo/handle01
     */
    @RequestMapping("/handle01")
    public ModelAndView handle01() {
        Date date = new Date();     //服务器时间
        System.out.println(date);
        //返回服务器时间到前端页面
        ModelAndView modelAndView = new ModelAndView();
        // addObject 其实是向请求域总设置参数  request.setAttribute("date",date)
        modelAndView.addObject("date",date);
        modelAndView.setViewName("success");
        return modelAndView;
    }
}

    1. xml文件配置controller扫描,配置spring web mvc三大件(视图解析器、处理器映射器、处理器适配器)
<?xml version="1.0" encoding="UTF-8"?>
<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"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--第三步:xml文件配置`controller`扫描,配置**spring web mvc**三大件(视图解析器、处理器映射器、处理器适配器)-->
    <!--开启controller扫描-->
    <context:component-scan base-package="com.lzx.controller"/>

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

    <!--自动注册最合适的处理器映射器,处理器适配器-->
    <mvc:annotation-driven/>
</beans>

    1. 将xml文件地址告诉Spring MVC(DispatcherServlet
    <!--第四步:将xml文件地址告诉Spring MVC(DispatcherServlet)-->
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc.xml</param-value>
    </init-param>

2.1. Spring MVC请求处理流程

79_2.png

流程说明

  • 第⼀步:⽤户发送请求⾄前端控制器DispatcherServlet
  • 第⼆步:DispatcherServlet收到请求调⽤HandlerMapping处理器映射器
  • 第三步:处理器映射器根据请求Url找到具体的Handler后端控制器),⽣成处理器对象及处理器拦截器(如果有则⽣成)⼀并返回DispatcherServlet
  • 第四步:DispatcherServlet调⽤HandlerAdapter处理器适配器去调⽤Handler
  • 第五步:处理器适配器执⾏Handler
  • 第六步:Handler执⾏完成给处理器适配器返回ModelAndView
  • 第七步:处理器适配器前端控制器返回 ModelAndViewModelAndViewSpringMVC 框架的⼀个底层对象,包括 ModelView
  • 第⼋步:前端控制器请求视图解析器去进⾏视图解析,根据逻辑视图名来解析真正的视图。
  • 第九步:视图解析器前端控制器返回View
  • 第⼗步:前端控制器进⾏视图渲染,就是将模型数据(在ModelAndView对象中填充到 request
  • 第⼗⼀步:前端控制器向⽤户响应结果

2.2. Spring MVC九大组件

  • HandlerMapping(处理器映射器)

    HandleMapping是用来查找Handler(处理器)的,Handler可以是一个类也可以是一个方法,标注了@RequestMapping注解的方法就是一个HandlerHandler负责具体实际的请求处理,HandleMapping的作用就是请求到来时,查找到请求相应的处理器HandlerInterceptor

  • HandlerAdapter(处理器适配器)

    HandlerAdapter是一个处理器适配器,因为Spring MVC中的Handler是任意形式的,只要能处理请求就可以,而把请求交给ServletServlet的方法结构都是doService(HttpServletRequest request,HttpServletResponse response)形式的,要让固定的Servlet处理方法调用Handler来进行处理,便是HandlerAdapter的指责。

  • HandlerExceptionResolve(处理器异常解析器)

    HandlerExceptionResolve是处理Handler异常情况的。它的作⽤是根据异常设置 ModelAndView,之后交给渲染⽅法进⾏渲染,渲染⽅法会将 ModelAndView 渲染成⻚⾯。

  • ViewResolve(视图解析器)

    ⽤于将String类型的视图名Locale解析为View类型的视图,只有⼀个resolveViewName()⽅法。ViewResolver 在这个过程主要完成两件事情:ViewResolver 找到渲染所⽤的模板(第⼀件⼤事)和所⽤的技术(第⼆件⼤事,其实也就是找到视图的类型,如JSP)并填⼊参数。默认情况下,Spring MVC会⾃动为我们配置⼀个InternalResourceViewResolver,是针对 JSP 类型视图的。

  • RequestToViewNameTranslator(请求转视图名转换器)

    它的作用是从请求中获取ViewName,因为ViewResolve是根据ViewName来查找View,但有时候Handler处理完后没有设置View,也没有设置ViewName,这时就需要这个组件从请求中查找ViewName

  • LocaleResolve(国际化解析器)

    用来处理国际化的一些东西。ViewResolver 组件的 resolveViewName ⽅法需要两个参数,⼀个是视图名,⼀个是 LocaleLocaleResolver ⽤于从请求中解析出 Locale,⽐如中国 Localezh-CN,⽤来表示⼀个区域。这个组件也是 i18n 的基础。

  • ThemeResolve(主题解析器)

    ThemeResolver 组件是⽤来解析主题的。主题是样式、图⽚及它们所形成的显示效果的集合。Spring MVC 中⼀套主题对应⼀个 properties⽂件,⾥⾯存放着与当前主题相关的所有资源,如图⽚、CSS样式等。创建主题⾮常简单,只需准备好资源,然后新建⼀个“主题名.properties”并将资源设置进去,放在classpath下,之后便可以在⻚⾯中使⽤了。SpringMVC中与主题相关的类有ThemeResolverThemeSourceThemeThemeResolver负责从请求中解析出主题名,ThemeSource根据主题名找到具体的主题,其抽象也就是Theme,可以通过Theme来获取主题和具体的资源。

  • MultipartResolve(多元素解析器)

    MultipartResolver ⽤于上传请求,通过将普通的请求包装成 MultipartHttpServletRequest 来实现。MultipartHttpServletRequest 可以通过 getFile() ⽅法直接获得⽂件。如果上传多个⽂件,还可以调⽤ getFileMap()⽅法得到Map<FileName,File>这样的结构,MultipartResolver 的作⽤就是封装普通的请求,使其拥有⽂件上传的功能。

  • FlashMapManager

    FlashMap ⽤于重定向时的参数传递,⽐如在处理⽤户订单时候,为了避免重复提交,可以处理完post请求之后重定向到⼀个get请求,这个get请求可以⽤来显示订单详情之类的信息。
    这样做虽然可以规避⽤户重新提交订单的问题,但是在这个⻚⾯上要显示订单的信息,这些数据从哪⾥来获得呢?因为重定向时么有传递参数这⼀功能的,如果不想把参数写进URL(不推荐),那么就可以通过FlashMap来传递。只需要在重定向之前将要传递的数据写⼊请求(可以通过ServletRequestAttributes.getRequest()⽅法获得)的属性OUTPUT_FLASH_MAP_ATTRIBUTE中,这样在重定向之后的HandlerSpring就会⾃动将其设置到Model中,在显示订单信息的⻚⾯上就可以直接从Model中获取数据。FlashMapManager 就是⽤来管理 FalshMap 的。

2.3. Spring MVC中的url-pattern的配置和原理剖析

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

    <!--
      方式一:带后缀,比如*.action, *.do, *.aaa
      方式二:/ 不包括.jsp
      方式三:/* 拦截所有,包括.jsp
    -->
    <url-pattern>/</url-pattern>
</servlet-mapping>

  • 问题

    上面说到<url-pattern>有三种配置方式,其中第二种配置为/,不会拦截.jsp,但是它也存在一些问题,那就是,它会拦截.html等静态资源(静态资源:除了servlet和jsp之外的js、css、pnd等)。

  • 原因

    这是因为这个配置覆写了web应用服务器(tomcat)的默认配置

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

  • 解决方案有两种

      1. 静态资源配置,方案一:如果是静态资源,交给web应用服务器去处理
    <!--静态资源配置,方案一:如果是静态资源,交给web应用服务器去处理-->
    <!--
        原理:添加该标签配置之后,会在Spring MVC上下文中定义一个DefaultServletHttpRequestHandler,
             其作用是对进入DispatcherServlet的url进行筛查,
             若发现是一个静态资源,转由web应用服务器(tomcat)默认的DefaultServlet来处理,
             若不是静态资源,继续由Spring MVC框架处理.
    -->
    <mvc:default-servlet-handler/>

 *  1.  静态资源配置,方案二:Spring MVC框架自己处理静态资源
    <!--
        静态资源配置,方案二:Spring MVC框架自己处理静态资源
            mapping: 约定的静态资源url规则
            location: 指定的静态资源存放位置
    -->
    <mvc:resources mapping="/resources/**" location="classpath:/"/>

2.4. Spring MVC的数据输出机制

SpringMVChandler方法上传入MapModelModelMap参数,并向这些参数中保存数据(放入到请求域),都能在页面获取到,原因是底层的数据封装是用的BindingAwareModelMap类,而BindingAwareModelMap类域MapModelMpdelMap的关系是这样的:

79_3.png

3. 请求参数绑定

  • SpringMVC对原⽣servlet api的⽀持

    如果要在SpringMVC中使⽤servlet原⽣对象,⽐如HttpServletRequest\HttpServletResponse\HttpSession,直接在Handler⽅法形参中声明使⽤即可。

  • SpringMVC接收简单数据类型参数

    • 接收简单数据类型参数,直接在handler⽅法的形参中声明即可,框架会取出参数值然后绑定到对应参数上。
    • 要求:传递的参数名和声明的形参名称保持⼀致
  • 绑定Pojo类型参数
    • 接收pojo类型参数,直接形参声明即可,类型就是Pojo的类型,形参名⽆所谓。
    • 要求:传递的参数名必须和Pojo的属性名保持⼀致
  • 绑定Pojo包装对象参数
    • 不管包装Pojo与否,它⾸先是⼀个pojo,那么就可以按照上述pojo的要求来
    • 绑定时候直接形参声明即可
    • 传参参数名和pojo属性保持⼀致,如果不能够定位数据项,那么通过属性名 + “.” 的⽅式进⼀步锁定数据
  • 绑定⽇期类型参数(需要配置⾃定义类型转换器
    • ⾃定义类型转换器
    package com.lzx.converter;

    import org.springframework.core.convert.converter.Converter;

    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;

    /**
     * ⾃定义日期类型转换器
     */
    public class DateConverter implements Converter<String, Date> {
        public Date convert(String source) {
            // 完成字符串向⽇期的转换
            SimpleDateFormat simpleDateFormat = new
                    SimpleDateFormat("yyyy-MM-dd");
            try {
                Date parse = simpleDateFormat.parse(source);
                return parse;
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

 *  注册自定义的类型转换器
    <!--自动注册最合适的处理器映射器,处理器适配器-->
    <mvc:annotation-driven conversion-service="conversionService"/>

    <!--注册⾃定义类型转换器-->
    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="com.lzx.converter.DateConverter"/>
            </set>
        </property>
    </bean>

4. 对 Restful ⻛格请求⽀持

4.1. 什么是RESTful

示例:
rest是⼀个url请求的⻛格,基于这种⻛格设计请求的url
没有rest的话,原有的url设计 http://localhost:8080/user/queryUserById.action?id=3
url中定义了动作(操作),参数具体锁定到操作的是谁
有了rest⻛格之后
rest中,认为互联⽹中的所有东⻄都是资源,既然是资源就会有⼀个唯⼀的uri标识它,代表它
http://localhost:8080/user/3 代表的是id为3的那个⽤户记录(资源)
锁定资源之后如何操作它呢?常规操作就是增删改查
根据请求⽅式不同,代表要做不同的操作
get 查询,获取资源
post 增加,新建资源
put 更新
delete 删除资源

4.2. (请求方式转换过滤器)表单中使用put和delete方法

由于表单中form表单中只允许getpost方法,所以需要在web.xml中配置请求⽅式过滤器(将特定的post请求转换为put和delete请求

  • 第一步,表单中添加一个method隐藏参数
<form method="post" action="/demo/handle/15/lisi">
    <!--隐藏参数指定方法-->
    <input type="hidden" name="_method" value="put"/>
    <input type="submit" value="提交rest_put请求"/>
</form>

  • 第二步,在web.xml中配置请求⽅式过滤器
    <!--配置springmvc请求⽅式转换过滤器,会检查请求参数中是否有_method参数,如果有就按照指定的请求⽅式进⾏转换-->
    <filter>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>

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

第二章 Spring MVC高级技术

1. 拦截器的使用

1.1. 拦截器、过滤器、监听器对比

  • Servlet:处理Request请求和Response响应
  • 过滤器(Filter):对Request请求起到过滤的作用,作用在Servlet之前,配置为/*可以过滤所有的资源(Servlet、js/css等静态资源)。
  • 监听器(Listener):实现了javax.servlet.ServletContextListener接口的服务器端组件,随web容器启动,只初始化一次,随后会一直运行监听,随着web容器应用的停止而销毁。
    • 作用一:做⼀些初始化⼯作,比如web应⽤中spring容器启动ContextLoaderListener
    • 作用二:监听web中的特定事件,⽐如HttpSession,ServletRequest的创建和销毁;变量的创建、销毁和修改等。
  • 拦截器(Inteceptor)

    是SpringMVC、Struts等表现层框架自己的组件,不会拦截静态资源,只会拦截访问的控制器方法Handler。
    从配置的角度看,

    • Servlet、Filter和Listener是配置在web.xml中的
    • ⽽interceptor是配置在表现层框架⾃⼰的配置⽂件中的

    拦截次数:三次

    • 在Handler业务逻辑执⾏之前拦截⼀次
    • 在Handler逻辑执⾏完毕但未跳转⻚⾯之前拦截⼀次
    • 在跳转⻚⾯之后拦截⼀次
  • 执行流程

79_4.png

1.2. 单个拦截器执行流程

79_5.png

    1. 首先执行拦截器的preHandle方法,返回true则继续向下执行Handler处理器,否则不再向下执行;
    1. Handler执行完毕后,视图未渲染之前,会执行postHandle方法;
    1. 在视图渲染完毕后,会执行afterCompletion方法。

1.3. 多个拦截器执行流程

79_6.png

假设有两个拦截器Interceptor1Interceptor2,并且在配置⽂件中,Interceptor1拦截器配置在前,如上图所示,preHandle方法按照配置顺序执行postHandleafterCompletion方法按照配置的相反顺序执行

2. 文件上传(处理multipart形式的数据)

  • 引入文件上传所需jar
    <!--⽂件上传所需jar坐标-->
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
    </dependency>

  • 配置文件上传解析器
    <!--配置文件上传解析器,id固定multipartResolver-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!--设置上传大小,单位字节-->
        <property name="maxUploadSize" value="1000000000"/>
    </bean>

3. 异常处理器

异常处理器需要实现HandlerExceptionResolver接口,现在我们一般使用注解的方式

package com.lzx.controller;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 优雅的全局异常处理
 */
@ControllerAdvice
public class GlobalExceptionResolver {

    @ExceptionHandler(ArithmeticException.class)
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("msg",e.getMessage());
        modelAndView.setViewName("error");
        return modelAndView;
    }
}

4. 基于Flash属性的跨重定向请求数据传递

重定向参数丢失有两种解决方案

  • 第一:参数上手动拼接参数
return "redirect:handle01?name=" + name;

但这种方式属于get请求,参数长度受限制,而且安全度不高。

  • 第二:使用SpringMVC提供的flash属性机制,向上下⽂中添加flash属性,框架会在session中记录该属性值,当跳转到⻚⾯之后框架会⾃动删除flash属性,不需要我们⼿动删除,通过这种⽅式进⾏重定向参数传递,参数⻓度和安全性都得到了保障
    /**
     * SpringMVC 重定向时参数传递的问题
     * 转发:A 找 B 借钱400,B没有钱但是悄悄的找到C借了400块钱给A
     * url不会变,参数也不会丢失,⼀个请求
     * 重定向:A 找 B 借钱400,B 说我没有钱,你找别⼈借去,那么A ⼜带着400块的借钱需求找到C
     * url会变,参数会丢失需要重新携带参数,两个请求
     */
    @RequestMapping("/handleRedirect")
    public String handleRedirect(String name, RedirectAttributes redirectAttributes) {
        // return "redirect:handle01?name=" + name; // 拼接参数安全性、参数⻓度都有局限
        // addFlashAttribute⽅法设置了⼀个flash类型属性,该属性会被暂存到session中,在跳转到⻚⾯之后该属性销毁
        redirectAttributes.addFlashAttribute("name",name);
        return "redirect:handle01";
    }

第三章 手写MVC框架

第四章 Spring MVC源码深度剖析

第五章 SSM整合

第六章 附录

1. 乱码问题

  • post请求乱码,web.xml中加⼊过滤器
<!-- 解决post乱码问题 -->
<filter>
    <filter-name>encoding</filter-name>
    <filter-class>
        org.springframework.web.filter.CharacterEncodingFilter
    </filter-class>
    <!-- 设置编码参是UTF8 -->
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

  • get请求乱码,修改tomcat下server.xml的配置
<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

文章永久链接:https://tech.souyunku.com/34167

未经允许不得转载:搜云库技术团队 » Spring MVC学习笔记

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们