PHP/Laravel 对照速查表
从 Laravel 出发查 Spring Boot:一个 Laravel 概念 → 对应的 Spring Boot 写法。遇到「这个在 Java 里怎么写」时,回这里找。
项目基础
| Laravel | Spring Boot |
|---|---|
composer.json | pom.xml |
composer require xxx | pom.xml 加 <dependency> |
composer install | mvn dependency:resolve |
.env | application.yml(+ 环境变量) |
config/app.php | application.yml 的 spring.* |
APP_ENV=dev | spring.profiles.active: dev |
php artisan serve | ./mvnw spring-boot:run |
public/index.php 入口 | XxxApplication.main() |
routes/web.php + routes/api.php | 注解路由(无路由文件) |
app/Models/ | 按业务模块建包(见 模块化) |
命名空间 App\Models\User | 包 com.example.blog.user.User |
use App\Models\User; | import com.example.blog.user.User; |
路由
| Laravel | Spring Boot |
|---|---|
Route::get('/posts', ...) | @GetMapping("/posts") |
Route::post('/posts', ...) | @PostMapping("/posts") |
Route::put('/posts/{id}', ...) | @PutMapping("/posts/{id}") |
Route::delete('/posts/{id}', ...) | @DeleteMapping("/posts/{id}") |
Route::prefix('api')->group(...) | @RequestMapping("/api") 加在类上 |
{post} 路径参数 | @PathVariable Long id |
$request->route('id') | @PathVariable("id") Long id |
控制器
| Laravel | Spring Boot |
|---|---|
| 控制器类 + 方法 | @RestController 类 + 方法 |
public function index() | public List<Post> index() |
public function store(Request $r) | public Post store(@RequestBody PostDto dto) |
return response()->json($x, 201) | ResponseEntity.status(201).body(x) |
return response()->noContent() | ResponseEntity.noContent().build() |
app(PostService::class) | 构造器注入 |
请求数据
| Laravel | Spring Boot |
|---|---|
$request->query('page') | @RequestParam int page |
$request->all() | @RequestBody Dto / Map |
$request->header('X-Foo') | @RequestHeader("X-Foo") String v |
$request->cookie('lang') | @CookieValue String lang |
$request->file('file') | @RequestParam("file") MultipartFile f |
$request->input() | 方法参数绑定(框架自动解析) |
中间件
| Laravel | Spring Boot |
|---|---|
| 全局中间件 | Filter(@Component) |
| 路由中间件 | HandlerInterceptor + WebMvcConfigurer.addInterceptors |
$next($request) 放行 | return true / chain.doFilter() |
| 中间件里塞数据 | request.setAttribute(...) + @RequestAttribute |
校验
| Laravel | Spring Boot |
|---|---|
$request->validate([...]) | DTO 字段注解 + @Valid |
| FormRequest | 入参 DTO + 校验注解(分组) |
'title' => 'required|max:100' | @NotBlank @Size(max = 100) |
| 自定义规则 | 自定义注解 + ConstraintValidator |
| 校验错误 422 | 默认 400,可在全局处理器映射 422 |
响应
| Laravel | Spring Boot |
|---|---|
return $posts;(自动 JSON) | return posts;(@RestController) |
response()->json($d, 201) | ResponseEntity.status(201).body(d) |
| Resource(出参结构) | 出参 DTO(PostResponse) |
$hidden 隐藏字段 | @JsonIgnore 或 DTO 不包含 |
统一 {code,message,data} | 自定义 ApiResponse<T> |
数据库
| Laravel | Spring Boot |
|---|---|
| Eloquent Model | Spring Data JPA(@Entity + Repository) |
Post::find($id) | postRepository.findById(id).orElseThrow() |
Post::create($data) | postRepository.save(entity) |
Post::where('status',1)->get() | findByStatus(1) |
$post->save() | postRepository.save(post) |
Post::destroy($id) | postRepository.deleteById(id) |
hasMany / belongsTo | @OneToMany / @ManyToOne |
belongsToMany | @ManyToMany @JoinTable |
with('relation') 防 N+1 | @EntityGraph(attributePaths=...) |
| Query Builder | JdbcTemplate |
| 原生手写 SQL + 映射 | MyBatis(XML Mapper) |
paginate() | Pageable(页码从 0 开始) |
| migration | Flyway(db/migration/V1__xxx.sql) |
DB::transaction(fn) | @Transactional |
| Seeder | CommandLineRunner / Flyway 种子数据 |
认证与安全
| Laravel | Spring Boot |
|---|---|
Auth::attempt() | authenticationManager.authenticate(...) |
auth()->user() | SecurityContextHolder / Authentication 参数 |
auth()->check() | Authentication != null && authenticated |
Auth::logout() | 清理 SecurityContext |
Hash::make / Hash::check | PasswordEncoder.encode / .matches |
Gate::authorize / Policy | @PreAuthorize + SpEL |
中间件 auth | .anyRequest().authenticated() |
| 401 / 403 定制 | AuthenticationEntryPoint / AccessDeniedHandler |
| Sanctum / JWT | Spring Security + JWT 过滤器链 |
扩展功能
| Laravel | Spring Boot |
|---|---|
| Event + Listener | ApplicationEvent + @EventListener |
Cache::remember | @Cacheable |
Cache::put / forget | @CachePut / @CacheEvict |
CACHE_DRIVER=redis | spring.cache.type: redis |
Storage::put | MultipartFile + 手动存(或 AWS S3 SDK) |
Http::get($url) | RestClient |
dispatch() 异步 | @Async |
| Queue + Job | RabbitMQ + @RabbitListener |
| 定时任务 Kernel | @Scheduled(六段式 cron) |
Mail::to()->send() | JavaMailSender + Thymeleaf 模板 |
RateLimiter / throttle | Bucket4j 拦截器 / Redis 限流 |
Log::info() | Lombok @Slf4j + log.info() |
| 测试 Feature/Unit | @SpringBootTest / JUnit 5 |
$this->get('/posts') | MockMvc |
| 接口文档 Scribe | SpringDoc OpenAPI |
最易踩坑的五个差异
| 差异 | 说明 |
|---|---|
| 六段式 cron | Spring 比 Laravel 多「秒」段,0 0 2 * * ? 才是每天 2 点 |
| JPA 分页从 0 开始 | PageRequest.of(page-1, size),前端第 1 页要减一 |
| 单例 Bean 共享 | Bean 默认单例,跨线程共享,别存请求级状态 |
| 已执行的迁移文件不能改 | Flyway 校验 checksum,改旧文件启动报错 |
@Async/@Transactional 同类调用失效 | 靠代理实现,必须通过注入的 Bean 调用 |