Spring Boot项目实战:构建RESTful API
项目背景
本文将介绍如何使用Spring Boot快速构建一个完整的RESTful API项目,包括用户管理、数据验证、异常处理等核心功能。
技术栈
- Spring Boot 3.x
- Spring Data JPA
- MySQL
- Maven
- Lombok
项目结构
src/main/java/com/example/demo
├── controller # 控制器层
├── service # 业务逻辑层
├── repository # 数据访问层
├── entity # 实体类
├── dto # 数据传输对象
├── exception # 异常处理
└── config # 配置类核心代码实现
1. 实体类定义
@Entity
@Table(name = "users")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String username;
@Column(nullable = false)
private String email;
@Column(nullable = false)
private String password;
@CreatedDate
private LocalDateTime createdAt;
@LastModifiedDate
private LocalDateTime updatedAt;
}2. Repository层
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username);
boolean existsByUsername(String username);
boolean existsByEmail(String email);
@Query("SELECT u FROM User u WHERE u.email = :email")
Optional<User> findByEmail(@Param("email") String email);
}3. Service层
@Service
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
public UserDTO createUser(CreateUserRequest request) {
// 验证用户名是否已存在
if (userRepository.existsByUsername(request.getUsername())) {
throw new DuplicateResourceException("用户名已存在");
}
// 验证邮箱是否已存在
if (userRepository.existsByEmail(request.getEmail())) {
throw new DuplicateResourceException("邮箱已被注册");
}
// 创建用户
User user = new User();
user.setUsername(request.getUsername());
user.setEmail(request.getEmail());
user.setPassword(passwordEncoder.encode(request.getPassword()));
User savedUser = userRepository.save(user);
return convertToDTO(savedUser);
}
public UserDTO getUserById(Long id) {
User user = userRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("用户不存在"));
return convertToDTO(user);
}
public List<UserDTO> getAllUsers() {
return userRepository.findAll().stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
}
public UserDTO updateUser(Long id, UpdateUserRequest request) {
User user = userRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("用户不存在"));
if (request.getEmail() != null) {
user.setEmail(request.getEmail());
}
User updatedUser = userRepository.save(user);
return convertToDTO(updatedUser);
}
public void deleteUser(Long id) {
if (!userRepository.existsById(id)) {
throw new ResourceNotFoundException("用户不存在");
}
userRepository.deleteById(id);
}
private UserDTO convertToDTO(User user) {
return new UserDTO(
user.getId(),
user.getUsername(),
user.getEmail(),
user.getCreatedAt()
);
}
}4. Controller层
@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
@Validated
public class UserController {
private final UserService userService;
@PostMapping
public ResponseEntity<ApiResponse<UserDTO>> createUser(
@Valid @RequestBody CreateUserRequest request) {
UserDTO user = userService.createUser(request);
return ResponseEntity.status(HttpStatus.CREATED)
.body(ApiResponse.success(user, "用户创建成功"));
}
@GetMapping("/{id}")
public ResponseEntity<ApiResponse<UserDTO>> getUserById(@PathVariable Long id) {
UserDTO user = userService.getUserById(id);
return ResponseEntity.ok(ApiResponse.success(user));
}
@GetMapping
public ResponseEntity<ApiResponse<List<UserDTO>>> getAllUsers() {
List<UserDTO> users = userService.getAllUsers();
return ResponseEntity.ok(ApiResponse.success(users));
}
@PutMapping("/{id}")
public ResponseEntity<ApiResponse<UserDTO>> updateUser(
@PathVariable Long id,
@Valid @RequestBody UpdateUserRequest request) {
UserDTO user = userService.updateUser(id, request);
return ResponseEntity.ok(ApiResponse.success(user, "用户更新成功"));
}
@DeleteMapping("/{id}")
public ResponseEntity<ApiResponse<Void>> deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return ResponseEntity.ok(ApiResponse.success(null, "用户删除成功"));
}
}5. 全局异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ApiResponse<Void>> handleResourceNotFound(
ResourceNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(ApiResponse.error(ex.getMessage()));
}
@ExceptionHandler(DuplicateResourceException.class)
public ResponseEntity<ApiResponse<Void>> handleDuplicateResource(
DuplicateResourceException ex) {
return ResponseEntity.status(HttpStatus.CONFLICT)
.body(ApiResponse.error(ex.getMessage()));
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ApiResponse<Map<String, String>>> handleValidationErrors(
MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(error ->
errors.put(error.getField(), error.getDefaultMessage())
);
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(ApiResponse.error("数据验证失败", errors));
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ApiResponse<Void>> handleGenericException(Exception ex) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(ApiResponse.error("服务器内部错误"));
}
}6. 统一响应格式
@Data
@AllArgsConstructor
public class ApiResponse<T> {
private boolean success;
private String message;
private T data;
private LocalDateTime timestamp;
public static <T> ApiResponse<T> success(T data) {
return new ApiResponse<>(true, "操作成功", data, LocalDateTime.now());
}
public static <T> ApiResponse<T> success(T data, String message) {
return new ApiResponse<>(true, message, data, LocalDateTime.now());
}
public static <T> ApiResponse<T> error(String message) {
return new ApiResponse<>(false, message, null, LocalDateTime.now());
}
public static <T> ApiResponse<T> error(String message, T data) {
return new ApiResponse<>(false, message, data, LocalDateTime.now());
}
}配置文件
application.yml
spring:
application:
name: demo-api
datasource:
url: jdbc:mysql://localhost:3306/demo_db?useUnicode=true&characterEncoding=utf8
username: root
password: your_password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
format_sql: true
dialect: org.hibernate.dialect.MySQL8Dialect
server:
port: 8080
servlet:
context-path: /
logging:
level:
root: INFO
com.example.demo: DEBUGAPI测试
创建用户
curl -X POST http://localhost:8080/api/users \
-H "Content-Type: application/json" \
-d '{
"username": "john_doe",
"email": "john@example.com",
"password": "password123"
}'获取所有用户
curl -X GET http://localhost:8080/api/users获取单个用户
curl -X GET http://localhost:8080/api/users/1更新用户
curl -X PUT http://localhost:8080/api/users/1 \
-H "Content-Type: application/json" \
-d '{
"email": "newemail@example.com"
}'删除用户
curl -X DELETE http://localhost:8080/api/users/1项目亮点
- 分层架构清晰:Controller、Service、Repository职责明确
- 统一异常处理:使用@RestControllerAdvice集中处理异常
- 数据验证:使用Bean Validation进行参数校验
- 统一响应格式:所有API返回统一的数据结构
- RESTful设计:遵循REST API设计规范
总结
本项目展示了如何使用Spring Boot构建一个标准的RESTful API,涵盖了实际开发中的常见场景和最佳实践。通过这个项目,可以学习到:
- Spring Boot的基本使用
- RESTful API的设计原则
- 数据库操作和ORM映射
- 异常处理和数据验证
- 项目分层架构
源码地址
完整项目代码已上传至GitHub:[项目地址]
欢迎Star和Fork!
Spring Boot项目实战:构建RESTful API
https://hjjjkh.github.io/posts/87f8a6e4