【Java・SpringBoot】NamedParameterJdbcTemplateでCRUD操作（SpringBootアプリケーション実践編19）

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

⭐️前回の記事
[【Java・SpringBoot】RowCallbackHandlerでコールバック / CSV出力機能（SpringBootアプリケーション実践編18）](https://qiita.com/suema0331/items/e3ca75dff8e9118772bc)

#NamedParameterJdbcTemplate
* **JdbcTemplate**では、`PreparedStatment`を使う際に、メソッドの引数の順番に注意を払う必要があったが、**NamedParameterJdbcTemplate**では不要。

#リポジトリークラスを追加
* リポジトリークラスでは、UserDaoインターフェースをimplements

###NamedJdbcTemplateの使い方
* NamedJdbcTemplateでは、PreparedStatementのSQL文に？ではなく`:<キー名>`を使う
        * `String sql = "INSERT INTO m_user(user_id,"
                +   " password,"
                +   " role)"
                + " VALUES(:userId,"
                +   " :password,"
                +   " :role)";`

###SQL文に入れるパラメーターを設定
* **SqlParameterSourceクラス**をnewして、addValue()メソッドにキーと値をセット
* addValue()の第一引数にキー名、第二引数に値をセット
    * `SqlParameterSource params = new MapSqlParameterSource().addValue("userId", user.getUserId())`
* NamedJdbcTemplateにSqlParameterSourceを渡せばOK
    * `return jdbc.update(sql, params);`

```NamedParameterJdbcTemplate.java
//略(全文は下記参考)

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

    @Autowired
    private NamedParameterJdbcTemplate jdbc;

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

        //SQL分
        String sql = "SELECT COUNT(*) FROM m_user";

        //パラメーター生成
        SqlParameterSource params = new MapSqlParameterSource();

        //全件取得してカウント
        return jdbc.queryForObject(sql, params, Integer.class);
    }

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

        //SQL文
        String sql = "INSERT INTO m_user(user_id,"
                +   " password,"
                +   " user_name,"
                +   " birthday,"
                +   " age,"
                +   " marriage,"
                +   " role)"
                + " VALUES(:userId,"
                +   " :password,"
                +   " :userName,"
                +   " :birthday,"
                +   " :age,"
                +   " :marriage,"
                +   " :role)";

        //パラメーター
        SqlParameterSource params = new MapSqlParameterSource()
                .addValue("userId", user.getUserId())
                .addValue("password", user.getPassword())
                .addValue("userName", user.getUserName())
                .addValue("birthday", user.getBirthday())
                .addValue("age", user.getAge())
                .addValue("marriage", user.isMarriage())
                .addValue("role", user.getRole());

        //SQL実行
        return jdbc.update(sql, params);
    }


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

        //SQL文
        String sql = "SELECT * FROM m_user";

        //パラメーター
        SqlParameterSource params = new MapSqlParameterSource();

        //SQL実行
        List<Map<String, Object>> getList = jdbc.queryForList(sql, params);

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

        //取得データ分loop
        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テーブルを１件更新.
    @Override
    public int updateOne(User user) {

        //SQL文
        String sql = "UPDATE M_USER"
                + " SET"
                +   " password = :password,"
                +   " user_name = :userName,"
                +   " birthday = :birthday,"
                +   " age = :age,"
                +   " marriage = :marriage"
                + " WHERE user_id = :userId";

        //パラメーター
        SqlParameterSource params = new MapSqlParameterSource()
                .addValue("userId", user.getUserId())
                .addValue("password", user.getPassword())
                .addValue("userName", user.getUserName())
                .addValue("birthday", user.getBirthday())
                .addValue("age", user.getAge())
                .addValue("marriage", user.isMarriage());

        //SQL実行
        return jdbc.update(sql, params);
    }

//略(全文は下記参考)

}
```

#サービスクラス修正
* UserDaoNamedJdbcImplを使用する

```UserService.java
//略(全文は下記参考)
@ServiceUserService
public class UserService {
    @Autowired
    @Qualifier("UserDaoNamedJdbcImpl")
    UserDao dao;
//略
}
```

#SpringBootを起動してホーム画面確認！
* http://localhost:8080/home
* ユーザー一覧に移ると、コンソールの表示がUserDaoNamedJdbcImplに変わっています
* NamedParameterJdbcTemplateを使ったクラスが使われていることがわかりました^^
* (注)NamedParameterJdbcTemplateではRowMapperは使えるが、BeanPropertyRowMapperは使えません


```
//コンソール
メソッド開始： List com.example.demo.login.domain.repository.jdbc.UserDaoNamedJdbcImpl.selectMany()
メソッド終了： List com.example.demo.login.domain.repository.jdbc.UserDaoNamedJdbcImpl.selectMany()
```


#(参考)コード全文

```NamedParameterJdbcTemplate.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.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.stereotype.Repository;

import com.example.demo.login.domain.model.User;
import com.example.demo.login.domain.repository.UserDao;

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

    @Autowired
    private NamedParameterJdbcTemplate jdbc;

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

        //SQL分
        String sql = "SELECT COUNT(*) FROM m_user";

        //パラメーター生成
        SqlParameterSource params = new MapSqlParameterSource();

        //全件取得してカウント
        return jdbc.queryForObject(sql, params, Integer.class);
    }

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

        //SQL文
        String sql = "INSERT INTO m_user(user_id,"
                +   " password,"
                +   " user_name,"
                +   " birthday,"
                +   " age,"
                +   " marriage,"
                +   " role)"
                + " VALUES(:userId,"
                +   " :password,"
                +   " :userName,"
                +   " :birthday,"
                +   " :age,"
                +   " :marriage,"
                +   " :role)";

        //パラメーター
        SqlParameterSource params = new MapSqlParameterSource()
                .addValue("userId", user.getUserId())
                .addValue("password", user.getPassword())
                .addValue("userName", user.getUserName())
                .addValue("birthday", user.getBirthday())
                .addValue("age", user.getAge())
                .addValue("marriage", user.isMarriage())
                .addValue("role", user.getRole());

        //SQL実行
        return jdbc.update(sql, params);
    }

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

        //SQL文
        String sql = "SELECT * FROM m_user WHERE user_id = :userId";

        //パラメーター
        SqlParameterSource params = new MapSqlParameterSource()
                .addValue("userId", userId);

        //SQL実行
        Map<String, Object> map = jdbc.queryForMap(sql, params);

        //結果返却用のインスタンスを生成
        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() {

        //SQL文
        String sql = "SELECT * FROM m_user";

        //パラメーター
        SqlParameterSource params = new MapSqlParameterSource();

        //SQL実行
        List<Map<String, Object>> getList = jdbc.queryForList(sql, params);

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

        //取得データ分loop
        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テーブルを１件更新.
    @Override
    public int updateOne(User user) {

        //SQL文
        String sql = "UPDATE M_USER"
                + " SET"
                +   " password = :password,"
                +   " user_name = :userName,"
                +   " birthday = :birthday,"
                +   " age = :age,"
                +   " marriage = :marriage"
                + " WHERE user_id = :userId";

        //パラメーター
        SqlParameterSource params = new MapSqlParameterSource()
                .addValue("userId", user.getUserId())
                .addValue("password", user.getPassword())
                .addValue("userName", user.getUserName())
                .addValue("birthday", user.getBirthday())
                .addValue("age", user.getAge())
                .addValue("marriage", user.isMarriage());

        //SQL実行
        return jdbc.update(sql, params);
    }

    //Userテーブルを１件削除.
    @Override
    public int deleteOne(String userId) {

        //SQL文
        String sql = "DELETE FROM m_user WHERE user_id = :userId";

        //パラメーター
        SqlParameterSource params = new MapSqlParameterSource()
                .addValue("userId", userId);

        //SQL実行
        int rowNumber = jdbc.update(sql, params);

        return rowNumber;
    }

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

        //M_USERテーブルのデータを全件取得するSQL
        String sql = "SELECT * FROM m_user";

        //ResultSetExtractorの生成
        UserRowCallbackHandler handler = new UserRowCallbackHandler();

        //クエリー実行＆CSV出力
        jdbc.query(sql, handler);
    }
}
```

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

import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

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


@Service
public class UserService {
    @Autowired
    @Qualifier("UserDaoNamedJdbcImpl")
    UserDao dao;

    /**
     * insert用メソッド.
     */
    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();
    }

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

    /**
     * １件更新用メソッド.
     */
    public boolean updateOne(User user) {

        // 判定用変数
        boolean result = false;

        // １件更新
        int rowNumber = dao.updateOne(user);

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

        return result;
    }

    /**
     * １件削除用メソッド.
     */
    public boolean deleteOne(String userId) {

        // １件削除
        int rowNumber = dao.deleteOne(userId);

        // 判定用変数
        boolean result = false;

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

    // ユーザー一覧をCSV出力する.
    public void userCsvOut() throws DataAccessException {
        // CSV出力
        dao.userCsvOut();
    }

    /**
     * サーバーに保存されているファイルを取得して、byte配列に変換する.
     */
    public byte[] getFile(String fileName) throws IOException {

        // ファイルシステム（デフォルト）の取得
        FileSystem fs = FileSystems.getDefault();

        // ファイル取得
        Path p = fs.getPath(fileName);

        // ファイルをbyte配列に変換
        byte[] bytes = Files.readAllBytes(p);

        return bytes;
    }
}
```