JSP 피피티

JSP 피피티 11강 서비스레이어

전설의개발자 2020. 9. 5. 10:47

Service Layer의 이해

-프로그램의 요구사항(비지니스 로직)을 담당하는 부분
하나의 웹 페이지에서 구현해야 하는 모든 기능을 JSP페이지에서 모두 구현할 경우, 한 페이지에서 구현해야 하는 내용이 지나치게 많아지기 때문에 효율적이지 못하며, 코드의 유지보수에도 좋지 않다.

Service Layer는 하나의 페이지가 구현해야 하는 기능 중 저수준의 데이터 처리로직(SQL 수행)웹 고유의 기능(요청에 대한 응답, UI구현)분리하고, 이를 연결해 주는 역할을 수행한다.

Service Layer의 구현 과정

-요구사항 정의

프로그램 개발시에 구현하고자 하는 기능을 미리 산정하는 과정

이 단계에서 도출된 기능들을 구체화 하는 것이 프로그래머의 역할

-요구사항을 하나의 기능 단위로 준비하기

*도출된 요구사항을 구현하기 위한 일련의 처리 로직을 비지니스 로직이라 한다.

*비지니스 로직을 표현하기 위한 기능 단위는 프로젝트의 요구사항에 부합해야 하므로, 요구사항 명세서가 명시하고 있는 기능들에 대해 인터페이스로 표현한다.

*Service Layer에서 정의되는 인터페이스의 역할은 데이터베이스 설계에 부합되는 데이터 처리로직을 수행하는 것이다.

만약에 기능구현까지 3단계로 나뉜다면 패키지 > 인터페이스 > 메서드 라고 하셨던거 같음

 

서비스 레이어 시작하기

servlet-context.xml에 서비스 구현체가 포함된 패키지 명시

<context:component-scan base-package="study.spring.simplespring.service.impl" />

구현할 기능을 정의한 인터페이스

/src/main/java/study.spring.simplespring.service/DepartmentService.java

package study.spring.practicespring.service;

import java.util.List;

import study.spring.practicespring.model.Department;

/*학과 데이터 관리 기능을 제공하기 위한 Service 계층*/
public interface DepartmentService {
	/**
	 * 학과 데이터 상세 조회
	 * @param Department 조회할 학과의 일련번호를 담고 있는 beans
	 * @return 조회된 데이터가 저장된 Beans
	 * @throws Exception
	 */
	public Department getDepartmentItem(Department input) throws Exception;
	
	/*
	 * 학과데이터 목록 조회
	 * @return 조회 결과에 대한 컬렉션
	 * @throw Exception
	 */
	public List<Department> getDepartmentList(Department input) throws Exception;
	
	/**
	 * 학과 데이터가 저장되어 있는 갯수 조회
	 * @return int
	 * @throws Exception
	 */
	public int getDepartmentCount(Department input) throws Exception;
	
	/**
	 * 학과 데이터 등록하기
	 * @param Department 저장할 정보를 담고 있는 Beans
	 * @return int
	 * @throws Exception
	 */
	public int addDepartment(Department input) throws Exception;
	
	/**
	 * 학과 데이터 수정하기
	 * @param Department 수정할 정보를 담고 있는 Beans
	 * @return int
	 * @throws Exception
	 */
	public int editDepartment(Department input) throws Exception;
	
	/**
	 * 학과 데이터 삭제하기
	 * @param Department 수정할 정보를 담고 있는 Beans
	 * @return int
	 * @throws Exception
	 */
	public int deleteDepartment(Department input) throws Exception;

}

구현체 클래스 작성

인터페이스를 상속받고 부모가 정의하고 있는 메서드를 오버라이드 한다.

/src/main/java/study.spring.simplespring.service.impl/DepartmentServiceImpl.java

package study.spring.practicespring.service.impl;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import lombok.extern.slf4j.Slf4j;
import study.spring.practicespring.model.Department;
import study.spring.practicespring.service.DepartmentService;

/*학과 데이터 관리 기능을 제공하기 위한 Service 계층에 대한 구현체*/
@Slf4j
@Service
public class DepartmentServiceImpl implements DepartmentService{
	/* MyBatis 세션 객체 주입 설정 */
    
    //구현체에서 MyBatis를 호출하기 위해서는 sqlSession이 필요하다.
	@Autowired
	SqlSession sqlSession;


	/**
	 * 학과 데이터 상세 조회
	 * @param Department 조회할 학과의 일련번호를 담고 있는 Beans
	 */
	@Override
	public Department getDepartmentItem(Department input) throws Exception {
		Department result = null;
		
		try {
			result = sqlSession.selectOne("DepartmentMapper.selectItem", input);
			
			if(result == null) {
				throw new NullPointerException("result=null");
			}
		}catch(NullPointerException e) {
			log.error(e.getLocalizedMessage());
			throw new Exception("조회된 데이터가 없습니다.");
		}catch(Exception e) {
			log.error(e.getLocalizedMessage());
			throw new Exception("데이터 조회에 실패했습니다.");
		}
	
		return result;
	}

	/**
	 * 학과 데이터 목록 조회
	 * @return 조회 결과에 대한 컬렉션
	 * @throws Exception
	 */
	@Override
	public List<Department> getDepartmentList(Department input) throws Exception {
		List<Department> result = null;
		
		try{
			result = sqlSession.selectList("DepartmentMapper.selectList", input);
			
			if(result == null){
				throw new NullPointerException("result=null");
			}
		}catch(NullPointerException e) {
			log.error(e.getLocalizedMessage());
			throw new Exception("조회된 데이터가 없습니다.");
		}catch(Exception e) {
			log.error(e.getLocalizedMessage());
			throw new Exception("데이터 조회에 실패했습니다.");
		}
		return result;
	}
	
	/**
	 * 학과 데이터가 저장되어 있는 갯수 조회
	 * @return int
	 * @throws Exception
	 */
	@Override
	public int getDepartmentCount(Department input) throws Exception {
		int result = 0;
		
		try {
			result = sqlSession.selectOne("DepartmentMapper.selectCountAll", input);
		}catch(Exception e) {
			log.error(e.getLocalizedMessage());
			throw new Exception("데이터 조회에 실패했습니다.");
		}
		
		return result;
	}
	
	/**
	 * 학과데이터 등록하기
	 * @param Department 저장할 정보를 담고 있는 Beans
	 * @return int
	 * @throws Exception
	 */
	@Override
	public int addDepartment(Department input) throws Exception{
		int result = 0;
		try {
			result = sqlSession.insert("DepartmentMapper.insertItem", input);
			
			if(result == 0) {
				throw new NullPointerException("result=0");
			}
		}catch(NullPointerException e) {
			log.error(e.getLocalizedMessage());
			throw new Exception("저장된 데이터가 없습니다.");
		}catch(Exception e) {
			log.error(e.getLocalizedMessage());
			throw new Exception("데이터 저장에 실패했습니다.");
		}
		
		return result;
	}
	
	/**
	 * 학과데이터 수정하기
	 * @param Department 수정할 정보를 담고 있는 Beans
	 * @return int
	 * @throws Exception
	 */
	@Override
	public int editDepartment(Department input) throws Exception {
		int result = 0;
		
		try {
			result = sqlSession.update("DepartmentMapper.updateItem", input);
			
			if(result ==0) {
				throw new NullPointerException("result=0");
			}
		}catch(NullPointerException e) {
			log.error(e.getLocalizedMessage());
			throw new Exception("수정된 데이터가 없습니다.");
		}catch(Exception e) {
			log.error(e.getLocalizedMessage());
			throw new Exception("데이터 수정에 실패했습니다.");
		}
		
		return result;
	}
	
	/**
	 * 학과 데이터 삭제하기
	 * @param Department 수정할 정보를 담고 있는 Beans
	 * @return int
	 * @throws Exception
	 */
	@Override
	public int deleteDepartment(Department input) throws Exception {
		int result = 0;
		
		try {
			result = sqlSession.delete("DepartmentMapper.deleteItem", input);
			
			if(result ==0) {
				throw new NullPointerException("result=0");
			}
		}catch(NullPointerException e) {
			log.error(e.getLocalizedMessage());
			throw new Exception("삭제된 데이터가 없습니다.");
		}catch(Exception e) {
			log.error(e.getLocalizedMessage());
			throw new Exception("데이터 삭제에 실패했습니다.");
		}
		
		return result;
	}

	
}

서비스 레이어를 작성했다면 잘 작성이 되었는지 단위테스트를 진행한다.

 

/src/test/java/study.spring.practicespring.service/DepartmentServiceTest.java

package study.spring.practicespring.service;

import java.util.List;

import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

import lombok.extern.slf4j.Slf4j;
import study.spring.practicespring.model.Department;

/*Lombok의 log4j 객체*/
//import lombok.extern.slf4j.Slf4j;
@Slf4j
/* JUnit에 의한 테스트 클래스로 정의 */
//import org.junit.runner.RunWith;
//import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
/*Spring의 설정 파일들을 읽어들이도록 설정(**은`모든` 이라는 의미)*/
//import org.springframework.test.context.ContextConfiguration;
@ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/spring/**/*-context.xml"})
/* 웹 어플리케이션임을 명시 */
//import org.springframework.test.context.web.WebAppConfiguration;
@WebAppConfiguration
/* 메서드 이름순서로 실행하도록 설정(설정하지 않을 경우 무작위 순서로 실행됨) */
//import org.junit.FixMethodOrder;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)

public class DepartmentServiceTest {
	/* Service객체 주입 설정 */
	//import org.springframework.beans.factory.annotation.Autowired;
	@Autowired
	private DepartmentService departmentService;
	
	/* 단일행 조회 테스트 */
	@Test
	public void testA() {
		//검색조건으로 사용될 POJO클래스 객체
		Department input = new Department();
		input.setDeptno(101);
		
		Department output = null;
		
		try {
			output = departmentService.getDepartmentItem(input);
			log.debug(output.toString());
		}catch(Exception e) {
			log.error(e.getLocalizedMessage());
			e.printStackTrace();
		}
	}
	
	/* 다중행 조회 테스트 */
	@Test
	public void testB() {
		//검색조건으로 사용도리 POJO클래스 객체
		Department input = new Department();
		input.setDname("공학");
		
		List<Department> output = null;
		
		try {
			output = departmentService.getDepartmentList(input);
			
			for(Department item:output) {
				log.debug(item.toString());
			}
		}catch(Exception e) {
			log.error(e.getLocalizedMessage());
			e.printStackTrace();
		}
	}
	
	/* 전체 데이터 수 조회 */
	@Test
	public void testC() {
		int count = 0;
		
		try {
			count = departmentService.getDepartmentCount(null);
			log.debug("전체 데이터 수: " + count);
		}catch(Exception e) {
			log.error(e.getLocalizedMessage());
			e.printStackTrace();
		}
	}
	
	/* 조건에 따른 데이터 수 조회 */
	@Test
	public void testD() {
		int count = 0;
		
		Department input = new Department();
		input.setDname("공학");
		
		try {
			count = departmentService.getDepartmentCount(input);
			log.debug("공학을 포함하는 학과이름을 갖는 데이터 수: " + count);
		}catch(Exception e) {
			log.error(e.getLocalizedMessage());
			e.printStackTrace();
		}
	}
	
	/* 데이터 저장 테스트 */
	@Test
	public void testE() {
		Department input = new Department();
		input.setDname("신규학과");
		
		int output = 0;
		
		try {
			output = departmentService.addDepartment(input);
			log.debug("저장된 데이터 수: " + output);
			//[중요] 생성된 Pk값을 MyBatis에 의해 입력 파라미터의 해당 멤버변수에 셋팅된다.
			log.debug("생성된 PK 갑 : " + input.getDeptno());
		}catch(Exception e) {
			log.error(e.getLocalizedMessage());
			e.printStackTrace();
		}
	}
	
	/* 데이트 수정 테스트 */
	@Test
	public void testF() {
		Department input = new Department();
		input.setDeptno(203);
		input.setDname("수정학과");
		input.setLoc("5호관");
		
		int output = 0;
		
		try {
			output = departmentService.editDepartment(input);
			log.debug("수정된 데이터 수: " + output);
		}catch(Exception e) {
			log.error(e.getLocalizedMessage());
			e.printStackTrace();
		}
		
	}
	
	/* 데이트 삭제 테스트 */
	@Test
	public void testG() {
		Department input = new Department();
		input.setDeptno(203);
		
		int output = 0;
		
		try {
			output = departmentService.deleteDepartment(input);
			log.debug("삭제된 데이터 수: " + output);
		}catch(Exception e) {
			log.error(e.getLocalizedMessage());
			e.printStackTrace();
		}
		
	}
}

 단위 테스트에서 testA()메서 드를 실행하면 

*참고용 Mapper

뭐 이런 식으로 코드가 작동 한다고 하셨다.

결과 확인