Spring 12 MyBatis(설정)

Kang.__.Mingu·2024년 9월 16일

Spring

목록 보기
11/21

Spring MVC 기능을 사용해 웹프로그램을 작성하는 방법

작성 순서 및 이유

  1. Table 생성

    • 데이터베이스에 필요한 테이블을 먼저 설계하고 생성한다. 데이터 구조를 먼저 잡아야 DTO 및 MyBatis 설정 등을 진행할 수 있기 때문에 필수적인 첫 단계이다.
  2. DTO 클래스 작성

    • 데이터베이스의 테이블과 매핑되는 DTO(Data Transfer Object) 클래스를 작성한다. 테이블의 컬럼과 매핑되는 필드를 가지며, 데이터를 주고받는 데 사용된다.
  3. Mapper.xml, Mapper.java 작성

    • Mapper.xml: SQL 쿼리를 작성하는 XML 파일로, MyBatis에서 실행할 SQL을 정의한다.

    • Mapper.java: Mapper 인터페이스로, XML 파일과 바인딩되어 쿼리 메서드를 선언한다.

    • 이름을 같게 하는 이유

      • 바인딩의 일관성

        • Mapper 인터페이스와 Mapper XML 파일의 이름을 동일하게 함으로써, 서로 바인딩이 쉽고 명확하게 이루어진다.
      • 유지보수성

        • 이름이 동일하면 파일을 찾고 관리하기 쉽다. 예를 들어, UserMapper.javaUserMapper.xml이 서로 바인딩되어 있어야 어떤 인터페이스와 어떤 XML이 연결되는지 혼동하지 않고 쉽게 파악할 수 있다.
      • MyBatis에서 자동 바인딩

        • MyBatis는 인터페이스와 XML의 네임스페이스가 일치하는 경우 자동으로 매핑한다. 이름을 동일하게 함으로써, 이 자동 매핑 기능을 활용하여 설정을 간단하게 유지할 수 있다.
  4. DAO 인터페이스와 클래스 작성

    • DAO 인터페이스
      • 데이터베이스와의 상호작용을 정의하는 메서드의 인터페이스 작성
    • DAO 클래스
      • DAO 인터페이스의 구현체로, 실제 비즈니스 로직을 구현하고 데이터베이스 쿼리를 실행하는 역할을 한다.
  5. Service 인터페이스와 클래스 작성

    • Service 인터페이스

      • 비즈니스 로직을 정의한다. DAO와 Controller 사이에서 중간 로직을 담당하며, 트랜잭션 처리 등을 관리한다.
    • Service 클래스

      • 인터페이스의 구현체로, 실제 비즈니스 로직을 수행하고, 필요한 경우 여러 DAO를 호출하여 복합적인 데이터를 처리한다.
  6. Controller 클래스 작성

    • 사용자의 요청을 처리하고, Service를 통해 비즈니스 로직을 실행하며, View로 데이터를 전달한다.

인터페이스와 클래스 작성의 의존성

  • 의존성을 높이는 것이 아닌, 낮추는 목적이다. 인터페이스와 클래스를 나누는 이유는 의존성을 낮춰서 코드의 유연성과 확장성을 높이는 것이다.

  • 의존성 주입(DI, Dependency Injection)
    Spring에서는 인터페이스를 통해 의존성 주입을 사용하여 구현체를 변경할 때 코드 수정을 최소화할 수 있다.

  • 확장성과 유지보구성
    인터페이스를 통해 코드가 특정 구현체에 의존하지 않도로고 만들면, 구현체 변경 시 코드 수정이 필요 없는 경우가 많아 유지보수가 용이해진다.


MyBatis 프레임워크의 로그 팩토리에 의해 발생되는 로그 이벤트를 Spring 프레임워크의 로그 구현체로 기록하는 방법

  1. log4jdbc-log4j2-jdbc4 라이브러리를 프로젝트에 빌드 처리 - 메이븐 : pom.xml

  2. Spring Bean Configuration File(root-context.xml)에서 DataSource 관련 클래스를 Spring Bean으로 등록한 bean 엘리먼트에서 driverClassName 필드와 url 필드에 저장된 값 변경

  3. [src/main/resources] 폴더에 [log4jdbc.log4j2.properties] 파일 작성
    => MyBatis 프레임워크에서 발생되는 로그 이벤트를 Spring 프레임워크의 로그 구현체에게 제공하기 위한 SpyLogDelegator 클래스를 설정하기 위한 파일

  4. SpyLogDelegator 객체에 의해 발생된 로그 이벤트를 Spring 프레임워크의 로그 구현체로 기록되도록 환경설정파일(log4j.xml) 변경 - logger 엘리먼트 추가


Spring MVC 기능으로 웹프로그램 작성시 MyBatis 프레임워크를 사용해 DAO 클래스를 작성하는 방법

  1. DataSource 관련 라이브러리와 MyBatis 관련 라이브러리를 프로젝트에 빌드 처리 - 메이븐 : pom.xml
    => ojdbc, spring-jdbc(spring-tx), mybatis, mybatis-spring
<!-- https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc11 -->
<!-- => Oracle DBMS Server에 접속할 수 있는 Driver 기능을 제공하기 위한 라이브러리 -->
<dependency>
	<groupId>com.oracle.database.jdbc</groupId>
	<artifactId>ojdbc11</artifactId>
	<version>23.5.0.24.07</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<!-- => Spring DAO 관련 기능을 제공하기 위한 라이브러리 - DataSource 관련 클래스 포함 -->
<!-- => 라이브러리 의존 관계에 의해 spring-tx 라이브러리(트렌젝션 처리)도 자동으로 빌드 처리 -->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-jdbc</artifactId>
	<version>${org.springframework-version}</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<!-- => Mybatis 프레임워크를 사용하기 위한 라이브러리 -->
<dependency>
	<groupId>org.mybatis</groupId>
	<artifactId>mybatis</artifactId>
	<version>3.5.16</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
	<groupId>org.mybatis</groupId>
	<artifactId>mybatis-spring</artifactId>
	<version>2.1.2</version>
</dependency>
  1. MyBatis 프레임워크의 환경설정파일(mybatis-config.xml - setting 엘리먼트) 작성
    => [src/main/webapp] 폴더에 환경설정파일을 작성해야 스프링 컨테이너(WebApplicationContext 객체)가 환경설정파일을 제공받아 SqlSessionFactory 객체 생성 가능

  2. Spring Bean Configuration File(root-context.xml)에 DataSource 관련 클래스, SqlSessionFactory 관련 클래스, SqlSession 관련 클래스, TransactionManager 관련 클래스를 Spring Bean으로 등록

  3. 매퍼 파일을 사용해 DAO 클래스 작성


Student

1. Student Table

이름       널?       유형            
-------- -------- ------------- 
NO       NOT NULL NUMBER(4)     
NAME              VARCHAR2(50)  
PHONE             VARCHAR2(20)  
ADDRESS           VARCHAR2(100) 
BIRTHDAY          DATE          

항상 테이블 먼저 설계 및 생성

2. Student DTO 클래스

  • 테이블의 행을 Java 클래스로 표현해 객체로 생성하기 위한 클래스

  • 데이터 처리 클래스(DAO 클래스 또는 Service 클래스)의 메소드에서 매개변수로 값을 전달받거나 값을 변환하기 위해 작성하는 클래스

  • Controller 클래스의 요청 처리 메소드의 매개변수로 전달값이 저장된 Command 객체로 제공받기 위해 사용 - 전달값의 이름과 필드의 이름이 같도록 작성해야됨

  • MyBatis 프레임워크를 사용할 경우 검색행의 컬럼값이 저장하기 위해 컬럼명과 같은 이름으로 필드를 작성해 자동 매핑되도록 설정해야한다.

@Data // Setter 메소드, Getter 메서드 등등 제공
@Builder // 객체 생성시 객체 필드에 필요한 값만 저장하기 위한 메서드
public class Student {
	private int no;
	private String name;
	private String phone;
	private String address;
	private String birthday;
}

3. StudentMapper(XML, Java)

StudentMapper.xml

Mapper.xml에서 사용되는 <mapper> 엘리먼트와 namespace 속성은 MyBatis에서 SQL 문과 Java 코드 간의 연결을 설정하는 데 중요한 역할을 한다. 이 요소들은 MyBatis가 SQL 쿼리를 올바르게 찾아서 실행하고, Java 인터페이스 메서드와 연동될 수 있도록 도와준다.

  1. <mapper> 엘리먼트

    • MyBatis에서 SQL 문을 정의하는 XML 파일의 루트 엘리먼트이다. <mapper> 엘리먼트는 XML 문서의 시작점으로, 그 내부에 SQL 쿼리를 정의하는 <select>, <insert>, <update>, <delete> 등의 요소를 포함한다.

    • <mapper> 엘리먼트는 반드시 namespace 속성을 포함해야 하며, XML 파일의 최상단에 위치한다.

  2. namespace 속성

    • namespace 속성은 해당 Mapper XML 파일이 어떤 Java 인터페이스와 연결되는지를 명시합니다. 쉽게 말해, 이 XML 파일의 SQL 쿼리들이 어떤 Java 인터페이스의 메서드들과 매핑되는지를 정의하는 것이다.
<mapper namespace="xyz.itwill09.mapper.StudentMapper">
	<insert id="insertStudent">
		insert into student values(#{no}, #{name}, #{phone}, #{address}, #{birthday})
	</insert>
	
	<select id="selectStudentList" resultType="Student">
		select no, name, phone, address, birthday from student order by no
	</select>
</mapper>

resultType

resultType 속성은 MyBatis의 <select> 엘리먼트에서 SQL 쿼리의 결과를 어떤 Java 객체로 매핑할지 지정하는 데 사용된다. 이 속성은 쿼리의 결과가 Java 객체로 자동으로 변환될 수 있도록 도와주고, 주로 DTO 클래스나 기본 Java 타입을 지정한다.

  • 쿼리 결과 자동 매핑
    MyBatis는 쿼리 결과의 컬럼 이름과 resultType으로 지정된 클래스의 필드 이름을 기준으로 자동으로 매핑한다. 예를 들어 SQL 쿼리에서 no, name, phone과 같은 컬럼을 반환하면, MyBatis는 이를 Student 클래스의 no, name, phone 필드에 자동으로 매핑한다.

resultMap

resultType이 간단한 자동 매핑을 제공한다면, resultMap은 복잡한 매핑 요구사항을 처리할 수 있다.

  • 정밀한 매핑
    resultMap은 SQL 쿼리 결과를 Java 객체로 매핑할 때, 컬럼과 객체 필드 간의 매핑을 상세하게 설정할 수 있다. 컬럼 이름과 객체 필드 이름이 다를 때나, 복합 객체를 매핑할 때 유용하다.

StudentMapper.java

public interface StudentMapper {
	// Student 객체를 입력받아 해당 객체의 데이터를 데이터베이스에 삽입하는 역할
	int insertStudent(Student student);
	// 데이터베이스에서 모든 학생 정보를 조회하여 반환하는 역할, Student 객체가 담긴 리스트가 반환
	List<Student> selectStudentList();
}

StudentDAO.java, StudentDAOImpl.java

  • DAO 클래스(Repository 클래스)
    저장매체에 행을 삽입하거나 저장된 행을 변경, 삭제, 검색하는 기능을 제공하기 위한 클래스

  • DAO 클래스가 교체되어도 의존관계로 설정된 Service 클래스에 영향을 최소화 하기 위해 인터페이스를 받아 구현체로 작성하는 것을 권장 - 유지보수의 효율성 증가

  • DBMS 서버를 저장매체로 사용해 SQL 명령을 전달하여 행의 삽입, 변경, 삭제, 검색 처리
    => DAO 클래스의 메소드는 DBMS 서버에 접속해 하나의 SQL 명령을 전달하여 실행하고 실행결과를 Java 객체(값)으로 반환되도록 작성 - JDBC

StudentDAO.java

public interface StudentDAO {
	int insertStudent(Student student);
	List<Student> selectStudentList();
}

StudentDAOImpl.java

  • DAO 클래스는 Service 클래스에서 객체로 제공받아 사용할 수 있도록 Spring Bean으로 등록

  • DAO클래스는 @Repository 어노테이션을 사용하여 Spring Bean으로 등록 처리

  • @Repository 어노테이션을 스프링 컨테이너가 처리하기 위해서는 반드시 클래스가 작성된 패키지 Spring Bean Configuration File(servlet-context.xml)의 component-scan 엘리먼트로 검색되도록 설정

@Repository
//final 제한자를 사용한 필드만 초기화 처리하는 생성자를 만들어 주는 어노테이션
@RequiredArgsConstructor
public class StudentDAOImpl implements StudentDAO {
	//DAO 클래스의 메소드에서는 매퍼에 등록된 SQL 명령을 제공받아 DBMS 서버에 전달하여 실행하고
	//실행결과를 Java 객체로 반환받기 위해 SqlSession 객체 필요
	// => SqlSession 객체가 저장될 수 있는 필드를 작성해 스프링 컨테이너로부터 객체를 제공받아
	//필드에 저장되도록 의존성 주입
	
	//필드에 @Autowired 어노테이션을 사용해 객체가 저장되도록 의존성 주입 
	// => 필드 레벨의 의존성 주입
	//@Autowired
	//private SqlSession sqlSession;

	//@Autowired 어노테이션을 사용한 생성자로 필드에 객체가 저장되도록 의존성 주입 
	// => 생성자 레벨의 의존성 주입 : 순환참조 방지
	// => 생성자를 하나만 작성된 경우 @Autowired 어노테이션 생략 가능
	private final SqlSession sqlSession;

	@Override
	public int insertStudent(Student student) {
		return sqlSession.getMapper(StudentMapper.class).insertStudent(student);
	}

	@Override
	public List<Student> selectStudentList() {
		return sqlSession.getMapper(StudentMapper.class).selectStudentList();
	}
}

sqlSession

sqlSession 객체는 MyBatis에서 SQL 명령을 실행하고, 데이터베이스와 상호작용하는 핵심 역할을 한다. sqlSession.getMapper(StudentMapper.class)를 사용하여 StudentMapper 인터페이스의 구현체를 얻어오고, 그 구현체의 메서드를 호출하여 SQL 명령을 실행한다.

StudentService.java, StudentServiceImpl.java

StudentService.java

public interface StudentService {
	void addStudent(Student student);
	List<Student> getStudentList();
}

StudentServiceImpl.java

  • Service 클래스
    클라이언트 요청에 대한 데이터 처리 기능을 제공하기 위한 클래스

  • Service 클래스의 메소드는 데이터 처리 기능에 필요한 명령을 DAO 객체의 메소드를 호출해 작성

  • Service 클래스가 교체되어도 의존관계로 설정된 Controller 클래스에 영향을 최소화 하기 위해 인터페이스를 받아 구현체로 작성하는 것을 권장 - 유지보수 효율성 증가

  • Service 클래스는 Controller 클래스에서 객체로 제공받아 사용할 수 있도록 Spring Bean으로 등록

  • Service 클래스는 @Service 어노테이션을 사용하여 Spring Bean으로 등록 처리

  • @Service 클래스는 @Service 어노테이션을 사용하여 Spring Bean으로 등록 처리

  • @Service 클래스는 어노테이션을 스프링 컨테이너가 처리하기 위해서는 반드시 클래스가 작성된 패키지를 Spring Bean Configuration File(servlet-context.xml)의 component-scan 엘리먼트로 검색되도록 설정

@Service
@RequiredArgsConstructor
public class StudentServiceImpl implements StudentService {
	//Service 클래스의 메소드에서는 DAO 클래스의 메소드를 호출할 수 있도록 DAO 객체 필요
	// => DAO 객체가 저장될 수 있는 필드를 작성해 스프링 컨테이너로부터 객체를 제공받아
	//필드에 저장되도록 의존성 주입 - 생성자 레벨의 의존성 주입
	private final StudentDAO studentDAO;

	@Override
	public void addStudent(Student student) {
		studentDAO.insertStudent(student);		
	}

	@Override
	public List<Student> getStudentList() {
		return studentDAO.selectStudentList();
	}
	
}

StudentController.java

  • Controller 클래스
    클라이언트의 요청을 처리하는 기능을 제공하기 위한 클래스

  • Controller 클래스의 요청 처리 메소드에서는 데이터 처리에 필요한 명령으로 Service 객체의 메소드를 호출해 작성

  • Controller 클래스는 Front Controller에서 객체로 제공받아 사용할 수 있도록 Spring Bean으로 등록

  • Controller 클래스는 @Controller 어노테이션을 사용하여 Spring Bean으로 등록 처리

  • @Controller 어노테이션을 스프링 컨테이너가 처리하기 위해서는 반드시 클래스가 작성된 패키지를 Spring Bean Configuration File(servlet-context.xml)의 component-scan 엘리먼트로 검색되도록 설정

@Controller
@RequiredArgsConstructor
@RequestMapping("/student")
public class StudentController {
	//Controller 클래스의 메소드에서는 Service 클래스의 메소드를 호출할 수 있도록 Service 객체 필요
	// => Service 객체가 저장될 수 있는 필드를 작성해 스프링 컨테이너로부터 객체를 제공받아
	//필드에 저장되도록 의존성 주입 - 생성자 레벨의 의존성 주입
	private final StudentService studentService;
	
	//학생정보를 입력받기 위한 JSP 문서의 뷰이름을 반환하는 요청 처리 메소드
	@RequestMapping(value = "/add", method = RequestMethod.GET)
	public String add() {
		return "student/student_add";
	}
	
	//학생정보를 전달받아 STUDENT 테이블에 행으로 삽입하고 학생목록을 출력하는 페이지를 요청할
	//수 있는 URL 주소로 응답하는 요청 처리 메소드
	@RequestMapping(value = "/add", method = RequestMethod.POST)
	public String add(@ModelAttribute Student student, Model model) {
		try {
			studentService.addStudent(student);
		} catch (Exception e) {
			model.addAttribute("message", "학생번호가 중복되거나 입력값에 문제가 있습니다.");
			return "student/student_add";
		}
		return "redirect:/student/display";//리다이렉트 이동
	}
	
	//STUDENT 테이블에 저장된 모든 행을 검색해 반환받은 학생목록을 Request Scope 속성값으로
	//저장하고 학생목록을 출력하는 JSP 문서의 뷰이름을 반환하는 요청 처리 메소드
	@RequestMapping("/display")
	public String display(Model model) {
		model.addAttribute("studentList", studentService.getStudentList());
		return "student/student_display";
	}
}
profile
최선을 다해 꾸준히 노력하는 개발자 망고입니당 :D

0개의 댓글