SpringMVC 系列博客(二):核心功能深入 —— 请求映射、返回值与参数绑定
目录
一、引言
二、请求映射:@RequestMapping 的全方位用法
2.1 修饰类 + 方法:实现 URL 分层
2.2 多维度匹配规则:value、method、params、headers
2.2.1 value:匹配 URL(核心属性)
2.2.2 method:匹配请求方法(GET/POST)
2.2.3 params:匹配请求参数
2.2.4 headers:匹配请求头(了解)
三、Controller 方法返回值类型:灵活控制跳转与数据
3.1 ModelAndView:既带数据又指定视图
3.2 String:仅指定视图(或跳转路径)
3.2.1 直接返回逻辑视图名
3.2.2 带转发(forward:)或重定向(redirect:)
3.3 void:无返回值(手动控制响应)
四、参数绑定:从前端到 Controller 的 “数据桥梁”
4.1 核心原理
4.2 常见参数绑定场景
4.2.1 场景 1:默认类型绑定(Servlet API)
4.2.2 场景 2:简单类型绑定(String、Integer、Boolean 等)
4.2.3 场景 3:POJO 类型绑定(实体类)
4.2.4 场景 4:集合类型绑定(数组、List、Map)
(1)数组绑定(如多选爱好)
(2)List 绑定(批量修改用户)
(3)Map 绑定(灵活存储键值对)
4.2.5 场景 5:自定义类型绑定(如日期转换)
五、第二篇总结
一、引言
在掌握 SpringMVC 基础入门后,我们需要深入其核心功能 ——请求映射(如何精准匹配 URL)、返回值类型(如何灵活控制页面跳转与数据传递)、参数绑定(如何便捷接收前端参数)。这些功能是 SpringMVC 开发的 “骨架”,直接决定了代码的简洁性与可维护性。本文将通过大量实例,带你逐一攻克这些核心知识点。
二、请求映射:@RequestMapping 的全方位用法
@RequestMapping
是 SpringMVC 中最核心的注解,用于将 URL 请求与 Controller 方法绑定。它可修饰类和方法,支持多维度匹配规则,实现精准的请求拦截。
注解@RequestMapping修饰类,提供初步的请求映射信息,相对于WEB应用的跟目录:
2.1 修饰类 + 方法:实现 URL 分层
- 类级别:定义 “基础 URL”,统一管理该类下所有方法的请求路径,避免重复编写。
- 方法级别:定义 “子 URL”,与类级别 URL 拼接成完整路径。
示例:
package com.jr.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;@Controller
@RequestMapping("/user") // 类级别:基础URL
public class UserController {// 完整URL:/user/reg.do@RequestMapping("/reg.do") public ModelAndView register() {ModelAndView mv = new ModelAndView();mv.setViewName("ok.jsp");return mv;}// 完整URL:/user/login.do@RequestMapping("/login.do") public ModelAndView login() {ModelAndView mv = new ModelAndView();mv.setViewName("ok.jsp");return mv;}
}
注意:若类级别未加@RequestMapping
,则方法级别 URL 直接对应项目根路径(如/reg.do
)。
2.2 多维度匹配规则:value、method、params、headers
@RequestMapping
提供多个属性,支持按 “URL、请求方法、请求参数、请求头” 组合匹配,满足复杂业务需求。
2.2.1 value:匹配 URL(核心属性)
- 支持单个 URL:
@RequestMapping(value = "/reg.do")
(value 可省略,简写为@RequestMapping("/reg.do")
)。 - 支持多个 URL:用数组表示,多个 URL 映射到同一方法。
示例:
// 访问/reg.do或/register.do,都触发register()方法
@RequestMapping(value = {"/reg.do", "/register.do"})
public ModelAndView register() {// 业务逻辑...
}
2.2.2 method:匹配请求方法(GET/POST)
限制方法仅处理指定 HTTP 请求(如仅允许 POST 提交表单),避免非法请求。
示例:
import org.springframework.web.bind.annotation.RequestMethod;// 仅处理POST请求,若用GET访问/reg.do会报405错误
@RequestMapping(value = "/reg.do", method = RequestMethod.POST)
public ModelAndView register() {// 业务逻辑...
}// 同时支持GET和POST
@RequestMapping(value = "/login.do", method = {RequestMethod.GET, RequestMethod.POST})
public ModelAndView login() {// 业务逻辑...
}
2.2.3 params:匹配请求参数
要求请求必须包含指定参数(或参数值满足条件),否则无法匹配。
示例:
// 1. 请求必须包含"username"和"password"参数(值无限制)
@RequestMapping(value = "/login.do", params = {"username", "password"})
public ModelAndView login() { ... }// 2. 请求必须包含"username=admin"和"password"参数
@RequestMapping(value = "/login.do", params = {"username=admin", "password"})
public ModelAndView login() { ... }// 3. 请求不能包含"age"参数
@RequestMapping(value = "/reg.do", params = {"!age"})
public ModelAndView register() { ... }
2.2.4 headers:匹配请求头(了解)
要求请求头包含指定信息(如 Referer、User-Agent),常用于限制请求来源。
示例:
// 仅处理从"http://localhost:8080"跳转过来的请求
@RequestMapping(value = "/reg.do", headers = "Referer=http://localhost:8080")
public ModelAndView register() { ... }
三、Controller 方法返回值类型:灵活控制跳转与数据
SpringMVC 支持 3 种核心返回值类型:ModelAndView
、String
、void
,分别适用于不同场景。
3.1 ModelAndView:既带数据又指定视图
最经典的返回值类型,封装 “模型数据”(供视图渲染)和 “逻辑视图名”(指定跳转页面),适用于需传递数据的场景。
示例:
@RequestMapping("/login.do")
public ModelAndView login(String username, String password) {ModelAndView mv = new ModelAndView();// 1. 封装模型数据(存入request作用域)mv.addObject("uname", username); // 等价于request.setAttribute("uname", username)// 2. 指定逻辑视图名if ("admin".equals(username) && "123".equals(password)) {mv.setViewName("success.jsp"); // 登录成功} else {mv.setViewName("login.jsp"); // 登录失败,返回登录页}return mv;
}
3.2 String:仅指定视图(或跳转路径)
返回值为String
时,仅表示 “逻辑视图名” 或 “跳转指令”,适用于无需传递数据(或通过其他方式传递数据)的场景。
3.2.1 直接返回逻辑视图名
// 返回逻辑视图名,视图解析器解析为物理路径(如"success.jsp")
@RequestMapping("/logout.do")
public String logout() {// 业务逻辑(如清除Session)return "login.jsp";
}
3.2.2 带转发(forward:)或重定向(redirect:)
通过forward:
或redirect:
前缀,显式指定跳转方式(默认是转发)。
- 转发(forward:):服务器内部跳转,地址栏 URL 不变,可共享 request 作用域数据。
- 重定向(redirect:):客户端跳转,地址栏 URL 改变,无法共享 request 数据(需用 Session 或 URL 参数传递)。
示例:
@RequestMapping("/testForward.do")
public String testForward() {// 转发到/login.jsp(服务器内部跳转)return "forward:login.jsp";
}@RequestMapping("/testRedirect.do")
public String testRedirect() {// 重定向到/login.do(客户端跳转,地址栏变为/login.do)return "redirect:login.do";
}
3.3 void:无返回值(手动控制响应)
返回值为void
时,需通过原生 Servlet API(HttpServletRequest
/HttpServletResponse
)手动控制跳转或响应,适用于自定义响应(如返回 JSON、文件下载)。
示例:
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@RequestMapping("/testVoid.do")
public void testVoid(HttpServletRequest request, HttpServletResponse response) throws Exception {// 1. 手动转发request.getRequestDispatcher("login.jsp").forward(request, response);// 2. 手动重定向(需处理中文乱码)// response.sendRedirect("login.jsp");// 3. 手动返回响应(如JSON)// response.setContentType("application/json;charset=UTF-8");// response.getWriter().write("{\"code\":200,\"msg\":\"success\"}");
}
四、参数绑定:从前端到 Controller 的 “数据桥梁”
参数绑定是 SpringMVC 的核心优势之一 —— 自动将前端请求参数(如表单、URL 参数)绑定到 Controller 方法的形参,无需手动调用request.getParameter()
。支持多种参数类型,从简单类型到复杂集合,覆盖所有业务场景。
4.1 核心原理
前端请求参数(key=value)→ SpringMVC 参数绑定组件 → 自动转换类型(如 String→Integer)→ 绑定到 Controller 方法形参。
参数绑定的过程:
4.2 常见参数绑定场景
4.2.1 场景 1:默认类型绑定(Servlet API)
Controller 方法可直接接收HttpServletRequest
、HttpServletResponse
、HttpSession
等 Servlet API 参数,SpringMVC 自动注入。
示例:
@RequestMapping("/testServletAPI.do")
public String testServletAPI(HttpServletRequest request, HttpServletResponse response, HttpSession session) {// 操作requestString username = request.getParameter("username");// 操作sessionsession.setAttribute("uname", username);return "success.jsp";
}
4.2.2 场景 2:简单类型绑定(String、Integer、Boolean 等)
若请求参数名与方法形参名一致,SpringMVC 自动绑定并转换类型。
示例:
前端表单(JSP):
<form action="login.do" method="post">用户名:<input type="text" name="username"><br>年龄:<input type="text" name="age"><br>是否记住:<input type="checkbox" name="remember" value="true"><br><input type="submit" value="登录">
</form>
Controller 方法:
// 参数名与表单name一致:username(String)、age(Integer)、remember(Boolean)
@RequestMapping("/login.do")
public ModelAndView login(String username, Integer age, Boolean remember) {System.out.println("用户名:" + username);System.out.println("年龄:" + age);System.out.println("是否记住:" + remember);ModelAndView mv = new ModelAndView();mv.setViewName("success.jsp");return mv;
}
特殊情况:参数名不一致(@RequestParam)
若前端参数名与方法形参名不同(如前端是uname
,方法形参是username
),需用@RequestParam
指定映射关系。
示例:
import org.springframework.web.bind.annotation.RequestParam;@RequestMapping("/login.do")
public ModelAndView login(// 前端参数名是uname,绑定到形参username@RequestParam(value = "uname") String username,// required=false:该参数非必传(默认true,必传)@RequestParam(value = "age", required = false) Integer age,// defaultValue:参数未传时的默认值@RequestParam(value = "remember", defaultValue = "false") Boolean remember) {// 业务逻辑...
}
4.2.3 场景 3:POJO 类型绑定(实体类)
若前端参数较多(如用户注册:用户名、密码、年龄、邮箱),可将参数封装为 POJO 实体类,SpringMVC 自动将参数绑定到 POJO 的属性(要求表单 name 与 POJO 属性名一致)。
示例:
定义 POJO 类(User.java):
package com.jr.pojo;public class User {private String username;private String password;private Integer age;private String email;// 必须提供无参构造(SpringMVC通过反射创建对象)public User() {}// getter和setter(必须,SpringMVC通过setter赋值)public String getUsername() { return username; }public void setUsername(String username) { this.username = username; }public String getPassword() { return password; }public void setPassword(String password) { this.password = password; }public Integer getAge() { return age; }public void setAge(Integer age) { this.age = age; }public String getEmail() { return email; }public void setEmail(String email) { this.email = email; }@Overridepublic String toString() {return "User{" +"username='" + username + '\'' +", password='" + password + '\'' +", age=" + age +", email='" + email + '\'' +'}';}
}
前端表单(JSP):
<form action="reg.do" method="post">用户名:<input type="text" name="username"><br>密码:<input type="password" name="password"><br>年龄:<input type="text" name="age"><br>邮箱:<input type="text" name="email"><br><input type="submit" value="注册">
</form>
Controller 方法:
@RequestMapping("/reg.do")
public ModelAndView register(User user) {System.out.println("用户信息:" + user); // 自动打印User对象属性ModelAndView mv = new ModelAndView();mv.addObject("user", user); // 传递POJO到视图mv.setViewName("success.jsp");return mv;
}
进阶:包装 POJO 绑定(POJO 嵌套)
若 POJO 中包含另一个 POJO(如 User 包含 Dept 部门信息),前端表单需用属性.子属性
格式命名。
示例:
包装 POJO(User.java):
public class User {private String username;private Dept dept; // 嵌套Dept对象// getter和setter...
}public class Dept {private Integer deptId;private String deptName;// getter和setter...
}
前端表单(JSP):
<form action="reg.do" method="post">用户名:<input type="text" name="username"><br>部门ID:<input type="text" name="dept.deptId"><br> <!-- 嵌套属性:dept.deptId -->部门名称:<input type="text" name="dept.deptName"><br> <!-- 嵌套属性:dept.deptName --><input type="submit" value="注册">
</form>
Controller 方法:
@RequestMapping("/reg.do")
public ModelAndView register(User user) {System.out.println("用户名:" + user.getUsername());System.out.println("部门ID:" + user.getDept().getDeptId());System.out.println("部门名称:" + user.getDept().getDeptName());// 业务逻辑...
}
4.2.4 场景 4:集合类型绑定(数组、List、Map)
适用于 “批量提交” 场景(如批量修改用户、批量选择爱好)。
(1)数组绑定(如多选爱好)
前端表单(JSP):
<form action="testArray.do" method="post">爱好:<br><input type="checkbox" name="hobbies" value="book">读书<br><input type="checkbox" name="hobbies" value="sport">运动<br><input type="checkbox" name="hobbies" value="music">音乐<br><input type="submit" value="提交">
</form>
Controller 方法:
@RequestMapping("/testArray.do")
public String testArray(String[] hobbies) {// 遍历数组for (String hobby : hobbies) {System.out.println("爱好:" + hobby);}return "success.jsp";
}
(2)List 绑定(批量修改用户)
List 需封装在 POJO 中(SpringMVC 不支持直接绑定 List 到方法形参)。
包装 POJO(UserList.java):
import java.util.List;public class UserList {private List<User> userList; // List<User>// getter和setter...
}
前端表单(JSP,用 JSTL 遍历 List):
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<form action="batchUpdate.do" method="post"><c:forEach items="${userList}" var="user" varStatus="status"><!-- 用status.index作为List索引 --><input type="hidden" name="userList[${status.index}].username" value="${user.username}">年龄:<input type="text" name="userList[${status.index}].age" value="${user.age}"><br></c:forEach><input type="submit" value="批量修改">
</form>
Controller 方法:
@RequestMapping("/batchUpdate.do")
public String batchUpdate(UserList userList) {for (User user : userList.getUserList()) {System.out.println("用户名:" + user.getUsername() + ",年龄:" + user.getAge());}return "success.jsp";
}
(3)Map 绑定(灵活存储键值对)
Map 同样需封装在 POJO 中。
包装 POJO(UserMap.java):
import java.util.Map;public class UserMap {private Map<String, User> userMap; // Map<键, User>// getter和setter...
}
前端表单(JSP):
<form action="testMap.do" method="post"><!-- Map的键为"user1",绑定User属性 -->用户名1:<input type="text" name="userMap['user1'].username" value="张三"><br>年龄1:<input type="text" name="userMap['user1'].age" value="20"><br><!-- Map的键为"user2",绑定User属性 -->用户名2:<input type="text" name="userMap['user2'].username" value="李四"><br>年龄2:<input type="text" name="userMap['user2'].age" value="22"><br><input type="submit" value="提交">
</form>
Controller 方法:
@RequestMapping("/testMap.do")
public String testMap(UserMap userMap) {Map<String, User> map = userMap.getUserMap();System.out.println("用户1:" + map.get("user1"));System.out.println("用户2:" + map.get("user2"));return "success.jsp";
}
4.2.5 场景 5:自定义类型绑定(如日期转换)
SpringMVC 默认支持 String→Integer、String→Boolean 等类型转换,但不支持 String→Date(日期格式不统一),需自定义类型转换器。
步骤 1:创建自定义转换器(实现 Converter 接口)
package com.jr.util;import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;// Converter<S, T>:S是源类型(String),T是目标类型(Date)
public class DateConverter implements Converter<String, Date> {@Overridepublic Date convert(String source) {// 定义日期格式(如"yyyy-MM-dd")SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");try {return sdf.parse(source); // 转换为Date} catch (ParseException e) {e.printStackTrace();return null;}}
}
步骤 2:在 springmvc.xml 中配置转换器
<!-- 1. 配置转换器工厂,注册自定义转换器 -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"><property name="converters"><list><!-- 注册自定义日期转换器 --><bean class="com.jr.util.DateConverter"/></list></property>
</bean><!-- 2. 开启注解驱动,并指定转换器 -->
<mvc:annotation-driven conversion-service="conversionService"/>
步骤 3:测试日期绑定
前端表单:
<form action="testDate.do" method="post">生日:<input type="text" name="birthday" value="2000-01-01"><br><input type="submit" value="提交">
</form>
Controller 方法:
@RequestMapping("/testDate.do")
public String testDate(Date birthday) {System.out.println("生日:" + birthday); // 自动转换为Date类型return "success.jsp";
}
五、第二篇总结
本文深入讲解了 SpringMVC 的三大核心功能:
- 请求映射:通过
@RequestMapping
的多属性组合,实现 URL、请求方法、参数的精准匹配; - 返回值类型:
ModelAndView
(带数据 + 视图)、String
(仅视图 / 跳转)、void
(手动控制响应),满足不同场景需求; - 参数绑定:从简单类型到复杂集合(数组、List、Map),再到自定义转换器,覆盖所有前端参数接收场景。
掌握这些功能后,你已具备开发复杂 SpringMVC 模块的能力。下一篇博客将聚焦进阶功能:拦截器、文件上传下载、Ajax 交互,以及最终的SSM 框架整合,带你实现企业级项目开发。