SpringMVC 请求映射
2025/9/17大约 7 分钟
SpringMVC 控制器与请求映射
学习目标
通过本教程,您将掌握:
- SpringMVC 控制器的基本概念
- 各种请求映射注解的使用
- 请求参数的获取和处理
- RESTful API 的设计和实现
控制器基础
什么是控制器?
控制器(Controller)是 SpringMVC 中处理用户请求的核心组件,负责:
- 接收请求:处理来自客户端的 HTTP 请求
- 业务调用:调用 Service 层处理业务逻辑
- 返回响应:将处理结果返回给客户端
控制器的创建
package com.example.springmvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 基础控制器示例
*/
@Controller
@RequestMapping("/demo")
public class DemoController {
@RequestMapping("/hello")
@ResponseBody
public String hello() {
return "Hello from DemoController!";
}
}
请求映射注解
@RequestMapping 详解
@RequestMapping
是最基础的请求映射注解,支持多种配置:
@Controller
@RequestMapping("/api/v1") // 类级别映射
public class ApiController {
// 基础映射
@RequestMapping("/info")
@ResponseBody
public String getInfo() {
return "API Information";
}
// 指定请求方法
@RequestMapping(value = "/users", method = RequestMethod.GET)
@ResponseBody
public String getUsers() {
return "Get all users";
}
// 多个路径映射
@RequestMapping(value = {"/home", "/index", "/"}, method = RequestMethod.GET)
public String home() {
return "home";
}
// 指定请求头
@RequestMapping(value = "/secure", headers = "X-API-Key=secret")
@ResponseBody
public String secureEndpoint() {
return "Secure data";
}
// 指定参数
@RequestMapping(value = "/search", params = "type=user")
@ResponseBody
public String searchUsers() {
return "Search users";
}
}
HTTP 方法专用注解
Spring 4.3+ 提供了更简洁的注解:
@RestController
@RequestMapping("/users")
public class UserController {
/**
* 获取所有用户
*/
@GetMapping
public List<User> getAllUsers() {
// 模拟数据
return Arrays.asList(
new User(1L, "张三", "zhang@example.com", 25),
new User(2L, "李四", "li@example.com", 30)
);
}
/**
* 根据ID获取用户
*/
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
return new User(id, "用户" + id, "user" + id + "@example.com", 25);
}
/**
* 创建新用户
*/
@PostMapping
public User createUser(@RequestBody User user) {
user.setId(System.currentTimeMillis()); // 模拟生成ID
return user;
}
/**
* 更新用户信息
*/
@PutMapping("/{id}")
public User updateUser(@PathVariable Long id, @RequestBody User user) {
user.setId(id);
return user;
}
/**
* 删除用户
*/
@DeleteMapping("/{id}")
public Map<String, Object> deleteUser(@PathVariable Long id) {
Map<String, Object> result = new HashMap<>();
result.put("success", true);
result.put("message", "用户 " + id + " 已删除");
return result;
}
}
参数获取
1. 路径变量 @PathVariable
@RestController
@RequestMapping("/path")
public class PathVariableController {
/**
* 单个路径变量
*/
@GetMapping("/user/{id}")
public String getUserById(@PathVariable Long id) {
return "User ID: " + id;
}
/**
* 多个路径变量
*/
@GetMapping("/user/{userId}/order/{orderId}")
public String getUserOrder(@PathVariable Long userId,
@PathVariable String orderId) {
return String.format("User: %d, Order: %s", userId, orderId);
}
/**
* 可选路径变量
*/
@GetMapping({"/category/{id}", "/category"})
public String getCategory(@PathVariable(required = false) Long id) {
return id != null ? "Category: " + id : "All categories";
}
/**
* 正则表达式约束
*/
@GetMapping("/product/{id:[0-9]+}")
public String getProduct(@PathVariable Long id) {
return "Product ID: " + id;
}
}
2. 请求参数 @RequestParam
@RestController
@RequestMapping("/param")
public class RequestParamController {
/**
* 基础参数获取
*/
@GetMapping("/search")
public String search(@RequestParam String keyword) {
return "搜索关键词: " + keyword;
}
/**
* 可选参数
*/
@GetMapping("/list")
public String getList(@RequestParam(required = false, defaultValue = "1") Integer page,
@RequestParam(required = false, defaultValue = "10") Integer size) {
return String.format("页码: %d, 大小: %d", page, size);
}
/**
* 参数名映射
*/
@GetMapping("/filter")
public String filter(@RequestParam("q") String query,
@RequestParam(value = "sort", defaultValue = "id") String sortBy) {
return String.format("查询: %s, 排序: %s", query, sortBy);
}
/**
* 数组参数
*/
@GetMapping("/tags")
public String getTags(@RequestParam String[] tags) {
return "标签: " + Arrays.toString(tags);
}
/**
* 集合参数
*/
@GetMapping("/ids")
public String getByIds(@RequestParam List<Long> ids) {
return "ID列表: " + ids;
}
}
3. 请求体 @RequestBody
@RestController
@RequestMapping("/body")
public class RequestBodyController {
/**
* JSON 对象
*/
@PostMapping("/user")
public User createUser(@RequestBody User user) {
// 处理用户创建逻辑
user.setId(System.currentTimeMillis());
return user;
}
/**
* JSON 数组
*/
@PostMapping("/users/batch")
public List<User> createUsers(@RequestBody List<User> users) {
// 批量创建用户
for (int i = 0; i < users.size(); i++) {
users.get(i).setId((long) (i + 1));
}
return users;
}
/**
* Map 参数
*/
@PostMapping("/data")
public Map<String, Object> processData(@RequestBody Map<String, Object> data) {
data.put("processed", true);
data.put("timestamp", System.currentTimeMillis());
return data;
}
}
4. 请求头 @RequestHeader
@RestController
@RequestMapping("/header")
public class RequestHeaderController {
/**
* 获取特定请求头
*/
@GetMapping("/auth")
public String checkAuth(@RequestHeader("Authorization") String token) {
return "Token: " + token;
}
/**
* 可选请求头
*/
@GetMapping("/info")
public String getInfo(@RequestHeader(value = "User-Agent", required = false) String userAgent) {
return "User-Agent: " + (userAgent != null ? userAgent : "Unknown");
}
/**
* 所有请求头
*/
@GetMapping("/all")
public Map<String, String> getAllHeaders(@RequestHeader Map<String, String> headers) {
return headers;
}
}
5. Cookie @CookieValue
@RestController
@RequestMapping("/cookie")
public class CookieController {
/**
* 获取 Cookie 值
*/
@GetMapping("/session")
public String getSession(@CookieValue("JSESSIONID") String sessionId) {
return "Session ID: " + sessionId;
}
/**
* 可选 Cookie
*/
@GetMapping("/preference")
public String getPreference(@CookieValue(value = "theme", defaultValue = "light") String theme) {
return "主题: " + theme;
}
}
表单处理
简单表单
@Controller
@RequestMapping("/form")
public class FormController {
/**
* 显示表单页面
*/
@GetMapping("/user")
public String showUserForm(Model model) {
model.addAttribute("user", new User());
return "user-form";
}
/**
* 处理表单提交
*/
@PostMapping("/user")
public String submitUserForm(@ModelAttribute User user, Model model) {
// 处理用户数据
user.setId(System.currentTimeMillis());
model.addAttribute("message", "用户创建成功: " + user.getName());
return "user-result";
}
/**
* 处理简单表单参数
*/
@PostMapping("/contact")
public String submitContact(@RequestParam String name,
@RequestParam String email,
@RequestParam String message,
Model model) {
model.addAttribute("name", name);
model.addAttribute("email", email);
model.addAttribute("message", message);
return "contact-result";
}
}
文件上传
@Controller
@RequestMapping("/upload")
public class FileUploadController {
/**
* 单文件上传
*/
@PostMapping("/single")
@ResponseBody
public Map<String, Object> uploadSingle(@RequestParam("file") MultipartFile file) {
Map<String, Object> result = new HashMap<>();
if (file.isEmpty()) {
result.put("success", false);
result.put("message", "文件不能为空");
return result;
}
try {
// 获取文件信息
String fileName = file.getOriginalFilename();
long fileSize = file.getSize();
String contentType = file.getContentType();
// 这里应该保存文件到磁盘或云存储
// file.transferTo(new File("/path/to/save/" + fileName));
result.put("success", true);
result.put("fileName", fileName);
result.put("fileSize", fileSize);
result.put("contentType", contentType);
} catch (Exception e) {
result.put("success", false);
result.put("message", "文件上传失败: " + e.getMessage());
}
return result;
}
/**
* 多文件上传
*/
@PostMapping("/multiple")
@ResponseBody
public Map<String, Object> uploadMultiple(@RequestParam("files") MultipartFile[] files) {
Map<String, Object> result = new HashMap<>();
List<Map<String, Object>> fileInfos = new ArrayList<>();
for (MultipartFile file : files) {
if (!file.isEmpty()) {
Map<String, Object> fileInfo = new HashMap<>();
fileInfo.put("fileName", file.getOriginalFilename());
fileInfo.put("fileSize", file.getSize());
fileInfo.put("contentType", file.getContentType());
fileInfos.add(fileInfo);
}
}
result.put("success", true);
result.put("fileCount", fileInfos.size());
result.put("files", fileInfos);
return result;
}
}
RESTful API 设计
RESTful 风格控制器
@RestController
@RequestMapping("/api/products")
public class ProductRestController {
// 模拟数据存储
private final Map<Long, Product> products = new ConcurrentHashMap<>();
private final AtomicLong idGenerator = new AtomicLong(1);
/**
* GET /api/products - 获取所有产品
*/
@GetMapping
public List<Product> getAllProducts(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
return new ArrayList<>(products.values());
}
/**
* GET /api/products/{id} - 获取指定产品
*/
@GetMapping("/{id}")
public ResponseEntity<Product> getProduct(@PathVariable Long id) {
Product product = products.get(id);
if (product != null) {
return ResponseEntity.ok(product);
}
return ResponseEntity.notFound().build();
}
/**
* POST /api/products - 创建新产品
*/
@PostMapping
public ResponseEntity<Product> createProduct(@RequestBody Product product) {
Long id = idGenerator.getAndIncrement();
product.setId(id);
products.put(id, product);
return ResponseEntity.status(HttpStatus.CREATED).body(product);
}
/**
* PUT /api/products/{id} - 更新产品
*/
@PutMapping("/{id}")
public ResponseEntity<Product> updateProduct(@PathVariable Long id,
@RequestBody Product product) {
if (products.containsKey(id)) {
product.setId(id);
products.put(id, product);
return ResponseEntity.ok(product);
}
return ResponseEntity.notFound().build();
}
/**
* DELETE /api/products/{id} - 删除产品
*/
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteProduct(@PathVariable Long id) {
if (products.remove(id) != null) {
return ResponseEntity.noContent().build();
}
return ResponseEntity.notFound().build();
}
/**
* GET /api/products/search - 搜索产品
*/
@GetMapping("/search")
public List<Product> searchProducts(@RequestParam String keyword) {
return products.values().stream()
.filter(p -> p.getName().contains(keyword))
.collect(Collectors.toList());
}
}
产品实体类
package com.example.springmvc.model;
import lombok.Data;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product {
private Long id;
private String name;
private String description;
private BigDecimal price;
private Integer stock;
private String category;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
响应处理
ResponseEntity 使用
@RestController
@RequestMapping("/api/response")
public class ResponseController {
/**
* 成功响应
*/
@GetMapping("/success")
public ResponseEntity<Map<String, Object>> success() {
Map<String, Object> data = new HashMap<>();
data.put("message", "操作成功");
data.put("timestamp", System.currentTimeMillis());
return ResponseEntity.ok(data);
}
/**
* 创建资源响应
*/
@PostMapping("/create")
public ResponseEntity<User> createResource(@RequestBody User user) {
user.setId(System.currentTimeMillis());
return ResponseEntity.status(HttpStatus.CREATED).body(user);
}
/**
* 资源不存在
*/
@GetMapping("/notfound/{id}")
public ResponseEntity<String> notFound(@PathVariable Long id) {
return ResponseEntity.notFound().build();
}
/**
* 自定义响应头
*/
@GetMapping("/headers")
public ResponseEntity<String> withHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.add("X-Custom-Header", "CustomValue");
headers.add("X-Timestamp", String.valueOf(System.currentTimeMillis()));
return ResponseEntity.ok()
.headers(headers)
.body("Response with custom headers");
}
}
异常处理
控制器级异常处理
@RestController
@RequestMapping("/api/exception")
public class ExceptionController {
@GetMapping("/error")
public String triggerError() {
throw new RuntimeException("这是一个测试异常");
}
@GetMapping("/validation/{id}")
public String validateId(@PathVariable Long id) {
if (id <= 0) {
throw new IllegalArgumentException("ID 必须大于 0");
}
return "ID 验证通过: " + id;
}
/**
* 处理 RuntimeException
*/
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<Map<String, Object>> handleRuntimeException(RuntimeException e) {
Map<String, Object> error = new HashMap<>();
error.put("error", "运行时异常");
error.put("message", e.getMessage());
error.put("timestamp", System.currentTimeMillis());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
}
/**
* 处理 IllegalArgumentException
*/
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<Map<String, Object>> handleIllegalArgument(IllegalArgumentException e) {
Map<String, Object> error = new HashMap<>();
error.put("error", "参数错误");
error.put("message", e.getMessage());
error.put("timestamp", System.currentTimeMillis());
return ResponseEntity.badRequest().body(error);
}
}
最佳实践
1. 控制器设计原则
设计原则
- 单一职责:每个控制器只处理相关的业务
- RESTful 风格:遵循 REST 设计规范
- 统一响应格式:保持 API 响应格式一致
- 异常处理:统一处理异常和错误
2. 注解使用建议
// ✅ 推荐:使用具体的 HTTP 方法注解
@GetMapping("/users")
@PostMapping("/users")
@PutMapping("/users/{id}")
@DeleteMapping("/users/{id}")
// ❌ 不推荐:使用通用的 @RequestMapping
@RequestMapping(value = "/users", method = RequestMethod.GET)
3. 参数验证
@PostMapping("/users")
public ResponseEntity<User> createUser(@Valid @RequestBody User user,
BindingResult result) {
if (result.hasErrors()) {
// 处理验证错误
Map<String, String> errors = new HashMap<>();
result.getFieldErrors().forEach(error ->
errors.put(error.getField(), error.getDefaultMessage())
);
return ResponseEntity.badRequest().body(null);
}
// 处理正常逻辑
return ResponseEntity.ok(user);
}
总结
本教程详细介绍了 SpringMVC 控制器和请求映射的核心概念:
- ✅ 控制器基础:@Controller 和 @RestController 的使用
- ✅ 请求映射:各种映射注解的详细用法
- ✅ 参数获取:多种参数获取方式和技巧
- ✅ RESTful API:标准的 REST API 设计
- ✅ 响应处理:ResponseEntity 的灵活使用
- ✅ 异常处理:控制器级异常处理机制
下一步学习
- 学习 SpringMVC 数据绑定与验证
- 了解视图解析和模板引擎
- 掌握拦截器和过滤器的使用
掌握了控制器和请求映射,您就能够构建功能完整的 Web API 了!