1. 概要

JPAエンティティにCRUD機能を提供するDAOレイヤーの実装は、ほとんどの場合回避したい反復的で時間のかかるタスクになる可能性があります。

幸い、 Spring Boot を使用すると、標準のJPAベースのCRUDリポジトリのレイヤーを介してCRUDアプリケーションを簡単に作成できます。

このチュートリアルでは、Spring BootおよびThymeleafを使用してCRUDWebアプリケーションを開発する方法を学習します。

2. Mavenの依存関係

この場合、単純な依存関係の管理、バージョン管理、およびプラグインの構成を spring-boot-starter-parentに依存します。

その結果、Javaバージョンをオーバーライドする場合を除いて、pom.xmlファイルでプロジェクトの依存関係のバージョンを指定する必要はありません。

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.0</version>
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
    </dependency>
</dependencies>

3. ドメインレイヤー

すべてのプロジェクトの依存関係がすでに整っているので、ナイーブなドメインレイヤーを実装しましょう。

簡単にするために、このレイヤーには、Userエンティティのモデリングを担当する単一のクラスが含まれます。

@Entity
public class User {
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    
    @NotBlank(message = "Name is mandatory")
    private String name;
    
    @NotBlank(message = "Email is mandatory")
    private String email;

    // standard constructors / setters / getters / toString
}

クラスに@Entityアノテーションを付けたことを覚えておいてください。したがって、 の場合、HibernateであるJPA実装は次のことができるようになります。ドメインエンティティでCRUD操作を実行します。Hibernateの紹介ガイドについては、Hibernate5とSpringのチュートリアルをご覧ください。

さらに、nameフィールドとemailフィールドを@NotBlank制約で制約しました。 これは、データベース内のエンティティを永続化または更新する前に、HibernateValidatorを使用して制約付きフィールドを検証できることを意味します。

これに関する基本については、 BeanValidationに関する関連チュートリアルを確認してください。

4. リポジトリレイヤー

この時点で、サンプルWebアプリケーションは何もしません。 しかし、それはもうすぐ変わります。

Spring Data JPA 最小限の手間でJPAベースのリポジトリ(DAOパターン実装のファンシーな名前)を実装できます。

Spring Data JPA は、Spring Bootの spring -boot-starter-data-jpa の主要コンポーネントであり、 JPA実装の上に配置された抽象化。 この抽象化レイヤーにより、独自のDAO実装を最初から提供しなくても、永続レイヤーにアクセスできます。

アプリケーションにUserオブジェクトの基本的なCRUD機能を提供するには、CrudRepositoryインターフェイスを拡張する必要があります。

@Repository
public interface UserRepository extends CrudRepository<User, Long> {}

以上です! CrudRepository インターフェースを拡張することにより、Spring DataJPAはリポジトリのCRUDメソッドの実装を提供します。

5. コントローラレイヤー

spring -boot-starter-data-jpa が基盤となるJPA実装の上に配置する抽象化レイヤーのおかげで、基本的なWeb層を介してWebアプリケーションにいくつかのCRUD機能を簡単に追加できます。

この場合、GETおよびPOST HTTPリクエストを処理し、それらを UserRepository 実装への呼び出しにマッピングするには、単一のコントローラークラスで十分です。

コントローラクラスは、SpringMVCの主要な機能のいくつかに依存しています。 Spring MVCの詳細なガイドについては、SpringMVCチュートリアルをご覧ください。

コントローラのshowSignUpForm()メソッドと addUser()メソッドから始めましょう。

前者はユーザーサインアップフォームを表示し、後者は制約されたフィールドを検証した後、データベースに新しいエンティティを保持します。

エンティティが検証に合格しなかった場合、サインアップフォームが再表示されます。

それ以外の場合、エンティティが保存されると、永続化されたエンティティのリストが対応するビューで更新されます。

@Controller
public class UserController {
    
    @GetMapping("/signup")
    public String showSignUpForm(User user) {
        return "add-user";
    }
    
    @PostMapping("/adduser")
    public String addUser(@Valid User user, BindingResult result, Model model) {
        if (result.hasErrors()) {
            return "add-user";
        }
        
        userRepository.save(user);
        return "redirect:/index";
    }

    // additional CRUD methods
}

/ indexURLのマッピングも必要です。

@GetMapping("/index")
public String showUserList(Model model) {
    model.addAttribute("users", userRepository.findAll());
    return "index";
}

UserController 内には、 showUpdateForm()メソッドもあります。このメソッドは、提供されたidに一致するUserエンティティのフェッチを担当します。 ]データベースから。

エンティティが存在する場合は、モデル属性として更新フォームビューに渡されます。

したがって、フォームにはnameおよびemailフィールドの値を入力できます。

@GetMapping("/edit/{id}")
public String showUpdateForm(@PathVariable("id") long id, Model model) {
    User user = userRepository.findById(id)
      .orElseThrow(() -> new IllegalArgumentException("Invalid user Id:" + id));
    
    model.addAttribute("user", user);
    return "update-user";
}

最後に、 UserControllerクラス内にupdateUser()メソッドと deleteUser()メソッドがあります。

最初のエンティティは更新されたエンティティをデータベースに保持し、最後のエンティティは指定されたエンティティを削除します。

いずれの場合も、永続化されたエンティティのリストはそれに応じて更新されます。

@PostMapping("/update/{id}")
public String updateUser(@PathVariable("id") long id, @Valid User user, 
  BindingResult result, Model model) {
    if (result.hasErrors()) {
        user.setId(id);
        return "update-user";
    }
        
    userRepository.save(user);
    return "redirect:/index";
}
    
@GetMapping("/delete/{id}")
public String deleteUser(@PathVariable("id") long id, Model model) {
    User user = userRepository.findById(id)
      .orElseThrow(() -> new IllegalArgumentException("Invalid user Id:" + id));
    userRepository.delete(user);
    return "redirect:/index";
}

6. ビューレイヤー

この時点で、Userエンティティに対してCRUD操作を実行する機能コントローラークラスを実装しました。 それでも、このスキーマにはまだ欠落しているコンポーネントがあります:ビューレイヤー。

src / main / resources / templates フォルダーの下に、サインアップフォームと更新フォームの表示、および永続化されたUserエンティティのリストのレンダリングに必要なHTMLテンプレートを作成する必要があります。 。

はじめに述べたように、テンプレートファイルを解析するための基盤となるテンプレートエンジンとしてThymeleafを使用します。

add-user.htmlファイルの関連セクションは次のとおりです。

<form action="#" th:action="@{/adduser}" th:object="${user}" method="post">
    <label for="name">Name</label>
    <input type="text" th:field="*{name}" id="name" placeholder="Name">
    <span th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></span>
    <label for="email">Email</label>
    <input type="text" th:field="*{email}" id="email" placeholder="Email">
    <span th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></span>
    <input type="submit" value="Add User">   
</form>

@ {/ adduser} URL式を使用して、フォームの action 属性と、動的コンテンツを埋め込むための ${}変数式を指定したことに注目してください。 nameおよびemailフィールドの値や検証後のエラーなどのテンプレート。

add-user.html と同様に、update-user.htmlテンプレートの外観は次のとおりです。

<form action="#" 
  th:action="@{/update/{id}(id=${user.id})}" 
  th:object="${user}" 
  method="post">
    <label for="name">Name</label>
    <input type="text" th:field="*{name}" id="name" placeholder="Name">
    <span th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></span>
    <label for="email">Email</label>
    <input type="text" th:field="*{email}" id="email" placeholder="Email">
    <span th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></span>
    <input type="submit" value="Update User">   
</form>

最後に、 index.html ファイルがあります。このファイルには、永続化されたエンティティのリストと、既存のエンティティを編集および削除するためのリンクが表示されます。

<div th:switch="${users}">
    <h2 th:case="null">No users yet!</h2>
        <div th:case="*">
            <h2>Users</h2>
            <table>
                <thead>
                    <tr>
                        <th>Name</th>
                        <th>Email</th>
                        <th>Edit</th>
                        <th>Delete</th>
                    </tr>
                </thead>
                <tbody>
                <tr th:each="user : ${users}">
                    <td th:text="${user.name}"></td>
                    <td th:text="${user.email}"></td>
                    <td><a th:href="@{/edit/{id}(id=${user.id})}">Edit</a></td>
                    <td><a th:href="@{/delete/{id}(id=${user.id})}">Delete</a></td>
                </tr>
            </tbody>
        </table>
    </div>      
    <p><a href="/signup">Add a new user</a></p>
</div>

簡単にするために、テンプレートはかなり骨格的に見え、不要な化粧品を追加せずに必要な機能のみを提供します。

HTML / CSSにあまり時間をかけずにテンプレートの外観を改善し、人目を引くようにするために、Shardsなどの無料のTwitterBootstrapUIキットを簡単に使用できます。

7. アプリケーションの実行

最後に、アプリケーションのエントリポイントを定義しましょう。

ほとんどのSpringBootアプリケーションと同様に、これは単純な古い main()メソッドで実行できます。

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

次に、IDEで「実行」をクリックし、ブラウザを開いて http:// localhost:8080をポイントします。

ビルドが正常にコンパイルされると、新しいエンティティを追加したり既存のエンティティを編集および削除したりするためのリンクを含む基本的なCRUDユーザーダッシュボードが表示されます。

8. 結論

この記事では、Spring BootとThymeleafを使用して基本的なCRUDWebアプリケーションを構築する方法を学びました。

いつものように、記事に示されているすべてのコードサンプルは、GitHubから入手できます。