本ページはプロモーションが含まれています。

スポンサーリンク

Webアプリケーション開発

SpringBootで編集画面を作成する

投稿日:

編集画面のサンプル

画面デモ

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

ディレクトリ構成

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/edit")
    public String edit(Long id, Model model) {

        // 編集可否チェック
        Child child = childrenService.get(id);
        if (Objects.isNull(child)) {
            model.addAttribute("message", "選択した子どもが存在しません。");
            return "children/index";
        }

        // 画面遷移
        ChildEditForm childEditForm = ChildrenControllerHelper.toEditForm(child);
        model.addAttribute("childEditForm", childEditForm);
        return "children/edit";
    }

    @PostMapping("/children/editConfirm")
    public String editConfirm(@Validated ChildEditForm childEditForm, BindingResult bindingResult, Model model) {

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

        // 編集可否チェック
        var child = ChildrenControllerHelper.toChild(childEditForm);
        boolean canRegister = childrenService.canEdit(child);
        if (!canRegister) {
            model.addAttribute("message", "既に同じ名前が登録されています。");
            return "children/edit";
        }

        // 画面遷移
        return "children/edit_confirm";
    }

    @PostMapping("/children/editFinish")
    public String editFinish(@Validated ChildEditForm childEditForm, BindingResult bindingResult, RedirectAttributes redirectAttributes) {

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

        // 編集実行
        var child = ChildrenControllerHelper.toChild(childEditForm);
        childrenService.edit(child);

        // 画面遷移
        redirectAttributes.addFlashAttribute("message", child.getName() + "を編集しました。");
        return "redirect:/children";
    }
}

編集のサービス層

@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;
    }

    /**
     * 1件取得する
     */
    public Child get(Long childId) {
        ChildrenEntity childrenEntity = childrenMapper.findById(childId);
        if (Objects.isNull(childrenEntity)) {
            return null;
        }
        return new Child(
                childrenEntity.getChildId(),
                childrenEntity.getName(),
                childrenEntity.getBirthday());
    }

    /**
     * 編集する
     */
    public void edit(Child newChild) {
        var childrenEntity = new ChildrenEntity(newChild.getChildId(), newChild.getName(), newChild.getBirthday());
        childrenMapper.update(childrenEntity);
    }

    /**
     * 編集可能かチェックする
     */
    public boolean canEdit(Child newChild) {

        List<ChildrenEntity> sameNameChildren = childrenMapper.findByName(newChild.getName());

        if (!sameNameChildren.isEmpty() && !sameNameChildren.get(0).getChildId().equals(newChild.getChildId())) {
            return false;
        }

        return true;
    }
}

編集のインテグレーション層

@Mapper
public interface ChildrenMapper {
    List<ChildrenEntity> selectAll();
    ChildrenEntity findById(Long childId);
    List<ChildrenEntity> findByName(String name);
    void update(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>

    <select id="findById" resultType="com.springhack.okozukaisystem.integration.entity.ChildrenEntity">
        SELECT c.child_id, c.name, c.birthday FROM children c WHERE c.child_id = #{childId}
    </select>

    <select id="findByName" resultType="com.springhack.okozukaisystem.integration.entity.ChildrenEntity">
        SELECT c.child_id, c.name, c.birthday FROM children c WHERE c.name = #{name}
    </select>

    <update id="update">
        UPDATE children SET name = #{name}, birthday = #{birthday} WHERE child_id = #{childId}
    </update>
</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">
<head>
    <meta charset="UTF-8">
    <title>子どもマスタ|子どものお小遣い帳アプリ</title>
</head>
<body>
    <header></header>
    <main>
        <h1>子どもを編集</h1>
        <div th:text="${message}"></div>
        <form method="POST" action="/children/editConfirm" th:object="${childEditForm}">
            <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>
            <input type="hidden" th:field="*{childId}">
            <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">
<head>
    <meta charset="UTF-8">
    <title>子どもマスタ|子どものお小遣い帳アプリ</title>
</head>
<body>
    <header></header>
    <main>
        <h1>編集する子どもを確認</h1>
        <div th:text="${message}"></div>
        <form method="POST" action="/children/editFinish" th:object="${childEditForm}">
            <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="*{childId}">
            <input type="hidden" th:field="*{name}">
            <input type="hidden" th:field="*{birthday}">
            <button onclick="location.href='/children/edit?id=123';return false;">キャンセル</button>
            <input type="submit" value="編集を確定する" />
        </form>
    </main>
    <footer>
        <a href="/">トップページ</a>
    </footer>
</body>
</html>

本ページはプロモーションが含まれています。

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

スポンサーリンク

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

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