◎ 비즈니스 계층
▷ 고객의 요구사항을 반영하는 계층, 프레젠테이션 계층과 영속 계층의 중간 다리 역할
▷ 영속 계층은 데이터베이스 기준으로 해 설계를 나눠 구현하지만, 비즈니스 계층은 로직을 기준으로 처리
◎ 쇼핑몰에서 상품 구매 예시
1. 쇼핑몰 로직이 '물건을 구매한 회원에게는 포인트 올려준다'고 하면 영속 계층의 설계는 '상품', '회원'으로 나누어 설계
2. 비즈니스 계층은 상품 영역, 회원 영역을 동시에 사용해서 하나의 로직 처리를 하므로 아래와 같은 구조
설계를 할 때는 원칙적으로 영역을 구분해서 작성해야 하며 일반적으로 비즈니스 영역에 있는 객체들은 '서비스'라는 용어 사용
1. 비즈니스 계층 설정
1. org.codehows.service 패키지 생성
2. 각 계층 간의 연결은 인터페이스를 이용해 느슨한 연결을 함, 게시물을 위해 인터페이스와 클래스 선언
(1) BoardService 인터페이스package org.codehows.service; import java.util.List; import org.codehows.domain.BoardVO; public interface BoardService { public void register(BoardVO board); public BoardVO get(Long bno); public boolean modify(BoardVO board); public boolean remove(Long bno); public List<BoardVO> getList(); }
▷ 메소드의 이름은 현실적인 로직의 이름 지정
▷ 명백하게 반환해야 할 데이터가 있는 'select'를 해야하는 메소드는 리턴 타입 지정 가능
▷ 게시물은 특정한 게시물을 가져오는 get() 메소드와 전체 리스트 구하는 getList()의 경우 처음부터 메소드 리턴 타입 결정 가능
(2) BoardServiceImpl 클래스package org.codehows.service; import java.util.List; import org.codehows.domain.BoardVO; import org.codehows.mapper.BoardMapper; import org.springframework.stereotype.Service; import lombok.AllArgsConstructor; import lombok.extern.log4j.Log4j; @Log4j @Service @AllArgsConstructor public class BoardServiceImpl implements BoardService { //spring 4.3 이상에서 자동 처리 private BoardMapper mapper; @Override public void register(BoardVO board) {} @Override public BoardVO get(Long bno) { return null; } @Override public boolean modify(BoardVO board) { return false; } @Override public boolean remove(Long bno) { return false; } @Override public List<BoardVO> getList() { return null; } }
▷ 여기서 중요한 것은 @Service라는 어노테이션
▷ @Service는 계층 구조상 주로 비즈니스 영역을 담당하는 객체임을 표시하기 위해 사용
▷ 작성된 어노테이션은 패키지를 읽어 들이는 동안 처리됨
▷ BoardServiceImpl가 정상적으로 동작하기 위해 BoardMapper 객체가 필요
▷ @Autowired와 같이 직접 설정해 줄 수 있고, Setter를 이용해 처리할 수도 있음
▷ Lombok을 이용한다면 아래와 같이 만들 수 있음@Log4j @Service public class BoardServiceImpl implemets BoardService{ @Setter(onMethod_ = @Autowired) private BoardMapper mapper; ...
▷ 스프링 4.3 부터는 단일 파라미터를 받는 생성자의 경우 필요한 파라미터를 자동으로 주입 가능
▷ @AllArgsContstructor는 모든 파라미터를 이용하는 생성자를 만들기 때문에 실제 코든느 BoardMapper를 주입 받는 생성자가 만들어지게 됨
(1) 스프링의 서비스 객체 설정(root-context.xml)
▷ 비즈니스 계층의 인터페이스와 구현 클래스가 작성되었다면 스프링의 빈으로 인식하기 위해 root-context.xml에
@Service 어노테이션이 있는 org.codehows.service 패키지를 스캔하도록 추가해야함
◎ root-context.xml 수정
1. namespaces 수정
2. source 수정
...(생략)... <context:component-scan base-package="org.codehows.service"></context:component-scan> </beans>
2. 비즈니스 계층의 구현과 테스트
▷ src/test/java → org.codehows.service 생성 → BoardServiceTests 클래스 생성 및 작성
package org.codehows.service; import static org.junit.Assert.assertNotNull; 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 lombok.Setter; import lombok.extern.log4j.Log4j; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml") @Log4j public class BoardServiceTests { @Setter(onMethod_ = {@Autowired }) private BoardService service; @Test public void testExist() { log.info(service); assertNotNull(service); } }
▷ BoardServiceTests 첫 테스트는 BoardService 객체가 제대로 주입 가능한지 확인하는 작업
▷ 정상적으로 BoardService 객체가 생성되고 BoardMapper가 주입되었다면 아래와 같이 BoardService 객체와 데이터베이스 관련 로그가 같이 출력됨
(1) 등록 작업의 구현과 테스트
▷ 등록 작업은 BoardServiceImpl에서 파라미터로 전달되는 BoardVO 타입의 객체를 BoardMapper를 통해 처리
◎ BoardServiceImpl 클래스 수정
...(생략)... @Override public void register(BoardVO board) { log.info("register......" + board); mapper.insertSelectKey(board); } ...(생략)...
void 대신 int를 사용해도 됩니다.
mapper의 insertSelectKey()를 이용해 나중에 생성된 게시물 번호를 확인할 수 있음
◎ BoardServiceTests 클래스 내용 추가
...(생략)... @Test public void testRegister() { BoardVO board = new BoardVO(); board.setTitle("새로 작성하는 글"); board.setContent("새로 작성하는 내용"); board.setWriter("newbie"); service.register(board); log.info("생성된 게시물의 번호: " + board.getBno()); } }
생성된 게시물 번호 확인할 수 있음
(2) 목록(리스트) 작업의 구현과 테스트
▷ BoardServiceImpl 클래스에서 현재 테이블에 저장된 모든 데이터를 가져오는 getList()는 아래와 같이 구현
◎ src/main/java → org.codehows.service → BoardServiceImpl.java 클래스 수정
...(생략)... @Override public List<BoardVO> getList() { log.info("getList.........."); return mapper.getList(); } }
◎ src/test/java → org.codehows.service → BoardServiceTests 클래스 내용 추가
...(생략)... @Test public void testGetList() { service.getList().forEach(board -> log.info(board)); } }
콘솔창에 아래와 같은 테이블 형태로 출력됩니다.
(3) 조회 작업의 구현과 테스트
▷ 조회는 게시물의 번호가 파라미터이고 BoardVO의 인스턴스가 리턴이 됨
◎ BoardServiceImpl 클래스 수정
...(생략)... @Override public BoardVO get(Long bno) { log.info("get......" + bno); return mapper.read(bno); } ...(생략)...
◎ BoardServiceTests 클래스 내용 추가
...(생략)... @Test public void testGet() { log.info(service.get(1L)); } }
테스트 결과는 아래와 같이 첫 번째
(4) 삭제/수정 구현과 테스트
▷ 삭제/수정은 메소드의 리턴 타입을 void로 설계할 수 있지만 엄격하게 처리하기 위해 Boolean 타입으로 처리
◎ BoardServiceImpl 클래스 수정
...(생략)... @Override public boolean modify(BoardVO board) { log.info("modify......" + board); return mapper.update(board) == 1; } @Override public boolean remove(Long bno) { log.info("remove......" + bno); return mapper.delete(bno) == 1; } ...(생략)...
정상적으로 수정과 삭제가 이루어지면 1이라는 값이 반환되기 때문에 '==' 연산자를 이용해서 true/false 처리할 수 있음
◎ BoardServiceTests 클래스 내용 추가
...(생략)... @Test public void testDelete() { // 게시물 번호의 존재 여부를 확인하고 테스트할 것 log.info("REMOVE RESULT: " + service.remove(2L)); } @Test public void testUpdate() { BoardVO board = service.get(1L); if(board == null) { return; } board.setTitle("제목 수정합니다."); log.info("MODIFY RESULT: " + service.modify(board)); } }
testDelete()의 경우 해당 게시물이 존재할 때 true를 반환하는 것을 확인할 수 있고, testUpdate()의 경우 특정한 게시물 먼저 조회하고, title 값을 수정한 후 이를 업데이트 함
게시물의 목록 확인, 등록, 선택한 게시물만 출력, 게시물 수정 및 삭제 등을 실시해보았습니다.
DB Table과 연동되어 있는 것을 확인할 수 있으며 오라클의 테이블에도 연동이 되는 것을 확인할 수 있습니다!
많은 분들의 피드백은 언제나 환영합니다! 많은 댓글 부탁드려요~~
'BackEnd > Spring' 카테고리의 다른 글
[코드로 배우는 스프링 웹 프로젝트] ch10 프레젠테이션(웹) 계층의 CRUD 구현 2 (0) | 2023.03.28 |
---|---|
[코드로 배우는 스프링 웹 프로젝트] ch10 프레젠테이션(웹) 계층의 CRUD 구현 1 (0) | 2023.03.28 |
[코드로 배우는 스프링 웹 프로젝트] ch08 영속/비즈니스 계층의 CRUD 구현 2(create, read, update, delete) (0) | 2023.03.28 |
[코드로 배우는 스프링 웹 프로젝트] ch08 영속/비즈니스 계층의 CRUD 구현 1(select, 테이블 출력) (0) | 2023.03.28 |
[코드로 배우는 스프링 웹 프로젝트] ch07 스프링 MVC 프로젝트 기본 구성 (0) | 2023.03.27 |