在 Spring Boot 中使用 Java Record
本文将带你了解如何在 Spring Boot 应用中利用 Java Record 来提高其效率和可读性。
Java Record 是什么?
Java Record 是一种专为保存不可变数据而设计的类。它们自动提供 equals()
、hashCode()
和 toString()
等方法的实现,大大减少了模板代码。因此,它们非常适合在 Spring Boot 应用中创建数据传输对象(DTO)、实体和其他模型类。
Java Record 示例
举一个简单的例子,用 Java Record 来表示一个 Person
。
public record Person(String name, int age) {}
在本例中,Person
是一个 Record,包含两个字段:name
和 age
。Java 自动为该 Record 提供了以下内容:
- 一个
public
构造函数:Person(String name, int age)
- 属性的
public
Getter 方法:name()
和age()
- 实现了
equals()
、hashCode()
和toString()
方法
使用 Getter 方法
Record 的主要特点之一是提供了用于访问字段的隐式 Getter 方法。这些方法以字段本身命名。
创建 Person
实例并使用其 Getter 方法:
public class Main {
public static void main(String[] args) {
Person person = new Person("Alice", 30);
// 调用 Getter 方法
String name = person.name();
int age = person.age();
System.out.println("Name: " + name);
System.out.println("Age: " + age);
}
}
输出如下:
Name: Alice
Age: 30
在 Spring Boot 中使用 Record 的主要优势
- 模板代码:Record 自动生成构造器、Getter 方法、
equals()
、hashCode()
和toString()
方法,大大减少了模板代码。 - 不可更改:Record 默认创建不可变的数据结构,因此非常适合数据完整性至关重要的使用场景。
- 职责明确:Record 的目的很明确 - 它只是数据的载体。这使代码更易于阅读和维护。
- 易于使用:开发人员只需一行代码就能定义一个 Record,从而使数据保存类的创建更简单、更高效。
Spring Boot 示例项目
软件版本:
- JDK:16+
- Spring Boot:3.0
你可以通过 Spring Initializr 初始化项目。添加 Spring Web、Spring Data JPA 和 H2 Database 等依赖。
示例项目由以下几层组成:
- Controller 层:处理 HTTP 请求和响应。
- Service 层:包含业务逻辑。
- Repository 层:处理数据持久化。
- Database:H2 内存数据库,以简化操作。
第 1 步:定义 Domain Record
首先,定义一个 User
Record,它是 Domain 实体。
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@Entity
public record User(@Id Long id, String name, String email) {}
如上,使用 Java Record 来定义实体,从而使实体定义简洁且不可更改。
第 2 步:Repository 层
接着,创建一个用于数据访问的 Repository 接口:
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {}
Spring Data JPA 会在运行时提供 Repository 实现。
第 3 步:Service 层
UserService
包含业务逻辑并与 UserRepository
交互:
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User createUser(User user) {
return userRepository.save(user);
}
public List<User> getAllUsers() {
return userRepository.findAll();
}
public User getUserById(Long id) {
return userRepository.findById(id).orElseThrow();
}
public User updateUser(Long id, User userDetails) {
User user = userRepository.findById(id).orElseThrow();
User updatedUser = new User(user.id(), userDetails.name(), userDetails.email());
return userRepository.save(updatedUser);
}
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
}
该 Service 类使用 UserRepository
执行 CRUD 操作。
第 4 步:Controller 层
在 Controller 中,将 CRUD 操作公开为 HTTP 端点:
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/users")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public User createUser(@RequestBody User user) {
return userService.createUser(user);
}
@GetMapping
public List<User> getAllUsers() {
return userService.getAllUsers();
}
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
return userService.getUserById(id);
}
@PutMapping("/{id}")
public User updateUser(@PathVariable Long id, @RequestBody User user) {
return userService.updateUser(id, user);
}
@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
}
}
UserController
处理 HTTP 请求,并调用 UserService
来完成 CRUD 操作。
第 5 步:使用 WebClient 进行测试
使用 WebClient
作为 REST 客户端来测试应用的 CRUD REST API。
首先,需要确保在 pom.xml
中包含了 spring-boot-starter-webflux 依赖。
下面是使用 WebClient
测试 CRUD 操作的完整代码:
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
public class RestClient {
private final WebClient webClient;
public RestClient() {
this.webClient = WebClient.create("http://localhost:8080");
}
public void createUser() {
User user = new User(1L, "John Doe", "john@example.com");
User createdUser = webClient.post()
.uri("/users")
.body(Mono.just(user), User.class)
.retrieve()
.bodyToMono(User.class)
.block();
System.out.println("Created User: " + createdUser);
}
public void getUser(Long id) {
User user = webClient.get()
.uri("/users/" + id)
.retrieve()
.bodyToMono(User.class)
.block();
System.out.println("User: " + user);
}
public void updateUser(Long id, User updatedUser) {
User user = webClient.put()
.uri("/users/" + id)
.body(Mono.just(updatedUser), User.class)
.retrieve()
.bodyToMono(User.class)
.block();
System.out.println("Updated User: " + user);
}
public void deleteUser(Long id) {
webClient.delete()
.uri("/users/" + id)
.retrieve()
.bodyToMono(Void.class)
.block();
System.out.println("Deleted User with ID: " + id);
}
public static void main(String[] args) {
RestClient client = new RestClient();
// 测试创建用户
client.createUser();
// 测试检索用户
client.getUser(1L);
// 测试更新用户
User updatedUser = new User(1L, "Jane Doe", "jane@example.com");
client.updateUser(1L, updatedUser);
// 测试删除用户
client.deleteUser(1L);
}
private record User(Long id, String name, String email) {}
}
运行服务器,执行 RestClient
测试类,输出如下:
Created User: User[id=1, name=John Doe, email=john@example.com]
User: User[id=1, name=John Doe, email=john@example.com]
Updated User: User[id=1, name=Jane Doe, email=jane@example.com]
Deleted User with ID: 1
Ref:https://www.javaguides.net/2023/12/using-java-records-with-spring-boot.html