😺
[SpringBoot2.7][MyBatis]MapperインターフェースとMapperXMLの階層違いによるエラーの解消法
環境
- Java -> 11
- SpringBoot -> 2.7.8
- org.mybatis.spring.boot:mybatis-spring-boot-starter -> 2.3.0
フォルダ構成
src
├── java
│ └── com
│ └── course
│ └── apispringbootmybatis
│ ├── ApiSpringbootMybatisApplication.java
│ ├── application
│ │ ├── controller
│ │ │ ├── EmployeeController.java
│ │ │ └── message
│ │ │ ├── EmployeeRequest.java
│ │ │ └── EmployeeResponse.java
│ │ └── exception
│ │ └── EmployeeNotFoundException.java
│ ├── config
│ │ └── ModelMapperConfig.java
│ ├── domain
│ │ ├── dto
│ │ │ ├── EmployeeDto.java
│ │ │ ├── HistoryDto.java
│ │ │ └── PersonalDto.java
│ │ ├── entity
│ │ │ ├── EmployeeEntity.java
│ │ │ ├── HistoryEntity.java
│ │ │ └── PersonalEntity.java
│ │ └── service
│ │ ├── EmployeeService.java
│ │ ├── impl
│ │ │ └── EmployeeServiceImpl.java
│ │ └── logic
│ │ ├── EmployeeLogic.java
│ │ └── impl
│ │ └── EmployeeLogicImpl.java
│ ├── enums
│ │ ├── Department.java
│ │ └── Gender.java
│ └── infrastructure
│ └── mapper
│ ├── EmployeeMapper.java
│ ├── HistoryMapper.java
│ └── PersonalMapper.java
└── resources
├── application.properties
├── mapper
│ ├── EmployeeMapper.xml
│ ├── HistoryMapper.xml
│ └── PersonalMapper.xml
└── mybatis-config.xml
コード
application.properties
# data source
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3006/company
spring.datasource.username=user
spring.datasource.password=password
# mybatis
mybatis.check-config-location=true
mybatis.config-location=classpath:/mybatis-config.xml
src/main/java/com/course/apispringbootmybatis/infrastructure/mapper/EmployeeMapper.java
/**
* Employeeテーブル Mapperクラス
*/
@Mapper
public interface EmployeeMapper {
/**
* 社員IDに該当する社員情報の取得.
*
* @param employeeId 社員ID
* @return 社員情報
*/
Optional<EmployeeDto> selectById(@Param("employeeId") String employeeId);
}
src/main/resources/mapper/EmployeeMapper.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="com.course.apispringbootmybatis.infrastructure.mapper.EmployeeMapper">
<!-- 取得結果とDtoとのマッピング定義-->
<resultMap id="employeeMap" type="EmployeeDto">
<id property="employeeId" column="EMP_EMPLOYEE_ID"/>
<result property="employeeName" column="EMP_EMPLOYEE_NAME"/>
<result property="gender" column="EMP_GENDER"/>
<result property="department" column="EMP_DEPARTMENT_ID" />
<association property="personal" javaType="PersonalDto">
<id property="employeeId" column="PD_EMPLOYEE_ID"/>
<result property="birthday" column="PD_BIRTHDAY"/>
<result property="telephoneNumber" column="PD_TELEPHONE_NUMBER"/>
<result property="mailAddress" column="PD_MAIL_ADDRESS"/>
</association>
<collection property="historyList" ofType="HistoryDto">
<!-- 複合主キー -->
<id property="startDate" column="HST_START_DATE"/>
<id property="employeeId" column="HST_EMPLOYEE_ID"/>
<id property="departmentId" column="HST_DEPARTMENT_ID"/>
<result property="content" column="HST_CONTENT"/>
</collection>
</resultMap>
<select id="selectById" resultMap="employeeMap">
SELECT
EMP.EMPLOYEE_ID as EMP_EMPLOYEE_ID,
EMP.EMPLOYEE_NAME as EMP_EMPLOYEE_NAME,
EMP.GENDER as EMP_GENDER,
EMP.DEPARTMENT_ID as EMP_DEPARTMENT_ID,
PD.EMPLOYEE_ID as PD_EMPLOYEE_ID,
PD.BIRTHDAY as PD_BIRTHDAY,
PD.TELEPHONE_NUMBER as PD_TELEPHONE_NUMBER,
PD.MAIL_ADDRESS as PD_MAIL_ADDRESS,
HST.START_DATE as HST_START_DATE,
HST.EMPLOYEE_ID as HST_EMPLOYEE_ID,
HST.DEPARTMENT_ID as HST_DEPARTMENT_ID,
HST.CONTENT as HST_CONTENT
FROM
EMPLOYEE EMP
LEFT JOIN PERSONAL PD
ON
EMP.EMPLOYEE_ID = PD.EMPLOYEE_ID
LEFT JOIN HISTORY HST
ON
EMP.EMPLOYEE_ID = HST.EMPLOYEE_ID
WHERE
EMP.EMPLOYEE_ID = #{employeeId}
</select>
</mapper>
エラー内容
Invalid bound statement (not found): com.course.apispringbootmybatis.infrastructure.mapper.EmployeeMapper.selectById
原因と対策
原因
EmployeeMapper#selectById
を実行しようと、プログラムがselectById
のSQLが定義されているEmployeeMapper.xml
を探しに行ったが、見つけられないためエラーとなっています。
SpringBoot+MyBatisでは、例えば下記のように、MapperインターフェースとMapperXMLのパスが同一階層の場合のみ自動でMapperXMLを読み込んでくれます。
ファイル | 階層 |
---|---|
Mapperインターフェース | src/main/java/infrastructure/mapper/EmployeeMapper.java |
MapperXML | src/main/resources/infrastructure/mapper/EmployeeMapper.xml |
現在のコードでは、MapperインターフェースとMapperXMLが同一階層にないことで、MapperXMLを自動で読み込んでくれず、期待するファイルが見つからないためエラーが発生しています。
対策
大きく2つの方法があります。
1. フォルダ階層を合わせる
MapperインターフェースとMapperXMLのパスが同一階層にすれば、自動でMapperXMLを読み込んでくれます。
ただ、今回のケースでいうと、resource配下のフォルダ階層が深くなってしまうのでこちらを採用するのは辞めます。
2. MapperXMLの格納場所をapplication.propertiesに定義する
こちらの方法であれば、MapperインターフェースとMapperXMLのパスが同一階層になくても、MapperXMLを読み込むことができます。
application.properties
mybatis.mapper-locations=classpath*:/mapper/*.xml
こちらの対策をすることで、エラーが解消しました。
Discussion