결론부터.
mapper.xml 파일을 resources에 넣고 싶지 않은 개발자들은 build.gradle 파일에 sourceSet 셋팅을 추가해주어야한다.
그러지 않으면 org.apache.ibatis.binding.BindingException이 날 것이고
당신은 애꿎은 namespace만 노려보면서 오타를 찾아 시간을 버릴 것이다.
sourceSets {
main {
resources { // 리소스 파일을 찾는다.
srcDirs = ["src/main/java", "src/main/resources"] // 이 경로에서
includes = ["**/*.xml", "**/application.properties"] // 이 유형의 파일을
}
}
}
XML 파일은 무엇이고 어째서 resources를 기본 폴더로 잡고 있을까?
src/main/java 디렉터리는 일반적으로 소스 코드가 위치하는 곳이다.
XML 파일은 소스 코드가 아니므로,
src/main/resources 디렉터리 내에 위치해야 한다.
MyBatis가 resources 디렉터리를 뒤지는 이유다.
그러나 가독성이 좋지 않지... 찾아가기도 어렵고...
SourceSet
이 때문에 sourceSet을 사용하는 것이다.
sourceSet은 Gradle의 리소스 복사 기능인데,
빌드 시 XML 파일을 클래스패스에 포함시켜준다.
다만... 스프링의 제어기능을 내가 제어해버리기 때문에 스프링의 유연성을 한계짓는다는 단점이 있다.
예를 들어 스프링은 앱을 구동할 때 application.properties 파일을 자동으로 찾아 실행해준다.
그런데 sourceSet을 사용할 경우, application.properties을 찾으라고 명시해주지 않으면, 찾지 못한다.
sourceSets {
main {
resources { // 리소스 파일을 찾는다.
srcDirs = ["src/main/java", "src/main/resources"] // 이 경로에서
// 이 때 srcDirs에서 resources를 지정하지 않으면 ~.properties 파일도 찾을 수 없게 되어서 앱이 실행되지 못한다.
// 이걸 지정하는 순간 정말 고대로 여기서 지정한 디렉터리만 검색을 하게 되는 것이다.
includes = ["**/*.xml", "**/application.properties"] // 이 유형의 파일을
}
}
}
그래서 xml 파일뿐만 아니라, application.properties파일도 찾으라고 지정을 해줘야하는 것.
srcDirs
이 속성을 통해 Gradle에게 프로젝트에서 소스 파일이 어디에 있는지를 알려준다.
includes, exclude
포함할 파일, 배제할 파일의 유형을 지정할 수 있다.
이 아래부터는 삽질 기록이다.
안해도 됨 → application.properties에 아래 값을 코딩하기
mybatis.config-location=classpath:mybatisConfig.xml
mybatis.mapper-locations=**/*.xml
그래도 삽질 덕에 위 코드에 대해 알게 된 점들 정리해본다.
mybatis.config-location 말 그대로 mybatisConfig.xml 파일의 위치를 말한다. (이 때 값을 빈값으로 둔다면, mybatisConfig.xml 파일을 무시한다. 오직 application.properties 설정으로 처리하게 된다.)
mybatis.mapper-locations= 말 그대로 mapper.xml 파일의 위치를 말한다.
's'의 유무를 잘 확인하시길 ㅎ;
classpath는 main/resoucres/를 가르킨다.
classpath*: | classpath: | |
설명 | 클래스패스 내의 모든 경로에서 일치하는 자원을 찾을 때 | 클래스패스 내에서 단일 자원을 찾을 때 |
동작 방식 | JAR 파일을 포함하여 클래스패스의 여러 위치에서 일치하는 모든 자원을 로드한다. | 클래스패스에서 하나의 위치에서 첫 번째로 일치하는 파일을 로드한다. |
사례 | classpath*:**/*.xml은 클래스패스의 모든 경로(다중 경로 포함)에서 *.xml 파일을 검색한다. 즉, 여러 경로에 있는 XML 파일들을 모두 로드한다. | classpath:mybatisConfig.xml은 클래스패스 내에서 mybatisConfig.xml 파일을 찾고, 첫 번째 일치하는 파일을 로드한다. |
안해도 됨 → mybatisConfig.xml에 아래 값을 코딩하기
xml 선언문이 없으면 인식하지 못할 수도 있대서 넣어봤으나 효과는 없었다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
xml 파일을 찾으라고 지시해주기. 역시 효과는 없었다.
<mapper resource="org/inin/mycinema/**/*.xml"/>
이 때 온점이 아니라 슬래쉬를 사용하는 것에 대해서 : 온점은 java에서 패키지를 관리할 때 사용하는 방식이므로, mybatis는 경로를 의미하는 슬래쉬를 넣어주는 것이 더 합당하다 볼 수 있겠다.
이 값들을 설정할 땐 application.properties나 mybatisConfig.xml이나 둘 중 하나에만 작성하는 게 나은 것 같다. 둘 다 넣으니 충돌나는 것 같음.
안해도 됨 → @MapperScan 사용하기
main 함수가 있는 클래스에 @MapperScan 어노테이션을 사용하라는 말도 많이 있었다.
@MapperScan("org.inin.mycinema")
상위 패키지에서 하위 패키지를 모두 스캔하는 설정.
여담. resouces폴더는 java가 아니므로 . 을 사용하여 접근할 수 없다.
resources 하위는 package경로가 아닌 directory 경로로 접근하게 된다.
만약 resources 밑에 새로운 디렉터리를 추가할 때 '.'을 사용하여 한번에 처리하려고 했다면 문제가 된다.
예를 들어 당신이 새로운 경로를 만들 때 'service.myservice.mapper.helloMapper'라고 경로를 추가했다면 이는
service
ㄴmyservice
ㄴ mapper
ㄴ helloMapper
라는 4레벨 뎁스의 모양이 아니라
service.myservice.mapper.helloMapper 라는 1레벨 뎁스의 경로가 생겨난다는 것이다. 그냥 긴 폴더명인 셈...
그럼 어떻게 하라고...? 디렉터리를 손수 하나하나 추가해주시면 된다. 이런다면 service/myservice/mapper/helloMapper 처럼 경로가 생기게 되는 것이다.
어찌보면 점(.)으로 접근하는 package는 자바 시스템의 부속품이니까... resources에서 동작 안하는 건 당연한걸지도...
resources에 mapper를 넣을 생각이 없는 나와는 상관없는 이슈였다만 읽으면서 재밌어서 추가해둔다.
https://woo-chang.tistory.com/58
'┝ framework > ┎ Spring' 카테고리의 다른 글
인증, 인가, JWT, Session, OAuth (0) | 2025.02.18 |
---|---|
spring webflux란? (0) | 2025.02.10 |
public String test(Model model) 에서 model은 왜 리턴타입이 아닌 파라미터로 있는걸까요 (0) | 2024.10.15 |
[java] RestTemplate의 get~ 메소드 중에는 왜 request 인자가 없을까? (0) | 2024.10.12 |
[spring] @Autowired와 생성자, mybatis의 mapper interface (0) | 2022.07.14 |