带你初窥Spring MVC的世界

提示:全民简历推广:https://www.qmjianli.com/?tg=H7IHLKZG

目 录

第1章 从Spring MVC开始

1.1 概述

早期,Web只能使用户浏览简单的静态资源,比如Html、CSS等。后来用户不再满足于只访问Html这种静态资源的现状,希望能够和服务器端进行动态的交互,即用户将所需请求发送到后端服务器,而服务器能够返回给用户所需的结果。而Servlet的出现实现了用户的愿望。
但随着时代的变迁,用户开发的项目越来越大,使用Servlet开发项目变得更加困难以及难以进行维护,用户渴望有更简单的方式简化项目开发,于是各种框架接踵而至,比如Strust、Spring MVC等。而Spring MVC是当今主流的Web开发框架。

1.2 MVC的简要介绍

1.2.1 MVC是什么?

MVC全名是Model-View-Controller,即模型-视图-控制器。其基本核心思想是分离视图页面、模型数据和业务逻辑,通过分层结构达到各层之间解耦的目的。

  1. 视图层(View):负责格式化数据并把它们呈现给用户,包括数据展示、用户交互、数据验证、界面设计等功能。
  2. 控制层(Controller):负责接收并转发请求,对请求进行处理后,指定视图并将响应结果发送给客户端。
  3. 数据模型层(Model):模型对象拥有最多的处理任务,是应用程序的主体部分,它负责数据逻辑(业务规则)的处理和实现数据操作(即在数据库中存取数据)。

1.2.2 MVC的架构图

MVC设计架构图

1.2.3 MVC的优缺点

优点:
  1. 多视图共享一个模型,大大提高了代码的可重用性
  2. MVC 三个模块相互独立,松耦合架构
  3. 控制器提高了应用程序的灵活性和可配置性
  4. 有利于软件工程化管理
缺点:
  1. 原理复杂
  2. 增加了系统结构和实现的复杂性
  3. 视图对模型数据的低效率访问

1.3 了解Spring MVC

1.3.1 介绍

Spring MVC 是一款基于 MVC 设计模式的轻量级 Web 开发框架,本质上相当于 Servlet。

1.3.2 Spring MVC的优点和功能

1.3.2.1 优点
  1. 强大的配置方式
  2. 可适配非侵入
  3. 明确的组件
  4. 可复用的代码
  5. 支持参数绑定和验证
  6. 支持处理器映射
  7. JSP表单标签库
  8. 支持国际化

1.3.3 Spring MVC的流程

1.3.3.1 流程结构图

Spring MVC流程

1.3.3.2 流程介绍
  1. 用户通过浏览器发起 HttpRequest 请求到前端控制器 (DispatcherServlet)。
  2. DispatcherServlet 将用户请求发送给处理器映射器 (HandlerMapping)。
  3. 处理器映射器 (HandlerMapping)会根据请求,找到负责处理该请求的处理器,并将其封装为处理器执行链 返回 (HandlerExecutionChain) 给 DispatcherServlet
  4. DispatcherServlet 会根据 处理器执行链 中的处理器,找到能够执行该处理器的处理器适配器(HandlerAdaptor) --注,处理器适配器有多个
  5. 处理器适配器 (HandlerAdaptoer) 会调用对应的具体的 Controller
  6. Controller 将处理结果及要跳转的视图封装到一个对象 ModelAndView 中并将其返回给处理器适配器 (HandlerAdaptor)
  7. HandlerAdaptor 直接将 ModelAndView 交给 DispatcherServlet ,至此,业务处理完毕
  8. 业务处理完毕后,我们需要将处理结果展示给用户。于是DisptcherServlet 调用 ViewResolver,将 ModelAndView 中的视图名称封装为视图对象
  9. ViewResolver 将封装好的视图 (View) 对象返回给 DIspatcherServlet
  10. DispatcherServlet 调用视图对象,让其自己 (View) 进行渲染(将模型数据填充至视图中),形成响应对象 (HttpResponse)
  11. 前端控制器 (DispatcherServlet) 响应 (HttpResponse) 给浏览器,展示在页面上。

1.3.4 安装方式

1.3.4.1 使用Jar包

使用Spring提供的jar包时,需要在项目新建目录,通常会命名为lib,将jar包放入到这个目录下,并将jar包加入到类路径下。
基本jar包有六个:

  1. 四个核心jar包:
    spring-core
    spring-bean
    spring-context
    spring-expression

  2. 两个必选的web的jar包,另外两个可选
    spring-web
    spring-webmvc
    spring-websocket(可选)
    spring-webflux(可选)

1.3.4.2 使用依赖

使用maven等构建工具构建项目,可向pom.xml文件加入spring mvc 的依赖。

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

注意:可以自己选择版本号

额外可能需要的依赖:

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
        <scope>provided</scope>
    </dependency>
    
	<dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>

    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.2</version>
        <scope>provided</scope>
    </dependency>

第2章 对Spring MVC提供的控制器的使用

2.1 控制器介绍

控制器是Spring MVC的核心部分。用户的请求经DispatcherServiet负责分发给Controller。Controller根据请求将Model进行处理。

2.2 spring MVC的配置

2.2.1 使用XML的配置

2.2.1.1 对web容器的配置

针对Spring mvc的配置文件存放位置不同,将有三种配置方式:

  1. 将Spring MVC的配置文件及Spring框架的其他文件存放至 WEB-INF目录下,此时文件名必须为 [servlet-name]-servlet.xml。因为根据servlet-name标签的值,springmvc 默认会去WEB-INF下 找叫做-servlet.xml的配置文件。(注:这里的[servlet-name]是web.xml文件中的servlet-name标签的值)
<?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_4_0.xsd"
         version="4.0">
         
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

注:通常情况访问html页面时,首先从当前web项目的web.xml文件寻找匹配的路径,如果没有找到,再从tomcat默认的web.xml匹配,将使用缺省的servlet。

  1. 将Spring MVC的配置文件及Spring框架的其他文件存放至 WEB-INF目录下,此时且文件名可以任意定义,但是 必须与 param-value标签的值 保持一致。
<?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_4_0.xsd"
         version="4.0">
         
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>namespace</param-name>
            <param-value>springmvc配置的文件名</param-value>
        </init-param>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
  1. 使用这种配置时,若是非maven构建的web项目,spring mvc及spring等其他的配置需要放在src的目录下(当然也可以在src下创建一个文件夹,用于放置这些配置文件,如:src/config/spring-dao.xml); 若是maven构建的web项目,spring mvc及spring其他的配置文件需要放在 resources 目录下(当然可以在resouces下创建文件夹,用于放置这些文件,如:resources/config/spring-dao.xml)。且文件名可以任意定义。
    注:也可以放在WEB-INF下,此时 param-value标签的值 /WEB-INF/spring-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_4_0.xsd"
         version="4.0">

    <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:spring-web.xml</param-value>
            
            <!-- 若需要加载多个文件时,使用以下方法 -->
            <!--
                方法一:
                    <param-value>classpath:spring-*.xml</param-value>
                
                方法二:
                    <param-value>classpath:spring-xxxxx.xml,classpath:spring-xxx.xml,classpath:spring-xxxx.xml</param-value>
            -->
            
            <!-- <param-value>classpath*:spring-web.xml</param-value> -->
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
2.2.1.2 对spring 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/beans/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/beans/spring-mvc.xsd">

    <!-- 扫描组件 -->
    <context:component-scan base-package="com.dc18669.aboutconfig.controller" />
    <!--开启注解驱动 -->
    <mvc:annotation-driven />

    <!-- ==================================================================  -->
    <!--    thymeleaf视图解析器-->
    <!--    配置视图解析器-->
    <!--
    <bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
        <property name="characterEncoding" value="UTF-8"></property>
        <property name="templateEngine">
            <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
                <property name="templateResolver">
                    <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
                        &lt;!&ndash; 视图前缀 &ndash;&gt;
                        <property name="prefix" value="/WEB-INF/templates/"/>
                        &lt;!&ndash; 视图后缀 &ndash;&gt;
                        <property name="suffix" value=".html"/>
                        <property name="templateMode" value="HTML5"/>
                        <property name="characterEncoding" value="UTF-8"/>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>
    -->

    <!-- ==================================================================  -->
    <!-- JSP视图解析器
        以下URLBasedViewResolver,InternalResourceViewResolver两种选其一即可
     -->
    <!-- URLBasedViewResolver -->
    <!--
    <bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceViewResolver"/> &lt;!&ndash;不能省略&ndash;&gt;
        &lt;!&ndash;前缀&ndash;&gt;
        <property name="prefix" value="/WEB-INF/jsp/"/>
        &lt;!&ndash;后缀&ndash;&gt;
        <property name="suffix" value=".jsp"/>
    </bean>
    -->


    <!-- InternalResourceViewResolver -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceViewResolver"/> <!--可以省略-->
        <!--前缀-->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!--后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>

    <!-- ==================================================================  -->
    <!-- freemarker模板 视图解析器
     -->
    <!-- FreeMarkerViewResolver -->
    <bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
        <property name="prefix" value="fm_"/>
        <property name="suffix" value=".ftl"/>
    </bean>
    <bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
        <property name="templateLoaderPath" value="/WEB-INF/ftl" />
    </bean>

    <!-- ==================================================================  -->
    <!-- 类型转换器 -->
    <!--
            Spring MVC 框架的 Converter<S,T> 是一个可以将一种数据类型转换成另一种数据类型的接口,
        这里 S 表示源类型,T 表示目标类型。开发者在实际应用中使用框架内置的类型转换器基本上就够了,
        但有时需要编写具有特定功能的类型转换器。

        内置类型转换器


        Spring MVC除了提供内置转换器外,允许用户自定义类型转换器
            自定义类型转换器
                需要以下几个步骤
                    1. 创建自定义类型转换器类,实现Converter<S,T>。
                    2. 注册类型转换器。
                    3. 创建相关视图。
     -->
    <mvc:annotation-driven conversion-service="conversionService" />
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <list>
                <bean class="com.dc18669.aboutconfig.converter.AboutConfigConverter" />
                <!-- 此处可以添加多个类型转换器 -->
            </list>
        </property>
    </bean>

    <!-- ==================================================================  -->
    <!-- 数据格式化 -->
    <!--
        Spring MVC 框架的 Formatter<T> 与 Converter<S, T> 一样,
        也是一个可以将一种数据类型转换成另一种数据类型的接口。
        不同的是,Formatter 的源类型必须是 String 类型,
        而 Converter 的源类型可以是任意数据类型。
        Formatter 更适合 Web 层,
        而 Converter 可以在任意层中。
        所以对于需要转换表单中的用户输入的情况,
        应该选择 Formatter,而不是 Converter。

        内置的格式化转换器
            Spring MVC 提供了几个内置的格式化转换器,具体如下。
            NumberFormatter:实现 Number 与 String 之间的解析与格式化。
            CurrencyFormatter:实现 Number 与 String 之间的解析与格式化(带货币符号)。
            PercentFormatter:实现 Number 与 String 之间的解析与格式化(带百分数符号)。
            DateFormatter:实现 Date 与 String 之间的解析与格式化。
        自定义格式化转换器
            自定义格式化转换器就是编写一个实现 org.springframework.format.Formatter 接口的 Java 类。该接口声明如下。
                public interface Formatter<T>
            这里的 T 表示由字符串转换的目标数据类型。该接口有 parse 和 print 两个接口方法,自定义格式化转换器类必须覆盖它们。
                public T parse(String s, java.util.Locale locale)
                public String print(T object, java.util.Locale locale)
            parse 方法的功能是利用指定的 Locale 将一个 String 类型转换成目标类型,print 方法与之相反,用于返回目标对象的字符串表示。
    -->
    <!--
    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="formatters">
            <list>
                <bean class="com.dc18669.aboutconfig.formatter.AboutConfigFormatter"/>
            </list>
        </property>
    </bean>
    -->
    <!-- 类型转换器和数据格式化,从bean的id上来看,两者不能同时被注册 -->

    <!-- ==================================================================  -->
    <!-- Spring MVC JSON数据交互 -->
    <mvc:annotation-driven>
        <!--配置@ResponseBody由fastjson解析 -->
        <mvc:message-converters>
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <property name="defaultCharset" value="UTF-8" />
            </bean>
            <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4" />
        </mvc:message-converters>
    </mvc:annotation-driven>
    <bean id="fastJsonpResponseBodyAdvice" class="com.alibaba.fastjson.support.spring.FastJsonpResponseBodyAdvice">
        <constructor-arg>
            <list>
                <value>callback</value>
                <value>jsonp</value>
            </list>
        </constructor-arg>
    </bean>

    <!-- ==================================================================  -->
    <!-- 与上述二选其一 -->
    <!-- Jackson使用 -->
    <!--
    <mvc:annotation-driven>
        <mvc:message-converters register-defaults="true">
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <constructor-arg value="UTF-8"/>
            </bean>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="objectMapper">
                    <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                        <property name="failOnEmptyBeans" value="false"/>
                    </bean>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
    -->


    <!-- ==================================================================  -->
    <!-- Spring MVC拦截器(Interceptor) -->
    <!-- Spring MVC 的拦截器(Interceptor)与 Java Servlet 的过滤器(Filter)类似,
        它主要用于拦截用户的请求并做相应的处理,通常应用在权限验证、记录请求信息的日志、判断用户是否登录等功能上。

        拦截器的定义
                在 Spring MVC 框架中定义一个拦截器需要对拦截器进行定义和配置,主要有以下 2 种方式。
            通过实现 HandlerInterceptor 接口或继承 HandlerInterceptor 接口的实现类(例如 HandlerInterceptorAdapter)来定义;
            通过实现 WebRequestInterceptor 接口或继承 WebRequestInterceptor 接口的实现类来定义。
    -->
    <mvc:interceptors>
        <!-- 配置一个全局拦截器,拦截所有请求 -->
        <bean class="com.dc18669.aboutconfig.interceptor.GbInterceptor" />
        <mvc:interceptor>
            <!-- 配置拦截器作用的路径 -->
            <mvc:mapping path="/**"/>
            <!-- 配置不需要拦截作用的路径 -->
            <!-- <mvc:exclude-mapping path="" /> -->
            <!-- 定义<mvc:interceptor>元素中,表示匹配指定路径的请求才进行拦截 -->
            <bean class="com.dc18669.aboutconfig.interceptor.AboutConfigInterceptor" />
        </mvc:interceptor>
        <!-- 还可以配置其他的拦截器 -->
    </mvc:interceptors>

    <!-- ==================================================================  -->
    <!-- Spring MVC 异常处理 -->
    <!--
        在 Spring MVC 应用的开发中,不管是操作底层数据库,还是业务层或控制层,都会不可避免地遇到各种可预知的、不可预知的异常。我们需要捕捉处理异常,才能保证程序不被终止。

          Spring MVC 有以下 3 种处理异常的方式(选其一即可):
            1. 使用 Spring MVC 提供的简单异常处理器 SimpleMappingExceptionResolver。
            2. 实现 Spring 的异常处理接口 HandlerExceptionResolver,自定义自己的异常处理器。
            3. 使用 @ExceptionHandler 注解实现异常处理.
                注意:该注解不是加在产生异常的方法上,而是加在处理异常的方法上。
                被 @ExceptionHandler 标记为异常处理方法,不能在方法中设置别的形参。但是可以使用 ModelAndView 向前台传递数据。
    -->
    <!-- 方法二:HandlerExceptionResolver
        Spring MVC 通过 HandlerExceptionResolver 处理程序异常,包括处理器异常、数据绑定异常以及控制器执行时发生的异常。HandlerExceptionResolver 仅有一个接口方法
        发生异常时,Spring MVC 会调用 resolveException() 方法,并转到 ModelAndView 对应的视图中,返回一个异常报告页面反馈给用户。
    -->
    <!-- <bean class="com.dc18669.aboutconfig.except.MyExceptionHandler"/> -->

    <!-- 方法一:SimpleMappingExceptionResolver
        全局异常处理可使用 SimpleMappingExceptionResolver 来实现。它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常。
    -->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <!-- 定义默认的异常处理页面,当该异常类型注册时使用 -->
        <property name="defaultErrorView" value="error"/>
        <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception -->
        <property name="exceptionAttribute" value="ex"/>
        <!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常页名作为值 -->
        <property name="exceptionMappings">
            <props>
                <prop key="ArithmeticException">error</prop>
                <!-- 在这里还可以继续扩展对不同异常类型的处理 -->
            </props>
        </property>
    </bean>

    <!-- ==================================================================  -->
    <!-- Spring MVC 文件上传 -->
    <!--
        Spring MVC 框架的文件上传基于 commons-fileupload 组件,并在该组件上做了进一步的封装,简化了文件上传的代码实现,取消了不同上传组件上的编程差异。

        MultipartResolver接口
            在 Spring MVC 中实现文件上传十分容易,它为文件上传提供了直接支持,即 MultpartiResolver 接口。MultipartResolver 用于处理上传请求,将上传请求包装成可以直接获取文件的数据,从而方便操作。

        MultpartiResolver 接口有以下两个实现类:
            StandardServletMultipartResolver:使用了 Servlet 3.0 标准的上传方式。
            CommonsMultipartResolver:使用了 Apache 的 commons-fileupload 来完成具体的上传操作。

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.2.2</version>
        </dependency>
    -->
    <bean id="multipartResolver"
          class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="5000000" />
        <property name="defaultEncoding" value="UTF-8" />
    </bean>

    <!-- ==================================================================  -->
    <!-- 使用resources过滤掉不需要dispatcherservlet的资源(即静态资源,例如css、js、html、images)。
    在使用resources时必须使用annotation-driven,否则resources元素会阻止任意控制器被调用 -->
    <!-- 允许js目录下的所有文件可见 -->
    <mvc:default-servlet-handler />
    <mvc:resources location="/" mapping="/**" />
</beans>

2.2.2 使用Java代码配置

2.2.2.1 对Web容器的配置(有两种)
方式一: 实现WebApplicationInitializer接口
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

/**
 * -类名可以自定义
 * -WEB容器配置类(使用此类后,就无需使用web.xml文件)
 * -此类相当于 web.xml
 * -在spring mvc中使用此类时,需要实现spring mvc框架提供的 WebApplicationInitializer 接口,
 * -Servlet3.0 以后支持
 * -AbstractAnnotationConfigDispatcherServletInitializer
 */
public class MyWebApplicationInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        // 构建一个application context
        AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
        //
        ac.register(SpringMVC.class);  // spring mvc 及spring 其他的配置类
        ServletRegistration.Dynamic dynamic = servletContext.addServlet("spring-mvc", new DispatcherServlet(ac));
        // dynamic.addMapping("*.html", "*.ajax", "*.css", "*.js", "*.gif", "*.jpg", "*.png");
        dynamic.addMapping("/");
        // dynamic.setLoadOnStartup(1);
        // dynamic.setMultipartConfig(new MultipartConfigElement(null, MAX_FILE_UPLOAD_SIZE, MAX_REQUEST_SIZE, FILE_SIZE_THRESHOLD));
    }
}
方式二: 继承于AbstractAnnotationConfigDispatcherServletInitializer类
package com.dc18669.aboutconfig.configs;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import javax.servlet.*;

public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        super.onStartup(servletContext);
    }

    /**
     * -在Spring中,应用上下文(ApplicationContext)的实例是可以范围化(Scoped)的,
     * -在Web MVC框架中,每个DispatcherServlet都可以有自己的Web应用上下文(WebApplicationContext),
     * -每个DispatcherServlet自己的WebApplicationContext继承所有的在根应用上下文中的bean。
     * -根应用上下文应该包含在其他DispatcherServlet中会用到的bean,比如DataSource等,
     * -这些在根应用上下文中的bean可以在DispatcherServlet自己的WebApplicationContext中被重载。
     *
     * @return
     */
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{RootConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMvcConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    @Override
    protected Filter[] getServletFilters() {
        return super.getServletFilters();
    }

    /**
     * -1.服务器启动时,配置文件上传的参数
     *
     * @param registration the {@code DispatcherServlet} registration to be customized
     */
    @Override
    protected void customizeRegistration(ServletRegistration.Dynamic registration) {
        // 需要在Spring MVC 配置类中进行注册
        MultipartConfigElement config = new MultipartConfigElement(null, 1024 * 1024 * 2, 1024 * 1024 * 4, 2);
        registration.setMultipartConfig(config);
    }
}
2.2.2.2 对Spring MVC的配置
package com.dc18669.aboutconfig.configs;

import com.dc18669.aboutconfig.converter.AboutConverter;
import com.dc18669.aboutconfig.interceptor.AboutInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ConversionServiceFactoryBean;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.support.FormattingConversionServiceFactoryBean;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.view.JstlView;
import org.springframework.web.servlet.view.UrlBasedViewResolver;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ITemplateResolver;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;

import java.util.LinkedList;
import java.util.List;

/**
 * =====================================================
 *
 * @Configuration 用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,
 * 这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,
 * 并用于构建bean定义,初始化Spring容器。
 * <p>
 * <p>
 * <p>
 * =======================================================
 * @EnableWebMvc 在@Configuration注解的配置类中添加,
 * 用于为该应用添加SpringMVC的功能,即添加之后可以在项目中,
 * 可以使用@RequestMapping,@Controller等注解来定义请求处理与请求uri的映射和其他SpringMvc提供的功能
 * <p>
 * 作用:
 * 1. 提供了SpringMVC的默认配置。(导入 WebMvcConfigurationSupport的配置)
 * 2. 如果存在多个@Configuration注解的类,则只能在其中一个类添加这个注解。
 * 而其他注解类如果需要自定义SpringMVC的配置来替代默认配置,则可以通过实现WebMvcConfigurer接口来支持。
 * 或者在@EnableWebMvc注解的类自身来实现WebMvcConfigurer接口,然后在该类中重写需要覆盖的默认配置所对应的方法或者添加相关配置。
 * <p>
 * 最佳实践:整个项目对于SpringMVC相关的配置,只使用一个配置类,在这个配置类使用@EnableWebMvc注解,
 * 并实现WebMvcConfigurer接口来自定义需要重写的默认配置,如通过addResourceHandlers方法来自定义静态资源的访问,
 * 默认是所有请求都是使用DispatcherSerlvet来处理,静态资源访问会404。示例如下:
 * <p>
 * public void addResourceHandlers(final ResourceHandlerRegistry registry) {
 * // addResourceHandler:配置匹配的静态资源的请求路径
 * // addResourceLocations:配置静态资源的位置
 * // 即请求路径为/static/**的请求都在/resources/目录查找
 * registry.addResourceHandler("/static/**").addResourceLocations("/resources/");
 * }
 * <p>
 * <p>
 * <p>
 * <p>
 * WebMvcConfigurationSupport与 DelegatingWebMvcConfiguration
 * 1. 除了可以在配置类加上@EnableWebMvc注解之外,也可以直接继承WebMvcConfigurationSupport或DelegatingWebMvcConfiguration,
 * 而不使用@EnableWebMvc注解,因为@EnableWebMvc内部也是使用WebMvcConfigurationSupport来完成SpringMVC默认配置的添加的。
 * <p>
 * 2. 如果是使用继承这两个类的方式,则需要在该子类中添加上@Configuration注解。对于覆盖的方法,
 * 如果父类方法存在@Bean注解,则在该子类对应的方法也要加上@Bean注解。
 * <p>
 * 3. 继承WebMvcConfigurationSupport:如果项目中没有通过使用WebMvcConfigurer接口的实现类来提供SpringMVC的配置,
 * 则可以只使用一个WebMvcConfigurationSupport的子类来启动和自定义SpringMVC的功能。
 * 因为@EnableWebMvc其实还有一个功能是汇集项目中所有实现了WebMvcConfigurer接口的类。
 * 而WebMvcConfigurationSupport是没有汇集项目中WebMvcConfigure接口实现类的功能的。示例如下:
 * @Configuration
 * @ComponentScan(basePackageClasses = { MyConfiguration.class })
 * public class MyConfiguration extends WebMvcConfigurationSupport {
 * @Override public void addFormatters(FormatterRegistry formatterRegistry) {
 * formatterRegistry.addConverter(new MyConverter());
 * }
 * @Bean public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
 * // Create or delegate to "super" to create and
 * // customize properties of RequestMappingHandlerAdapter
 * }
 * }
 * <p>
 * <p>
 * 4. 继承DelegatingWebMvcConfiguration:DelegatingWebMvcConfiguration是WebMvcConfigurationSupport的拓展子类,
 * 如果项目中也存在其他实现WebMvcConfigurer接口来提供配置的类,
 * 则可以继承DelegatingWebMvcConfiguration来替代@EnableWebMvc,两者提供的功能是一样的。
 * <p>
 * 与XML方式的对比
 * 基于Java编程方式,使用@EnableWebMvc注解启用SpringMvc;
 * 与基于XML方式,在dispatcher-servlet.xml(即DispatcherServlet所在的ApplicationContext对应的配置文件)中,
 * 添加 <mvc:annotation-driven />标签的方式效果是等价的。
 * <p>
 * 实现原理
 * 注解定义
 * @Retention(RetentionPolicy.RUNTIME)
 * @Target(ElementType.TYPE)
 * @Documented
 * @Import(DelegatingWebMvcConfiguration.class) public @interface EnableWebMvc {
 * }
 * 从注解定义可知使用了@Import来导入DelegatingWebMvcConfiguration.class。
 * @EnableWebMvc 在内部是使用WebMvcConfigurationSupport来实现SpringMVC功能的支持和提供默认配置。
 * 而DelegatingWebMvcConfiguration是的作用就是汇总项目中所有实现了WebMvcConfigurer接口的类,
 * 自身也是使用了@Configuration注解。
 * @Configuration public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
 * ...
 * }
 * <p>
 * <p>
 * WebMvcConfigurationSupport提供的SpringMvc的默认配置
 * WebMvcConfigurationSupport在项目中自动创建了以下这些SpringMvc中请求处理的核心组件:
 * <p>
 * HandlerMapping:请求处理器与请求uri映射
 * HandlerAdapter:请求执行器
 * HandlerExceptionResolverComposite:请求处理异常处理器
 * AntPathMatcher:路径匹配
 * 其他功能子组件:
 * ContentNegotiationManager,
 * DefaultFormattingConversionService,
 * OptionalValidatorFactoryBean,
 * HttpMessageConverter
 * 请求处理核心组件注册到BeanFactory
 * @EnableWebMvc 注解与@Configuration注解一样使用,在spring容器启动时,
 * ConfigurationClassPostProcessor这个BeanFactoryPostProcessor会查找使用了@Configuration注解的类,
 * 并处理该类上的其他注解,包括处理@EnableWebMvc注解。
 * @EnableWebMvc 注解通过@Import导入了DelegatingWebMvcConfiguration类,
 * DelegatingWebMvcConfiguration继承于WebMvcConfigurationSupport,且也使用了@Configuration注解。
 * 则ConfigurationClassPostProcessor会继续处理DelegatingWebMvcConfiguration,
 * 包括注册DelegatingWebMvcConfiguration内部使用@Bean注解的方法,即上面列举的这些请求处理的核心组件,
 * 对应的BeanDefinition到内部的BeanFactory中。
 * <p>
 * <p>
 * =======================================================
 * @ComponentScan 组件扫描,相当于 <context:component-scan base-package=""></context:component-scan>
 */
@Configuration
@EnableWebMvc
@ComponentScan("com.dc18669.aboutconfig.controller")
public class SpringMvcConfig implements WebMvcConfigurer {

    /**
     * -4.使用默认的servlet处理静态资源
     *
     * @param configurer
     */
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    /**
     * -View-Controller 可以忽略使用
     *
     * @param registry
     */
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        WebMvcConfigurer.super.addViewControllers(registry);
    }

    /**
     * -视图解析器
     */
    /**
     * -针对 thymeleaf 模板
     *
     * @return
     */
    @Bean
    public ITemplateResolver templateResolver() {
        // WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
        // ServletContextTemplateResolver需要一个ServletContext作为构造参数,可通过WebApplicationContext 的方法获得
        // ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(
                // webApplicationContext.getServletContext());
                
        SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
        templateResolver.setPrefix("/WEB-INF/templates/");
        templateResolver.setSuffix(".html");
        templateResolver.setCharacterEncoding("UTF-8");
        templateResolver.setTemplateMode(TemplateMode.HTML);
        return templateResolver;
    }

    //生成模板引擎并为模板引擎注入模板解析器
    @Bean
    public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver);
        return templateEngine;
    }

    //生成视图解析器并未解析器注入模板引擎
    @Bean
    public ViewResolver viewResolver(SpringTemplateEngine templateEngine) {
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setCharacterEncoding("UTF-8");
        viewResolver.setTemplateEngine(templateEngine);
        return viewResolver;
    }

    /**
     * JSP 视图解析器
     *
     * @return
     */
    @Bean
    public ViewResolver urlBasedViewResolver() {
        // InternalResourceViewResolver 继承了 UrlBasedViewResolver类
        UrlBasedViewResolver viewResolver;
        viewResolver = new UrlBasedViewResolver();
        viewResolver.setOrder(2);
        viewResolver.setPrefix("/WEB-INF/");
        viewResolver.setSuffix(".jsp");
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setCache(false);
        return viewResolver;
    }


    /**
     * -类型转换器
     * -数据格式共用此方法
     *
     * @param registry
     */
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new AboutConverter());
    }

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        WebMvcConfigurer.super.extendMessageConverters(converters);
    }

    /**
     * JSON 数据交互
     *
     * @param converters initially an empty list of converters
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter mapJacksonConverter = new MappingJackson2HttpMessageConverter();
        List<MediaType> mediaTypesList = new LinkedList<MediaType>();
        
        mediaTypesList.add(MediaType.APPLICATION_JSON_UTF8);
        mediaTypesList.add(MediaType.TEXT_HTML);
        mediaTypesList.add(MediaType.APPLICATION_JSON_UTF8);
        mapJacksonConverter.setSupportedMediaTypes(mediaTypesList); // 到这一步发现此方法接受List<MediaType>参数,然后又是一番尝试 o(╯□╰)o
        // List 只是一个接口,意味着不能通过LIst<Object> list=new List<Object> ()  实例化,需要给List赋一个子类对象, 比如LinkedList;
        converters.add(mapJacksonConverter);
    }

    /**
     * -配置拦截器
     *
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AboutInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/*");
    }


    /**
     * -配置异常处理器
     *
     * @param resolvers initially an empty list
     */
    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {

    }

    /**
     * -注册MultiPart解析器 ,Bean的名字必须为multipartResolver
     */
    @Bean
    public MultipartResolver multipartResolver() {
        return new StandardServletMultipartResolver();
    }
}

注意:这里用到了JSON,所以需要加入关于JSON的依赖

  1. 使用Jackson
<dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.5</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.9.5</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.5</version>
    </dependency>

    <dependency>
      <groupId>com.fasterxml.jackson.dataformat</groupId>
      <artifactId>jackson-dataformat-xml</artifactId>
      <version>2.9.5</version>
    </dependency>

    <dependency>
      <groupId>com.fasterxml.jackson.module</groupId>
      <artifactId>jackson-module-parameter-names</artifactId>
      <version>2.9.5</version>
    </dependency>

2.3 控制器的实现方式

2.3.1 实现Controller接口

2.3.1.1 前端代码

index.jsp

<%--
  Created by IntelliJ IDEA.
  User: MENGDEFANG
  Date: 2022/7/15
  Time: 23:22
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
  <a href="find?name=张三">点击我哦</a>
</body>
</html>

home.jsp

<%--
  Created by IntelliJ IDEA.
  User: MENGDEFANG
  Date: 2022/7/15
  Time: 23:16
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java"%>
<html>
<head>
    <title>Title</title>
</head>
<body>
    欢迎您,${name} 先生/女士
</body>
</html>

注:web容器的版本应该在3.0及以上,即以下的版本号,否则,${xxx}不会显示

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
         http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">

2.3.1.2 注册controller(配置bean)
2.3.1.2.1 使用XML配置
  1. xml配置方式一:使用默认的映射方式(BeanNameUrlHandlerMapping)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean name="/find" class="com.dc18669.spring.mvc.MyController"/>


    <!-- InternalResourceViewResolver -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/"/>
        <!--后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>
  1. xml配置方式二:使用默认的映射方式(BeanNameUrlHandlerMapping)
    通过BeanName与URL映射:BeanNameUrlHandlerMapping(默认)是根据controller的name名称来映射寻找controller,
    该HandlerMapping是默认开启的,即在Spring找不到handlerMapping的情况下会使用BeanNameUrlHandlerMapping
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 使用 BeanNameUrlHandlerMapping 作为映射方式的同时,可以为其 配置 适配器 SimpleControllerHandlerAdapter -->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
    <bean name="/find" class="com.dc18669.spring.mvc.MyController"/>


    <!-- InternalResourceViewResolver -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/"/>
        <!--后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>
  1. XML映射方式三:使用 SimpleUrlHandlerMapping 映射

SimpleUrlHandlerMapping是根据URL来映射寻找controller

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- SimpleUrlHandlerMapping -->
    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/find">find</prop>
                <!-- 可以添加多个 prop 属性 -->
            </props>
        </property>
    </bean>
    <bean id="find" class="com.dc18669.spring.mvc.MyController"/>


    <!-- InternalResourceViewResolver -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/"/>
        <!--后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>
  1. XML映射方式三:使用 ControllerClassNameHandlerMapping 映射(这里需要提及另一个 ControllerBeanNameHandlerMapping ,实现不提供)这种方式在应用种不常用
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- ControllerClassNameHandlerMapping -->
    <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>
    <bean id="find" class="com.dc18669.spring.mvc.MyController"/>


    <!-- InternalResourceViewResolver -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/"/>
        <!--后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

注:除了上述之外,还有一种是通过注解的方式实现URL映射,此处暂不提及

注:以上方式使用其中一个即可

2.3.1.2.2 使用Java代码配置

Web容器的配置

WebServiceConfig.java

package com.dc18669.spring.mvc.config;

import com.dc18669.spring.mvc.handler.SimpleControllerHandler;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class WebServiceConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
    	// 需要在此处将 SimpleControllerHandler 和  BeanNameUrlHandler 注册
        return new Class[]{SpringMVCConfig.class, SimpleControllerHandler.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

Spring MVC 的配置
SpringMVCConfig.java

package com.dc18669.spring.mvc.config;

/**
 * - 可以定义多个 被 @Configuration 注解 标记的类
 *-- 而且不一定要实现 WebMvcConfigurer 接口,
 * -- WebMvcConfigurer 的目的是实现 自定义的 bean 配置
 */

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.JstlView;
import org.springframework.web.servlet.view.UrlBasedViewResolver;

@Configuration
@EnableWebMvc
public class SpringMVCConfig implements WebMvcConfigurer {

    @Bean
    public ViewResolver urlBasedViewResolver() {
        // InternalResourceViewResolver 继承了 UrlBasedViewResolver类
        UrlBasedViewResolver viewResolver;
        viewResolver = new UrlBasedViewResolver();
        viewResolver.setOrder(2);
        viewResolver.setPrefix("/");
        viewResolver.setSuffix(".jsp");
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setCache(false);
        return viewResolver;
    }
}
  1. 使用 SimpleUrlHandlerMapping 处理器映射器 处理URL映射
package com.dc18669.spring.mvc.handler;

import com.dc18669.spring.mvc.AboutController;
import com.dc18669.spring.mvc.MyController;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;

import java.util.Collections;

@Configuration
public class SimpleControllerHandler {

    @Bean
    public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
        SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
        mapping.setOrder(1);
        mapping.setUrlMap(Collections.singletonMap("/find", new MyController()));
        return mapping;
    }
}
  1. 使用 BeanNameUrlHandlerMapping 处理器映射器,处理URL映射
package com.dc18669.spring.mvc.handler;

import com.dc18669.spring.mvc.MyController;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BeanNameUrlHandler {

    /**
     * 当然除了在此方法上使用 @Bean(name={"/find"}) 外,还可以在 Handler类上使用 注解 @Component("/find")等等
     *
     * -即
     * -- @Component("/find")
     *    public class MyController {
     *
     *    }
     * @return
     */
    @Bean(name = "/find")
    public MyController beanNameUrlHandler() {
        return new MyController();
    }
}

注:XML配置和Java代码配置选择其中一个即可

2.3.1.3 控制层的代码

MyController.java

package com.dc18669.spring.mvc;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import java.util.Map;

public class MyController implements Controller {
    @Override
    public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws Exception {
        String name = request.getParameter("name");
        System.out.println(name);
        ModelAndView modelAndView = new ModelAndView();
        // 将数据存储到model模型种
        modelAndView.addObject("name",name);
        Map<String, Object> model = modelAndView.getModel();
        String name1 = (String) model.get("name");
        System.out.println("model " + name1);
        // 设置返回的视图
        modelAndView.setViewName("home");
        return modelAndView;
    }
}


2.3.2 使用 实现 HttpRequestHandler接口

2.3.2.1 前端代码

index.jsp

<%--
  Created by IntelliJ IDEA.
  User: MENGDEFANG
  Date: 2022/7/15
  Time: 23:22
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
  <a href="find?name=张三">点击我哦</a>
</body>
</html>

home.jsp

<%--
  Created by IntelliJ IDEA.
  User: MENGDEFANG
  Date: 2022/7/15
  Time: 23:16
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java"%>
<html>
<head>
    <title>Title</title>
</head>
<body>
    欢迎您,${name} 先生/女士
</body>
</html>
2.3.2.2 配置Controller
2.3.2.2.1 使用 XML注册
  1. XML映射方法一:使用默认的URL映射方式 (不配置BeanNameUrlHandlerMapping)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean name="/find" class="com.dc18669.spring.mvc.AboutController" />


    <!-- InternalResourceViewResolver -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/"/>
        <!--后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>
  1. XML映射方法二:使用默认的URL映射方式。 (配置 BeanNameUrlHandlerMapping)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">


    <!-- 
        通过BeanName与URL映射:BeanNameUrlHandlerMapping(默认)是根据controller的name名称来映射寻找controller,
        该HandlerMapping是默认开启的,即在Spring找不到handlerMapping的情况下会使用BeanNameUrlHandlerMapping
     -->
    <!-- 配置handlerMapper  映射器 -->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
    <!-- HandlerAdapter,可以不要配置,若真要配置,使用 HttpRequestHandlerAdapter  -->
    <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter" />
    <bean name="/find" class="com.dc18669.spring.mvc.AboutController" />


    <!-- InternalResourceViewResolver -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/"/>
        <!--后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>
  1. XML映射方法三:使用 SimpleUrlHandlerMapping 处理器映射器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <!--  使用 SimpleUrlHandlerMapping 的URL映射器 -->
    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/find">find</prop>
            </props>
        </property>
    </bean>
    <bean id="find" class="com.dc18669.spring.mvc.AboutController" />


    <!-- InternalResourceViewResolver -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/"/>
        <!--后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>
  1. XML映射方式四:使用 ControllerClassNameHandlerMapping
    (这里需要提及另一个 ControllerBeanNameHandlerMapping ,实现不提供)这种方式在应用种不常用
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">



    <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>
    <bean id="find" class="com.dc18669.spring.mvc.AboutController" />


    <!-- InternalResourceViewResolver -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/"/>
        <!--后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

注:除了上述之外,还有一种是通过注解的方式实现URL映射,此处暂不提及
注:以上方式使用其中一个即可

2.3.2.2.2 使用 Java代码注册

Web容器的配置
WebServiceConfig.java

package com.dc18669.spring.mvc.config;

import com.dc18669.spring.mvc.handler.BeanNameUrlHandler;
import com.dc18669.spring.mvc.handler.SimpleControllerHandler;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class WebServiceConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        // 在这里进行  BeanNameUrlHandler 和 SimpleUrlHandler 的配置类 注册
        return new Class[]{SpringMVCConfig.class, BeanNameUrlHandler.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

Spring MVC的配置

SpringMVCConfig.java

package com.dc18669.spring.mvc.config;

/**
 * - 可以定义多个 被 @Configuration 注解 标记的类
 *-- 而且不一定要实现 WebMvcConfigurer 接口,
 * -- WebMvcConfigurer 的目的是实现 自定义的 bean 配置
 */

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.JstlView;
import org.springframework.web.servlet.view.UrlBasedViewResolver;

@Configuration
@EnableWebMvc
public class SpringMVCConfig implements WebMvcConfigurer {

    @Bean
    public ViewResolver urlBasedViewResolver() {
        // InternalResourceViewResolver 继承了 UrlBasedViewResolver类
        UrlBasedViewResolver viewResolver;
        viewResolver = new UrlBasedViewResolver();
        viewResolver.setOrder(2);
        viewResolver.setPrefix("/");
        viewResolver.setSuffix(".jsp");
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setCache(false);
        return viewResolver;
    }
}
  1. 使用 SimpleUrlHandlerMapping 处理器映射 来 进行URL映射

SimpleControllerHandler.java

package com.dc18669.spring.mvc.handler;

import com.dc18669.spring.mvc.AboutController;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;

import java.util.Collections;

@Configuration
public class SimpleControllerHandler {

    @Bean
    public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
        SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
        mapping.setOrder(1);
        System.out.println("=============");
        mapping.setUrlMap(Collections.singletonMap("/find", new AboutController()));
        return mapping;
    }
}
  1. 使用 BeanNameUrlHandlerMapping 处理器映射器 来映射 URL
package com.dc18669.spring.mvc.handler;

import com.dc18669.spring.mvc.AboutController;
import com.dc18669.spring.mvc.MyController;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BeanNameUrlHandler {

    /**
     * 当然除了在此方法上使用 @Bean(name={"/find"}) 外,还可以在 Handler类上使用 注解 @Component("/find")等等
     *
     * -即
     * -- @Component("/find")
     *    public class MyController {
     *
     *    }
     * @return
     */
    @Bean(name = "/find")
    public AboutController beanNameUrlHandler() {
        return new AboutController();
    }
}

2.3.2.3 控制层的代码
package com.dc18669.spring.mvc;

import org.springframework.ui.Model;
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

public class AboutController implements HttpRequestHandler {

    @Override
    public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String name = request.getParameter("name");

        System.out.println("name = " + name);

        HttpSession session = request.getSession();
        session.setAttribute("name",name);
        request.getRequestDispatcher("/home.jsp").forward(request,response);
    }
}

2.3.3 使用@Controller注解

2.3.3.1 前端代码

index.jsp

<%--
  Created by IntelliJ IDEA.
  User: MENGDEFANG
  Date: 2022/7/15
  Time: 23:22
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
  <a href="find?name=张三">点击我哦</a>
</body>
</html>

home.jsp

<%--
  Created by IntelliJ IDEA.
  User: MENGDEFANG
  Date: 2022/7/15
  Time: 23:16
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java"%>
<html>
<head>
    <title>Title</title>
</head>
<body>
    欢迎您,${name} 先生/女士
</body>
</html>
2.3.3.2 使用XML注册
<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd 
           http://www.springframework.org/schema/context 
           https://www.springframework.org/schema/context/spring-context.xsd">
    
    <!-- 开启组件扫描,使用被@Controller 等注解 标记的组件 会被扫描到,然后初始化 -->
    <context:component-scan base-package="com.dc18669.spring.mvc" />
    <!-- InternalResourceViewResolver -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/"/>
        <!--后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

注:这里只使用xml配置,暂不使用 Java代码配置,后面会使用Java代码的配置

2.3.3.3 控制层的代码
package com.dc18669.spring.mvc;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class AboutController  {

	//  @RequestMapping 注解可以放置到 类上面,也可以放到 方法上
    @RequestMapping("/find")
    public String find(String name, Model model) {
        System.out.println("name = " + name);
        model.addAttribute("name",name);
        // 逻辑视图
        return "home";
    }

}

2.4 请求参数

这里会需要使用到 JSON,所以 会加入 json包的依赖,这里使用Jackson,依赖上面有的,当然也可以使用 fastjson

fastjson的依赖

<dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>2.0.8.android</version>
    </dependency>

2.4.1 通用代码

注:这里的配置将使用 Java代码配置,不再使用XML的方式,全程使用注解

web容器
WebServiceConfig.java

package com.dc18669.spring.mvc.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class WebServiceConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMVCConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

SpringMVC的配置
这个类需要配置 json格式的数据转换器,而且也不使用jsp,改成 使用 html

注:这里使用的thymeleaf,用于返回的是html。当然,也可以使用freemarker模板

SpringMVCConfig.java

package com.dc18669.spring.mvc.config;

/**
 * - 可以定义多个 被 @Configuration 注解 标记的类
 * -- 而且不一定要实现 WebMvcConfigurer 接口,
 * -- WebMvcConfigurer 的目的是实现 自定义的 bean 配置
 */

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ITemplateResolver;

import java.util.LinkedList;
import java.util.List;

@Configuration
@EnableWebMvc
@ComponentScan("com.dc18669.spring.mvc")
public class SpringMVCConfig implements WebMvcConfigurer {

//    @Override
//    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
//        configurer.enable();
//    }

    // 这个是 用户无任何业务逻辑的单独跳转的代码
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/index").setViewName("login");
    }

    /**
     * JSON 数据交互
     *
     * @param converters initially an empty list of converters
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter mapJacksonConverter = new MappingJackson2HttpMessageConverter();
        List<MediaType> mediaTypesList = new LinkedList<>();
        // 到这一步发现此方法接受List<MediaType>参数,然后又是一番尝试 o(╯□╰)o
        // List 只是一个接口,意味着不能通过LIst<Object> list=new List<Object> ()  实例化,需要给List赋一个子类对象, 比如LinkedList;
        mediaTypesList.add(MediaType.APPLICATION_JSON_UTF8);
        mediaTypesList.add(MediaType.APPLICATION_JSON);
        mapJacksonConverter.setSupportedMediaTypes(mediaTypesList);
        converters.add(mapJacksonConverter);
    }



    @Bean
    public ITemplateResolver templateResolver() {
        SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();

        templateResolver.setPrefix("/");
        templateResolver.setSuffix(".html");
        templateResolver.setCharacterEncoding("UTF-8");
        templateResolver.setTemplateMode(TemplateMode.HTML);
        return templateResolver;
    }

    //生成模板引擎并为模板引擎注入模板解析器
    @Bean
    public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver);
        return templateEngine;
    }

    //生成视图解析器并未解析器注入模板引擎
    @Bean
    public ViewResolver viewResolver(SpringTemplateEngine templateEngine) {
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setCharacterEncoding("UTF-8");
        viewResolver.setTemplateEngine(templateEngine);
        return viewResolver;
    }
}

这里需要加入thymeleaf的依赖:

<dependency>
      <groupId>org.thymeleaf</groupId>
      <artifactId>thymeleaf</artifactId>
      <version>3.1.0.M2</version>
    </dependency>

	<!-- 这个是用于thymeleaf与spring 整合的 -->
    <dependency>
      <groupId>org.thymeleaf</groupId>
      <artifactId>thymeleaf-spring5</artifactId>
      <version>3.1.0.M2</version>
    </dependency>

2.4.2 普通形参

2.4.2.1 HTML代码

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<a href="/find?username=张三&password=zhang.san" >点击可加入</a>

<br />

<form action="/search" method="post">
  <label for="username">
    username:
    <input type="text" name="username" id="username" />
  </label>
  <br />

  <label for="password">
    password:
    <input type="password" name="password" id="password" />
  </label>
  <br />

  <input type="submit" value="点击可加入" />
</form>
</body>
</html>
2.4.2.2 Controller代码

这里的controller层都将使用注解。

这里 POST请求和GET请求都可以请求获取到数据

package com.dc18669.spring.mvc;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class MyController  {

    /**
     * -用于超链接,即 GET请求
     * @param username
     * @param password
     * @return
     */
    @RequestMapping("/find")
    public String superA (String username,String password) {
        System.out.println("username : " + username + " , password : " + password);
        return "home";
    }

    /**
     * -用于表单,即 POST请求
     * @param username
     * @param password
     * @return
     */
    @RequestMapping("/form_action")
    public String form(String username,String password) {
        System.out.println("username : " + username + " , password : " + password);
        return "home";
    }
}

2.4.3 使用HttpServietRequest对象

2.4.3.1 HTML代码

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<a href="find?username=张三&password=zhang.san" >点击可加入</a>

<br />

<form action="form_action" method="post">
  <label for="username">
    username:
    <input type="text" name="username" id="username" />
  </label>
  <br />

  <label for="password">
    password:
    <input type="password" name="password" id="password" />
  </label>
  <br />

  <input type="submit" value="点击可加入" />
</form>
</body>
</html>
2.4.3.2 Controller代码

这里 POST请求和GET请求都可以请求获取到数据

package com.dc18669.spring.mvc;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;

@Controller
public class MyController  {

    /**
     * -用于超链接,即 GET请求
     * @param username
     * @param password
     * @return
     */
    @RequestMapping("/find")
    public String superA (HttpServletRequest request) {
        System.out.println("username : " + request.getParameter("username") + " , password : " + request.getParameter("password"));
        return "home";
    }

    /**
     * -用于表单,即 POST请求
     * @param username
     * @param password
     * @return
     */
    @RequestMapping("/form_action")
    public String form(HttpServletRequest request) {
        System.out.println("username : " + request.getParameter("username") + " , password : " + request.getParameter("password"));
        return "home";
    }
}

2.4.4 使用路径变量

2.4.4.1 HTML代码

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<a href="find/12345?username=张三&password=zhang.san" >点击可加入</a>

<br />

<form action="form_action/12345" method="post">
  <label for="username">
    username:
    <input type="text" name="username" id="username" />
  </label>
  <br />

  <label for="password">
    password:
    <input type="password" name="password" id="password" />
  </label>
  <br />

  <input type="submit" value="点击可加入" />
</form>
</body>
</html>
2.4.4.4 Controller代码

对于这种路径变量,传入的置来源于url路径中对应的位置的路径

package com.dc18669.spring.mvc;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class MyController  {

    /**
     * -对于这种路径变量,传入的置来源于url路径中对应的位置的路径
     */
    /**
     * -用于超链接,即 GET请求
     * @param username
     * @param password
     * @return
     */
    @RequestMapping("/find/{id}")
    public String superA (@PathVariable("id") String id,String username,String password) {
        System.out.println("id : " + id + "  ,  username : " + username + " , password : " + password);
        return "home";
    }

    /**
     * -用于表单,即 POST请求
     * @param username
     * @param password
     * @return
     */
    @RequestMapping("/form_action/{id}")
    public String form(@PathVariable("id") String id,String username,String password) {
        System.out.println("id : " + id + " , username : " + username + " , password : " + password);
        return "home";
    }
}

注:路径变量的表现形式如:请求的url find/12345 , 而 @RequestMapping(“find/{id}”) 则是
url映射, 接收的方式 是 @PathVariable(“id”) String id, 即 @PathVariable
可以接收路径变量的值。

2.4.5 使用JavaBean

2.4.5.1 HTML代码

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<a href="find?username=张三&password=zhang.san" >点击可加入</a>

<br />

<form action="form_action" method="post">
  <label for="username">
    username:
    <input type="text" name="username" id="username" />
  </label>
  <br />

  <label for="password">
    password:
    <input type="password" name="password" id="password" />
  </label>
  <br />

  <input type="submit" value="点击可加入" />
</form>
</body>
</html>
2.4.5.2 Controller代码
package com.dc18669.spring.mvc;

import com.dc18669.spring.mvc.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class MyController  {

    /**
     * -用于超链接,即 GET请求
     * @param username
     * @param password
     * @return
     */
    @RequestMapping("/find")
    public String superA (User user) {
        System.out.println("GET请求=====");
        System.out.println("  ,  username : " + user.getUsername() + " , password : " + user.getPassword());
        return "home";
    }

    /**
     * -用于表单,即 POST请求
     * @param username
     * @param password
     * @return
     */
    @RequestMapping("/form_action")
    public String form(User user) {
        System.out.println("POST请求=====");
        System.out.println("  ,  username : " + user.getUsername() + " , password : " + user.getPassword());
        return "home";
    }
}

2.4.6 使用@RequestParam注解

2.4.6.1 HTML代码

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<a href="find?username=张三&password=zhang.san" >点击可加入</a>

<br />

<form action="form_action" method="post">
  <label for="username">
    username:
    <input type="text" name="username" id="username" />
  </label>
  <br />

  <label for="password">
    password:
    <input type="password" name="password" id="password" />
  </label>
  <br />

  <input type="submit" value="点击可加入" />
</form>
</body>
</html>
2.4.6.2 Controller代码
package com.dc18669.spring.mvc;

import com.dc18669.spring.mvc.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class MyController  {

    /**
     * -用于超链接,即 GET请求
     * @param username
     * @param password
     * @return
     */
    @RequestMapping("/find")
    public String superA (@RequestParam("username") String username,@RequestParam("password") String password) {
        System.out.println("GET请求=====");
        System.out.println("  ,  username : " + username + " , password : " + password);
        return "home";
    }

    /**
     * -用于表单,即 POST请求
     * @param username
     * @param password
     * @return
     */
    @RequestMapping("/form_action")
    public String form(@RequestParam("username") String username,@RequestParam("password") String password) {
        System.out.println("POST请求=====");
        System.out.println("  ,  username : " + username + " , password : " + password);
        return "home";
    }
}

注:@RequestParam 绑定的不能是 JavaBean对象,否则,会报错: Required request parameter
‘user’ for method parameter type User is not present

2.4.7 使用集合

2.4.7.1 HTML代码

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<a href="find?username=张三&password=zhang.san" >点击可加入</a>

<br />

<form action="form_action" method="post">
  <label for="username">
    username:
    <input type="text" name="username" id="username" />
  </label>
  <br />

  <label for="password">
    password:
    <input type="password" name="password" id="password" />
  </label>
  <br />

  <input type="submit" value="点击可加入" />
</form>
</body>
</html>
2.4.7.2 Controller代码
2.4.7.2.1 使用Map<K,V>,必须 使用 @RequestParam 注解 才能接收到从页面传入的值
package com.dc18669.spring.mvc;

import com.dc18669.spring.mvc.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.support.BindingAwareModelMap;
import org.springframework.web.bind.annotation.RequestMapping;


import java.util.Map;

@Controller
public class MyController  {

    /**
     * - 可以看到传递的为SpringMVC的BindingAwareModelMap类型,
     * SpringMVC中的隐含模型就是这个类型,其作用域等价于 request 域,
     * 当添加Model、ModelMap参数时,SpringMVC实际传入的就是这个隐含模型;
     * 向这个隐含模型种设置值后,在返回的页面中就能通过request域取值。
     */
    /**
     * -用于超链接,即 GET请求
     * @param username
     * @param password
     * @return
     */
    @RequestMapping("/find")
    public String superA (Map<String ,Object> map, Model model) {
        System.out.println("GET请求=====");
        System.out.println(map);
        System.out.println(map.getClass());
        System.out.println(map.getClass().getName());

        System.out.println("  ,  username : " + map.get("username") + " , password : " + map.get("password"));

        System.out.println("===========================================");


        return "home";
    }

    /**
     * -用于表单,即 POST请求
     * @param username
     * @param password
     * @return
     */
    @RequestMapping("/form_action")
    public String form(Map<String ,Object> map) {
        System.out.println("POST请求=====");
        System.out.println(map);
        System.out.println(map.getClass());
        System.out.println(map.getClass().getName());

        System.out.println("  ,  username : " + map.get("username") + " , password : " + map.get("password"));

        return "home";
    }
}

注意:
/**
* 上述代打印的 结果:
* GET请求=====
* {}
* class org.springframework.validation.support.BindingAwareModelMap
* org.springframework.validation.support.BindingAwareModelMap
* , username : null , password : null
* ===========================================**

 * 可以看到传递的为SpringMVC的BindingAwareModelMap类型,
 * SpringMVC中的隐含模型就是这个类型,其作用域等价于 request 域,
 * 当添加Model、ModelMap参数时,SpringMVC实际传入的就是这个隐含模型;
 * 向这个隐含模型种设置值后,在返回的页面中就能通过request域取值。
 *
 */

注意:上述的controller代码 使用Map类型接收参数时,是无法接收到从前端传递过来的值, 而使用 @RequestParam 注解后,就可以实现接收前端传递的值。GET请求和POST请求都可以。
代码如下:
public String superA (@RequestParam Map<String ,Object> map)

2.4.7.2.2 使用List<?>

在使用 @RequestParam 和 不使用 @RequestParam 注解 ,都无法获取 由前端页面 传入的参数值
不使用注解时,报:java.lang.IllegalStateException: No primary or single unique constructor found for interface java.util.List
使用注解时: 报错:Required request parameter ‘list’ for method parameter type List is not present

2.4.7.2.3 使用数组Array

在使用 @RequestParam 和 不使用 @RequestParam 注解 ,都无法获取 由前端页面 传入的参数值

2.4.8 使用@RequestBody注解

  1. GET 方式无请求体,所以 @RequestBody 接收数据时,前端必须是 POST 方式进行提交,然后给页面的数据默认也是 json。也就是说直接通过浏览器输入url时,@RequestBody获取不到json对象,需要用java编程或者基于ajax的方法请求,将Content-Type设置为application/json
  2. 同一个方法中, @RequestBody 与 @RequestParam() 可以同时使用,前者最多只能有一个,后者可以有多个
  3. @RequestBody 接收的是请求体里面的数据, @RequestParam 接收的是 key-value 里面的参数。
  4. @RequestBody 主要用来接收前端传递给后端的 json 格式的数据的(请求体中的数据的),有一个属性 required,表示参数是否必须要传,默认为 true. 也就说@RequestBody需要把所有请求参数作为json解析,因此,不能包含key=value这样的写法在请求url中,所有的请求参数都是一个json
2.4.8.1 使用AJAX

html 代码
login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<a href="find?username=张三&password=zhang.san" id="super_a">点击可加入</a>

<br/>

<form action="form_action" method="post">
    <label for="username">
        username:
        <input type="text" name="username" id="username"/>
    </label>
    <br/>

    <label for="password">
        password:
        <input type="password" name="password" id="password"/>
    </label>
    <br/>

    <input type="button" value="点击可加入" id="form_action"/>
</form>


<script type="text/javascript">
    window.onload = function () {
        const submit = function (method, url, params) {
            return new Promise((resolve, reject) => {
                const xhr = new XMLHttpRequest();
                xhr.open(method, url, false);
                // xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
                xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
                xhr.onreadystatechange = () => {
                    if (xhr.readyState !== 4) return;
                    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
                        resolve(JSON.parse(xhr.response));
                    } else {
                        reject(new Error("response error"));
                    }
                };
                xhr.send(JSON.stringify(params));
                // xhr.send(params);
            });
        };


        const btn = document.getElementById("form_action");
        btn.onclick = function () {
            submit("POST", "./form_action",
                {
                    username: document.getElementById("username").value,
                    password: document.getElementById("password").value
                }
            ).then(res => console.log(res)).catch(err => console.log(err));
        };
    };
</script>
</body>
</html>

controller 代码

  1. 使用 @RequestBody注解标记的 JavaBean
package com.dc18669.spring.mvc;

import com.dc18669.spring.mvc.model.User;
import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.Map;


@Controller
public class MyController {

	@RequestMapping(value = "/form_action", method = RequestMethod.POST)
	public String form(@RequestBody User user) {
			System.out.println("POST请求=====");
			System.out.println("  ,  username : " + user.getUsername() + " , password : " + user.getPassword());
			return "home";
	}

}
  1. 使用 @RequestBody注解标记 的Map。Map集合的value可以是 对象、基本类型、List集合、Map集合、数组等。
package com.dc18669.spring.mvc;

import com.dc18669.spring.mvc.model.User;
import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.Map;


@Controller
public class MyController {

    /**
     * -用于表单,即 POST请求
     *
     * @return
     */
    @RequestMapping(value = "/form_action", method = RequestMethod.POST)
    public String form(@RequestBody Map<String, Object> user) {
        System.out.println("POST请求=====");

        System.out.println("  ,  username : " + user.get("username") + " , password : " + user.get("password"));

        return "home";
    }
}
  1. 使用@RequestBody注解标记的 List。List集合的泛型 可以为 JavaBean 、也可以为 基本类型、Map、数组集合、List集合等
    html代码

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<a href="javascript:void(0)" id="super_a">点击可加入</a>

<br/>

<form action="form_action" method="post">
    <label for="username">
        username:
        <input type="text" name="username" id="username"/>
    </label>
    <br/>

    <label for="password">
        password:
        <input type="password" name="password" id="password"/>
    </label>
    <br/>

    <input type="button" value="点击可加入" id="form_action"/>
</form>


<script type="text/javascript">
    window.onload = function () {
        const submit = function (method, url, params) {
            return new Promise((resolve, reject) => {
                const xhr = new XMLHttpRequest();
                xhr.open(method, url, false);
                // xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
                xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
                xhr.onreadystatechange = () => {
                    if (xhr.readyState !== 4) return;
                    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
                        resolve(JSON.parse(xhr.response));
                    } else {
                        reject(new Error("response error"));
                    }
                };
                xhr.send(JSON.stringify(params));
                // xhr.send(params);
            });
        };

        const btn = document.getElementById("form_action");
        btn.onclick = function () {
            submit("POST", "./form_action",
                [{
                    username: document.getElementById("username").value,
                    password: document.getElementById("password").value
                },
                    {
                        username: '里斯',
                        password: '123456789'
                    }
                ]
            ).then(res => console.log(res)).catch(err => console.log(err));
        };
    };
</script>
</body>
</html>

controller代码

package com.dc18669.spring.mvc;

import com.dc18669.spring.mvc.model.User;
import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.List;
import java.util.Map;


@Controller
public class MyController {

    /**
     * -用于表单,即 POST请求
     *
     * @return
     */
    @RequestMapping(value = "/form_action", method = RequestMethod.POST)
    public String form(@RequestBody List<User> users) {
        System.out.println("POST请求=====");

        for (User user : users) {
            System.out.println("username  :  " + user.getUsername() + "  ,password  :  "  + user.getPassword());
        }
        return "home";
    }
}
  1. 使用@RequestBody注解标记的数组。

html代码
login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<a href="javascript:void(0)" id="super_a">点击可加入</a>

<br/>

<form action="form_action" method="post">
    <label for="username">
        username:
        <input type="text" name="username" id="username"/>
    </label>
    <br/>

    <label for="password">
        password:
        <input type="password" name="password" id="password"/>
    </label>
    <br/>

    <input type="button" value="点击可加入" id="form_action"/>
</form>


<script type="text/javascript">
    window.onload = function () {
        const submit = function (method, url, params) {
            return new Promise((resolve, reject) => {
                const xhr = new XMLHttpRequest();
                xhr.open(method, url, false);
                // xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
                xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
                xhr.onreadystatechange = () => {
                    if (xhr.readyState !== 4) return;
                    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
                        resolve(JSON.parse(xhr.response));
                    } else {
                        reject(new Error("response error"));
                    }
                };
                xhr.send(JSON.stringify(params));
                // xhr.send(params);
            });
        };

        const btn = document.getElementById("form_action");
        btn.onclick = function () {
            submit("POST", "./form_action",
                ['张三','里斯']
            ).then(res => console.log(res)).catch(err => console.log(err));
        };
    };
</script>
</body>
</html>

controller代码

package com.dc18669.spring.mvc;

import com.dc18669.spring.mvc.model.User;
import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.List;
import java.util.Map;


@Controller
public class MyController {

    /**
     * -用于表单,即 POST请求
     *
     * @return
     */
    @RequestMapping(value = "/form_action", method = RequestMethod.POST)
    public String form(@RequestBody String [] arr) {
        System.out.println("POST请求=====");

        for (String username : arr) {
            System.out.println("username : " + username);
        }
        return "home";
    }
}
  1. 使用@RequestBody注解标记的 String类型

html代码
login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<a href="javascript:void(0)" id="super_a">点击可加入</a>

<br/>

<form action="form_action" method="post">
    <label for="username">
        username:
        <input type="text" name="username" id="username"/>
    </label>
    <br/>

    <label for="password">
        password:
        <input type="password" name="password" id="password"/>
    </label>
    <br/>

    <input type="button" value="点击可加入" id="form_action"/>
</form>


<script type="text/javascript">
    window.onload = function () {
        const submit = function (method, url, params) {
            return new Promise((resolve, reject) => {
                const xhr = new XMLHttpRequest();
                xhr.open(method, url, false);
                // xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
                xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
                xhr.onreadystatechange = () => {
                    if (xhr.readyState !== 4) return;
                    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
                        resolve(JSON.parse(xhr.response));
                    } else {
                        reject(new Error("response error"));
                    }
                };
                xhr.send(JSON.stringify(params));
                // xhr.send(params);
            });
        };
        const btn = document.getElementById("form_action");
        btn.onclick = function () {
            submit("POST", "./form_action",
                {'username':"张三"}
            ).then(res => console.log(res)).catch(err => console.log(err));
        };
    };
</script>
</body>
</html>

controller 代码

package com.dc18669.spring.mvc;

import com.dc18669.spring.mvc.model.User;
import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.List;
import java.util.Map;


@Controller
public class MyController {

    /**
     * -用于表单,即 POST请求
     *
     * @return
     */
    @RequestMapping(value = "/form_action", method = RequestMethod.POST)
    public String form(@RequestBody String username) {
        System.out.println("POST请求=====");

        System.out.println("username : " + username);
        return "home";
    }
}

2.4.9 使用@ModelAttribute注解

@ModelAttribute注解标记在不同的位置,拥有不同的作用。其可标记的位置有:

  1. 被标记在 方法的形参上,可以用来接收参数
  2. 被标记在方法上,会根据返回值有不同的含义
  3. 被标记在方法的返回类型上,可以用来渲染视图
2.4.9.1 HTML代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<a href="javascript:void(0)" id="super_a">点击可加入</a>

<br/>

<form action="form_action" method="post">
    <label for="username">
        username:
        <input type="text" name="username" id="username"/>
    </label>
    <br/>

    <label for="password">
        password:
        <input type="password" name="password" id="password"/>
    </label>
    <br/>

    <input type="button" value="点击可加入" id="form_action"/>
</form>

</body>
</html>
2.4.9.2 Controller代码
package com.dc18669.spring.mvc;

import com.dc18669.spring.mvc.model.User;
import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;


@Controller
public class MyController {


    /**
     * -用于超链接,即 GET请求
     *
     * @return
     */
    @RequestMapping("/find")
    public String superA(@ModelAttribute User user) {
        System.out.println("GET请求=====");
        System.out.println("  ,  username : " + user.getUsername() + " , password : " + user.getPassword());

        System.out.println("===========================================");
        return "home";
    }

    /**
     * -用于表单,即 POST请求
     *
     * @return
     */
    @RequestMapping(value = "/form_action", method = RequestMethod.POST)
    public String form(@ModelAttribute String username) {
        System.out.println("POST请求=====");
        System.out.println("username : " + username);
        return "home";
    }
}

2.5 返回值

2.5.1 通用代码

同样是使用Java代码配置,配置如上

2.5.2 返回String类型

在Spring MVC框架上,返回String类型(没有被@ResponseBody注解标记),被认为是逻辑视图,会被视图解析器解析。

2.5.2.1 HTML代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="form_action" method="post">
    <label for="username">
        username:
        <input type="text" name="username" id="username"/>
    </label>
    <br/>

    <label for="password">
        password:
        <input type="password" name="password" id="password"/>
    </label>
    <br/>

    <input type="submit" value="点击可加入" id="form_action"/>
</form>
</body>
</html>
2.5.2.2 Controller代码
package com.dc18669.spring.mvc;

import com.dc18669.spring.mvc.model.User;
import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;


@Controller
public class MyController {

    /**
     * -用于表单,即 POST请求
     *
     * @return
     */
    @RequestMapping(value = "/form_action", method = RequestMethod.POST)
    public String form(String username,String password) {
        System.out.println("POST请求=====");
        System.out.println("username : " + username + "  ,  password  : " + password);
        return "home";
    }
}

2.5.3 View

2.5.3.1 HTML代码

注:暂无代码实现

2.5.3.2 Controller代码

注:暂无代码实现

2.5.4 返回Model类型

Sprig MVC允许返回Model类型,但是Model类型的数据是用来渲染页面的,而视图名是根据 请求的url 中自动获取,一般为请求路径的文件名。通过 RequestToViewNameTranslator组件解析。
如下实例的url为 home,其将作为逻辑视图名进行解析。

2.5.4.1 HTML代码

注:这个时候,使用普通的HTML将不合适,可以选择使用JSP或者是模板。

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="home" method="post">
    <label for="username">
        username:
        <input type="text" name="username" id="username"/>
    </label>
    <br/>

    <label for="password">
        password:
        <input type="password" name="password" id="password"/>
    </label>
    <br/>

    <input type="submit" value="点击可加入" id="form_action"/>
</form>

</body>
</html>

home.html

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1 th:text="${username}"></h1>
    <h1>来了小老弟!!!</h1>
</body>

</html>
2.5.4.2 Controller代码
package com.dc18669.spring.mvc;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;


@Controller
public class MyController {

    /**
     * -用于表单,即 POST请求
     *
     * @return
     */
    @RequestMapping(value = "/home", method = RequestMethod.POST)
    public Model form(String username, String password,Model model) {
        System.out.println("POST请求=====");
        System.out.println("username : " + username + "  ,  password  : " + password);
        model.addAttribute("username",username);
        return model;
    }
}

2.5.5 返回ModelAndView类型

2.5.5.1 HTML代码

注:这个时候,使用普通的HTML将不合适,可以选择使用JSP或者是模板。

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="form_action" method="post">
    <label for="username">
        username:
        <input type="text" name="username" id="username"/>
    </label>
    <br/>

    <label for="password">
        password:
        <input type="password" name="password" id="password"/>
    </label>
    <br/>

    <input type="submit" value="点击可加入" id="form_action"/>
</form>

</body>
</html>

home.html

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1 th:text="${username}"></h1>
    <h1>来了小老弟!!!</h1>
</body>

</html>
2.5.5.2 Controller代码
package com.dc18669.spring.mvc;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;


@Controller
public class MyController {

    /**
     * -用于表单,即 POST请求
     *
     * @return
     */
    @RequestMapping(value = "/form_action", method = RequestMethod.POST)
    public ModelAndView form(String username, String password) {
        System.out.println("POST请求=====");
        System.out.println("username : " + username + "  ,  password  : " + password);

        ModelAndView mv = new ModelAndView();
        mv.addObject("username",username);
        mv.setViewName("home");
        return mv;
    }
}

2.5.6 返回Void类型

返回Void类型时,默认的视图名为请求路径,这种情况和返回Model类型相似。当然除此之外,还可以使用 HttpServletRequest对象和HttpServletResponse对象 进行转发。下面实例使用和返回Model类型一样的方式

2.5.6.1 HTML代码

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="home" method="post">
    <label for="username">
        username:
        <input type="text" name="username" id="username"/>
    </label>
    <br/>

    <label for="password">
        password:
        <input type="password" name="password" id="password"/>
    </label>
    <br/>

    <input type="submit" value="点击可加入" id="form_action"/>
</form>

</body>
</html>

home.html

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1 th:text="${username}"></h1>
    <h1>来了小老弟!!!</h1>
</body>

</html>
2.5.6.2 Controller代码
package com.dc18669.spring.mvc;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

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


@Controller
public class MyController {

    /**
     * -用于表单,即 POST请求
     *
     * @return
     */
    @RequestMapping(value = "/home", method = RequestMethod.POST)
    public void form(String username, String password, Model model) {
        System.out.println("POST请求=====");
        System.out.println("username : " + username + "  ,  password  : " + password);


        model.addAttribute("username",username);

    }
}

2.5.7 使用@ResponseBody标记的返回值

@ResponseBody标记的返回值直接作为相应的内容,该类型对应的@RequestBody,同样是通过HttpMessageConverter把返回值转换后写入Http响应体中。返回json形式的对象。

2.5.6.1 HTML代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="form_action" method="post">
    <label for="username">
        username:
        <input type="text" name="username" id="username"/>
    </label>
    <br/>

    <label for="password">
        password:
        <input type="password" name="password" id="password"/>
    </label>
    <br/>

    <input type="button" value="点击可加入" id="form_action"/>
</form>
<script type="text/javascript">
    window.onload = function () {
        const submit = function (method, url, params) {
            return new Promise((resolve, reject) => {
                const xhr = new XMLHttpRequest();
                xhr.open(method, url, false);
                // xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
                xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
                xhr.onreadystatechange = () => {
                    if (xhr.readyState !== 4) return;
                    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
                        resolve(JSON.parse(xhr.response));
                    } else {
                        reject(new Error("response error"));
                    }
                };
                xhr.send(JSON.stringify(params));
                // xhr.send(params);
            });
        };
        const btn = document.getElementById("form_action");
        btn.onclick = function () {
            submit("POST", "./form_action",
                {
                    username:document.getElementById("username").value,
                    password:document.getElementById("password").value
                }
            ).then(res => console.log(res)).catch(err => console.log(err));
        };
    };
</script>
</body>
</html>
2.5.6.4 Controller代码
2.5.6.4.1 返回字符串

String类型返回值通常解析为跳转路径,但是加上@ResponseBody后返回结果不会被解析为跳转路径,而是直接写入HTTP响应正文中。

package com.dc18669.spring.mvc;

import com.dc18669.spring.mvc.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;


@Controller
public class MyController {

    /**
     * -用于表单,即 POST请求
     *
     * @return
     */
    @RequestMapping(value = "/form_action", method = RequestMethod.POST)
    @ResponseBody
    public String form(@RequestBody User user) {
        System.out.println("POST请求=====");
        System.out.println("username : " + user.getUsername() + "  ,  password  : " + user.getPassword());
        return "success";
    }
}

在这里插入图片描述

2.5.6.4.2 返回JavaBean
package com.dc18669.spring.mvc;

import com.dc18669.spring.mvc.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;


@Controller
public class MyController {

    /**
     * -用于表单,即 POST请求
     *
     * @return
     */
    @RequestMapping(value = "/form_action", method = RequestMethod.POST)
    @ResponseBody
    public User form(@RequestBody User user) {
        System.out.println("POST请求=====");
        System.out.println("username : " + user.getUsername() + "  ,  password  : " + user.getPassword());
        return user;
    }
}

返回结果为:
在这里插入图片描述

2.5.6.4.3 返回Map<K,V>
package com.dc18669.spring.mvc;

import com.dc18669.spring.mvc.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;


@Controller
public class MyController {

    /**
     * -用于表单,即 POST请求
     *
     * @return
     */
    @RequestMapping(value = "/form_action", method = RequestMethod.POST)
    @ResponseBody
    public Map<String,Object> form(@RequestBody User user) {
        System.out.println("POST请求=====");
        System.out.println("username : " + user.getUsername() + "  ,  password  : " + user.getPassword());
        Map<String,Object> map = new HashMap<>();
        map.put("user",user);
        return map;
    }
}

其返回结果为:
在这里插入图片描述

2.5.6.4.4 返回List<?>
package com.dc18669.spring.mvc;

import com.dc18669.spring.mvc.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Controller
public class MyController {

    /**
     * -用于表单,即 POST请求
     *
     * @return
     */
    @RequestMapping(value = "/form_action", method = RequestMethod.POST)
    @ResponseBody
    public List<User> form(@RequestBody User user) {
        System.out.println("POST请求=====");
        System.out.println("username : " + user.getUsername() + "  ,  password  : " + user.getPassword());
        List<User> users = new ArrayList<>();
        users.add(user);
        return users;
    }
}

其响应结果为:
在这里插入图片描述

2.5.6.4.5 返回数组Array
package com.dc18669.spring.mvc;

import com.dc18669.spring.mvc.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Controller
public class MyController {

    /**
     * -用于表单,即 POST请求
     *
     * @return
     */
    @RequestMapping(value = "/form_action", method = RequestMethod.POST)
    @ResponseBody
    public User[] form(@RequestBody User user) {
        System.out.println("POST请求=====");
        System.out.println("username : " + user.getUsername() + "  ,  password  : " + user.getPassword());
        User[] users = new User[2];
        users[0] = user;
        return users;
    }
}

其响应结果为:
在这里插入图片描述

2.5.8 使用@ModelAttribute注解标记

注:这类暂无代码

2.5.9 返回其他

2.5.9.1 返回HttpHeaders

只返回响应的头数据,不返回响应体,一般用于Http请求只需要获取响应头的情况

2.5.9.2 HttpEntity

结合HttpHeaders和@ResponseBody的功能,ResponseEntity还可以额外指定响应状态码

2.5.9.3 ResponseEntity

结合HttpHeaders和@ResponseBody的功能,ResponseEntity还可以额外指定响应状态码

2.5.9.4 DefferredResults

DeferredResult等异步结果:通过异步请求返回结果, 类型包括 DeferredResult Callable
ListenableFuture CompletionStage CompletableFuture
ResponseBodyEmitter SseEmitter StreamingResponseBody
等类型,均为异步请求支持的相关类型

注:这类暂无代码

2.6 请求转发和重定向

2.6.1 请求转发

2.6.1.1 HTML代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="form_action" method="post">
    <label for="username">
        username:
        <input type="text" name="username" id="username"/>
    </label>
    <br/>

    <label for="password">
        password:
        <input type="password" name="password" id="password"/>
    </label>
    <br/>

    <input type="submit" value="点击可加入" id="form_action"/>
</form>
</body>
</html>

注:POST请求和GET请求,效果一样

2.6.1.2 Controller代码
package com.dc18669.spring.mvc;

import com.dc18669.spring.mvc.model.User;
import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;


@Controller
public class MyController {

    /**
     * -用于表单,即 POST请求
     *
     * @return
     */
    @RequestMapping(value = "/form_action", method = RequestMethod.POST)
    public String form(String username,String password) {
        System.out.println("POST请求=====");
        System.out.println("username : " + username + "  ,  password  : " + password);
        // 所谓转发,是在逻辑视图前加 forward: 前缀,当然  forward: 前缀 可以省略不写,这个是默认的
        return "forward:home";
    }
}

注:POST请求和GET请求,效果一样

2.6.2 重定向

2.6.2.1 HTML代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="form_action" method="post">
    <label for="username">
        username:
        <input type="text" name="username" id="username"/>
    </label>
    <br/>

    <label for="password">
        password:
        <input type="password" name="password" id="password"/>
    </label>
    <br/>

    <input type="submit" value="点击可加入" id="form_action"/>
</form>
</body>
</html>

注:POST请求和GET请求,效果一样

2.6.2.2 Controller代码
package com.dc18669.spring.mvc;

import com.dc18669.spring.mvc.model.User;
import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;


@Controller
public class MyController {

    /**
     * -用于表单,即 POST请求
     *
     * @return
     */
    @RequestMapping(value = "/form_action", method = RequestMethod.POST)
    public String form(String username,String password) {
        System.out.println("POST请求=====");
        System.out.println("username : " + username + "  ,  password  : " + password);
        // 所谓重定向,是在重定向的url前加 redirect: 前缀,不能省略。
        return "redirect:home";
    }
}

注:POST请求和GET请求,效果一样

2.7 其他注解

第3章 关于Spring MVC的拦截器

3.1 拦截器简介

Spring MVC 的拦截器(Interceptor)与 Java Servlet 的过滤器(Filter)类似,它主要用于拦截用户的请求并做相应的处理,通常应用在权限验证、记录请求信息的日志、判断用户是否登录等功能上。

3.2 拦截器的实现

3.2.1 实现HandlerInterceptor接口

自定义拦截器,就是实现 HandlerInterceptor接口,并重写 其的三个方法.

package com.dc18669.spring.mvc.into;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

GlobalInterceptor.java

package com.dc18669.spring.mvc.into;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

public class GlobalInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

3.2.2 拦截器的配置

3.2.2.1 使用XML配置

使用 xml配置,就是 在 beans的配置文件中 使用 mvc:interceptors 标签包裹的拦截器配置。可以配置全局拦截器和局部拦截器。
当然,全局拦截器和局部拦截器不需要同时配置,根据需要进行配置即可。

<mvc:interceptors>
        <!-- 配置一个全局拦截器,拦截所有请求 -->
        <bean class="com.dc18669.spring.mvc.into.GlobalInterceptor " />
		
		<!-- 局部拦截器 -->
        <mvc:interceptor>
            <!-- 配置拦截器作用的路径 -->
            <mvc:mapping path="/**"/>
            <!-- 配置不需要拦截作用的路径 -->
            <!-- <mvc:exclude-mapping path="" /> -->
            <!-- 定义<mvc:interceptor>元素中,表示匹配指定路径的请求才进行拦截 -->
            <bean class="com.dc18669.spring.mvc.into.MyInterceptor " />
        </mvc:interceptor>
        <!-- 还可以配置其他的拦截器 -->
    </mvc:interceptors>
3.2.2.2 使用Java代码配置

在实现了 WebMvcConfigurer 接口的配置类中,重写 addInterceptors() 方法。

@Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 全局拦截器
        registry.addInterceptor(new GlobalInterceptor());
        // 局部拦截器,addPathPatterns :表示拦截的路径,excludePathPatterns:表示不拦截的路径
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/*");
    }

第4章 异常处理

4.1 异常处理的实现方式有三种

  1. 使用 Spring MVC 提供的简单异常处理器 SimpleMappingExceptionResolver。
  2. 实现 Spring 的异常处理接口 HandlerExceptionResolver,自定义自己的异常处理器。
  3. 使用 @ExceptionHandler 注解实现异常处理

4.2 异常处理的实现

4.2.1 使用 SimpleMappingExceptionResolver 处理异常

4.2.1.1 使用场景

通常是全局异常处理可使用 SimpleMappingExceptionResolver 来实现。它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常

4.2.1.2 配置
  1. 在 beans文件中的配置
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <!-- 定义默认的异常处理页面,当该异常类型注册时使用 -->
    <property name="defaultErrorView" value="error"></property>
    <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception -->
    <property name="exceptionAttribute" value="ex"></property>
    <!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常页名作为值 -->
    <property name="exceptionMappings">
        <props>
            <prop key="ArithmeticException">error</prop>
            <!-- 在这里还可以继续扩展对不同异常类型的处理 -->
        </props>
    </property>
</bean>
  1. 在java代码配置类中的配置
@Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {

        SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
        simpleMappingExceptionResolver.setDefaultErrorView("");
        
        resolvers.add(simpleMappingExceptionResolver);
    }

4.2.2 实现 HandlerExceptionResolver 接口

4.2.2.1 使用场景

通过 HandlerExceptionResolver 处理程序异常,包括处理器异常、数据绑定异常以及控制器执行时发生的异常。HandlerExceptionResolver 仅有一个接口方法

4.2.2.2 实现和配置
  1. 首先是实现接口HandlerExceptionResolver ,代码如下
package com.dc18669.spring.mvc.ex;

import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

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

public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        return null;
    }
}
  1. 配置

在 xml文件中配置

<bean class="com.dc18669.spring.mvc.ex.MyHandlerExceptionResolver"/>

在 java代码配置类中配置

	@Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {

        MyHandlerExceptionResolver myHandlerExceptionResolver = new MyHandlerExceptionResolver();

        resolvers.add(myHandlerExceptionResolver);
    }

4.2.3 使用@ExceptionHandler注解处理异常

注意:该注解不是加在产生异常的方法上,而是加在处理异常的方法上。
被 @ExceptionHandler 标记为异常处理方法,不能在方法中设置别的形参。
但是可以使用 ModelAndView 向前台传递数据。

package com.dc18669.spring.mvc;

import com.dc18669.spring.mvc.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;


@Controller
public class MyController {

    /**
     * -用于表单,即 POST请求
     *
     * @return
     */
    @RequestMapping(value = "/form_action", method = RequestMethod.POST)
    @ResponseBody
    public User[] form(@RequestBody User user) {
        System.out.println("POST请求=====");
        System.out.println("username : " + user.getUsername() + "  ,  password  : " + user.getPassword());
        User[] users = new User[2];
        users[0] = user;

        int a = 10 / 0;

        return users;
    }

    /**
     * ---- 
     * -ArithmeticException 表示异常类型
     *
     * 除此之外,还可以如下:
     * 自定义类上添加@ControllerAdvice注解,并在该类中添加@ExceptionHandler注解的方法
     * @ControllerAdvice 该注解会让你的异常处理类,变成全局的,否则只会在本类中处理。
     * @param e
     * @return
     */
    @ExceptionHandler(ArithmeticException.class)
    public ModelAndView error (Exception e) {

        ModelAndView mv = new ModelAndView();
        return mv;
    }
}

总结

  1. 当Ajax以application/x-www-form-urlencoded编码格式上传数据,必须使用JSON对象传递数据,后台需要使用@RequestParam或者HttpServletRequest来接收数据
  2. 当Ajax以application/json编码格式上传数据,必须使用JSON字符串传递数据,后台需要使用@RquestBody标识参数来获取数据,使用Map或者实体对象来接收数据,如果只单单是接收一个数组,可以使用List来接收数据。

注:Map 集合、List集合、数组、 使用@RequestBody注解标记的String 等接收参数值未验证通过。留待以后在验证。
还有 返回值为 View类型的代码,使用@ModelAttribute注解标记,等其他的未附代码的

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

枫很风流

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值