请求(参数绑定)
Laravel 的控制器方法通过
Request $request拿到请求数据;Spring Boot 把这件事做得更「声明式」:方法签名上写什么参数,框架就帮你解析什么,不需要一个个从$request里取。
请求数据从哪来
HTTP 请求的「数据携带点」就三个地方,Spring 各有一个注解:
| 数据位置 | Laravel 写法 | Spring Boot 写法 |
|---|---|---|
URL 路径段(/posts/{id}) | $request->route('id') | @PathVariable Long id |
URL 查询串(?page=2) | $request->query('page') | @RequestParam int page |
| 请求体(JSON/表单) | $request->all() | @RequestBody PostDto dto |
这三个注解是 Spring MVC 参数绑定的主力,必须掌握。
@PathVariable:路径参数
@GetMapping("/posts/{id}")
public Post show(@PathVariable Long id) {
return service.get(id);
}- 类型自动转换:
Long id会把字符串转成Long,转失败抛类型异常 - 参数名自动匹配
{id};如果方法参数名和占位符不一致,要显式指定:
@GetMapping("/posts/{postId}")
public Post show(@PathVariable("postId") Long id) { ... }为什么有时要显式写名字?
Java 编译默认会把参数名丢掉(除非 -parameters)。IDEA 里「Settings → Build → Compiler → Store info about method parameters」勾上后就可以不写。项目里通常统一开启,所以示例大多直接写参数名。
@RequestParam:查询参数
@GetMapping("/posts")
public List<Post> index(
@RequestParam(defaultValue = "1") int page,
@RequestParam(required = false) String keyword) {
...
}| 属性 | 作用 |
|---|---|
required = false | 可缺省(默认必填,缺了 400) |
defaultValue = "1" | 缺省时用默认值 |
name / value | 指定参数名(区别于方法参数名) |
宽松绑定
如果方法参数没有加任何注解(如 public Post show(Long id)),Spring 会智能地从「查询参数 → 路径参数 → 表单字段」里找同名数据,能自动转换就绑定。这个「宽松绑定」很方便,但团队里建议显式标注,可读性更好。
@RequestBody:JSON 请求体
这是和 Laravel 差别最大的地方。Laravel 里 $request->all() 拿到的是 PHP 数组;Spring 里 @RequestBody 直接把 JSON 反序列化成你声明的 DTO 对象:
@PostMapping("/posts")
public Post store(@RequestBody PostDto dto) {
return service.create(dto);
}// 请求体
{ "title": "Spring Boot 入门", "content": "..." }@Data
public class PostDto {
private String title;
private String content;
}框架(Jackson)把 JSON 自动映射到 DTO 的字段,字段名一一对应,多余字段默认忽略。
DTO 是什么
DTO(Data Transfer Object,数据传输对象)= 定义了「请求该长什么样 / 响应该长什么样」的普通类。它扮演两个 Laravel 角色:
- FormRequest:定义入参结构(这里是入参 DTO)
- Resource:定义出参结构(返回 DTO) 它是 Java 世界里比 PHP 更严格的「请求体即对象」约定。
请求体里的 JSON 数组
@PostMapping("/posts/batch")
public List<Post> batch(@RequestBody List<PostDto> dtos) { ... }宽松模式收所有字段
如果字段太多不想全声明,可以用 Map:
@PostMapping("/webhook")
public void webhook(@RequestBody Map<String, Object> payload) { ... }WARNING
能不用 Map 就不用 —— 类型安全全丢了,相当于 Laravel 里到处 $request->all()。定义明确的 DTO 更安全、更可读。
完整拿 HttpServletRequest
需要原生请求对象时(少见),直接声明:
@PostMapping("/upload")
public String upload(HttpServletRequest request) {
String token = request.getHeader("Authorization");
String method = request.getMethod();
String ip = request.getRemoteAddr();
...
}| 需求 | Laravel | Spring |
|---|---|---|
| 请求头 | $request->header('X-Foo') | request.getHeader("X-Foo") 或 @RequestHeader String xFoo |
| 请求方法 | $request->method() | request.getMethod() |
| 客户端 IP | $request->ip() | request.getRemoteAddr() |
| 上传文件 | $request->file('avatar') | @RequestPart MultipartFile avatar(见 文件存储) |
也可以用 @RequestHeader 注解直接绑定请求头:
@GetMapping("/info")
public String info(@RequestHeader("User-Agent") String ua) { ... }Cookie
@GetMapping("/cookie")
public String cookie(@CookieValue(value = "lang", defaultValue = "zh") String lang) { ... }参数绑定对照速查
| 场景 | 注解 | 类比 Laravel |
|---|---|---|
| 路径参数 | @PathVariable Long id | $request->route('id') |
| 查询参数 | @RequestParam String kw | $request->query('kw') |
| 请求头 | @RequestHeader String token | $request->header('token') |
| Cookie | @CookieValue String lang | $request->cookie('lang') |
| JSON 体 | @RequestBody PostDto dto | $request->validate() + all() |
| 文件 | @RequestPart MultipartFile f | $request->file('f') |
参数校验放在哪
参数绑定完成后,用 @Valid 触发校验:
@PostMapping("/posts")
public Post store(@Valid @RequestBody PostDto dto) {
return service.create(dto);
}DTO 上的校验注解(类似 Laravel FormRequest::rules()):
@Data
public class PostDto {
@NotBlank
@Size(max = 100)
private String title;
@NotBlank
private String content;
}校验失败默认返回 400。如何定制错误响应、如何写更复杂的规则,见 数据校验。