云计算百科
云计算领域专业知识百科平台

【Day42】SpringMVC 入门:DispatcherServlet 与请求映射

本文收录于「Java 学习日记」专栏,聚焦 SpringMVC 的核心骨架 ——DispatcherServlet 前端控制器与请求映射机制,从底层流程拆解到注解式实战,帮你打通 SpringMVC 入门的关键一步~

一、为什么要学 SpringMVC?

在前序的 Spring 核心学习中,我们掌握了 IOC/DI、AOP 等基础,但在 Web 开发场景下,还面临这些问题:

  • 手动编写 Servlet 需要处理请求分发、参数解析、视图跳转等重复逻辑,开发效率低;
  • 传统 MVC 手动实现的框架功能简陋,无法适配复杂的 Web 场景(如 RESTful 接口、文件上传);
  • 无法与 Spring 核心容器无缝整合,依赖注入、AOP 等特性无法在 Web 层复用。

而SpringMVC作为 Spring 框架的 Web 模块,完美解决了这些问题:

  • 基于 MVC 设计模式,封装了 Servlet 底层细节,提供简洁的注解式开发;
  • 核心组件 DispatcherServlet 统一处理所有请求,实现请求分发、参数绑定、视图解析等自动化;
  • 与 Spring 核心容器无缝整合,可直接复用 IOC/DI、AOP 等特性;
  • 支持 RESTful API、文件上传、拦截器、异常处理等企业级特性,是 Java Web 开发的主流框架。

今天这篇日记,我们从 SpringMVC 核心流程入手,聚焦 DispatcherServlet 和请求映射两大核心,通过实战掌握 SpringMVC 的入门用法。

二、SpringMVC 核心架构与工作流程

1. SpringMVC 核心组件

SpringMVC 的核心是 “前端控制器 + 组件化处理”,核心组件分工如下:

组件中文名称核心职责
DispatcherServlet 前端控制器 接收所有请求,分发到其他组件,核心调度者
HandlerMapping 处理器映射器 根据请求路径匹配对应的 Controller 方法
HandlerAdapter 处理器适配器 调用 Controller 方法,处理参数绑定、返回值解析
Controller/Handler 处理器(控制器) 处理请求逻辑,返回视图名 / 数据
ViewResolver 视图解析器 将视图名解析为具体的视图对象(如 JSP/HTML)
View 视图 渲染页面,返回响应给客户端
HandlerInterceptor 拦截器 对请求进行前置 / 后置处理(如登录校验)

2. SpringMVC 完整工作流程(核心)

用流程图直观展示请求从客户端到服务端的全流程:

3. 核心流程拆解(通俗版)

  • 请求进门:所有请求都先到 DispatcherServlet(相当于公司前台);
  • 找对应员工:HandlerMapping 根据请求 URL 找到对应的 Controller 方法(前台根据需求找对应业务员工);
  • 适配调用:HandlerAdapter 负责调用 Controller 方法,处理参数、返回值等细节(行政帮员工准备好工作条件);
  • 处理业务:Controller 处理具体业务逻辑,返回视图名(员工处理具体工作,告诉前台结果);
  • 找视图页面:ViewResolver 根据视图名找到具体的页面(前台根据结果找对应的输出模板);
  • 返回响应:View 渲染页面并返回给客户端(输出最终结果)。
  • 三、SpringMVC 入门实战:环境搭建与核心配置

    1. 开发环境准备

    • JDK:8 及以上;
    • 构建工具:Maven;
    • Web 容器:Tomcat 8.5+;
    • SpringMVC 版本:5.3.x(与 Spring 核心版本一致)。

    2. Maven 依赖配置(核心)

    xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>springmvc-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
    <spring.version>5.3.29</spring.version>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
    <!– SpringMVC核心依赖 –>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${spring.version}</version>
    </dependency>
    <!– Servlet API(Tomcat已提供,编译时依赖) –>
    <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
    </dependency>
    <!– JSP API(Tomcat已提供) –>
    <dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>jsp-api</artifactId>
    <version>2.2</version>
    <scope>provided</scope>
    </dependency>
    <!– JSTL(JSP标签库) –>
    <dependency>
    <groupId>jstl</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
    </dependency>
    </dependencies>

    <!– 构建配置:指定war包名称、编译插件 –>
    <build>
    <finalName>springmvc-demo</finalName>
    <plugins>
    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <configuration>
    <source>8</source>
    <target>8</target>
    </configuration>
    </plugin>
    <!– Tomcat插件(方便运行) –>
    <plugin>
    <groupId>org.apache.tomcat.maven</groupId>
    <artifactId>tomcat7-maven-plugin</artifactId>
    <version>2.2</version>
    <configuration>
    <port>8080</port>
    <path>/</path>
    </configuration>
    </plugin>
    </plugins>
    </build>
    </project>

    3. 配置 DispatcherServlet(web.xml)

    DispatcherServlet 是 SpringMVC 的核心,需要在web.xml中配置(相当于注册 “前台”):

    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">

    <!– 配置SpringMVC前端控制器DispatcherServlet –>
    <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!– 指定SpringMVC配置文件路径(默认/WEB-INF/[servlet-name]-servlet.xml) –>
    <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:springmvc-config.xml</param-value>
    </init-param>
    <!– 启动时加载(优先级1),Tomcat启动时就初始化DispatcherServlet –>
    <load-on-startup>1</load-on-startup>
    </servlet>

    <!– 映射所有请求到DispatcherServlet –>
    <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <!– /:匹配所有请求(除了JSP),/*:匹配所有请求(包括JSP,不推荐) –>
    <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!– 字符编码过滤器(解决POST请求中文乱码) –>
    <filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
    <param-name>encoding</param-name>
    <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
    <param-name>forceEncoding</param-name>
    <param-value>true</param-value>
    </init-param>
    </filter>
    <filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
    </web-app>

    4. SpringMVC 核心配置文件(springmvc-config.xml)

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

    <!– 1. 扫描Controller包下的注解(@Controller/@RequestMapping等) –>
    <context:component-scan base-package="com.example.controller"/>

    <!– 2. 开启SpringMVC注解驱动(支持@RequestMapping、参数绑定等) –>
    <mvc:annotation-driven/>

    <!– 3. 配置视图解析器(将视图名解析为JSP路径) –>
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <!– 前缀:JSP文件所在目录 –>
    <property name="prefix" value="/WEB-INF/views/"/>
    <!– 后缀:JSP文件后缀 –>
    <property name="suffix" value=".jsp"/>
    </bean>

    <!– 4. 静态资源放行(如CSS/JS/图片,否则DispatcherServlet会拦截) –>
    <mvc:default-servlet-handler/>
    </beans>

    四、请求映射实战:@RequestMapping 注解

    1. 核心注解说明

    @RequestMapping是 SpringMVC 中最核心的请求映射注解,用于将请求 URL 绑定到 Controller 方法,支持类级和方法级注解:

    注解属性作用示例
    value/path 指定请求 URL 路径 @RequestMapping("/user/query")
    method 指定请求方式(GET/POST/PUT/DELETE) method = RequestMethod.GET
    params 指定请求必须包含的参数 params = "id"(必须有 id 参数)
    headers 指定请求必须包含的请求头 headers = "Content-Type=application/json"
    produces 指定响应内容类型 produces = "application/json"

    2. 编写 Controller(核心)

    java

    运行

    package com.example.controller;

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

    import javax.servlet.http.HttpServletRequest;

    // 标记为SpringMVC控制器(由SpringMVC容器管理)
    @Controller
    // 类级请求映射:所有方法的URL前缀为/user
    @RequestMapping("/user")
    public class UserController {

    // 1. 基础映射:GET请求 /user/query → 匹配该方法
    @RequestMapping(value = "/query", method = RequestMethod.GET)
    public String queryUser(HttpServletRequest request, Model model) {
    // 1. 获取请求参数(原生Servlet方式)
    String userId = request.getParameter("id");
    // 2. 封装数据到Model(传递到视图)
    model.addAttribute("userId", userId);
    model.addAttribute("username", "Java日记");
    // 3. 返回视图名(视图解析器会解析为/WEB-INF/views/userInfo.jsp)
    return "userInfo";
    }

    // 2. 简化参数绑定:直接将参数绑定到方法参数
    @GetMapping("/detail") // @GetMapping = @RequestMapping(method=GET)
    public String userDetail(@RequestParam("id") String userId,
    @RequestParam(defaultValue = "18") Integer age,
    Model model) {
    model.addAttribute("msg", "用户ID:" + userId + ",年龄:" + age);
    return "detail";
    }

    // 3. 路径变量:RESTful风格(URL中嵌入参数)
    @GetMapping("/{id}/info")
    public String restfulDemo(@PathVariable("id") String userId, Model model) {
    model.addAttribute("restMsg", "RESTful风格:用户ID=" + userId);
    return "restful";
    }

    // 4. POST请求映射(配合表单提交)
    @PostMapping("/save") // @PostMapping = @RequestMapping(method=POST)
    public String saveUser(@RequestParam("username") String username,
    @RequestParam("password") String password,
    Model model) {
    model.addAttribute("saveMsg", "保存用户:" + username + " 成功");
    // 重定向(不会经过视图解析器,需加redirect:前缀)
    return "redirect:/user/success";
    }

    // 5. 跳转成功页
    @GetMapping("/success")
    public String success() {
    return "success";
    }

    // 6. 响应JSON数据(@ResponseBody:返回值直接作为响应体,不解析为视图)
    @GetMapping("/json")
    @ResponseBody
    public String getJson() {
    return "{\\"code\\":200,\\"msg\\":\\"success\\"}";
    }
    }

    3. 编写视图页面

    (1)用户信息页:/WEB-INF/views/userInfo.jsp

    jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
    <title>用户信息</title>
    </head>
    <body>
    <h1>用户信息页面</h1>
    <p>用户ID:${userId}</p>
    <p>用户名:${username}</p>
    </body>
    </html>

    (2)表单页:/WEB-INF/views/form.jsp

    jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
    <title>用户表单</title>
    </head>
    <body>
    <h1>用户注册</h1>
    <form action="${pageContext.request.contextPath}/user/save" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="提交">
    </form>
    </body>
    </html>

    (3)成功页:/WEB-INF/views/success.jsp

    jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
    <title>成功页</title>
    </head>
    <body>
    <h1>操作成功</h1>
    <p>${saveMsg}</p>
    </body>
    </html>

    4. 测试请求映射

    (1)测试 GET 请求

    访问:http://localhost:8080/user/query?id=1001效果:跳转到userInfo.jsp,展示用户 ID 和用户名。

    (2)测试 RESTful 风格

    访问:http://localhost:8080/user/1002/info效果:跳转到restful.jsp,展示 RESTful 风格的用户 ID。

    (3)测试 POST 请求
  • 访问:http://localhost:8080/user/form(需新增 form 方法返回 form 视图);
  • 填写表单并提交,会跳转到success.jsp,展示保存成功信息。
  • (4)测试 JSON 响应

    访问:http://localhost:8080/user/json效果:直接返回 JSON 字符串,而非跳转页面。

    5. 简化注解(Spring4.3+)

    为了简化@RequestMapping的 method 属性,Spring 提供了专用注解:

    简化注解等价于
    @GetMapping @RequestMapping(method=RequestMethod.GET)
    @PostMapping @RequestMapping(method=RequestMethod.POST)
    @PutMapping @RequestMapping(method=RequestMethod.PUT)
    @DeleteMapping @RequestMapping(method=RequestMethod.DELETE)

    五、核心避坑指南

    1. 常见问题与解决方案

    问题现象根因解决方案
    404 错误(页面找不到) 1. 视图解析器前缀 / 后缀配置错误;2. JSP 文件路径错误;3. 返回视图名错误 1. 核对 prefix/suffix;2. 检查 JSP 是否在 / WEB-INF/views/ 下;3. 核对返回的视图名
    405 错误(请求方法不允许) @RequestMapping 的 method 与实际请求方式不匹配 1. 检查 method 属性;2. 改用 @GetMapping/@PostMapping
    静态资源(CSS/JS)无法访问 DispatcherServlet 拦截了静态资源 添加<mvc:default-servlet-handler/>放行静态资源
    POST 请求中文乱码 未配置字符编码过滤器 在 web.xml 中配置 CharacterEncodingFilter
    @ResponseBody 返回中文乱码 响应编码未设置 在<mvc:annotation-driven/>中配置消息转换器,设置 UTF-8

    2. 最佳实践

  • URL 设计:遵循 RESTful 风格,用 URL 表示资源,用请求方式表示操作(GET 查询、POST 新增、PUT 修改、DELETE 删除);
  • 参数绑定:优先使用@RequestParam/@PathVariable,而非原生 HttpServletRequest,代码更简洁;
  • 视图跳转:
    • 服务器内部跳转:返回视图名(如return "userInfo");
    • 重定向:加redirect:前缀(如return "redirect:/user/success");
    • 响应 JSON:加@ResponseBody注解;
  • 包扫描:context:component-scan仅扫描 Controller 包(com.example.controller),避免扫描 Service/DAO,提升性能;
  • 静态资源:将 CSS/JS/ 图片放在webapp/static目录下,通过<mvc:default-servlet-handler/>放行。
  • 六、今日实战小任务

  • 基于实战案例,新增@PutMapping("/{id}/update")和@DeleteMapping("/{id}/delete")方法,实现 RESTful 风格的修改和删除;
  • 新增一个登录页面(login.jsp),通过@PostMapping("/login")处理登录请求,校验用户名密码(admin/123456),成功则重定向到首页,失败则返回登录页并提示错误信息;
  • 配置@ResponseBody返回 JSON 时的中文乱码问题,通过<mvc:annotation-driven/>配置 StringHttpMessageConverter 的编码为 UTF-8。

  • 总结

  • SpringMVC 的核心是 DispatcherServlet 前端控制器,统一接收并分发请求,通过 HandlerMapping 匹配 Controller 方法,HandlerAdapter 调用方法,ViewResolver 解析视图;
  • @RequestMapping是请求映射的核心注解,支持类级和方法级配置,可指定 URL、请求方式、参数等,Spring4.3 + 提供@GetMapping/@PostMapping等简化注解;
  • 视图解析器通过前缀(prefix)和后缀(suffix)将视图名解析为具体的 JSP 路径,重定向需加redirect:前缀,响应 JSON 需加@ResponseBody;
  • 核心避坑点:404/405 错误、静态资源访问、中文乱码,需重点关注配置文件和注解的正确性。
  • 下一篇【Day43】预告:SpringMVC 参数绑定与返回值处理:从简单参数到复杂对象,关注专栏继续解锁 SpringMVC 核心功能~若本文对你有帮助,欢迎点赞 + 收藏 + 关注,你的支持是我更新的最大动力💖!

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 【Day42】SpringMVC 入门:DispatcherServlet 与请求映射
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!