[코드로 배우는 스프링 웹 프로젝트] 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