Java API 接口从 0 到 1 实战指南
(2025–2026 年最常用、最务实写法,新手友好版)
目标:
用最短路径,让一个刚学完 JavaSE 的同学能在3–5 天内独立写出生产级 RESTful API(包含增删改查、分页、参数校验、统一响应、异常处理、日志、接口文档)。
技术选型推荐(2026 年新项目主流组合)
| 技术项 | 推荐选择(新手友好) | 为什么选它(2026 年视角) | 替代选项(可选了解) |
|---|---|---|---|
| 框架 | Spring Boot 3.3.x / 3.4.x | 自动配置最彻底、生态最全 | Spring MVC 纯手工 |
| Web 层 | @RestController + Spring Web | 最简单、最常用 | WebFlux(高并发场景) |
| JSON 处理 | Jackson(Spring Boot 默认) | 性能好、兼容性强 | Fastjson(慎用) |
| 参数校验 | jakarta.validation + @Valid | 标准、注解式、易读 | — |
| 统一响应 | 自定义 R / Result | 公司规范 90% 都这么做 | ResponseEntity |
| 异常处理 | @ControllerAdvice + @ExceptionHandler | 全局统一、优雅 | — |
| 日志 | lombok + slf4j + logback | 最轻、最常用 | log4j2 |
| 接口文档 | springdoc-openapi 2.x(OpenAPI 3) | 免费、美观、替代 swagger-ui | Knife4j(国内更流行) |
| 构建工具 | Maven(最稳) | 面试/公司项目主流 | Gradle(越来越多人用) |
| 数据库访问(可选) | MyBatis-Plus 3.5.x | 代码少、功能强、分页方便 | Spring Data JPA |
完整项目结构(推荐)
demo-api ├── src │ ├── main │ │ ├── java │ │ │ └── com/example/demo │ │ │ ├── common # 统一响应、异常、常量 │ │ │ ├── config # 配置类(可选) │ │ │ ├── controller │ │ │ ├── entity # 实体类 │ │ │ ├── mapper # MyBatis Mapper(可选) │ │ │ ├── service │ │ │ └── vo # 入参/出参 DTO │ │ └── resources │ │ ├── application.yml │ │ └── logback-spring.xml(可选) │ └── test └── pom.xml步骤 1:快速创建项目(5 分钟)
方式一(最推荐):
打开 https://start.spring.io/
配置:
- Project: Maven
- Language: Java
- Spring Boot: 3.3.5 或 3.4.x(最新稳定)
- Group: com.example
- Artifact: demo-api
- Java: 17 或 21
- Dependencies(至少选):
- Spring Web
- Lombok
- Spring Boot DevTools
- Validation
- SpringDoc OpenAPI UI
- (可选)MyBatis Plus + MySQL Driver + druid
Generate → 解压 → IDEA 打开
步骤 2:核心代码清单(复制粘贴就能跑)
1. 统一响应类(common/R.java)
packagecom.example.demo.common;importlombok.Data;@DatapublicclassR<T>{privateintcode;privateStringmsg;privateTdata;publicstatic<T>R<T>ok(){returnok(null);}publicstatic<T>R<T>ok(Tdata){R<T>r=newR<>();r.setCode(200);r.setMsg("success");r.setData(data);returnr;}publicstatic<T>R<T>error(intcode,Stringmsg){R<T>r=newR<>();r.setCode(code);r.setMsg(msg);returnr;}publicstatic<T>R<T>error(Stringmsg){returnerror(500,msg);}}2. 全局异常处理(common/GlobalExceptionHandler.java)
packagecom.example.demo.common;importjakarta.validation.ConstraintViolationException;importorg.springframework.http.HttpStatus;importorg.springframework.validation.BindException;importorg.springframework.web.bind.MethodArgumentNotValidException;importorg.springframework.web.bind.annotation.ExceptionHandler;importorg.springframework.web.bind.annotation.ResponseStatus;importorg.springframework.web.bind.annotation.RestControllerAdvice;@RestControllerAdvicepublicclassGlobalExceptionHandler{// 参数校验异常@ExceptionHandler({MethodArgumentNotValidException.class,BindException.class})@ResponseStatus(HttpStatus.BAD_REQUEST)publicR<Void>handleValidException(Exceptione){Stringmsg=e.getMessage();if(einstanceofMethodArgumentNotValidExceptionex){msg=ex.getBindingResult().getFieldError().getDefaultMessage();}elseif(einstanceofBindExceptionex){msg=ex.getAllErrors().get(0).getDefaultMessage();}returnR.error(400,msg);}// 通用异常兜底@ExceptionHandler(Exception.class)@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)publicR<Void>handleException(Exceptione){// 实际项目建议把异常信息记录日志returnR.error(500,"服务器内部错误:"+e.getMessage());}}3. 实体 + DTO 示例(以用户为例)
// entity/User.javapackagecom.example.demo.entity;importcom.baomidou.mybatisplus.annotation.IdType;importcom.baomidou.mybatisplus.annotation.TableId;importlombok.Data;@DatapublicclassUser{@TableId(type=IdType.AUTO)privateLongid;privateStringusername;privateStringemail;privateIntegerage;}// vo/UserVO.java(出参)@DatapublicclassUserVO{privateLongid;privateStringusername;privateStringemail;privateIntegerage;}// vo/UserQueryVO.java(分页查询入参)@DatapublicclassUserQueryVO{privateIntegerpage=1;privateIntegersize=10;privateStringusername;}4. Controller(最核心部分)
packagecom.example.demo.controller;importcom.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;importcom.baomidou.mybatisplus.extension.plugins.pagination.Page;importcom.example.demo.common.R;importcom.example.demo.entity.User;importcom.example.demo.service.UserService;importcom.example.demo.vo.UserQueryVO;importcom.example.demo.vo.UserVO;importjakarta.validation.Valid;importorg.springframework.beans.BeanUtils;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.*;importjava.util.List;importjava.util.stream.Collectors;@RestController@RequestMapping("/api/v1/users")publicclassUserController{@AutowiredprivateUserServiceuserService;// 新增@PostMappingpublicR<UserVO>create(@RequestBody@ValidUseruser){userService.save(user);UserVOvo=newUserVO();BeanUtils.copyProperties(user,vo);returnR.ok(vo);}// 修改@PutMapping("/{id}")publicR<UserVO>update(@PathVariableLongid,@RequestBody@ValidUseruser){user.setId(id);userService.updateById(user);UserVOvo=newUserVO();BeanUtils.copyProperties(user,vo);returnR.ok(vo);}// 删除@DeleteMapping("/{id}")publicR<Void>delete(@PathVariableLongid){userService.removeById(id);returnR.ok();}// 单个查询@GetMapping("/{id}")publicR<UserVO>getById(@PathVariableLongid){Useruser=userService.getById(id);if(user==null){returnR.error(404,"用户不存在");}UserVOvo=newUserVO();BeanUtils.copyProperties(user,vo);returnR.ok(vo);}// 分页查询(带条件)@GetMappingpublicR<Page<UserVO>>page(@ModelAttributeUserQueryVOquery){Page<User>page=newPage<>(query.getPage(),query.getSize());LambdaQueryWrapper<User>wrapper=newLambdaQueryWrapper<>();wrapper.like(query.getUsername()!=null,User::getUsername,query.getUsername());wrapper.orderByDesc(User::getId);Page<User>userPage=userService.page(page,wrapper);// 转 VOPage<UserVO>voPage=newPage<>();BeanUtils.copyProperties(userPage,voPage,"records");List<UserVO>records=userPage.getRecords().stream().map(u->{UserVOvo=newUserVO();BeanUtils.copyProperties(u,vo);returnvo;}).collect(Collectors.toList());voPage.setRecords(records);returnR.ok(voPage);}}5. application.yml(基础配置)
server:port:8080spring:application:name:demo-apidatasource:url:jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghaiusername:rootpassword:123456driver-class-name:com.mysql.cj.jdbc.Drivermybatis-plus:configuration:map-underscore-to-camel-case:trueglobal-config:db-config:id-type:auto最后 10 分钟检查清单(新手最容易忘)
- 加了 spring-boot-maven-plugin 吗?
- application.yml 数据库连得上吗?
- @RestController 而不是 @Controller?
- @Valid + jakarta.validation 依赖加了吗?
- lombok 插件装了吗?(IDEA)
- 启动类有 @SpringBootApplication?
- 浏览器打开 http://localhost:8080/swagger-ui.html 能看到文档吗?
- Postman 测试过所有接口了吗?
完成以上步骤,你就已经从 0 写出了一个相对规范、可维护、生产可用的 RESTful API 项目。
下一阶段推荐(按顺序)
- 加登录 + JWT 鉴权(最重要)
- 集成 Redis 做缓存
- 文件上传(MinIO / 阿里 OSS)
- 全局日志 + 请求链路追踪(TraceId)
- Docker 打包 + 部署
有哪一步卡住了?把报错信息或想加的功能告诉我,我直接给你最简代码补丁。加油!