101일차 Spring CRUD게시판-비즈니스 계층

쿠우·2022년 8월 29일
0

비즈니스 계층과 영속성 계층은 웹과는 관련이 없다. = root-context

지금부터 비즈니스 로직을 처리 service 패키지

-Service 인터페이스 만들기


package org.zerock.myapp.service;

import java.util.List;

import org.springframework.stereotype.Controller;
import org.zerock.myapp.domain.BoardDTO;
import org.zerock.myapp.domain.BoardVO;
import org.zerock.myapp.exception.ServiceException;


public interface BoardService {
	
	// 각 웹 3계층의 성격에 맞게 추상메소드의 이름을 결정하라
	
	// 1. 게시글 전체목록 획득(게시글 번호의 역순으로...)
	public abstract List<BoardVO> getList() throws ServiceException;
	
	// 2. 새로운 게시글 등록
	public abstract boolean register(BoardDTO dto) throws ServiceException;
	
	// 3. 기존 게시글 수정 
	public abstract boolean modify(BoardDTO dto) throws ServiceException;
	
	// 4. 기존 게시글 삭제 
	public abstract boolean remove(BoardDTO dto) throws ServiceException;
	
	//5. 특정 게시글 상세조회 
	public abstract BoardVO get(BoardDTO dto) throws ServiceException;
	
}// end interface

-Service 인터페이스의 구현클래스 만들기

(영속성 영역에 BoardMapper 클래스를 이용하는 것을 이해하는 것이 중요)

package org.zerock.myapp.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.zerock.myapp.domain.BoardDTO;
import org.zerock.myapp.domain.BoardVO;
import org.zerock.myapp.exception.ServiceException;
import org.zerock.myapp.mapper.BoardMapper;

import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;

@Log4j2
@NoArgsConstructor
// 핵심 비지니스 로직구현 
@Service
public class BoardServiceImpl implements BoardService {
	
	@Setter(onMethod_= @Autowired)
	private BoardMapper mapper;
	

	@Override
	public List<BoardVO> getList() throws ServiceException {
		log.trace(" getList() invoked.");
		
		try {
			return this.mapper.selectAllList();
		} catch (Exception e) {
			throw new ServiceException(e);
		} // try - catch
	}//getList

	@Override
	public boolean register(BoardDTO dto) throws ServiceException {
		log.trace(" register({}) invoked.", dto);

		try {
//			return this.mapper.insert(dto) == 1;
			return this.mapper.insertSelectKey(dto) == 1;
		} catch (Exception e) {
			throw new ServiceException(e);
		} // try - catch
		
	}//register

	@Override
	public boolean modify(BoardDTO dto) throws ServiceException {
		log.trace(" modify({}) invoked.", dto);

		try {
			return this.mapper.update(dto) == 1;
		} catch (Exception e) {
			throw new ServiceException(e);
		} // try - catch
		
	}//modify

	@Override
	public boolean remove(BoardDTO dto) throws ServiceException {
		log.trace(" remove({}) invoked.", dto);
		
		try {
			return this.mapper.delete(dto.getBno()) == 1;
		} catch (Exception e) {
			throw new ServiceException(e);
		} // try - catch
		
	}//remove

	@Override
	public BoardVO get(BoardDTO dto) throws ServiceException {
		log.trace(" get({}) invoked.", dto);
		
		try {
			return this.mapper.select(dto);
		} catch (Exception e) {
			throw new ServiceException(e);
		} // try - catch
	}//get

}//end class

-test

(어노테이션 사용과 전체적인 흐름만 파악하기 별거없음)

package org.zerock.myapp.service;

import static org.junit.jupiter.api.Assertions.assertNotNull;

import java.util.List;
import java.util.concurrent.TimeUnit;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.Timeout;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.zerock.myapp.domain.BoardDTO;
import org.zerock.myapp.domain.BoardVO;
import org.zerock.myapp.exception.ServiceException;

import lombok.Cleanup;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;

@Log4j2
@NoArgsConstructor

@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = {
		"file:src/main/webapp/WEB-INF/**/root-context.xml"
})

@TestInstance(Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BoardServiceTests {
	
	@Setter(onMethod_= {@Autowired})
	private BoardService service;
	
	@BeforeAll
	void beforeAll() {
		log.trace("beforeAll() invoked");
		
		assertNotNull(this.service);
		
		log.info("\t + this.service:{}" , this.service);
	}// beforeAll
	
	@Test
	@Order(1)
	@DisplayName("1. BoardService.getlist ")
	@Timeout(value = 3 , unit=TimeUnit.SECONDS)
	void testGetList() throws ServiceException {
		log.trace("testGetList() invoked.");
		
		@Cleanup("clear")
		List<BoardVO> list = this.service.getList();
		
		list.forEach(log::info);
	}//testGetList
	
	
	@Test
	@Order(2)
	@DisplayName("2. BoardService.register ")
	@Timeout(value = 3 , unit=TimeUnit.SECONDS)
	void testRegister() throws ServiceException {
		log.trace("testRegister() invoked.");
		
		BoardDTO dto = new BoardDTO();
		dto.setTitle("TITLE_NEW");
		dto.setContent("CONTENT_NEW");
		dto.setWriter("WRITER_NEW");
		
		log.info("\t + result : {}" , this.service.register(dto));
		
	}//testRegister
	
	@Test
	@Order(3)
	@DisplayName("3. BoardService.modify ")
	@Timeout(value = 3 , unit=TimeUnit.SECONDS)
	void testModify() throws ServiceException {
		log.trace("testModify() invoked.");
		
		BoardDTO dto = new BoardDTO();
		dto.setBno(77);
		dto.setTitle("TITLE_UPDATED");
		dto.setContent("CONTENT_UPDATED");
		dto.setWriter("WRITER_UPDATED");
		
		log.info("\t + result : {}" , this.service.modify(dto));
		
	}//testModify
	
	@Test
	@Order(4)
	@DisplayName("4. BoardService.remove ")
	@Timeout(value = 3 , unit=TimeUnit.SECONDS)
	void testRemove() throws ServiceException {
		log.trace("testRemove() invoked.");
		
		BoardDTO dto = new BoardDTO();
		dto.setBno(77);
		
		log.info("\t + result : {}" , this.service.remove(dto));
		
	}//testRemove
	
	@Test
	@Order(5)
	@DisplayName("4. BoardService.get ")
	@Timeout(value = 3 , unit=TimeUnit.SECONDS)
	void testGet() throws ServiceException {
		log.trace("testGet() invoked.");
		
		BoardDTO dto = new BoardDTO();
		dto.setBno(77);
		
		log.info("\t + BoardVO : {}" , this.service.get(dto));
		
	}//testGet
	
	
}//end class

(데이터 정렬에 대해)

- Oracle Hint 에 대해서 배우자!!!!
(https://devuna.tistory.com/35 여기서 참고)
Syntax: /+ oraclehint /
특징: Oracle Hint 의 문법을 잘못적용해도, SQL 구문 오류가 발생하지는 않습니다.
단지, Oracle Hint 의 효과를 받을 수 없는 게 문제이지요.
그리고 Oracle Hint 는 대소문자를 가리지 않습니다(case-insensitive)

tbl_board table의 PK column => BNO
PK 제약조건이 걸린 컬럼에는 자동으로 Unique Index 가 생성된다!!! (***)

- Oracle Hint 의 종류에 대해서 알아두자!
(1) /*+ index(tablename indexname) */ || /*+ index(tablename) */
바로 아래의 index_asc 힌트와 같음
(2) /*+ index_asc(tablename indexname) */ || /*+ index_asc(tablename) */
(3) /*+ index_desc(tablename indexname) */ || /*+ index_desc(tablename) */
(4) /*+ full(tablename) */

  • 소위 Table Full Scan(테이블 전체를 순차검색)을 발생시킴(인덱스 전혀 사용하지 않고...)
    어느때 사용? 테이블의 크기가 작을 때
    인덱스로 얻어낼 행의 비율이 전체 행의 약 20%를 초과하면, 검색성능이 떨어짐

사용
SELECT /*+ full(tbl_board) */ * FROM tbl_board;

- ROW_NUMBER() OAF를 이용한 방법
(https://gent.tistory.com/170 여기에 자세하게 적혀있음)

ROW_NUMBER() 구간내에서 정렬된 순서를 기준으로 반환
SELECT row_number() over(ORDER BY bno DESC) AS ROWN, t.* FROM tbl_board t;

WITH 절은 임시 테이블 또는 가상 테이블(쿼리문 내에서만 실행)
WITH T AS (SELECT row_number() over(ORDER BY bno DESC) AS ROWN, t.* FROM tbl_board t)

모든 컬럼에 대해 T테이블에서 rown조건에 맞춰 77 이상 87 미만의 수를 뽑아라
SELECT * FROM T WHERE rown between 77 AND 87;


profile
일단 흐자

0개의 댓글