[spring] 비즈니스 계층
업데이트:
비즈니스 계층은 고객의 요구사항을 반영하는 계층으로 프레젠테이션 계층과 영속 계층의 중간 다리 역할을 한다. 영속 계층은 데이터베이스를 기준으로 해서 설계를 나눠 구현하지만, 비즈니스 계층은 로직을 기준으로 처리한다.
비즈니스 계층의 설정
- 패키지, 파일 생성
// BoardService 인터페이스
package org.zerock.service;
import java.util.List;
import org.zerock.domain.BoardVO;
public interface BoardService {
public void register(BoardVO board);
public BoardVO get(Long bno);
public boolean modify(BoardVO bardVO);
public boolean remove(Long bno);
public List<BoardVO > getList();
}
BoardService 메서드를 설계할 때 메서드 이름은 현실적인 로직의 이름을 붙여 사용는게 관례이다.
// BoardService
package org.zerock.service;
import java.util.List;
import org.springframework.stereotype.Service;
import org.zerock.domain.BoardVO;
import org.zerock.mapper.BoardMapper;
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) {
}
}
BoardServiceImpl 클래스에서 가장 중요한 부분은 @Service
라는 어노테이션이다. @Service는 계층 구조상 주로 비즈니스 영역을 담당하는 객체임을 표시하기 위해 사용한다.
스프링의 서비스 객체 설명
인터페이스와 구현 클래스를 작성했다.
- root-context.xml Namespaces
<context:component-scan base-package="org.zerock.service"></context:component-scan>
비즈니스 계층의 구현과 테스트
테스트를 진행하기 위해 아래 테스트 클래스를 생성한다.
package org.zerock.service;
import static org.junit.Assert.assertNotNull;
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/wabapp/WEB-INF/spring/root_context.xml")
@Log4j
public class BoardServiceTests {
@Setter(onMethod_ = {@Autowired})
private BoardService service;
private void testExist(){
log.info(service);
assertNotNull(service);
}
}
작성후 BoardService 객체가 제대로 주입이 가능한지 확인하는 작업으로 시작된다. 만약 정상적으로 주입이 되었다면 다음과 같은 로그가 출력된다.
INFO : org.zerock.service.BoardServiceTests - org.zerock.service.BoardServiceImpl@5d8bafa9
INFO : org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@18eed359: startup date [Fri May 28 21:43:16 KST 2021]; root of context hierarchy
INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated...
등록 작업 구현과 테스트
등록 작업은 BoardServiceImpl에서 파라미터로 전달되는 BoardVO 타입의 객체를 BoardMapper를 통해서 처리한다.
// BoardServiceImpl 수정
@Override
public void register(BoardVO board) {
log.info("register.....:" + board);
mapper.insertSelectKey(board);
}
// BoardServiceTests 일부
@Test
public void testRegister() {
BoardVO board = new BoardVO();
board.setTitle("새로 작성하는 글");
board.setContent("새로 작성하는 글");
board.setWriter("newbie");
service.register(board);
log.info("생성된 게시글 번호 : " + board.getBno());
}
INFO : org.zerock.service.BoardServiceTests - 생성된 게시글 번호 : 19
조회 작업의 구현과 테스트
// BoardServiceImpl 일부
@Override
public BoardVO get(Long bno) {
log.info("get......" + bno);
return mapper.read(bno);
}
// 테스트 코드 클래스
@Test
public void testGet() {
log.info(service.get(1L));
}
삭제/수정 구현
삭제/수정 메서드의 리턴 타입을 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;
}
// BoardServiceTests 클래스
package org.zerock.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 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 BoardServiceTests {
@Setter(onMethod_ = {@Autowired})
private BoardService service;
@Test
public void testExist(){
log.info(service);
assertNotNull(service);
}
@Test
public void testRegister() {
BoardVO board = new BoardVO();
board.setTitle("새로 작성하는 글");
board.setContent("새로 작성하는 글");
board.setWriter("newbie");
service.register(board);
log.info("생성된 게시글 번호 : " + board.getBno());
}
@Test
public void testGet() {
log.info(service.get(1L));
}
@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 값을 수정한 후 이후를 업데이트한다.
- 참고 : 코드로 배우는 스프링 웹 프로젝트
댓글남기기