▸Spring MVC/기본 문법

스프링, Mybatis, MySQL_사용법(Mapper 인터페이스) [3/5]

코데방 2020. 3. 22.
728x90
- Develop OS : Windows10 Ent, 64bit
- WEB/WAS Server : Tomcat v9.0
- DBMS : MySQL 5.7.29 for Linux (Docker)
- Language : JAVA 1.8 (JDK 1.8)
- Framwork : Spring 3.1.1 Release
- Build Tool : Maven 3.6.3
- ORM : Mybatis 3.2.8

 

[ Mapper 인터페이스 ]

  • Mapper 설정 파일(xml)에 있는 SQL 쿼리문을 호출하기 위한 인터페이스
  • Mybatis3.0 이후부터 지원하는 방식

이전 방식이 Mapper 설정 파일(xml)에 있는 쿼리문의 ID를 직접 String 형태로 지정해서 사용했다면, Mapper 인터페이스를 사용한 방식은 인터페이스와 Mapper 설정 파일을 연동해두고 쿼리문의 ID와 동일한 메소드를 만들어둠으로써 해당 메소드를 호출하면 자동으로 쿼리문이 실행되도록 해주는 방식입니다.

 

메소드 방식으로 사용하니 IDE의 자동완성 기능을 활용할 수도 있고, 오탈자로 인한 실수를 예방하는 등의 장점이 있습니다. Mapper xml 파일 하나 당 하나의 인터페이스를 만들어주면 되는데, 이 인터페이스 자체가 DAO의 역할을 하게 됩니다. 별도의 DAO를 만들지 않고 Mapper 인터페이스를 DAO로 사용하는 사례들이 많습니다. 직접 작성하던 DAO 자체를 Mabatis에서 만들어준다고 볼 수 있습니다. 필요에 따라 둘 다 사용할 수도 있겠지만 불필요한 코드의 중복이 늘어날 가능성도 있습니다.

 

 

 

* 기존 방법

session.update("userDB.updateUser", vo);

 

 

* Mapper 인터페이스를 사용한 방법

		UserInfoMapper mapper = session.getMapper(UserInfoMapper.class);
		UserInfoVO vo = mapper.selectOne(userId);

 

기존 사용하던 SqlSessionTemplate 객체에 매퍼를 요청하면, xml 설정을 참조해 Mapper 인터페이스를 오버라이딩한 객체를 반환해줍니다. 그리고 이 객체의 메소드를 실행하면 결국 xml에서 설정해둔 SQL 쿼리가 실행되는 것과 동일하게 작동합니다. 자바의 메소드 형태로 쿼리문을 실행할 수 있도록 해줬기 때문에 조금 더 안정성 있는 재사용이 가능하다는 장점이 있고, DAO에 필요한 대부분의 기능을 Mybatis에서 작성해줍니다.

 

트랜잭션의 경우 쿼리를 호출하는 서비스 클래스의 메소드에 적용해주면 됩니다. 트랜잭션은 다음글을 참조해주시기 바랍니다. 

 

[Spring MVC/- 기본 문법] - 스프링, Mybatis, MySQL_트랜잭션 처리 [4/4]

 

 

 


 

 

 

[ Mybatis Mapper 인터페이스 사용 방법 ]

 

기본적인 Mybatis 설정 및 사용법은 이전글을 참조하시면 됩니다.

[Spring MVC/- 기본 문법] - 스프링, Mybatis, MySQL_연동 및 설정 방법 [1/4]

[Spring MVC/- 기본 문법] - 스프링, Mybatis, MySQL_사용법 [2/4]

 

 

 

1. 환경설정 파일에 VO 객체 등록

이전글에서 설명한 부분은 넘어가겠습니다.

 

추가로 주의해야할 점으로는 VO 객체에 생성자를 둘 경우, 생성자가 있을 경우와 생성자가 없을 경우를 모두 오버로딩해서 작성해줘야 한다는 것입니다. 리턴 타입이 VO 객체일 경우 Mybatis는 빈 객체 "new VO()"로 인스턴스를 생성한 뒤 setter를 통해 값을 주입해서 반환해줍니다. 이 때 생성자가 무조건 있어야 하는 VO라면 인스턴스 생성에 실패해서 예외를 뱉어내게 됩니다. 따라서 아래와 같이 오버로딩을 해줘야 합니다.

	// 생성자 오버로딩 필수
    
	// 생성자 있을 경우    
	public UserRememberMeVO(String username, String series, String token,
			Date lastUsed) {
		super();
		this.username = username;
		this.series = series;
		this.token = token;
		this.lastUsed = lastUsed;
	}
	
	// 생성자 없을 경우(Mybatis를 위함)
	public UserRememberMeVO() {
		
	}
<?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">

<configuration>
	<typeAliases>
		<typeAlias alias="UserInfoVO" type="hs.spring.hsweb.user.db.UserInfoVO" />
	</typeAliases>
</configuration>

 

 

 

2. Mapper xml 파일 작성

역시 이전과 작성 방법은 동일한데, 한 가지 다른점은 namespace에 인터페이스의 전체 경로를 기입해줘야 한다는 것입니다. 이 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="hs.spring.hsweb.user.db.UserInfoMapper">

	<select id="selectOne" parameterType="String" resultType="UserInfoVO">
		select * from user_info where user_id = #{value}
	</select>

</mapper>

 

 

 

3. Mapper 인터페이스 작성

package hs.spring.hsweb.user.db;

public interface UserInfoMapper {

	// 아이디 1개 select
	public UserInfoVO selectOne(String userId); 
}

 

 

 

4. Service 작성

기존에 사용하던 SqlSessionTemplate 객체에서 getMapper() 메소드를 실행해 오버라이딩된 인터페이스 객체를 얻어오면 됩니다. SqlSession 객체는 인터페이스입니다.

@Service
public class UserInfoService {

	@Resource(name="sqlSessoinTemplate")
	private SqlSession session;
	
	// selectOne
	public UserInfoVO selectOne(String userId) {

		// Mapper 인터페이스 객체 반환
		UserInfoMapper mapper = session.getMapper(UserInfoMapper.class);
		
		// xml 내용대로 오버라이딩된 인터페이스의 메소드 실행 
		UserInfoVO vo = mapper.selectOne(userId);
		
		return vo;
	}
}

 

 

 

5. 실행 테스트

 

간단히 jUnit을 사용해 테스트했습니다. @Service 어노테이션을 사용해 Bean으로 등록했으므로 컨테이너에서 가져와 사용할 수 있습니다.

 

[Spring MVC/- 개발 TIP] - jUnit, Spring-Test 라이브러리 사용법

 

	@Test
	public void mybatisInterface() {
		
		UserInfoService service = (UserInfoService) ctx.getBean("userInfoService");
		UserInfoVO vo = service.selectOne("codevang1004");
		System.out.println(vo.getUser_id());
		System.out.println(vo.getUser_pw());
	}

 

 

 


 

 

 

[ Mapper 인터페이스의 변환을 Bean으로 등록해 사용하는 방법 ]

 

위와 같이 SqlSessionTemplate에서 mapper 인터페이스 객체를 받아 사용하는 방법도 있지만, 미리 모든 mapper 인터페이스를 컨테이너에 bean으로 생성해둔 뒤 가져다 사용하는 방법도 있습니다.

 

내부적으로는 위의 과정을 수행하겠지만, 개발자 입장에서는 더 이상 코드에서 SqlSessionTemplate 객체를 생성할 필요 없이 필요한 Mapper 인터페이스 객체만 컨테이너에서 찾아와 사용해주면 됩니다.

 

 

1. 어노테이션 생성

MapperScannerConfigurer 클래스는 특정 범위에서 한번에 Mapper 인터페이스를 검색해서 각자 xml 설정에 맞게 오버라이딩한 뒤 Bean으로 만들어주는 역할을 합니다. Mapper 인터페이스만 따로 보관하는 전용 패키지를 만들 경우 문제가 없겠지만, 만약 다른 인터페이스가 같이 존재한다면 예외가 발생합니다. 따라서 해당 인터페이스가 Mapper 인터페이스라는 것을 명시해줄 어노테이션을 하나 만들어줍니다.

 

package hs.spring.hsweb.config;

public @interface MapperInterface {

}

 

 

 

2. Mapper 인터페이스에 어노테이션 선언

package hs.spring.hsweb.user.db;

import hs.spring.hsweb.config.MapperInterface;

@MapperInterface
public interface UserInfoMapper {

	// 아이디 1개 select
	public UserInfoVO selectOne(String userId); 
}

 

 

 

3. 루트 컨테이너 xml 설정

DB 관련 설정이 들어있는 xml 파일에 아래 코드를 추가해줍니다. 자기 자신이 코드에서 불러질 일이 없기 때문에 Bean id를 설정하지 않아도 무방하지만 하고 싶으면 해도 됩니다. 그냥 자신이 Bean으로 생성하면서 Mapper 인터페이스를 Bean으로 생성해주는 역할만 수행합니다.

 

  • basePackage : 이 패키지 범위 내의 인터페이스를 스캔하겠다.
  • annotationClass : 이 어노테이션이 있는 인터페이스만 스캔하겠다.
	<!-- Mapper 인터페이스 스캔 및 Bean 등록 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="hs.spring.hsweb.*" />
		<property name="annotationClass" value="hs.spring.hsweb.config.MapperInterface" />
	</bean>

 

 

 

4. Service 작성

필요한 Mapper 객체들이 컨테이너에 Bean으로 등록되었으므로 더 이상 session을 사용할 필요 없이, 바로 Mapper 객체를 찾아오면 됩니다. 자동 생성된 Mapper 객체들의 Bean id는 클래스의 앞글자만 소문자로 바뀐 이름입니다.

 

@Service
public class UserInfoService {

	// UserInfoMapper의 객체 주입
	@Resource(name="userInfoMapper")
	UserInfoMapper mapper;
	
	// selectOne
	public UserInfoVO selectOne(String userId) {

		// xml 내용대로 오버라이딩된 인터페이스의 메소드 실행 
		UserInfoVO vo = mapper.selectOne(userId);
		return vo;
	}
}

 

 

 

5. 테스트 수행

테스트 코드는 위와 동일합니다. 

 

	@Test
	public void mybatisInterface() {
		
		UserInfoService service = (UserInfoService) ctx.getBean("userInfoService");
		UserInfoVO vo = service.selectOne("codevang1004");
		System.out.println(vo.getUser_id());
		System.out.println(vo.getUser_pw());
	}
728x90

댓글

💲 추천 글