返回介绍

2.3.1 专注于应用程序功能

发布于 2025-04-21 21:10:07 字数 7734 浏览 0 评论 0 收藏

要为 Spring Boot 的自动配置博得好感,我可以在接下来的几页里向你演示没有 Spring Boot 的情况下需要写哪些配置。但眼下已经有不少好书写过这些内容了,再写一次并不能让我们更快地写好阅读列表应用程序。

既然知道 Spring Boot 会替我们料理这些事情,那么与其浪费时间讨论这些 Spring 配置,还不如看看如何利用 Spring Boot 的自动配置,让我们专注于应用程序代码。除了开始写代码,我想不到更好的办法了。

1. 定义领域模型

我们应用程序里的核心领域概念是读者阅读列表上的书。因此我们需要定义一个实体类来表示这个概念。代码清单 2-5 演示了如何定义一本书。

代码清单 2-5 表示列表里的书的 Book

package readinglist;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Book {

  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  private Long id;
  private String reader;
  private String isbn;
  private String title;
  private String author;
  private String description;

  public Long getId() {
    return id;
  }

  public void setId(Long id) {
    this.id = id;
  }

  public String getReader() {
    return reader;
  }

  public void setReader(String reader) {
    this.reader = reader;
  }

  public String getIsbn() {
    return isbn;
  }

  public void setIsbn(String isbn) {
    this.isbn = isbn;
  }

  public String getTitle() {
    return title;
  }

  public void setTitle(String title) {
    this.title = title;
  }

  public String getAuthor() {
    return author;
  }

  public void setAuthor(String author) {
    this.author = author;
  }

  public String getDescription() {
    return description;
  }

  public void setDescription(String description) {
    this.description = description;
  }

}

如你所见, Book 类就是简单的 Java 对象,其中有些描述书的属性,还有必要的访问方法。 @Entity 注解表明它是一个 JPA 实体, id 属性加了 @Id@GeneratedValue 注解,说明这个字段是实体的唯一标识,并且这个字段的值是自动生成的。

2. 定义仓库接口

接下来,我们就要定义用于把 Book 对象持久化到数据库的仓库了。4 因为用了 Spring Data JPA,所以我们要做的就是简单地定义一个接口,扩展一下 Spring Data JPA 的 JpaRepository 接口:

4 原文这里写的是 ReadingList 对象,但文中并没有定义这个对象,看代码应该是 Book 对象。 - 译者注

package readinglist;

import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ReadingListRepository extends JpaRepository<Book, Long> {

  List<Book> findByReader(String reader);

}

通过扩展 JpaRepositoryReadingListRepository 直接继承了 18 个执行常用持久化操作的方法。 JpaRepository 是个泛型接口,有两个参数:仓库操作的领域对象类型,及其 ID 属性的类型。此外,我还增加了一个 findByReader() 方法,可以根据读者的用户名来查找阅读列表。

如果你好奇谁来实现这个 ReadingListRepository 及其继承的 18 个方法,请不用担心,Spring Data 提供了很神奇的魔法,只需定义仓库接口,在应用程序启动后,该接口在运行时会自动实现。

3. 创建 Web 界面

现在,我们定义好了应用程序的领域模型,还有把领域对象持久化到数据库里的仓库接口,剩下的就是创建 Web 前端了。代码清单 2-6 的 Spring MVC 控制器就能为应用程序处理 HTTP 请求。

代码清单 2-6 作为阅读列表应用程序前端的 Spring MVC 控制器

package readinglist;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.List;

@Controller
@RequestMapping("/")
public class ReadingListController {

  private ReadingListRepository readingListRepository;

  @Autowired
  public ReadingListController(
             ReadingListRepository readingListRepository) {
    this.readingListRepository = readingListRepository;
  }

  @RequestMapping(value="/{reader}", method=RequestMethod.GET)
  public String readersBooks(
      @PathVariable("reader") String reader,
      Model model) {

    List<Book> readingList =
        readingListRepository.findByReader(reader);
    if (readingList != null) {
      model.addAttribute("books", readingList);
    }
    return "readingList";
  }

  @RequestMapping(value="/{reader}", method=RequestMethod.POST)
  public String addToReadingList(
            @PathVariable("reader") String reader, Book book) {
    book.setReader(reader);
    readingListRepository.save(book);
    return "redirect:/{reader}";
  }

}

ReadingListController 使用了 @Controller 注解,这样组件扫描会自动将其注册为 Spring 应用程序上下文里的一个 Bean。它还用了 @RequestMapping 注解,将其中所有的处理器方法都映射到了“/”这个 URL 路径上。

该控制器有两个方法。

  • readersBooks() :处理/{reader}上的 HTTP GET 请求,根据路径里指定的读者,从(通过控制器的构造器注入的)仓库获取 Book 列表。随后将这个列表塞入模型,用的键是 books ,最后返回 readingList 作为呈现模型的视图逻辑名称。

  • addToReadingList() :处理/{reader}上的 HTTP POST 请求,将请求正文里的数据绑定到一个 Book 对象上。该方法把 Book 对象的 reader 属性设置为读者的姓名,随后通过仓库的 save() 方法保存修改后的 Book 对象,最后重定向到/{reader}(控制器中的另一个方法会处理该请求)。

readersBooks() 方法最后返回 readingList 作为逻辑视图名,为此必须创建该视图。因为在项目开始之初我就决定要用 Thymeleaf 来定义应用程序的视图,所以接下来就在 src/main/ resources/templates 里创建一个名为 readingList.html 的文件,内容如代码清单 2-7 所示。

代码清单 2-7 呈现阅读列表的 Thymeleaf 模板

<html>
  <head>
    <title>Reading List</title>
    <link rel="stylesheet" th:href="@{/style.css}"></link>
  </head>

  <body>
    <h2>Your Reading List</h2>
    <div th:unless="${#lists.isEmpty(books)}">
      <dl th:each="book : ${books}">
        <dt class="bookHeadline">
          <span th:text="${book.title}">Title</span> by
          <span th:text="${book.author}">Author</span>
          (ISBN: <span th:text="${book.isbn}">ISBN</span>)
        </dt>
        <dd class="bookDescription">
          <span th:if="${book.description}"
                th:text="${book.description}">Description</span>
          <span th:if="${book.description eq null}">
                No description available</span>
        </dd>
      </dl>
    </div>
    <div th:if="${#lists.isEmpty(books)}">
      <p>You have no books in your book list</p>
    </div>

    <hr/>

    <h3>Add a book</h3>
    <form method="POST">
      <label for="title">Title:</label>
        <input type="text" name="title" size="50"></input><br/>
      <label for="author">Author:</label>
        <input type="text" name="author" size="50"></input><br/>
      <label for="isbn">ISBN:</label>
        <input type="text" name="isbn" size="15"></input><br/>
      <label for="description">Description:</label><br/>
        <textarea name="description" cols="80" rows="5">
        </textarea><br/>
      <input type="submit"></input>
    </form>

  </body>
</html>

这个模板定义了一个 HTML 页面,该页面概念上分为两个部分:页面上方是读者的阅读列表中的图书清单;下方是是一个表单,读者可以从这里添加新书。

为了美观,Thymeleaf 模板引用了一个名为 style.css 的样式文件,该文件位于 src/main/resources/ static 目录中,看起来是这样的:

body {
    background-color: #cccccc;
    font-family: arial,helvetica,sans-serif;
}

.bookHeadline {
    font-size: 12pt;
    font-weight: bold;
}

.bookDescription {
    font-size: 10pt;
}

label {
    font-weight: bold;
}

这个样式表并不复杂,也没有过分追求让应用程序变漂亮,但已经能满足我们的需求了。很快你就会看到,它能用来演示 Spring Boot 的自动配置功能。

不管你相不相信,以上就是一个完整的应用程序了 - 本章已经向你呈现了所有的代码。等一下,回顾一下前几页的内容,你看到什么配置了吗?实际上,除了代码清单 2-1 里的三行配置(这是开启自动配置所必需的),你不用再写任何 Spring 配置了。

虽然没什么 Spring 配置,但这已经是一个可以运行的完整 Spring 应用程序了。让我们把它运行起来,看看会怎样。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。