코드로 배우는 스프링 웹 프로젝트 P3: Chap09.비즈니스 계층
코드로 배우는 스프링 웹 프로젝트 - 개정판
코드로 배우는 스프링 웹 프로젝트 - Part3: Chap09.비즈니스 계층
2019년 7월 10일 인쇄판
Chapter09. 비즈니스 계층
비즈니스 계층은 고객의 요구사항을 ㅇ반영하는 계층으로 프레젠테이션 계층과 영속 계층의 중간 다리 역할을 하게 된다. 영속 계층은 Database 기준으로 해서 설계를 나눠 구현하지만 비즈니스 계층은 로직을 기준으로 해서 처리하게 된다.
일반적으로 비즈니스 영역에 있는 객체들은 서비스 용어로 많이 표현함.
9.1 비즈니스 계층의 설정
org.zerock.service 패키지 작성
설계를 할 때 각 계층 간 연결은 interface를 이용해 느슨한 연결을 한다.
BoardService 인터페이스와 Impl 클래스 선언
package org.zerock.service;
import java.util.List;
import org.zerock.domain.BoardVO;
public interface BoardService {
public boolean modify(BoardVO board);
public boolean remove(Long bno);
public List<BoardVO> getList();
}
BoardService 메서드 설계 시 메서드 이름은 현실적인 로직의 이름을 붙이는 게 관례이다.
package org.zerock.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.zerock.domain.BoardVO;
import org.zerock.mapper.BoardMapper;
import lombok.AllArgsConstructor;
import lombok.Setter;
import lombok.extern.log4j.Log4j;
@Service
@AllArgsConstructor
@Log4j
public class BoardServiceImpl implements BoardService{
@Setter(onMethod_ = @Autowired)
private BoardMapper mapper;
//spring 4.3 이상에선 자동 처리
@Override
public boolean modify(BoardVO board) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean remove(Long bno) {
// TODO Auto-generated method stub
return false;
}
@Override
public List<BoardVO> getList() {
// TODO Auto-generated method stub
return null;
}
}
** Log4j에서 에러가 뜨면 pom.xml에 scope-runtime 속성 제거
BoardServiceImpl 클래스에 가장 중요한 부분은 @Service라는 어노테이션.
@Service는 계층 구조상 주로 비즈니스 영역을 담당하는 객체임을 표시하기 위해 사용한다.
BoardServiceImpl이 정상적으로 작동하기 위해선 BoardMapper 객체가 필요.
스프링 4.3부터는 단일 파라미터를 받는 생성자의 경우 필요 파라미터를 자동 주입할 수 있다. @allArgsConstructor는 모든 파라미터를 이용하는 생성자를 만들기 때문에 실제 코드는 아래와 같이 BoardMapper를 주입받는 생성자가 만들어지게 된다.
9.1.1 스프링의 서비스 객체 설정 root-context.xml
비즈니스 계층의 인터페이스와 클래스가 작성되었다면 이를 스프링의 빈으로 인식하기 위해 root-context.xml에 @Service 어노테이션이 있는 org.zerock.service 패키지를 스캔하도록 추가해야 한다.
namespace 항목에 context 항목 추가.
<context:component-scan
base-package="org.zerock.service">
</context:component-scan>
</beans>
Java 설정의 경우
package org.zerock.config;
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
@Configuration
@MapperScan(basePackages= {"org.zerock.mapper"})
@ComponentScan(basePackages= {"org.zerock.mapper"})
public class RootConfig {
9.2 비즈니스 계층의 구현과 테스트
src/test/java 밑에 org.zerock.service.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 lombok.Setter;
import lombok.extern.log4j.Log4j;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
//Java Config
//@ContextConfiguration(classes={org.zerock.config.RootConfig.class})
@Log4j
public class BoardServiceTests {
@Setter(onMethod_ = {@Autowired})
private BoardService service;
@Test
public void testExist() {
log.info(service);;
assertNotNull(service);
}
}
9.2.1 등록 작업의 구현과 테스트
등록 작업은 BoardServiceImpl에서 파라미터로 전달되는 BoardVO 타입 객체를 BoardMapper를 통해 처리한다.
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 board);
public boolean remove(Long bno);
public List<BoardVO> getList();
}
package org.zerock.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.zerock.domain.BoardVO;
import org.zerock.mapper.BoardMapper;
import lombok.AllArgsConstructor;
import lombok.Setter;
import lombok.extern.log4j.Log4j;
@Service
@AllArgsConstructor
@Log4j
public class BoardServiceImpl implements BoardService{
@Setter(onMethod_ = @Autowired)
private BoardMapper mapper;
//spring 4.3 이상에선 자동 처리
@Override
public boolean modify(BoardVO board) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean remove(Long bno) {
// TODO Auto-generated method stub
return false;
}
@Override
public List<BoardVO> getList() {
// TODO Auto-generated method stub
return null;
}
@Override
public void register(BoardVO board) {
// TODO Auto-generated method stub
log.info("register....." + board);
mapper.insertSelectKey(board);
}
@Override
public BoardVO get(Long bno) {
// TODO Auto-generated method stub
return null;
}
}
BoardService는 void 타입으로 설계되었으므로 mapper.insertSelectKey() 반환값인 int를 사용하지 않고 있지만 필요하다면 int 타입을 이용해 처리할 수도 있다.
테스트
@Test
public void testRegister() {
BoardVO board = new BoardVO();
board.setTitle("새로 작성하는 글");
board.setContent("새로 작성하는 내용");
board.setWriter("newbie");
service.register(board);;
log.info("생성된 게시글의 번호 : " + board.getBno());
}
9.2.2 목록(리스트) 작업의 구현과 테스트
package org.zerock.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.zerock.domain.BoardVO;
import org.zerock.mapper.BoardMapper;
import lombok.AllArgsConstructor;
import lombok.Setter;
import lombok.extern.log4j.Log4j;
@Service
@AllArgsConstructor
@Log4j
public class BoardServiceImpl implements BoardService{
@Setter(onMethod_ = @Autowired)
private BoardMapper mapper;
//spring 4.3 이상에선 자동 처리
@Override
public boolean modify(BoardVO board) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean remove(Long bno) {
// TODO Auto-generated method stub
return false;
}
@Override
public List<BoardVO> getList() {
// TODO Auto-generated method stub
log.info("getList.....");
return mapper.getList();
}
@Override
public void register(BoardVO board) {
// TODO Auto-generated method stub
log.info("register....." + board);
mapper.insertSelectKey(board);
}
@Override
public BoardVO get(Long bno) {
// TODO Auto-generated method stub
return null;
}
}
테스트
@Test
public void testGetList() {
service.getList().forEach(board->log.info(board));
}
9.2.3 조회 작업의 구현과 테스트
@Override
public BoardVO get(Long bno) {
// TODO Auto-generated method stub
log.info("get......" + bno);
return mapper.read(bno);
}
테스트
@Test
public void testGet() {
log.info(service.get(9L));
}
}
9.2.4 삭제/수정 구현과 테스트
삭제 수정은 메서드의 리턴 타입을 void로 할 수 있지만 엄격하게 처리하기 위해 Boolean으로 한다.
@Override
public boolean modify(BoardVO board) {
// TODO Auto-generated method stub
log.info("modify....." + board);
return mapper.update(board) == 1;
}
@Override
public boolean remove(Long bno) {
// TODO Auto-generated method stub
log.info("remove....." + bno);
return mapper.delete(bno) == 1;
}
테스트)
@Test
public void testDelete() {
log.info("REMOVE RESULT : " + service.remove(2L));
}
@Test
public void testUpdate() {
BoardVO board = service.get(7L);
if(board==null) {
return;
}
board.setTitle("계속 수정합니다.");
log.info("MODIFY RESULT : " + service.modify(board));
}
}