路由
Laravel 把路由写在
routes/web.php和routes/api.php;Spring Boot 没有路由文件 —— 路由直接用注解写在控制器方法上。声明即注册,看到方法就知道它的 URL。
基本路由:@GetMapping 等
// Laravel
Route::get('/posts', [PostController::class, 'index']);// Spring Boot
@RestController
public class PostController {
@GetMapping("/posts")
public List<Post> index() {
return ...;
}
}四种 HTTP 动词对应四个注解:
| Laravel | Spring Boot |
|---|---|
Route::get | @GetMapping |
Route::post | @PostMapping |
Route::put | @PutMapping |
Route::delete | @DeleteMapping |
Route::patch | @PatchMapping |
Route::any / Route::match | @RequestMapping(method = {GET, POST}) |
@RequestMapping 是最底层的,其他都是它的简写:
@RequestMapping(value = "/posts", method = RequestMethod.GET)
// 等价于 @GetMapping("/posts")类上也可以加前缀
@RequestMapping 加在类上,就相当于 Laravel 的 Route::prefix('posts')->group(...):
@RestController
@RequestMapping("/posts")
public class PostController {
@GetMapping("/{id}") // 实际路径 /posts/{id}
public Post show(@PathVariable Long id) { ... }
}路径参数:{id} → @PathVariable
// Laravel
Route::get('/posts/{post}', [PostController::class, 'show']);
// 控制器
public function show(Post $post) { ... }@GetMapping("/posts/{id}")
public Post show(@PathVariable Long id) { ... }多个参数、正则约束:
@GetMapping("/posts/{id}/comments/{commentId}")
public Comment show(@PathVariable Long id,
@PathVariable Long commentId) { ... }| 功能 | Laravel | Spring Boot |
|---|---|---|
| 单参数 | {post} + $post | {id} + @PathVariable Long id |
| 默认值 | 路由参数必须有值 | 同左 |
| 正则约束 | where('id', '[0-9]+') | 一般不校验格式,交给类型转换(Long id 自动强转) |
类型转换
Laravel 里参数是字符串,靠 where 或模型绑定约束;Spring 里 @PathVariable Long id 的 Long 会自动做类型转换,URL 传非数字会抛类型异常(会被 异常处理 兜住)。
查询参数:?page=2 → @RequestParam
// Laravel
Route::get('/posts', [PostController::class, 'index']);
// 控制器里 $request->query('page', 1)@GetMapping("/posts")
public List<Post> index(@RequestParam(defaultValue = "1") int page,
@RequestParam(required = false) String keyword) {
...
}| 场景 | 写法 |
|---|---|
| 必填参数 | @RequestParam Long id(缺了就 400) |
| 可选参数 | @RequestParam(required = false) String keyword |
| 带默认值 | @RequestParam(defaultValue = "1") int page |
| 一次拿全部 | @RequestParam Map<String, String> params |
对比
Laravel 里所有查询参数都从 $request 拿;Spring 里直接声明方法参数,框架自动解析填充 —— 这就是「参数绑定」,写起来更短,签名即文档。
统一前缀与版本化
全局前缀(类似 Laravel Route::prefix('api'))
server:
servlet:
context-path: /api所有路由自动带上 /api 前缀,相当于 Laravel 的 api.php 路由文件。
按模块分组前缀
@RestController
@RequestMapping("/api/v1/posts")
public class PostController { ... }控制器动态注册:RouterFunction
大多数项目用注解就够了,但知道有「编程式」的写法可以避免误解(对应 Laravel 的闭包路由):
@Configuration
public class RouterConfig {
@Bean
public RouterFunction<ServerResponse> routes() {
return route()
.GET("/health", req -> ServerResponse.ok().body("ok"))
.build();
}
}路由相关常用技巧
| 需求 | 写法 |
|---|---|
| 多方法处理一个 URL | @GetMapping + @PostMapping 标在类上,或 @RequestMapping |
| 通配符 | @GetMapping("/files/**")(** 匹配多级路径) |
| 跳转 | 返回 ResponseEntity 或 redirect: 前缀视图 |
| 全局路由不存在处理 | 全局异常处理兜 404(见 异常处理) |
没有 REST 资源路由
Laravel 有 Route::resource() 一键生成 7 个 REST 路由;Spring Boot 没有对应的「一个注解生成全部」,每个方法都要显式声明(可以用 @RequestMapping 组合)。这是风格差异,不是缺陷 —— 显式更清晰。
路由注册的时机
- 注解路由:应用启动时由
RequestMappingHandlerMapping扫描所有@Controller方法,构建路由表 - 运行时不能再增减(与 Laravel 每次请求重建路由表不同,Spring 的路由表是启动时构建的静态结构)
启动即路由
这意味着 Spring Boot 的 URL 匹配非常快(内存 Map 查找),代价是改路由必须重启。Java 世界的主流就是「编译期/启动期固化 + 重启生效」,别和 PHP 的「每请求动态」思维混在一起。
接下来,深入控制器:控制器。