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)
package com.example.demo.common;
import lombok.Data;
@Data
public class R<T> {
private int code;
private String msg;
private T data;
public static <T> R<T> ok() {
return ok(null);
}
public static <T> R<T> ok(T data) {
R<T> r = new R<>();
r.setCode(200);
r.setMsg("success");
r.setData(data);
return r;
}
public static <T> R<T> error(int code, String msg) {
R<T> r = new R<>();
r.setCode(code);
r.setMsg(msg);
return r;
}
public static <T> R<T> error(String msg) {
return error(500, msg);
}
}
2. 全局异常处理(common/GlobalExceptionHandler.java)
package com.example.demo.common;
import jakarta.validation.ConstraintViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
// 参数校验异常
@ExceptionHandler({MethodArgumentNotValidException.class, BindException.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public R<Void> handleValidException(Exception e) {
String msg = e.getMessage();
if (e instanceof MethodArgumentNotValidException ex) {
msg = ex.getBindingResult().getFieldError().getDefaultMessage();
} else if (e instanceof BindException ex) {
msg = ex.getAllErrors().get(0).getDefaultMessage();
}
return R.error(400, msg);
}
// 通用异常兜底
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public R<Void> handleException(Exception e) {
// 实际项目建议把异常信息记录日志
return R.error(500, "服务器内部错误:" + e.getMessage());
}
}
3. 实体 + DTO 示例(以用户为例)
// entity/User.java
package com.example.demo.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
@Data
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String username;
private String email;
private Integer age;
}
// vo/UserVO.java(出参)
@Data
public class UserVO {
private Long id;
private String username;
private String email;
private Integer age;
}
// vo/UserQueryVO.java(分页查询入参)
@Data
public class UserQueryVO {
private Integer page = 1;
private Integer size = 10;
private String username;
}
4. Controller(最核心部分)
package com.example.demo.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.common.R;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import com.example.demo.vo.UserQueryVO;
import com.example.demo.vo.UserVO;
import jakarta.validation.Valid;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/api/v1/users")
public class UserController {
@Autowired
private UserService userService;
// 新增
@PostMapping
public R<UserVO> create(@RequestBody @Valid User user) {
userService.save(user);
UserVO vo = new UserVO();
BeanUtils.copyProperties(user, vo);
return R.ok(vo);
}
// 修改
@PutMapping("/{id}")
public R<UserVO> update(@PathVariable Long id, @RequestBody @Valid User user) {
user.setId(id);
userService.updateById(user);
UserVO vo = new UserVO();
BeanUtils.copyProperties(user, vo);
return R.ok(vo);
}
// 删除
@DeleteMapping("/{id}")
public R<Void> delete(@PathVariable Long id) {
userService.removeById(id);
return R.ok();
}
// 单个查询
@GetMapping("/{id}")
public R<UserVO> getById(@PathVariable Long id) {
User user = userService.getById(id);
if (user == null) {
return R.error(404, "用户不存在");
}
UserVO vo = new UserVO();
BeanUtils.copyProperties(user, vo);
return R.ok(vo);
}
// 分页查询(带条件)
@GetMapping
public R<Page<UserVO>> page(@ModelAttribute UserQueryVO query) {
Page<User> page = new Page<>(query.getPage(), query.getSize());
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.like(query.getUsername() != null, User::getUsername, query.getUsername());
wrapper.orderByDesc(User::getId);
Page<User> userPage = userService.page(page, wrapper);
// 转 VO
Page<UserVO> voPage = new Page<>();
BeanUtils.copyProperties(userPage, voPage, "records");
List<UserVO> records = userPage.getRecords().stream()
.map(u -> {
UserVO vo = new UserVO();
BeanUtils.copyProperties(u, vo);
return vo;
})
.collect(Collectors.toList());
voPage.setRecords(records);
return R.ok(voPage);
}
}
5. application.yml(基础配置)
server:
port: 8080
spring:
application:
name: demo-api
datasource:
url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
global-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 打包 + 部署
有哪一步卡住了?把报错信息或想加的功能告诉我,我直接给你最简代码补丁。加油!