Java/后端
SpringBoot 接口注解
记录了SpringBoot中的一些接口注解,后续还会有更新
Spring MVC 参数接收与 Controller
一、Controller 路径前缀
1. 全局前缀
在 application.yml 中配置:
server:
servlet:
context-path: /api
所有接口都会自动添加 /api:
实际请求:/api/users
2. Controller 前缀
@RestController
@RequestMapping("/users")
public class UserController {
}
类中的接口都会以 /users 开头。
如果同时配置了:
server:
servlet:
context-path: /api
最终路径是:
/api/users
不要在 Controller 中再次写 /api,否则会变成:
/api/api/users
二、@RestController
@RestController
public class UserController {
}
@RestController 等价于:
@Controller
@ResponseBody
它表示:
- 当前类是 Spring MVC 控制器;
- 方法返回值直接写入 HTTP 响应体;
- 返回 Java 对象时,通常由 Jackson 自动转换为 JSON。
例如:
@GetMapping("/users/1")
public User getUser() {
return new User(1, "张三");
}
响应结果:
{
"id": 1,
"name": "张三"
}
三、HTTP 方法映射
| 注解 | HTTP 方法 | 常见用途 |
|---|---|---|
@GetMapping | GET | 查询资源 |
@PostMapping | POST | 新增资源 |
@PutMapping | PUT | 全量修改 |
@PatchMapping | PATCH | 局部修改 |
@DeleteMapping | DELETE | 删除资源 |
示例:
@GetMapping("/users")
public List<User> list() {
return userService.findAll();
}
@PostMapping("/users")
public User add(@RequestBody User user) {
return userService.add(user);
}
Spring 启动时会根据 Controller 注解生成路由表:
| HTTP 方法 | 路径 | Controller 方法 |
|---|---|---|
| GET | /users | list() |
| GET | /users/{id} | getById() |
| POST | /users | add() |
| PUT | /users/{id} | update() |
| DELETE | /users/{id} | delete() |
请求进入 Spring 后,Spring 会同时匹配:
HTTP 方法 + 请求路径
常见结果:
- 路径不存在:
404 Not Found - 路径存在但 HTTP 方法不匹配:
405 Method Not Allowed
注解主要负责路由匹配和请求分发,真正的业务逻辑仍然需要自己编写。
四、Spring MVC 参数接收方式
常见的请求参数接收方式包括:
@PathVariable@RequestParam@RequestBody@RequestHeader@CookieValue@RequestPart@ModelAttribute
可以按照“数据从哪里来”进行记忆。
1. @PathVariable
@PathVariable 用于接收 URL 路径中的参数。
示例
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public User getById(@PathVariable int id) {
return userService.findById(id);
}
}
请求地址:
GET /users/18
18 会被传递给方法参数 id。
如果配置了全局前缀:
server:
servlet:
context-path: /api
实际请求地址为:
GET /api/users/18
参数名不同
@GetMapping("/{id}")
public User getById(@PathVariable("id") int userId) {
return userService.findById(userId);
}
这里:
URL 占位符:id
Java 参数名:userId
必须通过 @PathVariable("id") 明确指定对应关系。
常见用途
GET /users/18
GET /orders/1001
PUT /books/5
DELETE /products/8
通常用于表示具体资源的 ID。
2. @RequestParam
@RequestParam 用于接收 URL 查询参数,也就是 ? 后面的参数。
示例
@GetMapping("/users")
public User getById(@RequestParam int id) {
return userService.findById(id);
}
请求地址:
GET /users?id=18
参数 id=18 会传递给方法参数 id。
可选参数
@GetMapping("/users")
public List<User> list(
@RequestParam(required = false) String name,
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size
) {
return userService.search(name, page, size);
}
请求示例:
GET /users?name=张三&page=1&size=10
常用属性:
@RequestParam(required = false)
@RequestParam(defaultValue = "1")
@RequestParam("userName")
如果参数是必填的,但请求中没有传递,通常会返回 400 Bad Request。
参数名不同
@GetMapping("/users")
public User get(
@RequestParam("id") int userId
) {
return userService.findById(userId);
}
URL 中的参数名是 id,Java 方法参数名是 userId。
常见用途
GET /users?name=张三
GET /users?page=1&size=10
GET /products?category=book
GET /orders?status=paid
通常用于:
- 条件查询;
- 分页;
- 排序;
- 筛选;
- 搜索。
3. @RequestBody
@RequestBody 用于接收 HTTP 请求体中的数据,通常接收 JSON,并将 JSON 转换为 Java 对象。
示例
@PostMapping("/users")
public User add(@RequestBody User user) {
return userService.add(user);
}
请求:
POST /users
Content-Type: application/json
请求体:
{
"name": "张三",
"age": 18
}
JSON 字段会映射到 User 对象的属性:
public class User {
private String name;
private Integer age;
// getter、setter
}
请求头要求
通常需要:
Content-Type: application/json
否则 Spring 可能无法正确选择 JSON 转换器。
可以使用:
- Postman;
- Apifox;
- curl;
- 前端
fetch; - Axios。
常见搭配
新增:
@PostMapping("/users")
public User add(@RequestBody User user) {
return userService.add(user);
}
全量修改:
@PutMapping("/users/{id}")
public User update(
@PathVariable Long id,
@RequestBody User user
) {
user.setId(id);
return userService.update(user);
}
局部修改:
@PatchMapping("/users/{id}")
public User patch(
@PathVariable Long id,
@RequestBody UserPatchRequest request
) {
return userService.patch(id, request);
}
注意事项
一个 Controller 方法通常只能有一个 @RequestBody:
// 不推荐,也通常无法正常处理
public void method(
@RequestBody User user,
@RequestBody Address address
) {
}
如果请求体包含多个对象,应封装成一个请求 DTO:
public class CreateOrderRequest {
private User user;
private Address address;
}
然后:
@PostMapping("/orders")
public Order create(@RequestBody CreateOrderRequest request) {
return orderService.create(request);
}
@RequestBody 技术上不只适用于 POST,也可以用于 PUT、PATCH 等请求。虽然 GET 请求可能存在请求体,但很多客户端、代理和服务器不会稳定处理,因此通常不建议在 GET 中使用请求体。
4. @RequestHeader
用于接收请求头中的参数。
@GetMapping("/profile")
public User profile(
@RequestHeader("Authorization") String authorization
) {
return userService.getProfile(authorization);
}
请求头:
Authorization: Bearer token-value
也可以设置为可选:
@RequestHeader(
value = "X-Trace-Id",
required = false
) String traceId
常见用途:
AuthorizationUser-AgentContent-TypeAccept- 自定义追踪 ID
5. @CookieValue
用于获取 Cookie。
@GetMapping("/session")
public String session(
@CookieValue(value = "SESSION", required = false)
String sessionId
) {
return sessionId;
}
如果 Cookie 不存在且没有设置 required = false,可能返回 400 Bad Request。
6. @RequestPart
用于接收 multipart/form-data 请求,常见于文件上传。
@PostMapping("/avatar")
public String upload(
@RequestPart("file") MultipartFile file
) {
return fileService.save(file);
}
请求类型:
Content-Type: multipart/form-data
如果同时上传文件和 JSON:
@PostMapping(
value = "/articles",
consumes = MediaType.MULTIPART_FORM_DATA_VALUE
)
public Article create(
@RequestPart("file") MultipartFile file,
@RequestPart("article") Article article
) {
return articleService.create(file, article);
}
7. @ModelAttribute
用于接收表单参数,并自动封装成对象。
@PostMapping("/users")
public String add(@ModelAttribute User user) {
userService.add(user);
return "success";
}
表单数据:
name=张三&age=18
@ModelAttribute 常用于传统表单提交。前后端分离项目中,如果传递 JSON,通常使用 @RequestBody。
五、Controller 返回响应
1. 直接返回对象
@GetMapping("/{id}")
public User getById(@PathVariable Long id) {
return userService.findById(id);
}
Spring 会将返回的 Java 对象转换为 JSON。
2. 使用 ResponseEntity
ResponseEntity 可以同时控制:
- HTTP 状态码;
- 响应头;
- 响应体。
@GetMapping("/{id}")
public ResponseEntity<User> getById(
@PathVariable Long id
) {
User user = userService.findById(id);
if (user == null) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(user);
}
常见写法:
ResponseEntity.ok(body)
ResponseEntity.status(HttpStatus.CREATED).body(body)
ResponseEntity.notFound().build()
ResponseEntity.noContent().build()
ResponseEntity.badRequest().build()
3. @ResponseStatus
可以直接指定方法成功时的状态码:
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public User add(@RequestBody User user) {
return userService.add(user);
}
新增成功通常使用:
201 Created
删除成功且没有响应体时可以使用:
204 No Content
六、参数校验
可以使用 @Valid 或 @Validated 配合校验注解。
@PostMapping("/users")
public User add(@Valid @RequestBody User user) {
return userService.add(user);
}
实体类:
public class User {
@NotBlank
private String name;
@Min(1)
private Integer age;
}
常见校验注解:
@NotNull
@NotBlank
@NotEmpty
@Min
@Max
@Size
@Email
@Pattern
@NotBlank 适合字符串,@NotNull 适合判断对象是否为空。
七、跨域
开发前后端分离项目时,浏览器可能出现跨域问题。
局部配置:
@CrossOrigin
@RestController
@RequestMapping("/users")
public class UserController {
}
也可以配置具体来源:
@CrossOrigin(
origins = "http://localhost:5173"
)
生产项目通常更推荐进行全局 CORS 配置,而不是每个 Controller 都添加 @CrossOrigin。
八、完整 Controller 示例
@RestController
@RequestMapping("/books")
public class BookController {
private final BookService bookService;
public BookController(BookService bookService) {
this.bookService = bookService;
}
// 查询列表
// GET /books?author=张三&page=1&size=10
@GetMapping
public List<Book> list(
@RequestParam(required = false) String author,
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size
) {
return bookService.findAll(author, page, size);
}
// 查询单个
// GET /books/1
@GetMapping("/{id}")
public ResponseEntity<Book> getById(
@PathVariable Long id
) {
Book book = bookService.findById(id);
if (book == null) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(book);
}
// 新增
// POST /books
// Body: {"name":"Java","author":"张三"}
@PostMapping
public ResponseEntity<Book> add(
@Valid @RequestBody Book book
) {
Book savedBook = bookService.add(book);
return ResponseEntity
.status(HttpStatus.CREATED)
.body(savedBook);
}
// 全量修改
// PUT /books/1
@PutMapping("/{id}")
public ResponseEntity<Book> update(
@PathVariable Long id,
@Valid @RequestBody Book book
) {
book.setId(id);
Book updatedBook = bookService.update(book);
if (updatedBook == null) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(updatedBook);
}
// 局部修改
// PATCH /books/1
@PatchMapping("/{id}")
public ResponseEntity<Book> patch(
@PathVariable Long id,
@RequestBody BookPatchRequest request
) {
Book updatedBook = bookService.patch(id, request);
if (updatedBook == null) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(updatedBook);
}
// 删除
// DELETE /books/1
@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(
@PathVariable Long id
) {
boolean removed = bookService.deleteById(id);
if (!removed) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.noContent().build();
}
}
九、RESTful 风格
RESTful 不是某个 Spring 注解,而是一种接口设计风格。
核心特征:
- URL 使用名词表示资源;
- HTTP 方法表示操作;
- 使用状态码表达处理结果;
- 使用路径表示资源层级;
- 请求尽量保持无状态。
示例:
GET /books 查询书籍列表
GET /books/1 查询 ID 为 1 的书
POST /books 新增书籍
PUT /books/1 全量修改书籍
PATCH /books/1 局部修改书籍
DELETE /books/1 删除书籍
不推荐:
GET /getBooks
POST /deleteBook
GET /updateBook
更推荐:
GET /books
DELETE /books/1
PUT /books/1
需要注意,使用了 @GetMapping 并不自动保证方法内部一定是查询逻辑。RESTful 是开发者遵守的接口设计约定,Spring 只负责根据注解匹配和分发请求。
十、三种核心参数注解对比
| 注解 | 数据来源 | 典型 URL/请求 | 常见用途 |
|---|---|---|---|
@PathVariable | URL 路径 | /users/18 | 查询、修改、删除指定资源 |
@RequestParam | URL 查询参数 | /users?id=18 | 搜索、过滤、分页 |
@RequestBody | HTTP 请求体 | JSON Body | 新增、修改、复杂查询条件 |
记忆方式:
/users/18
使用:
@PathVariable
/users?id=18
使用:
@RequestParam
{
"name": "张三",
"age": 18
}
使用:
@RequestBody
常见搭配:
查询单个:GET + @PathVariable
查询列表:GET + @RequestParam
新增:POST + @RequestBody
全量修改:PUT + @PathVariable + @RequestBody
局部修改:PATCH + @PathVariable + @RequestBody
删除:DELETE + @PathVariable