-
JSP 피피티 11강 서비스레이어JSP 피피티 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
뭐 이런 식으로 코드가 작동 한다고 하셨다.
결과 확인
'JSP 피피티' 카테고리의 다른 글
JSP 피피티 12강 서비스 프로그램 구현(학과관리 페이지-학과검색) (0) 2020.09.06 JSP 피피티 12강 서비스 프로그램 구현(학과관리 페이지-학과추가) (0) 2020.09.05 JSP 피피티 10강 Spring MyBatis (0) 2020.09.03 JSP 피피티 07강 Spring Interceptor (0) 2020.09.01 JSP 피피티 07 Spring Framework (0) 2020.08.31