on
[코드로 배우는 스프링 웹 프로젝트] 8강. 영속(Peristence) / 비즈니스...
[코드로 배우는 스프링 웹 프로젝트] 8강. 영속(Peristence) / 비즈니스...
728x90
해당 프로젝트는 코드로 배우는 스프링 웹 프로젝트(개정판) 을 기반으로 진행됩니다.
이번 시간에는 코드를 이용해서 CRUD 작업을 진행해본다.
Persistence 계층의 작업은 다음 순서로 진행한다.
-. 테이블의 컬럼 구조를 반영한 VO(Value Object) 클래스의 생성
-. MyBatis의 Mapper 인터페이스의 작성 / XML 처리
-. 작성한 Mapper 인터페이스 테스트
1. Persistence(영속) 계층의 구현 준비
1) VO 클래스의 작성
<현재 테이블의 구성>
프로젝트에 org.zerock.domain 패키지를 생성하고, BoardVO 클래스를 정의한다.
BoardVO.java
: 생성한 테이블과 동일한 타입/명칭으로 정의한다.
package org.zerock.domain; import java.util.Date; import lombok.Data; @Data public class BoardVO { private Long bno; private String title; private String content; private String writer; private Date cdate; private Date udate; }
2) Mapper 인터페이스와 Mapper XML
: 우선, Mapper 패키지를 스캔(조사)할 수 있도록 root-context.xml을 아래와 같이 수정한다.
root-context.xml 일부
Mapper 인터페이스 작성하기
: 프로젝트에 org.zerock.mapper 패키지를 생성하고, BoardMapper 인터페이스를 정의한다.
BoardMapper.java
package org.zerock.mapper; import java.util.List; import org.zerock.domain.BoardVO; public interface BoardMapper { //게시글 전체 조회 public List getList(); }
Mapper XML 파일 작성하기
: src/main/resources 내에 패키지와 동일한 org/zerock/mapper 단계의 폴더를 생성하고 BoardMapper.xml 파일을 작성한다. (폴더는 한 번에 생성하지 말고 하나씩 생성하도록 하자.)
BoardMapper.xml
select * from tbl_board where bno > 0
<작성시 유의 사항>
-. 의 namespace 속성 값을 Mapper 인터페이스와 동일한 이름을 지정해야 한다.
-. 태그의 id 속성 값은 메소드의 이름과 일치해야 한다.
-. resultType 속성의 값은 select 쿼리의 결과를 특정 클래스의 객체로 만들기 위해서 설정한다.
-. XML에 사용한 CDATA 부분은 XML에서 부등호를 사용하기 위해 사용한다.
테스트 수행하기
: org.zerock.mapper.BoardMapperTests 클래스
BoardMapperTests.java
package org.zerock.mapper; 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 org.zerock.domain.BoardVO; import lombok.Setter; import lombok.extern.log4j.Log4j; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml") @Log4j public class BoardMapperTests { @Setter(onMethod_ = @Autowired) private BoardMapper mapper; @Test public void testGetList() { mapper.getList().forEach(board -> log.info(board)); } }
테스트 결과
작성 쿼리 정상 수행 모든 리스트 정상 조회 완료
728x90
2. Persistence(영속) 영역의 CRUD 구현
: MyBatis는 내부적으로 JDBC의 PreparedStatement를 활용 하고 필요한 파라미터를 처리하는 '?'에 대한 치환은 '#{속성}'을 이용해서 처리한다.
BoardMapper.java
package org.zerock.mapper; import java.util.List; import org.zerock.domain.BoardVO; public interface BoardMapper { //게시글 전체 조회 public List getList(); //게시글 삽입 : insert 처리 후 생성된 PK값을 알 필요 없는 경우 public void insert(BoardVO board); //게시글 삽입 : insert 처리 후 생성된 PK값을 알아야 할 경우 public void insertSelectKey(BoardVO board); //게시글 읽기 : 게시글 번호를 통해서 1개의 글 읽어오기 public BoardVO read(Long bno); //게시글 삭제 : 특정 게시글을 삭제하기 //삭제하고자하는 게시글이 있다면 1, 없으면 0 반환 public int delete(Long bno); //게시글 수정 : 특정 게시글 수정하기 //수정하고자하는 게시글이 있다면 1, 없으면 0 반환 public int update(BoardVO board); }
BoardMapper.xml
select * from tbl_board where bno > 0 insert into tbl_board (bno, title, content, writer) values (seq_board.nextval, #{title}, #{content}, #{writer}) select seq_board.nextval from dual insert into tbl_board (bno, title, content, writer) values (#{bno}, #{title}, #{content}, #{writer}) select * from tbl_board where bno = #{bno} delete from tbl_board where bno = #{bno} update tbl_board set title=#{title}, content=#{content}, writer=#{writer}, udate=sysdate where bno=#{bno}
BoardMapperTests.java (테스트 코드)
package org.zerock.mapper; 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 org.zerock.domain.BoardVO; import lombok.Setter; import lombok.extern.log4j.Log4j; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml") @Log4j public class BoardMapperTests { @Setter(onMethod_ = @Autowired) private BoardMapper mapper; @Test public void testGetList() { mapper.getList().forEach(board -> log.info(board)); } @Test public void testInsert() { BoardVO board = new BoardVO(); board.setTitle("새로 작성하는 글 테스트"); board.setContent("새로 작성하는 내용 테스트"); board.setWriter("newbie"); mapper.insert(board); log.info(board); } @Test public void testInsertSelectKey() { BoardVO board = new BoardVO(); board.setTitle("새로 작성하는 글 테스트 Select Key"); board.setContent("새로 작성하는 내용 테스트 Select Key"); board.setWriter("newbie"); mapper.insertSelectKey(board); log.info(board); } @Test public void testRead() { //존재하는 게시글 번호로 테스트 진행 필수 BoardVO board = mapper.read(1L); log.info(board); } @Test public void testDelete() { //존재하는 게시글 번호로 테스트 진행 필수 //삭제하고자하는 게시글이 있다면 1, 없으면 0 반환 log.info("DELETE COUNT: " + mapper.delete(22L)); } @Test public void testUpdate() { BoardVO board = new BoardVO(); board.setBno(29L); board.setTitle("수정한 글 입니다."); board.setContent("수정하는 내용 테스트"); board.setWriter("user00"); int count = mapper.update(board); log.info("UPDATE COUNT: " + count); } }
테스트 수행 결과
public void insert(BoardVO board); 수헹
public void insertSelectKey(BoardVO board); 수행
: bno 값이 먼저 구해지고, insert 할 때 미리 구한 값을 이용하는 것을 볼 수 있음.
public BoardVO read(Long bno); 수행
1번 글 정상 조회
public int delete(Long bno); 수행
22번 글이 삭제됨을 확인
public int update(BoardVO board); 수행
내용 수정 정상 확인
다음 시간에는 Business 계층의 로직을 좀 더 구체화 해보도록 한다!
반응형
from http://ee2ee2.tistory.com/46 by ccl(A) rewrite - 2021-12-22 19:01:21