SpringBoot Mybatis マッピング方法 



## ディレクトリをそろえる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637823/536f5316-8ba5-56a8-7735-77569efde292.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637823/0d812dc2-51c0-7525-4233-e320e705ce3b.png)


## Serviceクラス
```ShoppingListService.java
package com.example.householdAccountBook.application.service;
//import 省略

@Service
public class ShoppingListService {
    @Autowired
    ShoppingListMapper shoppingListMapper;
    //買い物リスト全件表示
    public List<ShoppingList>findAll(){
        return this.shoppingListMapper.showShoppingList();
    }
}
```
|ポイント|説明|
|----|----|
|`@Service`|ビジネスロジックを記載するソース。<br>mapper（自動生成）を「<b>`@Autowired`</b>」で宣言し、MyBatisを利用したDBアクセスを行う。<br>https://www.jcsc.co.jp/tech_blog/archives/21||
|ビジネスロジック|処理をして、その結果をデータベースに登録するシステム。<br>https://wa3.i-3-i.info/word13666.html||
|interfaceとインスタンス化|Mapper.javaにはinterfaceを記述するが、interfaceはインスタンス化できないので、＠Autowiredを使う。||

## Mapperインターフェース
```ShoppingListMapper.java
package com.example.householdAccountBook.domain.repository;
import com.example.householdAccountBook.domain.entity.ShoppingList;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;

@Mapper
public interface ShoppingListMapper {
    List<ShoppingList> showShoppingList();
　　
　　void insertShoppingList(ShoppingList shoppinglist)

    void deleteShoppingList(ShoppingList shoppinglist)
}
```

## Mapper.xml
```ShoppingListMapper.xml
<?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="マッピングするjavaクラスの場所">

		SELECT
		    A.history_id,
		    CASE WHEN DATE_ADD(A.lasttime_housework_date, INTERVAL(B.interval_day)DAY) = CURRENT_DATE() THEN "本日"
		        WHEN DATE_ADD(A.lasttime_housework_date, INTERVAL(B.interval_day)DAY) <![CDATA[ < ]]> CURRENT_DATE() THEN "超過"
		        WHEN DATE_ADD(A.lasttime_housework_date, INTERVAL(B.interval_day)DAY) <![CDATA[ > ]]> CURRENT_DATE() THEN ""
		    END AS nexttime_schedule_label,
		    C.category_name,
		    B.housework_name,
		    DATE_ADD(A.lasttime_housework_date, INTERVAL(B.interval_day)DAY) AS nexttime_houosework_date,
		    DATEDIFF(CURRENT_DATE,DATE_ADD(A.lasttime_housework_date, INTERVAL(B.interval_day)DAY))*-1 AS nexttime_schedule_numerical,
		    D.user_name AS lasttime_user
		FROM
		    housework_history AS A 
		    INNER JOIN housework_works AS B 
		        ON A.works_id = B.works_id 
		    INNER JOIN housework_category AS C 
		        ON B.category_id = C.category_id 
		    INNER JOIN housework_users AS D 
		        ON A.user_id = D.user_id
		WHERE 
		    A.history_id=#{historyId};
    
    <insert id="insertShoppingList">
        INSERT INTO ShoppingList(
          place,
          category,
          itemName,
          created_at,
          updated_at
        ) value (
          #{place},
          #{category},
          #{itemName},
          now(),
          now(),
        )
    </insert> 

    <delete id="deleteShoppingList">
	DELETE FROM shopping WHERE id = #{id}
    </delete>

</mapper>
```
|項目|説明|記入例|
|----|----|----|
|mapper namespace|マッピングするjavaクラスの場所|com.example.householdAccountBook.domain.repository.ShoppingListMapper|
|resultType|結果を詰める箱|com.example.householdAccountBook.domain.entity.ShoppingList|
|不等式|MyBatisで不当式を書く場合は右記のようにする。|<![CDATA[ < ]]><br><![CDATA[ > ]]>|
|変数|#{変数名}|#{historyId}|
【公式】https://mybatis.org/mybatis-3/ja/sqlmap-xml.html

## うまくいかない時 insertの戻り値をvoidにしなかった例
|エラー|説明|
|----|----|
|insertMemberInfo' has an unsupported return type|insert分をマッピングする際は、戻り値をvoidにしないとエラーとなる。||

## うまくいかない時 Mapperクラス 二つ以上の引数には<span>@</span>Param
```:エラー
void insertNewHistory(Integer worksId,Integer userId);
```
```:エラー解消
void insertNewHistory(@Param("worksId") Integer worksId,@Param("userId")Integer userId);
```
|エラー内容|原因|
|----|----|
|org.apache.ibatis.binding.BindingException: Parameter 'worksId' not found. Available parameters are [arg3, arg2, param5, arg4, arg1, arg0, param3, param4, param1, param2]|引数が2つ以上の場合は<span>@</span>Paramが必要||
https://qiita.com/5zm/items/0864d6641c65f976d415

## うまくいかない時 戻り値の注意点
例えばSQLでSELECTで抽出したIDなどの数値を戻したい場合でも、戻り値の型をInteger等にするとキャストエラーになる。戻り値は、xmlファイルのresultTypeで指定したEntityクラスの型にしないといけない。(下の例ではHouseworkList型)
下の例ではSELECTで抽出したcategoryIDはあくまでHouseworkListクラスのメンバー変数へ入るので、
戻り値の型はHouseworkList型にして、getter等で取り出して使用する必要がある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637823/08f4cfa2-ea0c-55cf-b288-95b488cc3564.png)

|エラー内容|原因|
|----|----|
|class com.example.householdAccountBook.entity.HouseworkList cannot be cast to class java.lang.Integer|HouseworkListをIntegerにキャストできない。||




## entityクラス
```:HogeEntity.java
中略
import lombok.Data;

@Data
public class HogeEntity{
  private Integer hogehogeId;
  private String hogehogeName;
}

```
## うまくいかない時
###xmlで指定したネームスペースとファイル名が不一致だった例
|エラー内容|原因|
|----|----|
| org.apache.ibatis.builder.BuilderException:<br><b>Wrong namespace.</b> Expected 'com.example.demo.mapper.<b>Demomapper</b>' but found 'com.example.demo.mapper.<b>DemoMapper</b>'.|xmlファイルのネームスペースにはDemo<b>Mapper</b>と指定しているが、ファイル名がDemo<b>mapper</b>になっている||
https://qiita.com/YuichiTanaka007/items/78b628b179774dfe4783#%E3%82%AF%E3%83%A9%E3%82%B9%E5%90%8D%E3%82%92%E3%83%AA%E3%83%95%E3%82%A1%E3%82%AF%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0%E3%81%99%E3%82%8B

### コントローラー→サービスクラス→マッパークラスにアクセスしようとしてもNullPointerExceptionが返ってくる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637823/2c8a8279-5906-bf7f-82b9-9ea41a48f4e7.png)

|エラー内容|原因|
|----|----|
|java.lang.NullPointerException|サービスクラスへアクセスする場合は「`@AutoWired`」でアクセスしなければならない||

## Listの中身をデバッグする
```
System.out.println(worksContentsList.get(0).toString());
```
|項目|説明|
|----|----|
|get(0)|Listの要素を指定するにはget(i)を使う||
|toString()|メンバー変数の中身を一気に見ることができる||