SpringMVC快速入门之请求与响应
SpringMVC中请求(Request)与响应(Response)是核心交互流程:客户端通过请求传递数据,服务器处理后通过响应返回结果,掌握请求参数的接收和响应结果的处理,是开发Web接口的基础。
一、请求处理:获取请求参数
SpringMVC提供了多种注解简化请求参数的获取,无需像原生Servlet那样手动调用request.getParameter()
。
1.1 普通参数获取(@RequestParam)
适用于获取URL查询参数(?name=张三&age=25
)或表单提交的参数。
1.1.1 基础用法
@Controller
@RequestMapping("/user")
public class UserController {
/**
* 获取普通参数
* URL示例:/user/query?name=张三&age=25
*/
@GetMapping("/query")
public String queryUser(
// @RequestParam:绑定参数(默认必填)
@RequestParam String name,
// 可指定参数名(若参数名与变量名一致,可省略@RequestParam)
@RequestParam("age") Integer userAge,
Model model) {
model.addAttribute("message", "姓名:" + name + ",年龄:" + userAge);
return "result"; // 跳转结果页面
}
}
1.1.2 可选参数与默认值
若参数非必填,可通过required=false
设置,或指定默认值:
/**
* 可选参数与默认值
* URL示例:/user/search?keyword=Spring(或无参数)
*/
@GetMapping("/search")
public String search(
// 可选参数(required=false)
@RequestParam(required = false) String keyword,
// 默认值(若参数为空,使用默认值)
@RequestParam(defaultValue = "10") Integer size,
Model model) {
model.addAttribute("message", "关键词:" + (keyword == null ? "无" : keyword) + ",每页条数:" + size);
return "result";
}
核心说明:
- 若参数名与方法参数名一致,
@RequestParam
可省略(如String name
等价于@RequestParam String name
); - 基本类型(
int
)需确保参数存在,否则会报错,建议使用包装类(Integer
)并设置required=false
。
1.2 路径变量(@PathVariable)
适用于REST风格的URL(如/user/1
),从URL路径中获取参数。
/**
* 路径变量
* URL示例:/user/1/detail
*/
@GetMapping("/{id}/detail")
public String getUserDetail(
// 从路径中获取id(与URL中的{id}对应)
@PathVariable Integer id,
Model model) {
model.addAttribute("message", "查询ID为" + id + "的用户详情");
return "result";
}
进阶用法:多路径变量
/**
* 多路径变量
* URL示例:/user/1/order/100
*/
@GetMapping("/{userId}/order/{orderId}")
public String getOrder(
@PathVariable("userId") Integer uId,
@PathVariable Integer orderId, // 变量名与{orderId}一致,可省略value
Model model) {
model.addAttribute("message", "用户ID:" + uId + ",订单ID:" + orderId);
return "result";
}
1.3 表单数据绑定到对象
当参数较多时(如用户注册),可将参数自动绑定到Java对象。
1.3.1 定义实体类
package com.example.pojo;
import lombok.Data;
@Data // Lombok注解,自动生成getter/setter
public class User {
private String username;
private Integer age;
private String email;
}
1.3.2 绑定对象参数
/**
* 表单数据绑定到对象
* 表单提交示例:username=张三&age=25&email=test@example.com
*/
@PostMapping("/register")
public String registerUser(
// 自动将参数绑定到User对象(参数名与对象属性名一致)
User user,
Model model) {
model.addAttribute("message", "注册用户:" + user.getUsername()
+ ",年龄:" + user.getAge()
+ ",邮箱:" + user.getEmail());
return "result";
}
核心说明:
- 要求表单参数名或查询参数名与对象的属性名一致(如
username
对应user.getUsername()
); - 支持嵌套对象(如
User
包含Address
对象,参数名需为address.city
)。
1.4 获取请求头与Cookie(@RequestHeader、@CookieValue)
1.4.1 获取请求头
/**
* 获取请求头
*/
@GetMapping("/header")
public String getHeader(
// 获取User-Agent请求头
@RequestHeader("User-Agent") String userAgent,
// 获取Accept请求头
@RequestHeader("Accept") String accept,
Model model) {
model.addAttribute("message", "浏览器信息:" + userAgent + ",Accept:" + accept);
return "result";
}
1.4.2 获取Cookie
/**
* 获取Cookie
*/
@GetMapping("/cookie")
public String getCookie(
// 获取名为JSESSIONID的Cookie值
@CookieValue(value = "JSESSIONID", required = false) String sessionId,
Model model) {
model.addAttribute("message", "JSESSIONID:" + (sessionId == null ? "无" : sessionId));
return "result";
}
1.5 获取JSON请求体(@RequestBody)
适用于接收前端发送的JSON数据(如Ajax请求),需结合@ResponseBody
使用。
1.5.1 依赖准备
确保添加Jackson依赖(用于JSON解析):
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.3</version>
</dependency>
1.5.2 接收JSON数据
/**
* 接收JSON请求体
* 请求体示例:{"username":"张三","age":25}
*/
@PostMapping("/json")
@ResponseBody // 返回JSON(而非跳转页面)
public User receiveJson(@RequestBody User user) {
// 处理逻辑(如保存用户)
user.setUsername(user.getUsername() + "_processed"); // 修改用户名
return user; // 返回处理后的对象(自动转为JSON)
}
测试方式:
使用Postman发送POST请求:
- URL:
http://localhost:8080/user/json
- 请求头:
Content-Type: application/json
- 请求体:
{"username":"张三","age":25}
响应结果(JSON):
{"username":"张三_processed","age":25,"email":null}
二、响应处理:返回结果给客户端
SpringMVC的响应方式分为两类:页面跳转(返回视图)和数据响应(返回JSON、字符串等)。
2.1 页面跳转(ModelAndView)
通过返回逻辑视图名或ModelAndView
实现页面跳转,适用于传统JSP开发。
2.1.1 返回逻辑视图名(推荐)
/**
* 返回逻辑视图名(默认跳转页面)
*/
@GetMapping("/toIndex")
public String toIndex(Model model) {
model.addAttribute("title", "首页"); // 向视图传递数据
return "index"; // 逻辑视图名,由视图解析器转为/WEB-INF/views/index.jsp
}
2.1.2 使用ModelAndView
/**
* 使用ModelAndView跳转页面
*/
@GetMapping("/toDetail")
public ModelAndView toDetail() {
ModelAndView mav = new ModelAndView();
mav.setViewName("detail"); // 设置逻辑视图名
mav.addObject("id", 1); // 添加数据(等价于Model.addAttribute)
mav.addObject("name", "商品详情");
return mav;
}
2.2 重定向与转发
2.2.1 重定向(redirect:)
重定向会发起新的请求,地址栏URL会变化,之前的Model
数据会丢失:
/**
* 重定向
*/
@GetMapping("/redirect")
public String redirect() {
// 重定向到首页(可跳转至其他Controller接口)
return "redirect:/toIndex";
}
2.2.2 转发(forward:)
转发是服务器内部跳转,地址栏URL不变,Model
数据可共享:
/**
* 转发
*/
@GetMapping("/forward")
public String forward() {
// 转发到详情页(仅能跳转至当前应用内的路径)
return "forward:/toDetail";
}
2.3 返回JSON数据(@ResponseBody)
适用于Ajax请求或前后端分离项目,通过@ResponseBody
将对象转为JSON返回。
2.3.1 基础用法
@Controller
@RequestMapping("/api/user")
public class UserApiController {
/**
* 返回单个对象
* URL:/api/user/1
*/
@GetMapping("/{id}")
@ResponseBody // 将返回值转为JSON
public User getUser(@PathVariable Integer id) {
// 模拟查询数据库
User user = new User();
user.setUsername("张三");
user.setAge(25);
user.setEmail("zhangsan@example.com");
return user; // 自动转为JSON
}
/**
* 返回集合
* URL:/api/user/list
*/
@GetMapping("/list")
@ResponseBody
public List<User> getUserList() {
List<User> list = new ArrayList<>();
list.add(new User("张三", 25, "zhangsan@example.com"));
list.add(new User("李四", 28, "lisi@example.com"));
return list; // 自动转为JSON数组
}
/**
* 返回自定义结果(统一响应格式)
* URL:/api/user/login
*/
@PostMapping("/login")
@ResponseBody
public Result login(
@RequestParam String username,
@RequestParam String password) {
if ("admin".equals(username) && "123456".equals(password)) {
// 登录成功
return Result.success("登录成功", new User(username, 0, null));
} else {
// 登录失败
return Result.error("用户名或密码错误");
}
}
}
// 统一响应结果类
@Data
class Result {
private int code; // 状态码(200成功,400失败)
private String message; // 提示信息
private Object data; // 数据
// 成功响应
public static Result success(String message, Object data) {
Result result = new Result();
result.code = 200;
result.message = message;
result.data = data;
return result;
}
// 错误响应
public static Result error(String message) {
Result result = new Result();
result.code = 400;
result.message = message;
return result;
}
}
测试结果:
访问/api/user/1
,响应JSON:
{"username":"张三","age":25,"email":"zhangsan@example.com"}
访问/api/user/login?username=admin&password=123456
,响应JSON:
{"code":200,"message":"登录成功","data":{"username":"admin","age":0,"email":null}}
2.3.2 @RestController简化配置
若控制器所有方法都返回JSON,可使用@RestController
替代@Controller
(自动为所有方法添加@ResponseBody
):
// @RestController = @Controller + @ResponseBody
@RestController
@RequestMapping("/api/book")
public class BookApiController {
// 无需添加@ResponseBody,自动返回JSON
@GetMapping("/{id}")
public Book getBook(@PathVariable Integer id) {
return new Book(id, "SpringMVC教程", "技术书籍");
}
}
三、实战案例:用户注册与查询
结合请求与响应的核心知识点,实现用户注册(表单提交)和查询(JSON响应)功能。
3.1 注册页面(register.jsp)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>用户注册</title>
</head>
<body>
<form action="/user/register" method="post">
用户名:<input type="text" name="username"><br>
年龄:<input type="number" name="age"><br>
邮箱:<input type="email" name="email"><br>
<button type="submit">注册</button>
</form>
</body>
</html>
3.2 结果页面(result.jsp)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>结果页</title>
</head>
<body>
<h1>${message}</h1>
</body>
</html>
3.3 Controller完整实现
@Controller
@RequestMapping("/user")
public class UserController {
// 跳转注册页面
@GetMapping("/toRegister")
public String toRegister() {
return "register";
}
// 处理注册(表单提交)
@PostMapping("/register")
public String register(User user, Model model) {
// 模拟保存用户(实际项目中调用Service)
model.addAttribute("message", "注册成功!用户信息:" + user);
return "result";
}
// 按条件查询(返回JSON)
@GetMapping("/api/query")
@ResponseBody
public Result query(
@RequestParam(required = false) String username,
@RequestParam(required = false) Integer minAge) {
// 模拟查询
List<User> users = new ArrayList<>();
users.add(new User("张三", 25, "zhangsan@example.com"));
users.add(new User("李四", 30, "lisi@example.com"));
return Result.success("查询成功", users);
}
}
3.4 测试流程
- 访问
/user/toRegister
,填写表单提交; - 注册成功后跳转至结果页,显示用户信息;
- 访问
/user/api/query?username=张三
,获取JSON格式的查询结果。
四、常见问题与避坑指南
4.1 参数绑定失败(400 Bad Request)
错误信息:Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'
原因:
- 参数类型不匹配(如前端传递字符串,后端接收为
Integer
); - 缺少必填参数(
@RequestParam
默认必填)。
解决方案:
- 确保参数类型匹配(如年龄参数传递数字,而非字符串);
- 非必填参数添加
required=false
; - 若参数可能为空,使用包装类(
Integer
)而非基本类型(int
)。
4.2 JSON解析失败(400 Bad Request)
错误信息:HttpMessageNotReadableException: JSON parse error
原因:
- 请求头未设置
Content-Type: application/json
; - JSON格式错误(如缺少引号、逗号);
- JSON字段与对象属性不匹配(如拼写错误)。
解决方案:
- 发送JSON请求时,务必设置
Content-Type: application/json
; - 检查JSON格式(可通过JSON校验工具验证);
- 确保JSON字段名与对象属性名一致(区分大小写)。
4.3 @ResponseBody返回406 Not Acceptable
错误信息:406 Not Acceptable
原因:
- 缺少Jackson依赖,无法将对象转为JSON;
- 请求头
Accept
设置不当(如仅接受text/html
,但返回JSON)。
解决方案:
- 添加Jackson依赖(
jackson-databind
); - 检查请求头
Accept
是否包含application/json
(或不限制Accept
)。
总结:请求与响应的核心要点
SpringMVC的请求与响应是前后端交互的核心:
请求处理:
- 普通参数用
@RequestParam
,路径参数用@PathVariable
; - 多参数用对象绑定,JSON参数用
@RequestBody
; - 灵活使用可选参数和默认值,避免参数缺失错误。
- 普通参数用
响应处理:
- 页面跳转返回逻辑视图名,配合
Model
传递数据; - JSON响应用
@ResponseBody
或@RestController
; - 重定向与转发需区分使用场景(重定向适合外部链接,转发适合内部跳转)。
- 页面跳转返回逻辑视图名,配合
避坑关键:
- 参数绑定注意类型匹配和必填性;
- JSON处理确保依赖正确和格式规范;
- 前后端约定参数名和数据格式,减少沟通成本。
若这篇内容帮到你,动动手指支持下!关注不迷路,干货持续输出!
ヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノ