SSM之SpringMVC_ch3——SpringMVC流程

SSM之SpringMVC_ch3——SpringMVC流程

SpringMVC运行流程

请求----->响应 流程图如下:

运行流程

  • 1.用户通过浏览器发送请求,该请求通过部署在web.xml文件中的DispatcherServlet负责处理

  • 2.DispatcherServlet接收到请求,会通过容器中的一个或多个HandlerMapping对象来处理URL。HandlerMapping对象也是部署在Spring中的Bean,它实现了HandlerMapping接口来获取对应的Handler

  • 3.HandlerMapping对象根据URL返回对应的Handler对象

    Handler对象:对Controller中用于请求的方法的包装。

  • 4.一旦DispatcherServlet确定了合适的Handler,就会选择合适的HandlerAdapter来处理Handler

  • 5.HandlerAdapter在准备调用Handler(控制器的特定方法)之前,会先对请求参数进行一些处理(通过HttpMessageConverter),主要包括如下处理

    • 消息转换:将请求数据(如JSON、XML等)转换成对象,将对象转换成指定格式(如JSON、XML等)的响应数据等
    • 数据转换:对请求数据进行类型转换,如将String转换为Integer、Double等
    • 数据校验:校验数据的有效性(长度、格式等),将校验结果存储到BindingResult或Error中
  • 6.当控制器处理完请求后,会将Model(早期也包括ModelAndView)返回给HandlerAdapter

  • 7.HandlerAdapter再将视图模型返回给DispatcherServlet

  • 8.当DispatcherServlet接收到视图模型,会通过容器中的一个或多个ViewReslover(视图解析器)来处理

  • 9.视图解析器返回视图对象。即根据视图名称确定对象的视图资源

  • 10.确定了要呈现的视图后,将Model数据传递给对应的视图,视图负责呈现数据并生成最后的响应,响应呈现给用户。

纵观上述的流程,不难发现SpringMVC的运行流程中涉及的核心组件:

  • DispatcherServlet:核心控制器,需要在web.xml中配置
  • HandlerMapping:负责将请求URL映射到对应的Handler。可以自主选择配置合适的HandlerMapping类
  • Controller:控制器。需要定义Controller并使用合适注解修饰该类及其中的处理方法
  • HandlerAdapter:它负责调用Controller之前对请求参数进行一些前置处理,通常不需要自己关心
  • ViewReslover:视图解析器。它负责根据视图名确定对应的视图资源,一般都需要自主选择配置合适的视图解析器
  • View:视图资源。自主编写的视图页面

DispatcherServlet详解

在DispatcherServlet源码中有这样一个方法

protected void initStrategies(ApplicationContext context) {
    // 初始化上传文件解析器
    initMultipartResolver(context);
    // 初始化国际化解析器
    initLocaleResolver(context);
    // 初始化主题解析器
    initThemeResolver(context);
    // 初始化HandlerMapping对象
    initHandlerMappings(context);
    // 初始化HandlerAdapter对象
    initHandlerAdapters(context);
    // 初始化处理器异常解析器
    initHandlerExceptionResolvers(context);
    // 初始化视图名解析器
    initRequestToViewNameTranslator(context);
    // 初始图视图解析器
    initViewResolvers(context);
    // 初始化FlashMap管理器
    initFlashMapManager(context);
}
特殊Bean说明
HandlerMapping将请求URL映射到对应的Handler
HandlerAdapter主要用于帮助DispatcherServlet调用控制器,即对DispatcherServlet屏蔽控制器的各种细节
HandlerExceptionResolver将异常映射到视图
ViewReslover将逻辑视图名解析到实际视图(View对象)
LocaleResovler/LocaleContextResolver解析客户端正在使用的语言、区域设置及所在时区,以便呈现国际化页面
ThemeResolver解析Web应用程序可以使用的主体
MultipartResolver解析multi-part请求,主要用于支持对HTML表单的文件上传
FlashMapManager负责存储和检索一个请求传递到另一个请求的"input"和"output"属性

1.国际化解析器

该解析器只允许有一个实例,解析步骤如下

  • 查找名为localeResolver、类型为LocaleResolver的Bean作为国际化解析器
  • 如果未找到,则使用默认的实现类AcceptHeaderLocaleResolver作为国际化解析器

2.主题解析器

该解析器只允许有一个实例,解析步骤如下

  • 查找名为themeResolver、类型为ThemeResolver的Bean作为主题解析器
  • 如果未找到,则使用默认的实现类FixedThemeResolver作为主题解析器

3.HandlerMapping映射器

该解析器允许有多个实例,解析步骤如下

  • 如果detectAllHandlerMappings属性为true(默认为true),则根据类型匹配机制查找容器中所有类型为HandlerMapping的Bean,并将它们作为HandlerMapping映射器
  • 如果detectAllHandlerMappings属性为false,则查找名为handlerMapping、类型为HandlerMapping的Bean作为HandlerMapping映射器
  • 如果都未找到,则使用DispatcherServlet.properties配置文件中指定的两个实现类各创建一个映射器,并将它们添加到HandlerMapping映射器列表

4.HandlerAdapter(处理器适配器)

该解析器允许有多个实例,解析步骤如下

  • 如果detectAllHandlerAdapters属性为true(默认为true),则根据类型匹配机制查找容器中所有类型为HandlerAdapter的Bean,并将它们作为HandlerAdapter适配器
  • 如果detectAllHandlerAdapters属性为false,则查找名为handlerAdapter、类型为HandlerAdapter的Bean作为HandlerAdapter适配器
  • 如果都未找到,则使用DispatcherServlet.properties配置文件中指定的三个实现类各创建一个适配器,并将它们添加到处理器适配器列表

5.处理器异常解析器

该解析器允许有多个实例,解析步骤如下

  • 如果detectAllHandlerExceptionResolvers属性为true(默认为true),则根据类型匹配机制查找容器中所有类型为HandlerExceptionResolvers的Bean,并将它们作为HandlerExceptionResolver异常解析器
  • 如果detectAllHandlerExceptionResolvers属性为false,则查找名为handlerExceptionResolver、类型为HandlerExceptionResolver的Bean作为HandlerExceptionResolver异常解析器
  • 如果都未找到,则使用DispatcherServlet.properties配置文件中指定的三个实现类各创建一个适配器,并将它们添加到处理器异常解析器列表

6.视图名解析器

该解析器只允许有一个实例,解析步骤如下

  • 查找名为viewNameTranslator、类型为RequestToViewNameTranslator的Bean作为视图名解析器
  • 如果未找到,则使用默认的实现类DefaultRequestToViewNameTranslator作为视图名解析器

7.视图解析器

该解析器允许有多个实例,解析步骤如下

  • 如果detectAllViewResolvers属性为true(默认为true),则根据类型匹配机制查找容器中所有类型为ViewResolver的Bean,并将它们作为ViewResolver视图解析器
  • 如果detectAllViewResolvers属性为false,则查找名为viewResolver、类型为ViewResolver的Bean作为ViewResolver视图解析器
  • 如果都未找到,则使用DispatcherServlet.properties配置文件中指定的InternalResourceViewResolver作为视图解析器

8.文件上传解析器

该解析器只允许有一个实例,解析步骤如下

  • 查找名为multipartResolver、类型为MultipartResolver的Bean作为文件上传解析器
  • 如果没有自定义MultipartResolver类型的Bean,DispatcherServlet将不会加载该类型组件

9.FlashMap管理器

该解析器只允许有一个实例,解析步骤如下

  • 查找名为flashMapManager、类型为SessionFlashMapManger的Bean作为FlashMap管理器
  • 如果未找到,则使用默认的实现类SessionFlashMapManger作为FlashMap管理器

<mvc:annotation-driven>功能

主要在容器中配置了以下三个特殊Bean

  • HandlerMapping:使用RequestMappingHandlerMapping作为该特殊Bean的实现类
  • HandlerAdapter:使用RequestMappingHandlerAdapter作为该特殊Bean的实现类
  • HandlerExceptionResolver:使用ExceptionHandlerExceptionResolver作为该特殊Bean的实现类

静态资源处理

现在一般都对RESTful风格的URL支持,及URL后不带有任何后缀,因此SpringMVC的拦截URL设置为"/",即DispatcherServlet会拦截所有请求(包括静态资源的请求)。

Spring支持两种静态资源处理方法:静态资源映射和使用容器默认的Servlet

静态资源映射

使用<mvc:resource.../>为静态资源映射一个虚拟路径,接下来其他资源都可通过虚拟路径访问静态变量。

使用<mvc:resources.../>时可以指定的属性

  • location:必须属性,指定被映射的静态资源的物理路径
  • mapping:必须属性,指定被映射的静态资源的虚拟路径
  • cache-period:可选属性,指定该静态资源的缓存时间,单位是秒。
  • order:可选属性,指定处理静态资源映射的Handler的order值。值越小优先级越高

dispatcher-servlet.xml中的静态资源映射

<!--    将/static/images/路径下的资源映射为/imgs/**虚拟路径下的资源-->
<mvc:resources mapping="/imgs/**" location="/static/images/"/>

运行结果

运行结果

如果希望显示控制浏览器对静态资源的缓存,可以为<mvc:resource/>设置cache-period属性或者是<cache-controller/>子元素,cache-period属性只能指定一个整数值代表缓存时间(单位是秒),而<cache-controle/>子元素可以控制更多的缓存选项。

<!--    通过cache-period设置缓存一天,24*60*60 = 86400s-->
<mvc:resources mapping="/imgs/**" location="/static/images/" cache-period="86400"/>
<!--    通过cache-control子元素控制-->
<mvc:resources mapping="/imgs/**" location="/static/images/">
    <mvc:cache-control max-age="86400" cache-public="true" no-transform="false"/>
</mvc:resources>

<cache-control>的一些属性:

  • must-revalidate:true或false,用于为“Cache-Control”响应头添加must-revalidate指令。当缓存的响应过期时,该指令控制是否重新验证缓存。
  • no-cache:true或false,用于为“Cache-Control”响应头添加no-cache指令。该指令控制是否总是重新验证缓存的响应
  • no-store:true或false,用于为“Cache-Control”响应头添加no-store指令。该指令控制是否永不缓存响应
  • no-transform:true或false,用于为“Cache-Control”响应头添加no-transform指令。该指令控制缓存是否先对响应进行转换(例如压缩、优化以节省空间)
  • cache-public:true或false,用于为“Cache-Control”响应头添加cache-public指令。该指令控制是否任何缓存都允许缓存服务器响应
  • cache-private:true或false,用于为“Cache-Control”响应头添加cache-private指令。该指令控制是否使用私人缓存,而不是共享缓存来缓存服务器响应
  • proxy-revalidate:true或false,用于为“Cache-Control”响应头添加proxy-revalidate指令。与must-revalidate指令功能大致相同,区别是该指令仅对共享缓存有效
  • max-age:true或false,用于为“Cache-Control”响应头添加max-age指令。控制缓存服务器的响应时间。与cache-period属性的功能基本相同
  • s-maxage:true或false,用于为“Cache-Control”响应头添加s-maxage指令。该指令与max-age指令大致相同,区别是该指令仅对共享缓存有效
  • stale-while-revalidate:true或false,用于为“Cache-Control”响应头添加stale-while-revalidate指令。该指令控制缓存数据过期多少秒之内依然有效
  • stale-if-error:true或false,用于为“Cache-Control”响应头添加stale-if-error指令。当错误发生时,该属性指定的数值控制缓存的过期响应还可以使用多少秒

配置默认Servlet

其大致原理是:DispatcherServlet拦截请求后,会对请求进行分流

  • 对于静态资源的请求,DispatcherServlet会将该请求分流给Web容器的默认Servlet处理
  • 对于动态资源的请求,DispatcherServlet会调用HandlerMapping解析请求。

使用<mvc:default-servlet-handler/>配置默认Servlet,配置时可以指定一个default-servlet-name属性,用于指定Web容器中默认Servlet的名字;如果不指定该属性,则默认使用"default"的Servlet作为默认Servlet。Tomcat中可以看到已有default的Servlet配置,因此一般都省略default-servlet-name属性的配置。

dispatcher-servlet.xml中默认Servlet的配置

<!--    让SpringMVC处理静态资源,如.css,.js文件-->
<mvc:default-servlet-handler/>

运行结果

运行结果

视图解析器

种类繁多,暂时只介绍SpringMVC默认的视图解析器

转发与重定向

  • 转发(forward)代表仍然是同一个请求,因此转发到目标资源后请求参数、请求属性都不会丢失
  • 重定向(redirect)表示重新发送请求,重定向会生成一个新的请求,因此重定向后请求参数、请求属性都会丢失

InternalResourceViewResolver

InternalResourceViewResolver是UrlBasedViewResovler的子类。

InternalResourceViewResolver默认使用InternalResourceView作为viewClass。其优势之处在于可以“智能”选择视图类。

  • 如果类加载路径中有JSTL类库,它会默认使用JstlView作为viewClass
  • 如果类加载路径中没有JSTL类库,它会默认使用InternalResourceView作为viewClass

通常只需要配置prefix和suffix属性

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

重定向视图

InternalResourceViewResolver支持为视图名指定"redict:"前缀,这样可以让视图解析器创建RedirectView来重定向指定视图。实际上,也可以让控制器的处理方法直接返回RedirectView对象,强制DispatcherServlet不再使用正常的视图解析,而是执行重定向。

package com.reflect.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.view.RedirectView;

/**
 * author: Administrator
 * date: 2021/1/10 - 11:03
 */
@Controller
public class HelloController {
    @RequestMapping("/hello")
    public View Hello(Model model) {
        model.addAttribute("msg","Hello,SpringMVCRedirect");
        return new RedirectView("redirect.jsp");
    }
}

启动Tomcat访问主页之后,在后面加上hello访问即可。即localhost:8080/SpringMVC_ch3/hello

注意:必须要将跳转到的jsp放在web的根目录下。

运行结果

运行结果

原因是因为重定向是一次新的请求,地址栏中就可以看出变化了,model中的msg不再以请求方式传递给重定向目标,在页面中使用${msg}将获取不到任何数据。

将数据传给重定向目标

由以上的运行结果,引发的一个问题——会丢失请求属性和请求参数。即使SpringMVC中重定向改进了一步,会自动将model中的数据拼接在转发的URL后;但还是存在两个限制

  • 追加在URL后面的model数据只能是String或基本类型及其包装类;而且追加在URL后面的model数据长度是有限的。
  • 追加在URL后面的model数据直接显示在浏览器地址栏中,这样存在安全隐患

为了解决重定向后model数据丢失问题,SpringMVC提出了“Flash属性”的解决方案。即SpringMVC在重定向之前将model中的数据临时保存起来,当重定向完成后再将临时保存的数据放入新的model中,然后立刻清空临时存储的数据。

SpringMVC使用FlashMap保存model中的临时数据,FlashMap继承了HashMap<String,Object>,其实就是一个Map对象;而FlashMapManager对象则负责保存、放入model数据。目前,SpringMVC为FlashMapmanager接口只提供了一个SessionFlashMapManager实现类,这意味着FlashMapManager会使用session临时存储model数据。

对于每个请求,FlashMapManager都会维护"input"和"output"两个FlashMap属性,其中input属性存储了从上一个请求传入的数据,而output属性则存储了将要传给下一个请求的数据。

此处出于文章篇幅考虑,不往深处继续叙说。有兴趣可以自行研究。

请求映射与参数处理

最常用的RequestMappingHandlerMapping映射器,还有"古董级"的映射器BeanNameUrlHandlerMapping、改进版的映射器SimpleUrlHandlerMapping、和为WebSocket提供支持的映射器WebSocketHandlerMapping。

通过实现Controller接口来实现控制器的方式是Struts1时代,这种方式不值得推荐。

目前SpringMVC推荐的主流HandlerMapping就是RequestMappingHandlerMapping,所以有必要了解其注解形式及其变体

@Requestmapping注解

此注解用于修饰控制器类,也可修饰控制器类中的方法。

  • 修饰类时,指定的地址就相当于“基础路径”。意味着该控制器类中的所有处理方法映射的路径都应添加此基础路径。
  • 修饰方法时,指定的地址就相当于“当前路径”。当指定了“基础路径”时,那么处理方法实际访问映射就是"基础路径" + “当前路径”
常用属性
  • value:指定被修饰的类或方法映射的请求地址。最常用的属性
  • name:给映射地址一个名称
  • method:指定被修饰的类或方法使用哪种方法请求。只支持GET、POST、HEAD、OPTIONS、PUT、PATCH、DELETE、TRACE这几个枚举值。不指定时代表可处理各种请求
  • consumes:指定被修饰的类或方法只处理内容类型
  • produces:指定被修饰的类或方法只处理包含指定Accept请求头的请求
  • params:指定被修饰的类或方法只处理包含指定参数的请求
  • headers:与params类型,只不过它是基于请求头进行判断的
  • path:与value相同。value其实是path的别名
其它变体

变体Mapping前的单词即代表只能处理的请求。并且这些变体都只能修饰方法,不能修饰类。

  • @GetMapping
  • @PostMapping
  • @PutMapping
  • @DeleteMapping
  • PatchMapping

处理方法运行返回的返回值类型

处理方法最常见的返回值就是String对象,也见过View对象,和实现Controller接口必须返回的ModelAndView对象。

  • String:代表该处理方法返回的逻辑视图名
  • ModelAndView:早期控制器的处理方法要求返回该对象,用于组合视图对象和model
  • View:代表该处理方法返回的视图对象
  • HttpHeaders:希望服务器响应只有响应头,没有响应体。
  • Map或Model:该类型的返回值包含的属性将被添加到隐式的model中。
  • @ResponseBody:使用该注解修饰处理方法,该方法返回值将由HttpMessageConverter负责转换,并将该返回值直接作为响应输出。
  • @ModelAttribute:使用该注解修饰处理方法,该方法返回值将被绑定为model的指定属性

@RequestParam注解与MultiValueMap

@RequestParam是一个最基本的注解,专门用于修饰控制器的处理方法的形参,将查询参数、表单域参数甚至multipart请求的part参数映射到该形参。

  • value:String类型,指定被修饰的参数对应的请求参数名
  • name:String类型,value属性的别名
  • required:boolean类型,指定该请求参数是否必须,默认为true
  • defaultValue:String类型,当该请求参数不存在或为null时,为其指定默认值
@RequestMapping("/hello")
public View Hello(@RequestParam("username") name, Model model) {
    model.addAttribute("msg","Hello,SpringMVCRedirect");
    return new RedirectView("redirect.jsp");
}

SpringMVC还提供一种处理请求参数的方法:将控制器的处理方法声明为Map<String,String>或MultiValueMap<String,String>,这样请求的所有参数都会被自动传入该Map对象中;其中key作为参数名,value作为参数值。

MultiValueMap<String,String>是Spring提供的类型,它其实就是Map<K,List>的子类,其中key代表请求参数名,对应的value(List)代表多个请求参数值

@RequestMapping("/hello")
public View Hello(@RequestParam MultiValueMap<String,String>params,Model model) {
    model.addAttribute("msg","Hello,SpringMVCRedirect");
    return new RedirectView("redirect.jsp");
}

但是上述方式并不值得推荐,更简便的方式是:采用自定义的复合类型的形参接收请求参数。

假如用户提交的有name、password这两个参数——程序可定义一个User类型的参数,User类中包含name、password这两个属性——属性名和请求参数名相同,SpringMVC将会自动将name、password自动封装成User对象。甚至无须@RequestParam注解修饰。

@PathVariable获取路径变量值

@PathVariable获取正则表达式

路径模式

当存在多个路径模式与请求URL匹配时,SpringMVC将按"精确优先"原则进行匹配

  • 路径模式包含的路径变量越少、通配符越少,SpringMVC认为它越精确。

    例:/hotels/{hotel}/*只包含一个路径变量和一个通配符,它会被认为比/hotels/{hotel}/**更精确,因为后者包含一个路径变量和两个通配符

  • 如果两个路径模式包含的路径变量和通配符数量相同,长度更长的路径模式会被认为更精确

    例:/foo/bar*/foo/*两个路径模式都只包含一个通配符,但前者的长度更长,因此它会被认为更精确

  • 当两个路径模式包含的路径变量和通配符总数相同时,通配符较少的路径模式会被认为更精确。

    例:/hotels/{hotel}/hotels/*都只包含一个路径变量和通配符,但前者只包含路径变量,没有包含通配符,因此它会被认为更精确。

还有以下匹配规则:

  • /**路径几乎可匹配任何请求地址,因此任何路径都比它更精确。
  • /public/**几乎可匹配/public/路径下的任何请求地址,因此任何不包含**通配符的路径模式都比它更精确。

全部代码

项目结构图

项目结构图

1.web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
         version="5.0">

    <!--    必须的配置-->
    <!--    注册DispatcherServlet-->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--        关联一个springMVC的配置文件:[servlet-name]-servlet.xml-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:dispatcher-servlet.xml</param-value>
        </init-param>
        <!--        启动级别为1-->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!--    / 匹配所有的请求(不包括.jsp的请求)-->
    <!--    /* 匹配所有的请求(包括.jsp的请求)-->
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!--    非必须的配置-->
    <!--    使用ContextLoaderListener在Web应用启动时初始化Spring容器-->
    <!--    配置了此选项之后要配置applicationContext.xml配置文件,否则将会报错-->
<!--    <listener>-->
<!--        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>-->
<!--    </listener>-->
</web-app>

2.dispatcher-servlet.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"
       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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--    自动扫描-->
    <context:component-scan base-package="com.reflect.controller"/>
<!--    开启mvc支持驱动-->
    <mvc:annotation-driven/>


<!--    将/static/images/路径下的资源映射为/imgs/**虚拟路径下的资源-->
    <mvc:resources mapping="/imgs/**" location="/static/images/"/>
<!--    通过cache-period设置缓存一天,24*60*60 = 86400s-->
    <mvc:resources mapping="/imgs/**" location="/static/images/" cache-period="86400"/>
<!--    通过cache-control子元素控制-->
    <mvc:resources mapping="/imgs/**" location="/static/images/">
        <mvc:cache-control max-age="86400" cache-public="true" no-transform="false"/>
    </mvc:resources>

    <!--    让SpringMVC处理静态资源,如.css,.js文件-->
    <mvc:default-servlet-handler/>

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

</beans>

3.index.jsp

<%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2021/1/10
  Time: 8:46
  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>
  $END$
  <div>
    <img src="static/images/javasource.png"
         width="300px" height="300px">
  </div>
  <br>
  <br>
  <br>
  <div>
    <img src="${pageContext.request.contextPath}/imgs/javasource.png"
         width="300px" height="300px">
  </div>
  </body>
</html>

4.HelloController.java

package com.reflect.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.view.RedirectView;

/**
 * author: Administrator
 * date: 2021/1/10 - 11:03
 */
@Controller
public class HelloController {
    @RequestMapping("/hello")
    public View Hello(Model model) {
        model.addAttribute("msg","Hello,SpringMVCRedirect");
        return new RedirectView("redirect.jsp");
    }
}

5.redirect.jsp

<%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2021/1/10
  Time: 11:07
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Redirect</title>
</head>
<body>
    <h1>This Is Redirect Page!!!</h1>
    ${msg}
</body>
</html>
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值