Service

스프링 Container가 anotation을 bean으로 등록하고 실행하게 되는데,

객체를 생성하고 setter를 통해서 자기가 테스트하려는 기능을 변경하는 작업을 수동으로 하는게 아니라

초기부터 변경을 할수 있기로 하겠다라고 해서 생성자 방식으로 하는 방법이 있음

테스트에서 가장 많은 생성자 주입부분을사용함

테스트케이스에 보면 before 어노테이션이 있어서 시작될때 mocked 이라는 가짜 객체를 넣어서 하는 경우도 있음


Service 계층

@Service //(1) : 전형적인 서비스 코드
@Transactional //(2) 트렌잭션을 관리 하겠다라는 표현
public class BookServiceImpl implements BookService{
 private final BookRepository repository;
 
 //생성자 주입방식으로 bean에 등록
 public BookServiceImpl(BookRepository repository){
   this.repository = repository;
}
 
 //method를 BookService에서 선언해 두었기 때문에 덮어쓰기 했다.
 @Override
 public Optional<Book> findById(Long id){
   return repository.findById(id);
}
 
 @Override
 public List<Book> findAll(OffSetPageRequest request){
   return repository.findAll(request.getPageRequest()).getContent();
}
}package com.merona.study.service;

import com.merona.study.domain.Book;

import java.util.Optional;

public interface BookService {

   Optional<Book> findById(Long id);
}
package com.merona.study.service;

import com.merona.study.domain.Book;
import com.merona.study.domain.BookRepository;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.Optional;

@Service
@Transactional
// save, delete 등을 추가 하기 위해서
public class BookServiceImpl implements BookService {

   private final BookRepository bookRepository;

   //생성자 주입
   public BookServiceImpl(BookRepository bookRepository) {
       this.bookRepository = bookRepository;
  }


   @Override
   public Optional<Book> findById(Long id) {
       return bookRepository.findById(id);
  }

}
package com.merona.study.service;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;


@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class BookServiceImplTest {


   @Autowired
   BookService bookService;

//expected 오류가 날것이라는 예측을 하는 어노테이션 옵션
   @Test(expected=RuntimeException.class)
   public void testFindById(){
       Long id = 1L;
       bookService.findById(id)
              .orElseThrow(()->new RuntimeException("Not found"));
  }

}@ControllerAdvice(annotations = {RestController.class})
@ResponseBody
public class GlobalRestControllerAdvice{
 
 @Exceptionhandler(BookNotFoundException.class)
 public ApiResponse<Void> handleException(Exception e){
   Log.error("Occurred Exception: {} ", e);
   return ApiResponse.error(e.getMassage());
}
}package springboot_api;

import com.merona.study.domain.Book;
import com.merona.study.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/books")
public class BookController {
   @Autowired
   BookService bookService;

   @GetMapping("/{bookId}")
   public ResponseEntity<Book> findById(Long bookId){
       Book book = bookService.findById(bookId)
              .orElseThrow( ()-> new RuntimeException("Not Found" + bookId));
       //http status 는 번호로 관리되는데 정상적으로 하면 200 ok 가 반환된다.
       return ResponseEntity.ok( book);
  }
}

@Profile -Type


Spring REST DOCs : api 문서에 대한 설명을 html로 만들어서 관리할 수 있다.

  • 시스템의 자원에 대한 접근 및 제어를 제공하는 API

  • 자원에 대한 접근 및 제어

    • GET /books

    • GET /books/{bookId}

    • POST /books

    • PUT /books/{bookId}

    • DELETE /books/{booksId}

  • 스프링에서는 요청에 따라 등록 되어 있는 적절한 HttpMessageConverter를 통해서 응답데이터를 반환한다.

REST api


예제 코드

restContrller에 오류가 발행사게 되면 exception handler를 반환할 수도 있다.

  • @ControllerAdvice를 이용한 처리

@ControllerAdvice를 이용한 처리

@Controller 예외 처리

 

  • DispatcherServlet에 등록된 @RequestMapping 등록되고 추후에 요청이 오면 해당하는 메서드를 찾아서 호출됨

  • 템플릿 엔진이 랜더링 할 뷰 페이지를 지정

  • 호출된 API에서 처리한 응답을 반환

@Controller

참고 : https://www.slideshare.net/hanmomhanda/spring-mvc-fullflow

anotation의 타입은 class, method에 추가할 수 있다.

@RequestMapping() : 클래스 타입의 레벨이 있을수도있고, Spring dispatcher Servelt이 controller 라고하는 anotation을 훓으면서 RequestMapping 있는 타입을 찾고 이후 차근차근 내려가게 된다.

@RestController 또는 @Controller

Controller


테스트 코드

BookRepository를 생성자에 주입하여 사용하는 BookServiceImpl 클래스

bookService 인터페이스

예제 코드

  • 트랜잭션(@Transactional) 관리 영역

    • 행위 시작, 종료 시까지 정상적으로 될때까지는 종료, 데이터 이상시에는 되돌리는 롤백을 하게됨

  • 서로 다른 도메인 연계(DI, @Autowired) 작업 영역

    • book과 category라는 엔티티를 서로 상호 작용을 하는 영역

  • @Controller와 @Repository 사이의 중계

@Service


'BackEnd > SpringBoot' 카테고리의 다른 글

Spring Boot Logging (1)  (0) 2020.04.16
Request Body 의 값 BadRequest 로 보내기  (0) 2020.04.11
SpringBoot(4) -T-Academy  (0) 2019.05.24
SpringBoot(2) -T-Academy  (0) 2019.05.21
SpringBoot 시작하기(1)-T-Academy  (0) 2019.05.20

+ Recent posts