1️⃣ DB 테이블 생성
2️⃣ Mapper XML & DTO 작성
데이터베이스 테이블로 부터 데이터를 CRUD를 하기 위한 sql문들을 작성
select를 하기 위한 resultType을 BoardDto로 설정
3️⃣ DAO 인터페이스 작성
4️⃣ DAO 인터페이스 구현 & 테스트
나중에 DAO가 바뀔 때 (데이터베이스 종류 등) @Service쪽에 영향을 받지 않게 class가 아닌 인터페이스로 주입받게 함
Mapper 작성한 다음에 바로 구현해도 된다.
➡️ Extract Interface 기능(intelliJ)을 쓰면 바로 인터페이스 만들 수 있음
JDBC 할 떄는 우리가 값도 세팅해주고 실행할 결과를 우리가 직접 꺼내서 써야 됐는데, MyBatic는 값을 지정하고 읽어오는 것을 자동으로 해주기 때문에 우리는 단순히 sqlSession에 있는 메서드를 호출만 해주면 된다. 그리고 input 값들 알맞게 지정해 주기! result 타입에 알맞게 쓰기!
✔️ 계층간의 데이터를 주고 받기 위해 사용되는 객체
int는 null이 뜨면 에러가 뜬다. ➡️ 변환 에러를 막기 위해 Integer 사용
데이터베이스의 값들을 DTO로 옮긴다. 그래서 타입이름이랑 다 맞아야 한다.
✔️ 관심사, 역할, 계층 분리
계층으로 분리를 해놓았기 때문에 각 계층마다 데이터를 주고 받아야 되는데 그 데이터를 DTO로 쓴다.
@Repository ➡️ DAO
DAO에서 Try-catch를 써서 예외를 처리하게 되면 커밋해야 될지 롤백해야 될지 트랜잭션에서는 모른다. 그래서 @Repository
에서는 예외처리를 하지 않는다. throws 해줘야 한다. @Service
에서 감당할 수 있는 부분만 예외처리 하고 할 수 없으면 @Contorller
로 던진다.
✔️ Mapper 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.fastcampus.ch4.dao.BoardMapper">
<select id="select" parameterType="int" resultType="BoardDto">
select bno,
title,
content,
writer,
view_cnt,
comment_cnt,
reg_date,
up_date
from board
where bno = #{bno}
</select>
</mapper>
<?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="BoardDto" type="kr.ac.jipark09.domain.BoardDto"/>
</typeAliases>
</configuration>
✔️ DAO & DTO 작성
package kr.ac.jipark09.dao;
import kr.ac.jipark09.domain.BoardDto;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@Repository
public class BoardDao {
@Autowired
SqlSession session;
String namespace = "kr.ac.jipark09.dao.BoardMapper.";
public BoardDto select(int bno) throws Exception {
return session.selectOne(namespace + "select", bno);
}
}
package kr.ac.jipark09.domain;
import java.util.Date;
import java.util.Objects;
public class BoardDto {
private Integer bno;
private String title;
private String content;
private String writer;
private int view_cnt;
private int comment_cnt; // 댓글 갯수
private Date reg_date;
public BoardDto() {}
public BoardDto(String title, String content, String writer) {
this.title = title;
this.content = content;
this.writer = writer;
}
public Integer getBno() {
return bno;
}
public void setBno(Integer bno) {
this.bno = bno;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getWriter() {
return writer;
}
public void setWriter(String writer) {
this.writer = writer;
}
public int getView_cnt() {
return view_cnt;
}
public void setView_cnt(int view_cnt) {
this.view_cnt = view_cnt;
}
public int getComment_cnt() {
return comment_cnt;
}
public void setComment_cnt(int comment_cnt) {
this.comment_cnt = comment_cnt;
}
public Date getReg_date() {
return reg_date;
}
public void setReg_date(Date reg_date) {
this.reg_date = reg_date;
}
@Override
public String toString() {
return "BoardDto{" +
"bno=" + bno +
", title='" + title + '\'' +
", content='" + content + '\'' +
", writer='" + writer + '\'' +
", view_cnt=" + view_cnt +
", comment_cnt=" + comment_cnt +
", reg_date=" + reg_date +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BoardDto boardDto = (BoardDto) o;
return Objects.equals(bno, boardDto.bno) && Objects.equals(title, boardDto.title) && Objects.equals(content, boardDto.content) && Objects.equals(writer, boardDto.writer);
}
@Override
public int hashCode() {
return Objects.hash(bno, title, content, writer);
}
}
✔️ DAO 인터페이스 구현 & 테스트
package kr.ac.jipark09.dao;
import kr.ac.jipark09.domain.BoardDto;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/spring/**/root-context.xml"})
public class BoardDaoImplTest {
@Autowired
BoardDao boardDao;
@Test
public void select() throws Exception {
BoardDto boardDto = boardDao.select(1);
System.out.println(boardDto);
assertTrue(boardDto.getBno().equals(1));
}
}
✔️ #{} ➡️ PreparedStatment
sql문에서 값에대해서만 ?를 쓸 수 있다.
: 타입에 따라서 따옴표를 달아주기 때문에 안붙여줘도 된다.
기본적으로 이것을 사용한다.
✔️ ${} ➡️ Statement
문자열을 구성하기 때문에 직접 따옴표를 달아줘야 한다.
테이블 이름도 ${tableName}으로 써도 된다.
➡️ 제약이 적고 유연함
➡️ 하지만 보안에 취약함
값을 동적으로 사용하기 위해 꼭 써야 한다면 내부적으로만 사용해야 한다.
✔️ XML내의 특수 문자(<, >, $, ...)는 < >로 변환 필요
✔️ 특수문자가 포함된 쿼리를 <![CDTA[...]]>로 감싼다.
< >
이렇게 바꿔줘야 한다.<![CDTA[... ]]>
로 감싸면 특수문자를 사용할 수 있게 된다. 이 안에서는 XML태그가 없다라는 것을 명시하게 된다. 전부 Character data라는 것Reference
: https://fastcampus.co.kr/dev_academy_nks