Spring Boot实现简单的restful API接口
1. 背景介绍
RESTful API 是现代软件开发中的一种常见技术,它基于 REST 架构,提供了一种轻量级、灵活的方式来构建和访问网络资源。Spring Boot 是一个用于构建 Spring 应用程序的框架,它简化了开发过程,使得开发者可以更快地构建高质量的应用程序。
在本文中,我们将讨论如何使用 Spring Boot 开发 RESTful API,包括其核心概念、算法原理、最佳实践、应用场景、工具和资源推荐以及未来发展趋势。
2. 核心概念与联系
2.1 RESTful API
RESTful API 是一种基于 HTTP 协议的网络架构风格,它提供了一种简单、灵活、可扩展的方式来构建和访问网络资源。RESTful API 的核心概念包括:
资源(Resource):网络资源是 RESTful API 的基本组成部分,它们可以是文件、数据库记录、服务等。
URI(Uniform Resource Identifier):用于唯一标识资源的字符串。
HTTP 方法:用于操作资源的方法,例如 GET、POST、PUT、DELETE 等。
状态码:用于表示请求的处理结果的三位数字代码,例如 200(OK)、404(Not Found)等。
2.2 Spring Boot
Spring Boot 是一个用于构建 Spring 应用程序的框架,它提供了一系列的工具和库,使得开发者可以更快地构建高质量的应用程序。Spring Boot 的核心概念包括:
自动配置:Spring Boot 提供了一系列的自动配置,使得开发者无需手动配置应用程序的各种依赖关系和配置参数。
应用程序启动器:Spring Boot 提供了一系列的应用程序启动器,使得开发者可以快速搭建 Spring 应用程序。
依赖管理:Spring Boot 提供了一系列的依赖管理工具,使得开发者可以轻松管理应用程序的依赖关系。
3. 核心算法原理和具体操作步骤以及数学模型公式详细讲解
3.1 RESTful API 的核心算法原理
RESTful API 的核心算法原理是基于 HTTP 协议的 CRUD 操作。CRUD 操作包括:
创建(Create):使用 POST 方法创建新的资源。
读取(Read):使用 GET 方法读取资源。
更新(Update):使用 PUT 或 PATCH 方法更新资源。
删除(Delete):使用 DELETE 方法删除资源。
3.2 Spring Boot 的核心算法原理
Spring Boot 的核心算法原理是基于 Spring 框架的组件和依赖注入。Spring Boot 提供了一系列的组件,例如:
应用程序上下文:用于管理应用程序的配置和资源。
Bean 工厂:用于管理应用程序的依赖关系和组件。
自动配置:用于自动配置应用程序的各种依赖关系和配置参数。
4. 数学模型公式详细讲解
4.1 URI
URI(Uniform Resource Identifier)是一个用于标识资源的字符串。URI的基本格式如下:
scheme:[//[userinfo@]host[:port]][/]path[?query][#fragment]
其中,scheme表示URI的协议(如http或https),host表示资源所在的服务器,port表示服务器的端口号,path表示资源的路径,query表示请求参数,fragment表示资源内的锚点。
4.2 HTTP方法
HTTP方法是用于操作资源的请求方式,常见的HTTP方法有:
GET:用于请求资源
POST:用于创建新资源
PUT:用于更新资源
DELETE:用于删除资源
4.3 状态码
HTTP状态码是用于描述请求的处理结果的三位数字代码。常见的状态码有:
200(OK):请求成功
201(Created):请求成功并创建了新资源
400(Bad Request):请求有误
404(Not Found):请求的资源不存在
500(Internal Server Error):服务器内部错误
5.创建接口实践
5.1全流程
整体逻辑串起来(以"新增用户"为例)
- 客户端发送
POST /api/users,body 是 JSON - Spring MVC 把 JSON 反序列化为
User对象,@Valid触发校验 - 校验通过 →
UserController.add()调用userService.saveUser(user) UserServiceImpl.saveUser()调用userMapper.insert(user)- MyBatis 执行
UserMapper.xml中的 INSERT 语句,把#{username}等替换为实际值 - 数据库返回受影响行数 = 1,
user.id被回填 - Controller 返回
201 Created+ 新用户 JSON - 如果途中任何一步抛异常 →
GlobalExceptionHandler拦截 → 返回400 + {"error": "..."}

D:\新建文件夹\demo4\ ← 项目根目录
├── pom.xml
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ └── demo4/ ← ★ 包名已改为 demo4
│ │ │ ├── Demo4Application.java ← ★ 启动类改名
│ │ │ ├── controller/
│ │ │ │ └── UserController.java
│ │ │ ├── service/
│ │ │ │ ├── UserService.java
│ │ │ │ └── impl/
│ │ │ │ └── UserServiceImpl.java
│ │ │ ├── mapper/
│ │ │ │ └── UserMapper.java
│ │ │ ├── entity/
│ │ │ │ └── User.java
│ │ │ └── exception/
│ │ │ └── GlobalExceptionHandler.java
│ │ └── resources/
│ │ ├── application.properties
│ │ └── mapper/ ← ★ XML 映射文件放在这里
│ │ └── UserMapper.xml
│ └── test/ (测试目录可忽略)
└── ...
5.2entity/User.java(实体类 / 数据模型)
package com.example.demo4.entity;
import jakarta.validation.constraints.Max; // 最大值校验
import jakarta.validation.constraints.Min; // 最小值校验
import jakarta.validation.constraints.NotBlank; // 非空非空白校验
import jakarta.validation.constraints.Size; // 长度校验
import lombok.Data; // Lombok 注解,自动生成 getter/setter/toString/equals
@Data // Lombok 神器:一个注解顶一堆模板代码(getter、setter、toString、equals、hashCode)
public class User {
private Long id; // 主键 ID,Long 长整型
@NotBlank(message = "用户名不能为空") // username 不能是 null、空串或纯空格
@Size(max = 50, message = "用户名长度不能超过50") // username 最大长度 50
private String username;
@Size(max = 10, message = "姓名长度不能超过10") // name 最大长度 10(可为空)
private String name;
@Min(value = 0, message = "年龄不能小于0") // age 最小值 0
@Max(value = 150, message = "年龄不能大于150") // age 最大值 150
private Integer age;
@Size(max = 1, message = "性别只能为单个字符") // gender 最大长度 1(如 "男"/"女")
private String gender;
}
作用:对应数据库 user 表的 Java 实体。校验注解会在 Controller 层 @Valid 时自动触发。
5.3mapper/UserMapper.java(数据访问接口)
package com.example.demo4.mapper;
import com.example.demo4.entity.User;
import org.apache.ibatis.annotations.Mapper; // MyBatis 的 @Mapper 注解
import org.apache.ibatis.annotations.Param; // @Param 给参数起名字,SQL 里用 #{名字} 引用
import java.util.List;
@Mapper // 告诉 MyBatis:给这个接口生成一个代理实现类,注册为 Spring Bean
public interface UserMapper {
int insert(User user); // 新增,返回受影响行数(>0 表示成功)
int updateById(User user); // 根据 id 更新
int deleteById(@Param("id") Long id); // 根据 id 删除,@Param("id") 让 SQL 里能用 #{id}
User selectById(@Param("id") Long id); // 根据 id 查询单个
List<User> selectAll(); // 查询全部
}
作用:接口本身只有方法签名,真正的 SQL 写在 UserMapper.xml 中,MyBatis 通过方法名找到对应的 SQL 执行。
5.4service/UserService.java(业务接口)
package com.example.demo4.service;
import com.example.demo4.entity.User;
import java.util.List;
public interface UserService {
User saveUser(User user); // 新增用户,返回含主键的对象
User updateUser(Long id, User user); // 更新指定 id 的用户
void deleteUser(Long id); // 删除用户(无返回值)
User getUserById(Long id); // 查询单个用户
List<User> getAllUsers(); // 查询所有用户
}
作用:定义业务层契约。Controller 只依赖这个接口,不关心具体实现 —— 这就是"面向接口编程",方便解耦和替换实现。
5.5service/impl/UserServiceImpl.java(业务实现)
package com.example.demo4.service.impl;
import com.example.demo4.entity.User;
import com.example.demo4.mapper.UserMapper;
import com.example.demo4.service.UserService;
import lombok.RequiredArgsConstructor; // Lombok:为 final 字段生成构造方法
import org.springframework.stereotype.Service; // 声明为 Service 层 Bean
import java.util.List;
@Service // 告诉 Spring:这是一个 Service Bean,交给容器管理
@RequiredArgsConstructor // Lombok:给下面的 final 字段 userMapper 生成构造方法
// → Spring 通过构造方法自动注入 UserMapper(构造器注入,推荐方式)
public class UserServiceImpl implements UserService {
private final UserMapper userMapper; // final 必须在构造时赋值,由 Lombok 生成的构造方法注入
@Override
public User saveUser(User user) {
int rows = userMapper.insert(user); // 调用 Mapper 执行 INSERT
if (rows <= 0) throw new RuntimeException("新增用户失败"); // 受影响行数<=0 说明失败
return user; // 返回 user(此时 id 已被回填)
}
@Override
public User updateUser(Long id, User user) {
User existing = userMapper.selectById(id); // 先查一下这个 id 的用户存不存在
if (existing == null) throw new RuntimeException("用户不存在,ID: " + id);
user.setId(id); // 把路径里的 id 设进 user 对象
int rows = userMapper.updateById(user); // 执行 UPDATE
if (rows <= 0) throw new RuntimeException("更新用户失败");
return userMapper.selectById(id); // 返回更新后的最新数据
}
@Override
public void deleteUser(Long id) {
if (userMapper.selectById(id) == null) throw new RuntimeException("用户不存在,ID: " + id);
int rows = userMapper.deleteById(id); // 执行 DELETE
if (rows <= 0) throw new RuntimeException("删除用户失败");
}
@Override
public User getUserById(Long id) {
User user = userMapper.selectById(id);
if (user == null) throw new RuntimeException("用户不存在,ID: " + id);
return user;
}
@Override
public List<User> getAllUsers() {
return userMapper.selectAll(); // 直接返回全部,空表就返回空 List
}
}
作用:业务逻辑都在这里。每个写操作(增/改/删)都做了"先校验存在 + 检查受影响行数"的双重保险。
5.6controller/UserController.java(控制器 / 接口入口)
package com.example.demo4.controller;
import com.example.demo4.entity.User;
import com.example.demo4.service.UserService;
import jakarta.validation.Valid; // 触发实体上校验注解的开关
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus; // HTTP 状态码枚举
import org.springframework.http.ResponseEntity; // 响应实体(包含状态码 + body)
import org.springframework.web.bind.annotation.*; // 一次性导入所有 web 注解
import java.util.List;
@RestController // = @Controller + @ResponseBody,返回值自动转 JSON
@RequestMapping("/api/users") // 这个类下所有接口的公共前缀都是 /api/users
@RequiredArgsConstructor // Lombok 给 final 字段生成构造方法 → Spring 注入 userService
public class UserController {
private final UserService userService; // 依赖业务接口(不是实现类,面向接口编程)
@GetMapping // 处理 GET /api/users
public ResponseEntity<List<User>> list() {
return ResponseEntity.ok(userService.getAllUsers());
// ResponseEntity.ok() → 状态码 200,body 是用户列表
}
@GetMapping("/{id}") // 处理 GET /api/users/5(5 是路径变量)
public ResponseEntity<User> getById(@PathVariable Long id) {
// @PathVariable 把 URL 里的 {id} 提取为 Long id 参数
return ResponseEntity.ok(userService.getUserById(id));
}
@PostMapping // 处理 POST /api/users
public ResponseEntity<User> add(@Valid @RequestBody User user) {
// @RequestBody:把请求体 JSON 自动反序列化为 User 对象
// @Valid:触发 User 实体上的校验注解(@NotBlank、@Size 等)
return ResponseEntity.status(HttpStatus.CREATED).body(userService.saveUser(user));
// 状态码 201(CREATED)表示资源创建成功,body 是新用户(含生成的 id)
}
@PutMapping("/{id}") // 处理 PUT /api/users/5
public ResponseEntity<User> update(@PathVariable Long id, @Valid @RequestBody User user) {
return ResponseEntity.ok(userService.updateUser(id, user)); // 200 + 更新后的数据
}
@DeleteMapping("/{id}") // 处理 DELETE /api/users/5
public ResponseEntity<Void> delete(@PathVariable Long id) {
userService.deleteUser(id);
return ResponseEntity.noContent().build();
// 204 No Content,body 为空,表示删除成功
}
}
作用:对外暴露 5 个 RESTful 接口,是 HTTP 请求进入应用的入口。
5.7exception/GlobalExceptionHandler.java(全局异常处理)
package com.example.demo4.exception;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException; // @Valid 校验失败时抛出
import org.springframework.web.bind.annotation.ExceptionHandler; // 异常处理器注解
import org.springframework.web.bind.annotation.RestControllerAdvice; // 全局异常通知
import java.util.HashMap;
import java.util.Map;
@RestControllerAdvice // 全局拦截所有 @RestController 抛出的异常,返回值自动转 JSON
public class GlobalExceptionHandler {
@ExceptionHandler(RuntimeException.class) // 拦截所有 RuntimeException 及其子类
public ResponseEntity<Map<String, String>> handleRuntime(RuntimeException ex) {
Map<String, String> error = new HashMap<>();
error.put("error", ex.getMessage()); // 把异常消息放进 JSON
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
// 返回 400 + {"error": "具体错误信息"}
}
@ExceptionHandler(MethodArgumentNotValidException.class) // 专门拦截 @Valid 校验失败
public ResponseEntity<Map<String, String>> handleValid(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(err ->
errors.put(err.getField(), err.getDefaultMessage())
// 遍历所有校验失败的字段,以 "字段名 → 错误信息" 存入 Map
// 比如 {"username": "用户名不能为空", "age": "年龄不能大于150"}
);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errors); // 400 + 所有字段错误
}
}
作用:项目里任何地方抛出的异常,都会被这里拦截并统一转换成 JSON 响应,避免把堆栈直接暴露给客户端。
5.8resources/mapper/UserMapper.xml(SQL 映射文件)
<?xml version="1.0" encoding="UTF-8" ?> <!-- XML 声明 -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- MyBatis Mapper DTD 约束 -->
<mapper namespace="com.example.demo4.mapper.UserMapper">
<!-- namespace 必须等于 UserMapper 接口的全限定名,这样 MyBatis 才能把 SQL 和接口方法对应 -->
<resultMap id="BaseResultMap" type="User">
<!-- resultMap:把数据库列 → Java 属性 的映射关系 -->
<id column="id" property="id"/> <!-- <id> 表示主键列 -->
<result column="username" property="username"/> <!-- 普通列映射 -->
<result column="name" property="name"/>
<result column="age" property="age"/>
<result column="gender" property="gender"/>
</resultMap>
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
<!-- id="insert" 对应 UserMapper.insert 方法 -->
<!-- useGeneratedKeys + keyProperty:让数据库自增主键回填到 user.id -->
INSERT INTO user (username, name, age, gender)
VALUES (#{username}, #{name}, #{age}, #{gender})
<!-- #{xxx} 是 MyBatis 占位符,会从 user 对象取对应属性值 -->
</insert>
<update id="updateById">
UPDATE user SET username=#{username}, name=#{name}, age=#{age}, gender=#{gender}
WHERE id=#{id}
</update>
<delete id="deleteById">
DELETE FROM user WHERE id=#{id}
</delete>
<select id="selectById" resultMap="BaseResultMap">
<!-- resultMap="BaseResultMap":用上面定义的映射规则把行 → User 对象 -->
SELECT id, username, name, age, gender FROM user WHERE id=#{id}
</select>
<select id="selectAll" resultMap="BaseResultMap">
SELECT id, username, name, age, gender FROM user
</select>
</mapper>
作用:把 SQL 语句和 Mapper 接口方法绑定。#{xxx} 是预编译占位符(防 SQL 注入)。
5.9application.properties(配置文件)
spring.datasource.url=jdbc:mysql://localhost:3306/blog_platform?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&characterEncoding=utf8
# 数据库连接地址:MySQL 在本地 3306,库名 blog_platform
# useSSL=false:不用 SSL
# allowPublicKeyRetrieval=true:允许 MySQL 8 的公钥检索(之前报错的修复)
# serverTimezone=Asia/Shanghai:时区上海
# characterEncoding=utf8:编码 UTF-8
spring.datasource.username=root # MySQL 用户名
spring.datasource.password=xxxxxx # MySQL 密码
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # MySQL 8 的 JDBC 驱动类
mybatis.mapper-locations=classpath:mapper/*.xml # 扫描 resources/mapper 下所有 XML
mybatis.type-aliases-package=com.example.demo4.entity # 这个包下的类可以用简短别名(如 User 而非全限定名)
mybatis.configuration.map-underscore-to-camel-case=true # user_name → userName 自动驼峰转换
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl # 控制台打印 SQL 日志
Spring Boot主启动类启动后可以通过swagger文档来测试接口是否正确
更多推荐




所有评论(0)