Spring Boot中使用record四种简化用法

Java中引入的Record类型可以通过压缩同源代码来帮助我们提高可读性和表现力的几个场景。

1、在控制器中使用Record
通常,Spring Boot控制器使用简单的POJO 类进行操作,这些类通过网络将数据传回客户端。例如,查看这个简单的控制器端点,它返回作者列表,包括他们的书籍:

@GetMapping("/authors")
public List<Author> fetchAuthors() {
  return bookstoreService.fetchAuthors();
}

在这里,Author与 Book可以是POJO 的简单数据载体,用record是这样:

public record Book(String title, String isbn) {}
public record Author(String name, String genre, List<Book> books) {}

就是这样!Jackson 库(Spring Boot 中的默认 JSON 库)会自动将 Author/Book 类型的实例转换为 JSON。

2、模板中用Record
Thymeleaf 可能是 Spring Boot 应用程序中使用最多的模板引擎。Thymeleaf 页面(HTML 页面)通常由 POJO 类承载的数据填充,这意味着 Java 记录也能正常工作。

让我们来看看前面的 Author 和 Book 记录以及下面的控制器端点:

@GetMapping("/bookstore")
public String bookstorePage(Model model) {
  
  model.addAttribute(
"authors",
  bookstoreService.fetchAuthors());
  
  return
"bookstore";
}

通过 fetchAuthors() 返回的 List<Author> 被存储在模型中名为 authors 的变量下。该变量用于填充 bookstore.html,如下所示:

...
<ul th:each="author : ${authors}">
  <li th:text=
"${author.name} + ' (' + ${author.genre} + ')'" />
  <ul th:each=
"book : ${author.books}">
    <li th:text=
"${book.title}" />
  </ul>
</ul>
...

代码:Java Coding Problems SE.

3、使用Record进行配置
假设在 application.properties 中有以下两个属性(也可以用 YAML 表示):

bookstore.bestseller.author=Joana Nimar
bookstore.bestseller.book=Prague history

Spring Boot 通过 @ConfigurationProperties 将此类属性映射到 POJO。但也可以使用记录。例如,这些属性可以如下方式映射到 BestSellerConfig 记录:

@ConfigurationProperties(prefix = "bookstore.bestseller")
public record BestSellerConfig(String author, String book) {}

接下来,在 BookstoreService(典型的 Spring Boot 服务)中,我们可以注入 BestSellerConfig 并调用其访问器:

@Service
public class BookstoreService {
  
  private final BestSellerConfig bestSeller;

  public BookstoreService(BestSellerConfig bestSeller) {
    this.bestSeller = bestSeller;
  }
  
  public String fetchBestSeller() {
     return bestSeller.author() + " | " + bestSeller.book();
  }
}

代码: bundled code


4、Record和依赖注入
在前面的示例中,我们使用 SpringBoot 提供的典型机制--通过构造函数进行依赖注入(也可以通过 @Autowired 进行)--将 BookstoreService 服务注入到 BookstoreController 中:

@RestController
public class BookstoreController {
  
  private final BookstoreService bookstoreService;
  
  public BookstoreController(BookstoreService bookstoreService) {
    this.bookstoreService = bookstoreService;
  }
  
  @GetMapping("/authors")
  public List<Author> fetchAuthors() {
    return bookstoreService.fetchAuthors();
  }
}


但是,我们可以通过将其改写为记录record来压缩这个类,如下所示:

@RestController
public record BookstoreController(BookstoreService bookstoreService) {
  
  @GetMapping("/authors")
  public List<Author> fetchAuthors() {
    return bookstoreService.fetchAuthors();
  }
}

该记录record的规范构造函数将与我们的显式构造函数相同。

代码: GitHub.