2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Java・SpringBoot】Spring JDBC でユーザー詳細画面(SpringBootアプリケーション実践編12)

Posted at

ホーム画面からユーザー一覧画面に遷移し、ユーザーの詳細を表示するアプリケーションを作成して、Spring JDBCの使い方について学びます⭐️
前回はユーザー一覧画面を作ったので、今回はユーザー詳細画面を作ります^^
構成は前回の記事を参考にしてください

⭐️前回の記事
【Java・SpringBoot】Spring JDBC でユーザー一覧画面(SpringBootアプリケーション実践編11)

#リポジトリークラスに1件検索するメソッドを実装
###queryForMapメソッドで1件取得

  • 戻り値はMap型
  • 第1引数:SQL文、第2引数以降にPreparedStatementを指定
    • Map<String, Object> map = jdbc.queryForMap("SELECT * FROM m_user" + " WHERE user_id = ?", userId);
    • 戻り値のMapのgetメソッドにカラム名を指定することで、値を取得する
UserDaoJdbcImpl.java
package com.example.demo.login.domain.repository.jdbc;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import com.example.demo.login.domain.model.User;
import com.example.demo.login.domain.repository.UserDao;

@Repository("UserDaoJdbcImpl")
public class UserDaoJdbcImpl implements UserDao {

    @Autowired
    JdbcTemplate jdbc;

    // Userテーブルの件数を取得.
    @Override
    public int count() throws DataAccessException {

        //全件取得してカウント
        int count = jdbc.queryForObject("SELECT COUNT(*) FROM m_user", Integer.class);

        return count;
    }

    // Userテーブルにデータを1件insert.
    @Override
    public int insertOne(User user) throws DataAccessException {

        //1件登録
        int rowNumber = jdbc.update("INSERT INTO m_user(user_id,"
                + " password,"
                + " user_name,"
                + " birthday,"
                + " age,"
                + " marriage,"
                + " role)"
                + " VALUES(?, ?, ?, ?, ?, ?, ?)",
                user.getUserId(),
                user.getPassword(),
                user.getUserName(),
                user.getBirthday(),
                user.getAge(),
                user.isMarriage(),
                user.getRole());

        return rowNumber;
    }

    // Userテーブルのデータを1件取得
    @Override
    public User selectOne(String userId) throws DataAccessException {

        // 1件取得
        Map<String, Object> map = jdbc.queryForMap("SELECT * FROM m_user"
                + " WHERE user_id = ?", userId);

        // 結果返却用の変数
        User user = new User();

        // 取得したデータを結果返却用の変数にセットしていく
        user.setUserId((String) map.get("user_id")); //ユーザーID
        user.setPassword((String) map.get("password")); //パスワード
        user.setUserName((String) map.get("user_name")); //ユーザー名
        user.setBirthday((Date) map.get("birthday")); //誕生日
        user.setAge((Integer) map.get("age")); //年齢
        user.setMarriage((Boolean) map.get("marriage")); //結婚ステータス
        user.setRole((String) map.get("role")); //ロール

        return user;
    }

    // Userテーブルの全データを取得.
    @Override
    public List<User> selectMany() throws DataAccessException {

        // M_USERテーブルのデータを全件取得
        List<Map<String, Object>> getList = jdbc.queryForList("SELECT * FROM m_user");

        // 結果返却用の変数
        List<User> userList = new ArrayList<>();

        // 取得したデータを結果返却用のListに格納していく
        for (Map<String, Object> map : getList) {

            //Userインスタンスの生成
            User user = new User();

            // Userインスタンスに取得したデータをセットする
            user.setUserId((String) map.get("user_id")); //ユーザーID
            user.setPassword((String) map.get("password")); //パスワード
            user.setUserName((String) map.get("user_name")); //ユーザー名
            user.setBirthday((Date) map.get("birthday")); //誕生日
            user.setAge((Integer) map.get("age")); //年齢
            user.setMarriage((Boolean) map.get("marriage")); //結婚ステータス
            user.setRole((String) map.get("role")); //ロール

            //結果返却用のListに追加
            userList.add(user);
        }

        return userList;
    }

    // Userテーブルを1件更新.
    @Override
    public int updateOne(User user) throws DataAccessException {
        return 0;
    }

    // Userテーブルを1件削除.
    @Override
    public int deleteOne(String userId) throws DataAccessException {
        return 0;
    }

    //SQL取得結果をサーバーにCSVで保存する
    @Override
    public void userCsvOut() throws DataAccessException {

    }
}

#サービスクラスに1件取得用のメソッド追加

UserService.java
package com.example.demo.login.domain.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.example.demo.login.domain.model.User;
import com.example.demo.login.domain.repository.UserDao;

@Service
public class UserService {
    @Autowired
    UserDao dao;

    public boolean insert(User user) {
        // insert実行
        int rowNumber = dao.insertOne(user);
        // 判定用変数
        boolean result = false;

        if (rowNumber > 0) {
            // insert成功
            result = true;
        }
        return result;
    }

    public int count() {
        return dao.count();
    }

    public List<User> selectMany() {
        // 全件取得
        return dao.selectMany();
    }

    /**
     * 1件取得用メソッド.
     */
    public User selectOne(String userId) {
        // selectOne実行
        return dao.selectOne(userId);
    }
}

#ホーム画面用のコントローラークラスを修正
###動的なURLに対応したメソッドを作る

  • @GetMapping@PostMappingの値に**/{<変数名>}を付ける**
    • ユーザーIDを受け取る場合は、@GetMapping(/userDetail/{id})
    • 通常は/userDetail/{id}とすればいいが。。。
    • ユーザーIDがメールアドレス形式の場合、sample@xxx.co.jpというユーザーIDが渡されてくると、sample@xxx.coしか受け取れない
      • 正規表現を使用して**@GetMapping("/userDetail/{id:.+}")**とする

###@PathVariable

  • @PathVariableアノテーションを付けると、渡されてきたパス(URL)の値を引数の変数に入れることができる
    • 例:@PathVariable("id") String userId) {...}
    • http://localhost:8080/userDetail/sample@xxx.co.jpというURLでリクエストが来た場合、
      sample@xxx.co.jpという値が引数のuserIdという変数に入れられる
HomeController.java
package com.example.demo.login.controller;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import com.example.demo.login.domain.model.SignupForm;
import com.example.demo.login.domain.model.User;
import com.example.demo.login.domain.service.UserService;

@Controller
public class HomeController {

    @Autowired
    UserService userService;
    //結婚ステータスのラジオボタン用変数
    private Map<String, String> radioMarriage;

    /**
     * ラジオボタンの初期化メソッド
     */
    private Map<String, String> initRadioMarrige() {
        Map<String, String> radio = new LinkedHashMap<>();
        // 既婚、未婚をMapに格納
        radio.put("既婚", "true");
        radio.put("未婚", "false");
        return radio;
    }

    @GetMapping("/home")
    public String getHome(Model model) {
        //コンテンツ部分にユーザー詳細を表示するための文字列を登録
        model.addAttribute("contents", "login/home :: home_contents");
        return "login/homeLayout";
    }

    @GetMapping("/userList")
    public String getUserList(Model model) {

        //コンテンツ部分にユーザー一覧を表示するための文字列を登録
        model.addAttribute("contents", "login/userList :: userList_contents");
        //ユーザー一覧の生成
        List<User> userList = userService.selectMany();
        //Modelにユーザーリストを登録
        model.addAttribute("userList", userList);
        //データ件数を取得
        int count = userService.count();
        model.addAttribute("userListCount", count);
        return "login/homeLayout";
    }

    /**
     * ユーザー詳細画面のGETメソッド用処理.
     */
    @GetMapping("/userDetail/{id:.+}")
    public String getUserDetail(@ModelAttribute SignupForm form,
            Model model,
            @PathVariable("id") String userId) {
        // ユーザーID確認
        System.out.println("userId = " + userId);

        // コンテンツ部分にユーザー詳細を表示するための文字列を登録
        model.addAttribute("contents", "login/userDetail :: userDetail_contents");
        // 結婚ステータス用ラジオボタンの初期化
        radioMarriage = initRadioMarrige();
        // ラジオボタン用のMapをModelに登録
        model.addAttribute("radioMarriage", radioMarriage);

        // ユーザーIDのチェック
        if (userId != null && userId.length() > 0) {
            // ユーザー情報を取得
            User user = userService.selectOne(userId);
            // Userクラスをフォームクラスに変換
            form.setUserId(user.getUserId()); //ユーザーID
            form.setUserName(user.getUserName()); //ユーザー名
            form.setBirthday(user.getBirthday()); //誕生日
            form.setAge(user.getAge()); //年齢
            form.setMarriage(user.isMarriage()); //結婚ステータス
            // Modelに登録
            model.addAttribute("signupForm", form);
        }
        return "login/homeLayout";
    }

    @PostMapping("/logout")
    public String postLogout() {
        return "redirect:/login";
    }

    @GetMapping("/userList/csv")
    public String getUserListCsv(Model model) {
        return getUserList(model);
    }
}

#ユーザー詳細画面作成

userDetail.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
    <meta charset="UTF-8"></meta>
</head>
<body>
    <div th:fragment="userDetail_contents">
        <div class="row">
            <div class="col-sm-5">
                <div class="page-header">
                    <h1>ユーザー詳細</h1>
                </div>
                <form method="post" th:action="@{/userDetail}" th:object="${signupForm}">
                    <table class="table table-bordered table-hover">
                        <tr>
                            <!-- ユーザーID(入力不可) -->
                            <th class="active col-sm-2">ユーザID</th>
                            <td class="col-sm-3">
                                <div class="form-group">
                                    <input type="text" class="form-control"
                                        th:field="*{userId}"
                                        readonly="readonly" />
                                </div>
                            </td>
                        </tr>
                        <tr>
                            <!-- パスワード -->
                            <th class="active">パスワード</th>
                            <td>
                                <div class="form-group"
                                    th:classappend="${#fields.hasErrors('password')} ? 'has-error'">
                                    <input type="text" class="form-control"
                                        th:field="*{password}" />
                                    <span class="text-danger"
                                        th:if="${#fields.hasErrors('password')}"
                                        th:errors="*{password}">
                                        password error
                                    </span>
                                </div>
                            </td>
                        </tr>
                        <tr>
                            <!-- ユーザー名 -->
                            <th class="active">ユーザ名</th>
                            <td>
                                <div class="form-group"
                                    th:classappend="${#fields.hasErrors('userName')} ? 'has-error'">
                                    <input type="text" class="form-control"
                                        th:field="*{userName}" />
                                    <span class="text-danger"
                                        th:if="${#fields.hasErrors('userName')}"
                                        th:errors="*{userName}">
                                        userName error
                                    </span>
                                </div>
                            </td>
                        </tr>
                        <tr>
                            <!-- 誕生日 -->
                            <th class="active">誕生日</th>
                            <td>
                                <div class="form-group"
                                    th:classappend="${#fields.hasErrors('birthday')} ? 'has-error'">
                                    <input type="text" class="form-control"
                                        placeholder="yyyy/MM/dd"
                                        th:field="*{birthday}" />
                                    <span class="text-danger"
                                        th:if="${#fields.hasErrors('birthday')}"
                                        th:errors="*{birthday}">
                                        birthday error
                                    </span>
                                </div>
                            </td>
                        </tr>
                        <tr>
                            <!-- 年齢 -->
                            <th class="active">年齢</th>
                            <td>
                                <div class="form-group"
                                    th:classappend="${#fields.hasErrors('age')} ? 'has-error'">
                                    <input type="text" class="form-control"
                                        th:field="*{age}" />
                                    <span class="text-danger"
                                        th:if="${#fields.hasErrors('age')}"
                                        th:errors="*{age}">
                                        age error
                                    </span>
                                </div>
                            </td>
                        </tr>
                        <tr>
                            <!-- 結婚 -->
                            <th class="active">結婚</th>
                            <td>
                                <div class="form-group">
                                    <div th:each="item : ${radioMarriage}">
                                        <input type="radio" name="radioMarrige"
                                            th:value="${item.value}"
                                            th:text="${item.key}"
                                            th:field="*{marriage}">
                                        </input>
                                    </div>
                                    <span class="text-danger"
                                        th:if="${#fields.hasErrors('marriage')}"
                                        th:errors="*{marriage}">
                                        marriage error
                                    </span>
                                </div>
                            </td>
                        </tr>
                    </table>
                    <!-- 更新ボタン -->
                    <button class="btn btn-primary btn-lg pull-right"
                        type="submit"
                        name="update">
                        更新
                    </button>
                    <!-- 削除ボタン -->
                    <button class="btn btn-danger btn-lg" type="submit" name="delete">
                        削除
                    </button>
                </form>
            </div>
        </div>
    </div>
</body>
</html>

#SpringBootを起動してユーザ一覧画面確認!

  • http://localhost:8080/userList
  • ユーザ一覧から、ユーザ詳細画面に遷移します
  • パスワード以外の情報が反映されました〜^^

詳細.png

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?