AI 摘要

文章系统梳理 Spring MVC 入门要点:回顾 MVC 与 JSP Model 2 思想;示范 XML 与注解两种配置方式搭建 Hello 工程;详解 DispatcherServlet 请求流转机制;演示 @RequestMapping、@RequestParam、Model/ModelAndView/Map 出参及中文乱码处理;配置 InternalResourceViewResolver 简化视图路径,为后续 SSM 整合奠定扎实基础。

MVC 模式

MVC 概述

MVC 模式即 Model-View-Controller(模型-视图-控制器)模式,是开发 Web 应用程序时常用的一种代码分层方式。

MVC 模式的三层:

  • 模型(Model):负责处理业务逻辑和数据,对应 Java Bean,即 POJO 实体、DAO 层、Service 层。
  • 视图(View):负责处理数据并将数据呈现给用户,对应 JSP、HTML。
  • 控制器(Controller):负责接收并转发请求,对应 Servlet。

JSP Model 2

JSP + Servlet + Java Bean 的模式是典型的 JSP Model 2 模式。

JSP Model 1

早期的 JSP Model 1 模式中,缺少 Servlet,只由 JSP + Java Bean 组成,JSP 代替 Servlet 接受请求并处理数据,再将处理结果返回给前端。

在 JSP Model 1 模式中,JSP 身兼多职,既要负责视图层的数据展示,又要负责业务流程控制,结构混乱,因此更推荐 JSP Model 2 模式。

MVC 总结

MVC 模式的处理过程:

  • 视图层提供交互页面,并发送用户输入的请求给控制器层。
  • 控制器层接收用户的请求,并决定该调用的模型,调用对应的 Service 层、DAO 层操作数据。
  • 模型层根据用户请求进行相应的业务逻辑处理,并返回处理结果。
  • 控制器层根据返回的处理结果,通过视图层展示结果给用户。

MVC 模式的优点:

  • MVC 三个模块相互独立,松耦合架构。
  • 多视图共享一个模型,大大提高代码的可重用性。
  • 控制器提高了应用程序的灵活性和可配置性。
  • 有利于软件工程化管理。

MVC 模式的缺点:

  • 增加了系统结构和实现的复杂性,不适合小型规模的项目。
  • 视图层与模型之间需要控制器做中间的连接控制,所以效率较低。

常见的 MVC 框架:Struts 1.0、Struts 2.0、Spring MVC 等。

搭建 Spring MVC 环境

Spring MVC 概述

Spring MVC 是 Spring 提供的一个基于 MVC 模式设计的 Web 层框架。

Spring MVC 是基于 Servlet 实现的,使用了 Controller 代替掉 JSP Model 2 模型中的 Servlet,实现了更优雅、更高效的 JSP Model 2 的模型。

Spring MVC 的优点:

  • 角色划分清晰:Model、View、Controller 各司其职,各负其责。
  • 配置功能灵活:基于 Spring,可以使用 XML 或注解的方式开发 Spring MVC,使用 Spring IoC/AOP 特性解决问题。
  • 功能丰富:提供了 Web 应用开发的一整套流程,包含功能各异的技术工具,可以方便地配合使用。
  • 可灵活选择视图:可以根据项目实际需求选择 JSP、HTML、Velocity 等视图技术。
  • 支持国际化:提供国际化支持,可以轻松地实现不同语言之间的切换。

第一个 Spring MVC 程序

搭建 Spring MVC 开发环境的步骤:

  • 新建项目,并添加 Web 框架支持。
  • 导入 JAR 依赖包:Spring、Spring MVC、JSP。
  • 编写 Spring MVC 核心配置文件 springmvc-servlet.xml。
  • 编写 Web 应用配置文件 web.xml。
  • 编写 Spring MVC Controller 类。
  • 编写 JSP 视图页面。
  • 使用 Tomcat 运行 Spring MVC 程序。

示例:第一个 Spring MVC 程序

添加 Web 框架支持、导入相关依赖 JAR 文件,并添加为库。

示例效果:

Log4J 配置文件(classpath:log4j.properties):

log4j.rootLogger=debug,CONSOLE

##################
# Console Appender
##################
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.Threshold=debug
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern= - (%r ms) - %d{yyyy-M-d HH:mm:ss}%x[%5p](%F:%L) %m%n

Spring MVC 核心配置文件(classpath:springmvc-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:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">
  

</beans>

Web 应用配置文件(/web/WEB-INF/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">
    <!--
        Spring MVC底层是基于Servlet实现的
        需要将所有的请求交给Spring MVC的控制器来处理
        在web.xml中需要配置DispatcherServlet
        DispatcherServlet:前端控制器,是Spring MVC的核心
    -->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 为前端控制器加载Spring MVC核心配置文件 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc-servlet.xml</param-value>
        </init-param>
        <!-- 指定编码为UTF-8 -->
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <!-- 指定Tomcat启动时就加载前端控制器 -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!-- 定义前端控制器-Servlet的请求路径 -->
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <!-- /:所有的请求全部进入前端控制器,让前端控制器来做后续的工作 -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

Hello 控制器(cn.duozai.controller.HelloController):

/**
 * 控制器类继承AbstractController类,并重写handleRequestInternal方法
 */
public class HelloController extends AbstractController {

    /**
     * 处理Web请求
     *
     * @param httpServletRequest 请求对象
     * @param httpServletResponse 响应对象
     * @return 模型视图对象
     */
    @Override
    protected ModelAndView handleRequestInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        System.out.println("Spring MVC框架搭建成功啦");

        // 提供一个视图页面给用户
        return new ModelAndView("/WEB-INF/jsp/hello.jsp");
    }

}

Hello 视图页面(/web/WEB-INF/jsp/hello.jsp):

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>Spring MVC开发环境搭建成功</h1>
</body>
</html>

Spring MVC 核心配置文件(classpath:springmvc-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:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--
        为HelloController控制器指定请求路径
        id属性:Bean对象的名称
        name属性:给控制器绑定的请求路径

        请求/hello时,就会由HelloController中的handleRequestInternal方法进行处理
    -->
    <bean name="/hello" class="cn.duozai.controller.HelloController"/>

</beans>

添加 Tomcat 服务器:

示例效果:


使用注解开发 Spring MVC

在 Spring MVC 中,可以使用注解的方式进行开发。

Spring MVC 的基本注解:

名称描述
@Controller标记控制器类
@RequestMapping指定方法的请求路径d

示例:使用注解开发 Spring MVC

Spring MVC 核心配置文件(classpath:springmvc-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:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 开启Spring MVC注解 -->
    <mvc:annotation-driven/>
    <!-- 开启Spring IoC注解 -->
    <context:component-scan base-package="cn.duozai"/>

</beans>

Hello 控制器(cn.duozai.controller.HelloController):

/**
 * @Controller注解:标记为控制器Bean对象,即将该类交给Spring管理
 */
@Controller
public class HelloController {

    /**
     * 处理/hello请求
     * @RequestMapping注解:指定请求信息映射
     * value属性:指定请求路径
     *
     * @return 模型视图对象
     */
    @RequestMapping(value = "/hello")
    public ModelAndView hello() {
        System.out.println("Spring MVC框架搭建成功啦");

        // 提供一个视图页面给用户
        return new ModelAndView("/WEB-INF/jsp/hello.jsp");
    }

}

示例效果:


Spring MVC 流程梳理

Spring MVC 请求处理流程图:

Spring MVC 请求处理流程分析:

  • 用户发送请求(/hello)到 Web 服务器(Tomcat)。
  • 在 Web 服务器中,配置了 Spring MVC 的前端控制器 DispatcherServlet,前端控制器会接收到用户请求。
  • 前端控制器根据用户的请求信息(/hello),找到对应的页面控制器/方法(HelloController-hello 方法),并执行处理请求的方法。
  • 页面控制器/方法调用 Service 层、DAO 层操作数据,数据操作结果返回给控制器。
  • 页面控制器/方法将数据操作结果、视图页面路径保存在模型视图对象 ModelAndView 中,并将模型视图对象返回给前端控制器。
  • 前端控制器获取到模型视图对象后,根据对应的视图页面(hello.jsp)渲染视图页面。
  • 视图页面渲染完毕后,前端控制器将视图页面响应展示给用户。

Spring MVC 体系结构图:

Spring MVC 体系结构分析:

  • 用户发送请求到服务器,前端控制器(DispatcherServlet)接收到用户的请求。
  • 前端控制器(DispatcherServlet)通过处理器映射(HandlerMapping)来根据请求信息找到处理该请求的处理器(Handler),即控制器中的处理请求的方法。
  • 前端控制器(DispatcherServlet)通过处理器适配器(HandlerAdapter)调用实际处理请求的处理器(Handler)。
  • 在处理请求的过程中,处理器(Handler)可能会使用消息处理器(HttpMessageConverter)来处理 HTTP 消息的转换,包括数据绑定、数据转换、数据格式化和数据验证。
  • 处理器(Handler)处理完请求后,会把数据和视图信息保存到模型视图对象(ModelAndView)中,并将模型视图对象(ModelAndView)返回给前端控制器(DispatcherServlet)。
  • 前端控制器(DispatcherServlet)使用视图解析器(ViewResolver)来解析模型视图对象(ModelAndView)中的视图信息,找到对应的视图页面(View)。
  • 前端控制器(DispatcherServlet)将模型数据(Model)渲染到视图页面(View)中,并将视图页面返回给用户。

前后端数据交互

@RequestMapping 注解处理映射

Spring MVC 提供了 @RequestMapping 注解,用于处理映射关系。

@RequestMapping 注解的基本属性:

名称描述
value给方法绑定的请求路径
method限定 HTTP 请求方式

使用 @RequestMapping 注解处理映射时,需要注意:

  • @RequestMapping 注解可以加在控制器上,也可以加在控制器中的方法上。
  • @RequestMapping 注解映射请求信息后,通过类定义的请求信息 + 方法定义的请求信息来进行访问。
  • @RequestMapping 注解映射的请求信息(请求方式 + 请求路径)必须保证全局唯一。
  • @RequestMapping 注解可以为同一个方法映射多个请求路径。
  • 通常会为控制器的 @RequestMapping 注解定义不同的值,以便于区分请求,不易出错,通过请求 URL 就可以明确看出是属于哪一个业务模块下的功能。

@RequestMapping 注解的 value 属性用于将不同的请求路径映射到对应的控制器方法上,即给控制器方法绑定请求路径,当用户访问该路径时,就会执行这个控制器方法。


示例:使用 @RequestMapping 注解定义请求路径

Hello 控制器(cn.duozai.controller.HelloController):

/**
 * @Controller注解:标记为控制器Bean对象,即将该类交给Spring管理
 * @RequestMapping注解:为控制器中的所有方法添加统一的请求路径前缀
 * 访问控制器中的方法时,使用类请求路径+方法请求路径进行访问
 * 请求路径在整个项目中必须保证唯一性
 */
@Controller
@RequestMapping("/admin")
public class HelloController {

    /**
     * 处理/hello请求
     * @RequestMapping注解:指定请求信息映射
     * value属性:指定请求路径
     *
     * @return 模型视图对象
     */
    @RequestMapping(value = "/hello")
    public ModelAndView hello() {
        // ...
    }

    /**
     * 处理/h1和/h2请求
     *
     * @return 模型视图对象
     */
    @RequestMapping(value = {"/h1", "h2"})
    public ModelAndView hello2() {
        // ...
    }

}

示例效果:


@RequestMapping 注解可以通过 method 属性为方法指定 RequestMethod 枚举类中定义的请求方式。

RequestMethod 枚举类中的请求方式:

名称描述
GET限定方法只能通过 GET 方式进行访问,常用于查询功能
POST限定方法只能通过 POST 方式进行访问,常用于新增功能
PUT限定方法只能通过 PUT 方式进行访问,常用于修改功能
DELETE限定方法只能通过 DELETE 方式进行访问,常用于删除功能

示例:使用 @RequestMapping 注解定义请求方式

Hello 控制器(cn.duozai.controller.HelloController):

@Controller
@RequestMapping("/admin")
public class HelloController {

    /**
     * 处理/hello请求
     * @RequestMapping注解:指定请求信息映射
     * value属性:指定请求路径
     * method属性:指定请求方式,RequestMethod枚举
     *
     * @return 模型视图对象
     */
    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public ModelAndView hello() {
        // ...
    }

    /**
     * 处理/h1和/h2请求
     *
     * @return 模型视图对象
     */
    @RequestMapping(value = {"/h1", "h2"}, method = RequestMethod.POST)
    public ModelAndView hello2() {
        // ...
    }

}

示例效果:


@RequestMapping 注解有衍生注解,可以更便捷地为方法指定请求方式。

@RequestMapping 的衍生注解:

名称描述
@GetMapping同 RequestMethod.GET
@PostMapping同 RequestMethod.POST
@PutMapping同 RequestMethod.PUT
@DeleteMapping同 RequestMethod.DELETE

示例:使用 @RequestMapping 的衍生注解注解定义请求方式

Hello 控制器(cn.duozai.controller.HelloController):

@Controller
@RequestMapping("/admin")
public class HelloController {

    /**
     * 处理/hello请求
     *
     * @return 模型视图对象
     */
    @GetMapping(value = "/hello")
    public ModelAndView hello() {
        // ...
    }

    /**
     * 处理/h1和/h2请求
     *
     * @return 模型视图对象
     */
    @PostMapping(value = {"/h1", "h2"})
    public ModelAndView hello2() {
        // ...
    }

}

@RequestParam 注解处理入参

Spring MVC 提供了 @RequestParam 注解,用于接收视图页面传递给方法的参数。

@RequestParam 注解的基本属性:

名称描述
name视图页面传递给方法的参数名称
required参数是否必须,默认为 true,若请求中不包含该参数,则抛出异常
defaultValue当参数不传或传入空值时,为参数赋予默认值

控制器方法要接收视图页面传递的参数,只需要在方法中定义传入的参数,并在该参数前添加 @RequestParam 注解。


示例:使用 @RequestParam 注解接收参数

首页视图页面(/web/WEB-INF/jsp/index.jsp):

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="/hello" method="post">
    请输入姓名:<input type="text" name="name"><br><br>
    请输入年龄:<input type="text" name="age"><br><br>
    <input type="submit" value="提交">
</form>
</body>
</html>

Hello 控制器(cn.duozai.controller.HelloController):

@Controller
public class HelloController {

    private static final Logger logger = Logger.getLogger(HelloController.class);

    /**
     * 提供表单
     *
     * @return 模型视图对象
     */
    @GetMapping("/index")
    public ModelAndView index() {
        return new ModelAndView("/WEB-INF/jsp/index.jsp");
    }

    /**
     * 处理表单请求
     * @RequestParam注解:接收表单传递过来的参数
     * name属性:对应表单元素的name属性,即参数名称
     *
     * @param name 视图页面表单传递的name参数
     * @param age 视图页面表单传递的age参数
     * @return 模型视图对象
     */
    @PostMapping("/hello")
    public ModelAndView hello(@RequestParam(name = "name") String name,
                              @RequestParam(name = "age") Integer age) {
        logger.debug("视图页面表单传递的姓名 => " + name);
        logger.debug("视图页面表单传递的年龄 => " + age);

        // 暂时不返回视图页面
        return null;
    }

}

示例效果:


默认情况下,被 @RequestParam 注解标记的参数是必传的,可以通过 @RequestParam 注解的 required 属性设置为非必传,使用 defaultValue 属性设置参数的默认值。


示例:使用 @RequestParam 为参数设置默认值

Hello 控制器(cn.duozai.controller.HelloController):

@Controller
public class HelloController {

    private static final Logger logger = Logger.getLogger(HelloController.class);

    /**
     * 提供表单
     *
     * @return 模型视图对象
     */
    @GetMapping("/index")
    public ModelAndView index() {
        // ...
    }

    /**
     * 处理表单请求
     * @RequestParam注解:接收表单传递过来的参数
     * name属性:对应表单元素的name属性,即参数名称
     * required属性:参数是否必须传递
     * defaultValue属性:参数默认值
     *
     * @param name 视图页面表单传递的name参数
     * @param age 视图页面表单传递的age参数
     * @return 模型视图对象
     */
    @PostMapping("/hello")
    public ModelAndView hello(@RequestParam(name = "name") String name,
                              @RequestParam(name = "age", required = false, defaultValue = "18") Integer age) {
        // ...
    }

}

示例效果:


解决入参中文乱码问题

Spring MVC 控制器方法入参时,会出现接收中文参数乱码问题,可以在 Web 应用配置文件中增加 String 字符编码过滤器并配置字符编码为 UTF-8 来解决中文乱码问题。


示例:解决入参中文乱码问题

Web 应用配置文件(/web/WEB-INF/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">
    <!-- ... -->

    <!-- 解决入参中文乱码问题 -->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

示例效果:


ModelAndView 对象处理出参

Spring MVC 中将数据传递给视图页面,可以使用 ModelAndView 对象处理出参。

ModelAndView 对象即模型视图对象,其既可以包含视图信息,也可以包含模型数据。

ModelAndView 对象的基本方法:

名称描述
ModelAndView addObject(String k, Object v)将数据以 k-v 的形式添加到模型视图对象中
数据可以是基本数据类型、复杂数据类型等
在 JSP 视图页面中通过 EL 表达式来取值
void setViewName(String viewName)设置视图页面的路径

示例:使用 ModelAndView 对象处理出参

Hello 控制器(cn.duozai.controller.HelloController):

@Controller
public class HelloController {

    // ...

    /**
     * 处理表单请求
     *
     * @param name 视图页面表单传递的name参数
     * @param age 视图页面表单传递的age参数
     * @return 模型视图对象
     */
    @PostMapping("/hello")
    public ModelAndView hello(@RequestParam(name = "name") String name,
                              @RequestParam(name = "age",required = false, defaultValue = "18") Integer age) {
        logger.debug("视图页面表单传递的姓名 => " + name);
        logger.debug("视图页面表单传递的年龄 => " + age);

        ModelAndView mv = new ModelAndView();
        // 将数据添加到ModelAndView模型视图对象中
        // 在JSP页面中就可以通过EL表达式获取数据
        mv.addObject("name", name);
        mv.addObject("age", age);

        // 设置视图页面文件路径
        mv.setViewName("/WEB-INF/jsp/hello.jsp");

        // 返回模型视图对象
        return mv;
    }

}

Hello 视图页面(/web/WEB-INF/jsp/hello.jsp):

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>Hello!</h1>
<!-- 使用JSP-EL表达式获取模型视图对象中的数据 -->
<h1>您的姓名:${name}</h1>
<h1>您的年龄:${age}</h1>
</body>
</html>

示例效果:


Model 对象处理出参

Spring MVC 中将数据传递给视图页面,可以使用 Model 对象处理出参。

Model 对象即模型对象,控制器方法可以接收一个 Model 类型的参数,用于存放模型数据,控制器方法不再返回 ModelAndView,直接返回视图页面的路径字符串。

Model 对象的基本方法:

名称描述
void addAttribute(String k, Object v)将数据以 k-v 的形式添加到模型对象中
数据可以是基本数据类型、复杂数据类型等
在 JSP 视图页面中通过 EL 表达式来取值

使用 Model 对象处理出参,是 Spring MVC 的标准用法。


示例:使用 Model 对象处理出参

用户实体类(cn.duozai.entity.User):

public class User {

    /**
     * 姓名
     */
    private String name;

    /**
     * 年龄
     */
    private Integer age;

    /**
     * 网址
     */
    private String website;

    // ...
  
}

Hello 控制器(cn.duozai.controller.HelloController):

@Controller
public class HelloController {

    // ...

    /**
     * 处理表单请求
     *
     * @param model Model模型对象
     * @param name 视图页面表单传递的name参数
     * @param age 视图页面表单传递的age参数
     * @return 视图页面文件路径
     */
    @PostMapping("/hello")
    public String hello(Model model,
                       @RequestParam(name = "name") String name,
                       @RequestParam(name = "age",required = false, defaultValue = "18") Integer age) {
        logger.debug("视图页面表单传递的姓名 => " + name);
        logger.debug("视图页面表单传递的年龄 => " + age);

        // 实例化User对象
        User user = new User();
        user.setName(name);
        user.setAge(age);
        user.setWebsite("http://www.duozai.cn");

        // 将数据添加到Model模型对象中
        model.addAttribute("userObject", user);

        // 返回视图页面文件路径
        return "/WEB-INF/jsp/hello.jsp";
    }

}

Hello 视图页面(/web/WEB-INF/jsp/hello.jsp):

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>Hello!</h1>
<!-- 使用JSP-EL表达式获取模型视图对象中的数据 -->
<h1>您的姓名:${userObject.name}</h1>
<h1>您的年龄:${userObject.age}</h1>
<h1>您的网址:${userObject.website}</h1>
</body>
</html>

示例效果:


Map 对象处理出参

Spring MVC 中将数据传递给视图页面,可以使用 Map 对象处理出参,使用方式同 Model 对象。


示例:使用 Map 对象处理出参

Hello 控制器(cn.duozai.controller.HelloController):

@Controller
public class HelloController {

    // ...

    /**
     * 处理表单请求
     *
     * @param mapModel Map对象
     * @param name 视图页面表单传递的name参数
     * @param age 视图页面表单传递的age参数
     * @return 视图页面文件路径
     */
    @PostMapping("/hello")
    public String hello(Map<String, Object> mapModel,
                        @RequestParam(name = "name") String name,
                        @RequestParam(name = "age",required = false, defaultValue = "18") Integer age) {
        logger.debug("视图页面表单传递的姓名 => " + name);
        logger.debug("视图页面表单传递的年龄 => " + age);

        // 实例化User对象
        User user = new User();
        user.setName(name);
        user.setAge(age);
        user.setWebsite("http://www.duozai.cn");

        // 将数据添加到Map对象中
        mapModel.put("userObject", user);

        // 返回视图页面文件路径
        return "/WEB-INF/jsp/hello.jsp";
    }

}

视图解析器

视图解析器概述

Spring MVC 视图解析器(View Resolver)负责将控制器方法返回的视图页面的路径解析为实际要呈现给客户端的物理视图,如一个 JSP 页面、HTML 页面等。

Spring MVC 常见的视图解析器:

  • InternalResourceViewResolver:处理 JSP 视图的经典视图解析器,它会将视图名称解析为相对于特定前缀和后缀的 JSP 文件路径。
  • ThymeleafViewResolver:用于和 Thymeleaf 模板引擎配合使用。
  • FreeMarkerViewResolver:用于和 FreeMarker 模板引擎配合使用。

借助 InternalResourceViewResolver 视图解析器,可以在 Spring MVC 核心配置文件中配置视图文件路径前缀为“/WEB-INF/jsp/”,后缀为“.jsp”,当控制器返回“index” 时,视图文件路径就会被解析成“/WEB-INF/jsp/index.jsp”。


示例:视图解析器

Spring MVC 核心配置文件(classpath:springmvc-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:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 开启Spring MVC注解 -->
    <mvc:annotation-driven/>
    <!-- 开启Spring IoC注解 -->
    <context:component-scan base-package="cn.duozai"/>

    <!-- 配置视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 视图页面文件路径前缀 -->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!-- 视图页面文件路径后缀 -->
        <property name="suffix" value=".jsp"/>
    </bean>

</beans>

Hello 控制器(cn.duozai.controller.HelloController):

@Controller
public class HelloController {

    private static final Logger logger = Logger.getLogger(HelloController.class);

    /**
     * 提供一个表单
     *
     * @return 视图页面文件名称
     */
    @GetMapping("/index")
    public String index() {
        // 返回视图页面文件名称
        // 视图解析器拼接的视图路径为:/WEB-INF/jsp/index.jsp
        return "index";
    }

    /**
     * 处理表单请求
     *
     * @param model Model模型对象
     * @param name 视图页面表单传递的name参数
     * @param age 视图页面表单传递的age参数
     * @return 视图页面文件名称
     */
    @PostMapping("/hello")
    public String hello(Model model,
                        @RequestParam(name = "name") String name,
                        @RequestParam(name = "age",required = false, defaultValue = "18") Integer age) {
        // ...

        // 返回视图页面文件名称
        return "hello";
    }

}

示例效果: