Spring + Mybatisの設定(application.yml)

# 初めに
本記事ではMybatisの設定を「__application.yml__」に行う方法について記載しています。Mybatisの設定方法は色々あると思いますが今回は「__application.yml__」での設定方法についてですので注意してください。また、本記事は詳細なMybatisの設定についての解説ではなくあくまで設定ができるかどうかだけなので細かな設定内容については以下を参照してください。

https://mybatis.org/mybatis-3/ja/index.html

# 構成内容
Springのプロジェクトのパッケージ構成は以下を想定します。
```
app(プロジェクト名)
    - src
    - main
        - java
            - jp
                - com
                    - app
                        - controller
                            - TestController1.java (今回は気にしなくてよい)
                        - service
                            - TestService1.java
                            - TestService1Impl.java
                        - entity
                            - TestRequestEntity1.java
                            - TestResponseEntity1.java
                        - mapper
                            - TestMapper1.java
                        - AppApplication.java (Mainクラス)
                        - ServletInitializer.java

        - resources
            - jp
                - com
                    - app
                        - mapper
                            - TestMapper1.xml 
            - application.yml
    - test
        - java
            - jp
                - com
                    - app
                        - service
                            - TestService1.java (動作確認用テストクラス)
```
「__PostgreSQL__」を今回は使用します。
```:PostgreSQの設定内容
DB名：test
ユーザ名；test
パスワード：test
```
```:usersテーブル作成sql
CREATE TABLE users(
  id integer,
  name varchar(50)
);
```

# 設定手順
|手順No|概要|
|---|---|
|[No.1](#no1)|__Mainクラスへの設定(AppApplication.java)__|
|[No.2](#no2)|__application.ymlへの設定__|
|[No.3](#no3)|__動作確認__|


## No.1
メインクラスに __MapperScan__ を記述します。記述方法は以下のように行います。
```
@MapperScan("Mapperを作成するパッケージ")
```
例えばこんな感じです。
```: AppApplication.java
package jp.com.app;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@MapperScan("jp.com.app.mapper")
@SpringBootApplication
public class AppApplication {

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

}
```

importと合わせて2行追加するだけです。簡単ですね。

## No.2
「__application.yml__」にmybatisの設定を行います。今回は、MybatisでSQLの条件や戻り値の型をJavaBeansで設定する際にパッケージ名をapplication.ymlで設定することでいちいちMapper.xmlでパッケージ名まで記載しなくて良いように設定できることを目指します。

SQLの「__parameterType__」や「__resultType__」にパッケージ名を指定しないとエラーになる。
```:この設定をしない場合
<select id="selectUsers" parameterType="jp.com.app.entity.TestRequestEntity1" resultType="jp.com.app.entity.TestResponseEntity1">
    SELECT
        id,
        name
    FROM
        users
    WHERE 
        id = #{id}
</select>
```
SQLの「__parameterType__」や「__resultType__」にパッケージ名を記載しなくても良くなる。
```:設定した場合
<select id="selectUsers" parameterType="TestRequestEntity1" resultType="TestResponseEntity1">
    SELECT
        id,
        name
    FROM
        users
    WHERE 
        id = #{id}
</select>
```
「__application.yml__」を以下のように記載します。
```:application.yml
spring:
  datasource:
    driver-class-name: org.postgresql.Driver
    url: jdbc:postgresql://localhost:5432/test # DB名
    username: test # PostgreSQLのユーザ名
    password: test # PostgreSQLのパスワード

mybatis:
  type-aliases-package: jp.com.app.entity
```
## No,3
CRUDを試してみます。
```:TestService1.java
package jp.com.app.service;

import java.util.List;

import jp.com.app.dto.TestRequestDto1;
import jp.com.app.dto.TestResponseDto1;

public interface TestService1 {
    /**
     * ユーザデータ取得
     * @param requestDto 検索条件
     * @return 画面設定データ
     */
    public List<TestResponseDto1> getUserData(TestRequestDto1 requestDto);

    /**
     * ユーザデータ追加
     * @param requestDto 追加ユーザ情報
     */
    public void addUserData(TestRequestDto1 requestDto);

    /**
     * ユーザデータ更新
     * @param requestDto 更新ユーザ情報
     */
    public void updateUserData(TestRequestDto1 requestDto);

    /**
     * ユーザデータ削除
     * @param requestDto 削除ユーザ情報
     */
    public void deleteUserData(TestRequestDto1 requestDto);

    
}

```
```:TestServiceImpl.java
package jp.com.app.service;

import java.util.LinkedList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import jp.com.app.dto.TestRequestDto1;
import jp.com.app.dto.TestResponseDto1;
import jp.com.app.entity.TestRequestEntity1;
import jp.com.app.entity.TestResponseEntity1;
import jp.com.app.mapper.TestMapper1;

@Service
public class TestService1Impl implements TestService1{
    @Autowired
    TestMapper1 testMapper1;

    /**
     * ユーザデータ取得
     * @param requestDto 検索条件
     * @return 画面設定データ
     */
    @Override
    public List<TestResponseDto1> getUserData(TestRequestDto1 requestDto) {

        TestRequestEntity1 requestEntity = dtoTranseformToEntity(requestDto);

        List<TestResponseEntity1> responseEntityList = testMapper1.selectUsers(requestEntity);
        
        return entityTransformDto(responseEntityList);
    }

    /**
     * ユーザデータ追加
     * @param requestDto 追加ユーザ情報
     */
    @Override
    public void addUserData(TestRequestDto1 requestDto) {
        testMapper1.insertUsers(dtoTranseformToEntity(requestDto));
    }

    /**
     * ユーザデータ更新
     * @param requestDto 更新ユーザ情報
     */
    @Override
    public void updateUserData(TestRequestDto1 requestDto) {
        testMapper1.updatetUsers(dtoTranseformToEntity(requestDto));        
    }

    /**
     * ユーザデータ削除
     * @param requestDto 削除ユーザ情報
     */
    @Override
    public void deleteUserData(TestRequestDto1 requestDto) {
        testMapper1.deleteUsers(dtoTranseformToEntity(requestDto));
        
    }

    /**
     * dtoをentityへ変換
     * @param dto
     * @return entity
     */
    private TestRequestEntity1 dtoTranseformToEntity(TestRequestDto1 requestDto){
        TestRequestEntity1 requestEntity = new TestRequestEntity1();
        requestEntity.setId(Integer.parseInt(requestDto.getId()));
        requestEntity.setName(requestDto.getName());
        return requestEntity;
    }

    /**
     * entityをdtoへ変換
     * @param entity
     * @return dto
     */
    private List<TestResponseDto1> entityTransformDto(List<TestResponseEntity1> responseEntityList){
        List<TestResponseDto1> responseDtoList = new LinkedList<TestResponseDto1>();
        for(TestResponseEntity1 responseEntity :responseEntityList){
            TestResponseDto1 responseDto = new  TestResponseDto1();
            responseDto.setId(responseEntity.getId().toString());
            responseDto.setName(responseEntity.getName());
            responseDtoList.add(responseDto);
        }
        return responseDtoList;
    }
}
```

```:TestMapper1.java
package jp.com.app.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import jp.com.app.entity.TestRequestEntity1;
import jp.com.app.entity.TestResponseEntity1;

@Mapper
public interface TestMapper1 {
    public List<TestResponseEntity1> selectUsers(TestRequestEntity1 requestEntity);

    public void insertUsers(TestRequestEntity1 requestEntity);

    public void updatetUsers(TestRequestEntity1 requestEntity);

    public void deleteUsers(TestRequestEntity1 requestEntity);
}
```
「__Mapper.xml__」の「__parameterType__」と「__resultType__」にパッケージ名を記載していません。
```
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="jp.com.app.mapper.TestMapper1">
   <select id="selectUsers" parameterType="TestRequestEntity1" resultType="TestResponseEntity1">
      SELECT
         id,
         name
      FROM
         users
      WHERE 
         id = #{id}
   </select>
   <insert id="insertUsers" parameterType="TestRequestEntity1">
      INSERT INTO users
      (
         id, 
         name
      )
      VALUES 
      (
         #{id}, 
         #{name}
      )
   </insert>
   <update id="updatetUsers" parameterType="TestRequestEntity1">
      UPDATE
         users
      SET
         name = #{name}
      WHERE
         id = #{id}
   </update>
   <delete id="deleteUsers" parameterType="TestRequestEntity1">
      DELETE
      FROM
         users
      WHERE
         id = #{id}
   </delete>
</mapper>
```
動作確認用の実行クラスです。System.out.println(res);でDBの取得結果を表示しています。
```:
package jp.com.app.service;

import java.util.List;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;

import jp.com.app.dto.TestRequestDto1;
import jp.com.app.dto.TestResponseDto1;

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class TestService1Test {
    @Autowired
    TestService1 service;

    @Test
    public void 動作確認_検索()throws Exception{
        TestRequestDto1 requestDto = new TestRequestDto1();
        requestDto.setId("1");
        requestDto.setName("Tarou");
        service.addUserData(requestDto);
        List<TestResponseDto1> res = service.getUserData(requestDto);
        System.out.println(res);
    }

    @Test
    public void 動作確認_追加()throws Exception{
        TestRequestDto1 requestDto = new TestRequestDto1();
        requestDto.setId("2");
        requestDto.setName("Jirou");
        service.addUserData(requestDto);
        List<TestResponseDto1> res = service.getUserData(requestDto);
        System.out.println(res);
    }

    @Test
    public void 動作確認_更新()throws Exception{
        TestRequestDto1 requestDto = new TestRequestDto1();
        requestDto.setId("3");
        requestDto.setName("Sabu");
        service.addUserData(requestDto);
        requestDto.setName("Saburou");
        service.updateUserData(requestDto);
        List<TestResponseDto1> res = service.getUserData(requestDto);
        System.out.println(res);
    }

    @Test
    public void 動作確認_削除()throws Exception{
        TestRequestDto1 requestDto = new TestRequestDto1();
        requestDto.setId("4");
        requestDto.setName("Sirou");
        service.addUserData(requestDto);
        service.deleteUserData(requestDto);
        List<TestResponseDto1> res = service.getUserData(requestDto);
        System.out.println(res);
    }
}
```
テストクラスの実行結果が以下のようにテストクラスで追加した値が表示されれば成功です。
```:実行結果
[]
[TestResponseDto1(id=3, name=Saburou), TestResponseDto1(id=3, name=Saburou)]
[TestResponseDto1(id=1, name=Tarou), TestResponseDto1(id=1, name=Tarou), TestResponseDto1(id=1, name=Tarou), TestResponseDto1(id=1, name=Tarou), TestResponseDto1(id=1, name=Tarou), TestResponseDto1(id=1, name=Tarou), TestResponseDto1(id=1, name=Tarou)]
[TestResponseDto1(id=2, name=Jirou), TestResponseDto1(id=2, name=Jirou)]
```

以上、でし。

# 最後に
ここまで見ていただきありがとうございます。