スポンサーリンク

Webアプリケーション開発

SpringBootで新規登録画面を作成する

投稿日:2022年2月11日 更新日:

新規登録画面のサンプル

画面デモ

このサンプルコードで、次のような画面を作成します。
新規登録するだけの簡易な画面になります。

ディレクトリ構成

project-root/src
 ├── main
 │   ├── java
 │   │   └── com
 │   │       └── springhack
 │   │           └── okozukaisystem
 │   │               ├── OkozukaiSystemApplication.java
 │   │               ├── business
 │   │               │   └── ChildrenService.java
 │   │               ├── domain
 │   │               │   └── Child.java
 │   │               ├── integration
 │   │               │   ├── entity
 │   │               │   │   └── ChildrenEntity.java
 │   │               │   └── mapper
 │   │               │       └── ChildrenMapper.java
 │   │               └── presentation
 │   │                   ├── children
 │   │                   │   ├── ChildrenController.java
 │   │                   │   └── ChildrenControllerHelper.java
 │   └── resources
 │       ├── com
 │       │   └── springhack
 │       │       └── okozukaisystem
 │       │           └── integration
 │       │               └── mapper
 │       │                   └── ChildrenMapper.xml
 │       └── templates
 │           ├── children
 │           │   ├── index.html
 │           │   ├── register.html
 │           │   ├── register_confirm.html

テーブル構造

このサンプルでは下記のテーブルを使用します。

child_idBIGINT
nameVARCHAR(50)
birthdayDATE
children

新規登録のコントローラー層

@Controller
public class ChildrenController {

    private final ChildrenService childrenService;

    public ChildrenController(ChildrenService childrenService) {
        this.childrenService = childrenService;
    }

    @RequestMapping("/children")
    public String index(Model model) {

        // 子どもリストを取得
        List<Child> children = childrenService.getAll();

        // 画面表示
        model.addAttribute("children", children);
        return "children/index";
    }

    @GetMapping("/children/register")
    public String register(Model model) {
        model.addAttribute("childRegisterForm", new Child(null, null, null));
        return "children/register";
    }

    @PostMapping("/children/registerConfirm")
    public String registerConfirm(@Validated ChildRegisterForm childRegisterForm, BindingResult bindingResult, Model model) {

        // 入力チェック
        if (bindingResult.hasErrors()) {
            return "children/register";
        }

        // 登録可否チェック
        boolean canRegister = childrenService.canRegister(childRegisterForm.getName());
        if (!canRegister) {
            model.addAttribute("message", "既に同じ名前が登録されています。");
            return "children/register";
        }

        // 画面表示
        return "children/register_confirm";
    }

    @PostMapping("/children/registerFinish")
    public String registerFinish(@Validated ChildRegisterForm childRegisterForm, BindingResult bindingResult, Model model, RedirectAttributes redirectAttributes) {

        // 入力チェック
        if (bindingResult.hasErrors()) {
            return "children/register";
        }

        // 登録可否チェック
        boolean canRegister = childrenService.canRegister(childRegisterForm.getName());
        if (!canRegister) {
            model.addAttribute("message", "既に同じ名前が登録されています。");
            return "children/register";
        }

        // 登録実行
        var child = ChildrenControllerHelper.toChild(childRegisterForm);
        childrenService.register(child);

        // 画面遷移
        redirectAttributes.addFlashAttribute("message", child.getName() + "を登録しました。");
        return "redirect:/children?id=" + child.getChildId();
    }
}

新規登録のサービス層

@Service
public class ChildrenService {

    private final ChildrenMapper childrenMapper;

    public ChildrenService(ChildrenMapper childrenMapper) {
        this.childrenMapper = childrenMapper;
    }

    /**
     * 全件取得する
     */
    public List<Child> getAll() {
        // DBから取得
        List<ChildrenEntity> allChildren = childrenMapper.selectAll();
        var children = allChildren
                .stream()
                .map(child -> new Child(child.getChildId(), child.getName(), child.getBirthday()))
                .collect(Collectors.toList());
        return children;
    }

    /**
     * 登録可能かチェックする
     *
     * @param name
     * @return
     */
    public boolean canRegister(String name) {
        List<ChildrenEntity> sameNameChildren = childrenMapper.findByName(name);
        if (!sameNameChildren.isEmpty()) {
            return false;
        }

        return true;
    }

    /**
     * 登録する
     */
    public void register(Child newChild) {
        var childrenEntity = new ChildrenEntity(null, newChild.getName(), newChild.getBirthday());
        childrenMapper.insert(childrenEntity);
    }
}

新規登録のインテグレーション層

@Mapper
public interface ChildrenMapper {
    List<ChildrenEntity> selectAll();
    void insert(ChildrenEntity newChild);
}

DB接続にはMybatisを使用しました。
そのため、@Repositoryではなく@Mapperを付与したインターフェースを作成し、命名は「テーブル名+Mapper」とします。


<mapper namespace="com.springhack.okozukaisystem.integration.mapper.ChildrenMapper">
    <select id="selectAll" resultType="com.springhack.okozukaisystem.integration.entity.ChildrenEntity">
        SELECT c.child_id, c.name, c.birthday FROM children c
    </select>

    <insert id="insert">
        INSERT INTO children (name, birthday) VALUES (#{name}, #{birthday})
    </insert>
</mapper>

Mybatisの場合は、ネイティブSQLを使用しますので、
MapperのselectAllとinsertに対するSQLを定義しておきます。


@AllArgsConstructor
@Data
public class ChildrenEntity {
    private Long childId;
    private String name;
    private LocalDate birthday;
}

Childrenテーブルに対するエンティティを作成します。
MybatisでSELECT結果を自動で格納させるために、@AllArgsConstructorを付与します。

新規登録で使用するモデル

@AllArgsConstructor
@Getter
public class Child {

    /** ID */
    private Long childId;

    /** 名前 */
    private String name;

    /** 誕生日 */
    private LocalDate birthday;
}

新規登録画面のビュー

一覧表示画面
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>子どもマスタ|子どものお小遣い帳アプリ</title>
</head>
<body>
    <header></header>
    <main>
        <h1>子どもマスタ</h1>
        <div th:text="${message}"></div>
        <table border="1">
            <tr>
                <th>名前</th>
                <th>生年月日</th>
                <th>年齢</th>
                <th>操作</th>
            </tr>
            <tr th:each="child: ${children}">
                <td th:text="${child.name}"></td>
                <td th:text="${child.birthday}"></td>
                <td>TODO</td>
                <th>
                    <button th:attr="onclick='location.href=\'/children/edit?id=' + ${child.childId} + '\''">編集</button>
                    <button th:attr="onclick='location.href=\'/children/remove?id=' + ${child.childId} + '\''">削除</button>
                </th>
            </tr>
        </table>
        <a href="/children/register">子どもを登録</a>
    </main>
    <footer>
        <a href="/">トップページ</a>
    </footer>
</body>
</html>

登録入力画面

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="ja">
<head>
    <meta charset="UTF-8">
    <title>子どもマスタ|子どものお小遣い帳アプリ</title>
</head>
<body>
    <header></header>
    <main>
        <h1>子どもを登録</h1>
        <div th:text="${message}"></div>
        <form method="POST" action="/children/registerConfirm" th:object="${childRegisterForm}">
            <table border="1">
                <tr>
                    <th>名前</th>
                    <td>
                        <input type="text" th:field="*{name}">
                        <span th:errors="*{name}"></span>
                    </td>
                </tr>
                <tr>
                    <th>生年月日</th>
                    <td>
                        <input type="date" th:field="*{birthday}">
                        <span th:errors="*{birthday}"></span>
                    </td>
                </tr>
            </table>
            <button onclick="location.href='/children';return false;">キャンセル</button>
            <input type="submit" value="登録内容を確認" />
        </form>
    </main>
    <footer>
        <a href="/">トップページ</a>
    </footer>
</body>
</html>

登録確認画面

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="ja">
<head>
    <meta charset="UTF-8">
    <title>子どもマスタ|子どものお小遣い帳アプリ</title>
</head>
<body>
    <header></header>
    <main>
        <h1>登録する子どもを確認</h1>
        <div>登録します。よろしいですか?</div>
        <form method="POST" action="/children/registerFinish" th:object="${childRegisterForm}">
            <table border="1">
                <tr>
                    <th>名前</th>
                    <td th:text="*{name}"></td>
                </tr>
                <tr>
                    <th>生年月日</th>
                    <td th:text="*{birthday}"></td>
                </tr>
            </table>
            <input type="hidden" th:field="*{name}">
            <input type="hidden" th:field="*{birthday}">
            <button onclick="location.href='/children/register';return false;">キャンセル</button>
            <input type="submit" value="確定" />
        </form>
    </main>
    <footer>
        <a href="/">トップページ</a>
    </footer>
</body>
</html>

Udemyのハンズオン動画講座でSpringBootのスキルを磨く!

スポンサーリンク

-Webアプリケーション開発

Copyright© 【Spring Hack】 , 2022 All Rights Reserved Powered by AFFINGER5.