오늘은 Springboot와 Mybatis를 연동하는 방법에 대해 알아보도록 하겠다.
- SpringBoot (JAVA 11, Maven)
- Thymeleaf
- MySQL
- Spring Initializr 링크
https://start.spring.io
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>mybatisStudy</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mybatisStudy</name>
<description>for my mybatis study</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
전체 application.properties
# mysql config
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mytestdb?serverTimezone=UTC&characterEncoding=UTF-8
spring.datasource.username={본인DB's username}
spring.datasource.password={본인DB's password}
# mybatis config
mybatis.type-aliases-package=com.example.mybatisStudy.vo
mybatis.mapper-locations=mybatis/mapper/**/*.xml
소스 분석
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
JDBC 드라이버 클래스의 이름 지정 (위 클래스는 MySQL JDBC 드라이버 클래스)
spring.datasource.url=jdbc:mysql://localhost:3306/{본인db명}?serverTimezone=UTC&characterEncoding=UTF-8
본인 DB의 IP와 스키마 이름 지정 (나머지는 그대로 사용하고 {본인db명} 부분만 본인 db로 변경)
spring.datasource.username={본인DB's username}
spring.datasource.password={본인DB's password}
본인 DB의 username과 password 기입
mybatis.type-aliases-package={mapper resultType}
DB의 조회 결과 데이터를 담을 클래스 package 지정 (=resultType)
mybatis.mapper-locations={mapper 경로}
mapper가 위치한 경로 설정
Controller
package com.example.mybatisStudy.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import com.example.mybatisStudy.service.MemberService;
import com.example.mybatisStudy.vo.MemberVo;
@Controller
@RequestMapping("/")
public class MemberController {
@Autowired
private MemberService memberService;
@RequestMapping(value="/index")
public String index(Model model) {
List<MemberVo> memberList = memberService.getAllMember();
System.out.println("size: " + memberList.size());
model.addAttribute("memberList",memberList);
return "index";
}
}
List<MemberVo> memberList = memberService.getAllMember();
-> MemberVo 객체 리스트를 List형태로 불러온다.
model.addAttribute("memberList",membetList);
-> Thymeleaf를 통해 memberList 데이터를 가져와 뿌려주기 위해 Model 사용
Service
// Service.java
package com.example.mybatisStudy.service;
import java.util.List;
import com.example.mybatisStudy.vo.MemberVo;
public interface MemberService {
public List<MemberVo> getAllMember();
}
// ServiceImpl.java
package com.example.mybatisStudy.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.mybatisStudy.repository.MemberRepository;
import com.example.mybatisStudy.service.MemberService;
import com.example.mybatisStudy.vo.MemberVo;
@Service
public class MemberServiceImpl implements MemberService{
@Autowired
private MemberRepository memberRepository;
@Override
public List<MemberVo> getAllMember(){
return memberRepository.getAllMember();
}
}
현재 프로젝트는 Mybatis 연동을 위한 단순 기능만을 제공하므로 Service단은 다른 로직 없이 바로 Dao로 넘긴다.
@Override
public List<MemberVo> getAllMember(){
return memberRepository.getAllMember();
}
Repository
package com.example.mybatisStudy.repository;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.example.mybatisStudy.vo.MemberVo;
@Mapper
public interface MemberRepository {
List<MemberVo> getAllMember();
}
@Mapper
public interface MemberRepository {
List<MemberVo> getAllMember();
}
기존 Spring MVC는 SqlSession, SqlSessionFactory와 같은 클래스를 통해 설정하고 Dao단에서 selectOne과 같은 함수를 call하여 처리했다.
SpringBoot의 @Mapper를 사용하게 되면 application.properties에서 설정한 경로를 바탕으로 알아서 쿼리 xml 파일과 매핑해주기 때문에 위의 일련의 과정을 생략할 수 있다.
- Vo
package com.example.mybatisStudy.vo;
public class MemberVo {
private String user_no;
private String user_nm;
private String user_id;
public String getUser_no() {
return user_no;
}
public void setUser_no(String user_no) {
this.user_no = user_no;
}
public String getUser_nm() {
return user_nm;
}
public void setUser_nm(String user_nm) {
this.user_nm = user_nm;
}
public String getUser_id() {
return user_id;
}
public void setUser_id(String user_id) {
this.user_id = user_id;
}
}
lombok을 사용해서 코드를 간결히 처리할 수도 있지만 이번 프로젝트는 lombok 사용이 주요 목표가 아니니 getter/setter를 각각 만들어주었다.
- Mybatis 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.example.mybatisStudy.repository.MemberRepository">
<select id="getAllMember" resultType="MemberVo">
SELECT user_no, user_nm, user_id FROM MEMBER_INFO
</select>
</mapper>
<?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">
위 부분은 Mybatis를 사용하기 위한 기본 설정부분으로 똑같이 기입해주면 된다.
<mapper namespace="com.example.mybatisStudy.dao.MemberDao">
<select id="getAllMember" resultType="MemberVo">
SELECT user_no, user_nm, user_id FROM MEMBER_INFO
</select>
</mapper>
namespace부분은 @Mapper와 매핑시키기 위한 경로를 기입하는 부분으로
본인이 @Mapper 어노테이션으로 Mapper를 만들어놓은 경로를 입력해주면 된다.
resultType은 원래 전체 패키지경로를 입력해줘야하지만 앞서 application.properties에서
mybatis.type-aliases-package=com.example.mybatisStudy.vo
위와 같이 상위 패키지명을 기입해줬기 때문에 해당 경로 하위 객체명만 기입해주면 된다.
<!DOCTYPE html>
<html>
<head lang="en" xmlns:th="http://thymeleaf.org">
<meta charset="UTF-8">
<style>
table {
font-family: arial, sans-serif;
border-collapse: collapse;
width: 100%;
}
td, th{
border: 1px solid black;
text-align: left;
}
tr:nth-child(even){
background-color:#dddddd;
}
</style>
<title>Insert title here</title>
</head>
<body>
<h1>회원 리스트</h1>
<table>
<thead>
<tr>
<th>회원번호</th>
<th>아이디</th>
<th>이름</th>
</tr>
</thead>
<tbody>
<tr th:each="member : ${memberList}">
<td><span th:text="${member.user_no}"></span></td>
<td><span th:text="${member.user_id}"></span></td>
<td><span th:text="${member.user_nm}"></span></td>
</tr>
</tbody>
</table>
</body>
</html>
<tbody>
<tr th:each="member : ${memberList}">
<td><span th:text="${member.user_no}"></span></td>
<td><span th:text="${member.user_id}"></span></td>
<td><span th:text="${member.user_nm}"></span></td>
</tr>
</tbody>
Thymeleaf를 사용하게 되면 Back단에서 Model 객체를 통해 넘긴 값을 바로 받아서 사용할 수 있다.
th:each문을 통해 해당 객체 리스트를 받아오고 th:text를 통해 객체 내부 값을 출력하도록 만든다.
Thymeleaf는 이번 주제와 상관없는 부분이기 때문에 이에 대한 문법은 추후, 따로 작성해보도록 하겠다.
프로그래밍 설계도 있을까요?