1. BoardDao의 작성
1) DB테이블 생성

2) Mapper XML & DTO 작성
<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
FROM board
WHERE bno = #{bno}
</select>
DB테이블로부터 CRUD하기 위한 SQL문들을 작성해야한다.
3) DAO 인터페이스 작성
public interface BoardDao {
BoardDto select(Integer bno) throws Exception;
int delete(Integer bno) throws Exception;
int insert(BoardDto bno) throws Exception;
int update(BoardDto bno) throws Exception;
int increaseViewCnt(Integer bno) throws Exception;
}
4) DAO 인터페이스 구현 & 테스트
@Repository
public class BoardDaoImpl implements BoardDao {
@Autowired
private SqlSession session;
private static String namespace = "com.fastcampus.ch4.dao.BoardMapper.";
public BoardDto select(Integer bno) throws Exception {
return session.selectOne(namespace + "select", bno);
} // T selectOne(String statement, Object parameter)
2. DTO란? Data Transfer Object
- 계층간의 데이터를 주고 받기 위해 사용되는 객체
create table board {
bno int auto_increment primary key,
title varchar(45) not null,
content text not null,
writer varchar(30) not null,
view_cnt int default 0 not null,
comment_cnt int default 0 null,
reg_date datetime null
};
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;
// 생성자, getter & setter, toString()
// ...
}
게시판에서 글을 읽을 때 DB 테이블에 있는 데이터를 BoardDto라는 객체에 담아서 가져와야하고,
게시판에 글을 쓸 때는 Dto라는 객체에 값을 채워서 DB에 있는 Board 테이블에 저장하는 것이다.
게시물 번호는 INTEGER로 설정하였는데, 변환 에러를 피하기 위해 int 대신 사용했다.

사용자가 요청한 데이터를 DTO에 담아서 Service 계층 -> Repository 계층으로 데이터를 전달할 필요가 있다.
계층으로 분리를 해놓았기 때문에 각 계층간에 데이터를 전달할 때 사용하는게 DTO이다.
해당 데이터가 DB에 저장되고, 조회를 하면 그 조회를 한 데이터를 DTO에 담아서 각 계층을 거쳐서 응답하게
되는 것이다.
@Repository 계층 DAO에서는 예외처리를 하지 않고, 예외를 던진다.
@Service 계층에서 던진 예외를 받으면 예외는 @Controller와 @Service가 둘 다 처리한다.(예외 되던지기)
@Service에서 예외를 처리하면 @Controller는 해당 예외를 알 수 없으므로, @Service가 예외의 일부는
처리하고 다시 예외를 던져서 @Controller에서도 예외를 처리할 수도 있다.
@Service, @Controller, 둘 다 처리 중 어떻게 예외를 처리할지는 고민 사항이며,
복잡하면 @Controller로 넘겨서 처리하자!
- BoardDao, BoardDaoImpl, BoardDaoImplTest, boardMapper.xml 생성




테스트가 통과하고 null이 아닌 값이 나와 결과가 잘 나온 것을 확인할 수 있다.
다음은 게시물 번호가 일치하면,

board 컬럼에 맞게 열을 하나 삽입한 후 게시물 넘버가 일치하면 boardDto가 출력되도록 테스트를 수행한다.
테스트가 통과되면 Dao도 잘 주입되었고, DB에 있는 내용을 잘 가져온 걸 확인할 수 있다.
3. #{} ${}의 차이
<insert id="insert" parameterType="BoardDto">
INSERT INTO board
(title, content, writer)
VALUES
(#{title}, #{content}, #{writer})
</insert>
String sql = "INSERT INTO board"
+ "(title, content, writer)"
+ "VALUES"
+ "(?,?,?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
int result = pstmt.executeUpdate();
PreparedStatement를 쓰도록 바뀌고 ?로 바뀐다.
PreparedStatement는 sql문에서 오로지 들어갈 값들에만 사용할 수 있다.
#으로 시작하는건 PreparedStatement를 이용.
타입에 따라서 자동으로 문자라면 ""를 붙여준다.
외부에서 넘어온 값을 사용할 때 SQL Injection과 같은 상황을 막아준다. 값에만 사용할 수 있으니까!
<insert id="insert" parameterType="BoardDto">
INSERT INTO board
(title, content, writer)
VALUES
('&{title}', '&{content}', '&{writer}')
</insert>
String sql = "INSERT INTO board"
+ "(title, content, writer)"
+ "VALUES"
+ "('"title+"','"+content+"','"writer"')";
Statement stmt = conn.createStatement(sql);
int result = stmt.executeUpdate(sql);
일반 Statement로 바뀐다.
여기선 ''를 사용해야한다. 일반 Statement를 사용하기 때문에 직접 문자열을 구성하도록 되어있다.
이게 더 유연하고 제약이 적다. 테이블 이름 board 대신에도 ${table}이런식으로 동적으로 바꿀 수 있다.
(#은 값만 사용 가능)
SQL Injection방지에 취약하다.
가능하면 #을 사용하지만, 동적으로 SQL을 구성할 때는 $도 필요하다.
그래서 $는 내부적으로만 사용하고, $일 때 외부에서 입력받은 값을 사용할 땐 철저하게 검증해서 사용해야 한다.
#을 기본으로 쓰고 잘 안되면 $으로 바꿔서 사용해보자.
4. XML의 특수 문자 처리
- XML내의 특수 문자(<,>,&,...)는 < >로 변환 필요
- 또는 특수문자가 포함된 쿼리를 <![CDATA[와 ]]>로 감싼다.
<update id="update" parameterType="BoardDto">
UPDATE board
SET title = #{title}
, content = #{content}
, up_date = now()
WHERE bno = #{bno} and bno <> 0
</update>
<> 이런것들은 태그로 사용하는 문자이기 때문에 들어가 있으면 에러가 날 수 있다.
<가 < , >가 >이며, 이를 변환해서 사용해줘야 한다.
<update id="update" parameterType="BoardDto">
<![CDATA[
UPDATE board
SET title = #{title}
, content = #{content}
, up_date = now()
WHERE bno = #{bno} and bno <> 0
]]>
</update>
SQL문은 <, >를 알아보기 힘들고, 변환해야 하는 문자들이 많을 때는 <![CDATA[와 ]]> 전체를 이 태그로 감싸면 된다.
그러면 이 안에서는 태그가 없다는 뜻이다.
CDATA -> 전부 문자 데이터
'Spring' 카테고리의 다른 글
| ch4 04. 게시판 목록 만들기와 페이징 - TDD (2) (0) | 2023.03.17 |
|---|---|
| ch4 03. 게시판 목록 만들기와 페이징 - TDD (1) (0) | 2023.03.17 |
| ch4 01. MyBatis의 소개와 설정 (0) | 2023.03.16 |
| ch3 21. 서비스 계층의 분리와 @Transactional(3) (0) | 2023.03.15 |
| ch3 20. 서비스 계층의 분리와 @Transactional(2) (0) | 2023.03.15 |