本文最后更新于70 天前,其中的信息可能已经过时,如有错误请发送邮件到3082654005@qq.com
第一部分:从0开始写一个接口 (Hands-on Tutorial)
假设我们使用最流行的 Spring Boot 框架来创建一个简单的 GET /users/{id} 接口,用于根据用户ID查询用户信息。
第1步:环境准备
- 安装JDK:确保安装了JDK 8或以上版本。
- 安装IDE:推荐使用 IntelliJ IDEA (社区版即可) 或 Eclipse。
- 创建项目:使用 Spring Initializr 快速生成项目。
- Project: Maven
- Language: Java
- Spring Boot: 选择最新的稳定版(如3.2.x)
- Group:
com.example(你的公司域名反写) - Artifact:
demo - Packaging: Jar
- Java: 选择你安装的JDK版本
- Dependencies: 添加
Spring Web(这是构建Web接口的核心)
点击“Generate”下载压缩包,并解压到你的工作目录,用IDE打开。
第2步:理解项目结构
打开项目后,你会看到类似这样的结构:
text
src
└── main
├── java
│ └── com
│ └── example
│ └── demo
│ ├── DemoApplication.java // Spring Boot启动类
│ └── controller // 【建议创建】存放控制器(接口)的包
│ └── service // 【建议创建】存放业务逻辑的包
│ └── entity // 【建议创建】存放实体类的包
└── resources
└── application.properties // 配置文件
第3步:编写代码
我们将遵循 MVC(Model-View-Controller) 模式。
- 创建实体类 (Model)
在entity包下创建User.java,代表一个用户数据模型。javapackage com.example.demo.entity; public class User { private Long id; private String name; private String email; // 1. 无参构造器 public User() { } // 2. 带参构造器 public User(Long id, String name, String email) { this.id = id; this.name = name; this.email = email; } // 3. Getter和Setter方法 (必须要有,否则无法序列化为JSON) public Long getId() { return id; } public void setId(Long id) { this.id = id; } // … 省略name和email的getter和setter } - 创建控制器 (Controller)
在controller包下创建UserController.java。这里定义接口的URL、方法和参数。javapackage com.example.demo.controller; import com.example.demo.entity.User; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @RestController // 这个注解标明这个类是一个控制器,并且返回的是JSON数据,而不是视图页面。 public class UserController { // 模拟一些静态数据,代替数据库 private static final List<User> USER_LIST = Arrays.asList( new User(1L, “张三”, “zhangsan@example.com”), new User(2L, “李四”, “lisi@example.com”) ); // @GetMapping 注解将HTTP GET请求映射到特定的方法上。 // {id} 是路径变量。 @GetMapping(“/users/{id}”) public User getUserById(@PathVariable Long id) { // @PathVariable 用来接收路径变量 // 简单的业务逻辑:遍历列表查找用户 return USER_LIST.stream() .filter(user -> user.getId().equals(id)) .findFirst() .orElseThrow(() -> new RuntimeException(“User not found with id: ” + id)); // 如果没找到,抛出一个异常 } }
第4步:运行和测试
- 启动应用:运行
DemoApplication.java中的main方法。 - 测试接口:打开浏览器或使用Postman等API测试工具,访问
http://localhost:8080/users/1。
你应该能看到返回的JSON数据:json{ “id”: 1, “name”: “张三”, “email”: “zhangsan@example.com” }
恭喜!你已经从0到1完成了第一个接口。但这只是一个开始,真实的工作场景要复杂得多。
第二部分:如何在工作中写好一个接口 (Best Practices)
写一个“能跑”的接口很简单,但写一个“好”接口需要考虑到很多方面。
1. 清晰的职责划分 (MVC & Layer Architecture)
不要把所有代码都写在Controller里!优秀的后端代码应该有清晰的分层:
- Controller层:只负责接收请求、解析参数、调用Service、返回响应。不应该包含复杂的业务逻辑。
- Service层:核心业务逻辑所在的地方。处理业务规则、计算、事务管理等。
- Repository/Dao层:负责与数据库进行交互,执行CRUD(增删改查)操作。
在我们的例子中,应该创建一个 UserService 接口及其实现类 UserServiceImpl,将查找用户的逻辑从Controller挪到Service中。Controller只负责调用 userService.getUserById(id)。
2. 规范的 RESTful 设计
- URL语义化:使用名词复数,而不是动词。
/users比/getUsers更好。 - HTTP方法:正确使用HTTP动词表达操作意图。
GET:查询/获取资源POST:创建新资源PUT:更新整个资源PATCH:部分更新资源DELETE:删除资源
- 状态码:返回合适的HTTP状态码。
200 OK:成功201 Created:创建成功400 Bad Request:客户端请求错误(如参数校验失败)404 Not Found:资源不存在500 Internal Server Error:服务器内部错误
3. 全面的参数校验 (Validation)
永远不要相信前端传来的数据!必须在后端进行校验。
- 使用注解:在实体类字段上使用
javax.validation.constraints或jakarta.validation.constraints包下的注解。javapublic class User { @NotNull(message = “用户ID不能为空”) private Long id; @NotBlank(message = “用户名不能为空”) @Size(max = 50, message = “用户名长度不能超过50个字符”) private String name; @Email(message = “邮箱格式不正确”) private String email; } - 在Controller方法中使用
@Valid:java@PostMapping(“/users”) public User createUser(@RequestBody @Valid User user) { // @Valid 会触发校验 return userService.createUser(user); } - 处理校验异常:通常使用
@ControllerAdvice进行全局异常处理,统一返回格式。
4. 统一的响应格式 (Response Wrapper)
不要直接返回实体对象,应该用一个统一的包装类包裹起来,方便前端处理。
java
// 定义一个标准响应类
public class ApiResponse<T> {
private int code; // 状态码 (200, 400, 500等,或自定义业务码)
private String message; // 提示信息
private T data; // 返回的数据
// 成功静态方法
public static <T> ApiResponse<T> success(T data) {
ApiResponse<T> response = new ApiResponse<>();
response.setCode(200);
response.setMessage("Success");
response.setData(data);
return response;
}
// 失败静态方法...
// Getter and Setter...
}
// Controller中这样用
@GetMapping("/users/{id}")
public ApiResponse<User> getUserById(@PathVariable Long id) {
User user = userService.getUserById(id);
return ApiResponse.success(user);
}
这样,所有接口返回的格式都是 {“code": 200, "message": "Success", "data": {...}}。
5. 细致的异常处理 (Exception Handling)
使用 @ControllerAdvice 和 @ExceptionHandler 进行全局异常处理,避免将晦涩的服务器异常直接抛给前端。
java
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(RuntimeException.class)
@ResponseBody
public ApiResponse<String> handleRuntimeException(RuntimeException e) {
// 记录日志
return ApiResponse.fail(500, "服务器繁忙,请稍后再试: " + e.getMessage());
}
// 专门处理参数校验异常
@ExceptionHandler(MethodArgumentNotValidException.class)
public ApiResponse<String> handleValidationException(MethodArgumentNotValidException e) {
String errorMessage = e.getBindingResult().getFieldError().getDefaultMessage();
return ApiResponse.fail(400, errorMessage);
}
}
6. 必不可少的日志 (Logging)
在关键位置添加日志,方便排查问题。
- 记录入参和出参:特别是在复杂接口中。
- 记录业务操作:比如“用户XXX下单成功”。
- 使用SLF4J + Logback:java@Slf4j // Lombok注解,自动生成log变量 @RestController public class UserController { @GetMapping(“/users/{id}”) public ApiResponse<User> getUserById(@PathVariable Long id) { log.info(“Received request for user id: {}”, id); // 使用{}占位符 User user = userService.getUserById(id); log.info(“Return user: {}”, user); return ApiResponse.success(user); } }
7. 接口文档 (API Documentation)
代码写完,文档也要生成。不要维护单独的Word文档,代码一变文档就过期。
- 使用 Swagger/OpenAPI:通过在代码中添加注解(如
@Operation,@ApiResponse),自动生成实时、可交互的API文档。访问http://localhost:8080/swagger-ui.html即可查看。
8. 性能与安全 (Performance & Security)
- 性能:关注数据库查询效率(使用索引),必要时引入缓存(Redis)。
- 安全:
- 敏感数据(如密码)加密存储。
- 接口权限控制(使用Spring Security),防止越权访问。
- 防止SQL注入(使用MyBatis等ORM框架本身就解决了这个问题)。
- 防止XSS攻击(对用户输入进行转义)。
总结:写好一个接口的 checklist
- 设计:URL和HTTP方法是否符合RESTful规范?
- 参数:是否对所有输入参数进行了校验?
- 分层:业务逻辑是否放在了Service层?
- 响应:是否使用了统一的响应格式?
- 异常:是否处理了可能的异常并返回友好提示?
- 日志:是否在关键位置添加了日志记录?
- 文档:是否更新或生成了API文档(如Swagger)?
- 安全:是否考虑了权限、SQL注入、XSS等安全问题?
从写出第一个接口到写出一个健壮、可靠、易维护的接口,需要不断地学习和实践。希望这份指南能为你提供一个清晰的路径!


