[12.29] 내일배움캠프[Spring] TIL-42

박상훈·2022년 12월 29일
0

내일배움캠프[TIL]

목록 보기
42/72

[12.29] 내일배움캠프[Spring] TIL-42

1. Spring Exception

  • ResponseHeader 에 응답 코드 담아서 보냄(403..500...200..)

HttpStatus,ResponseEntity

  • 코드 따고 들어가보면 enum으로 다 정의되어 있음!! 엄청 편리..!

  • 여태까지 우리의 코드에서는 Client의 실수 ( ex.중복 이름, 중복된 어떤 작업실행) 했을 때,
    throw로 Exception을 던져줬었다. -> 500 인데 그러면 클라이언트 실수가 아니라 서버코드 오류라는 뜻 -> 서버 코드 오류가 아닌데도 서버코드 오류 찾고 있는거에요...하아..!
  • 그렇기 때문에 응답을 보낼 때 예외가 아닌 errorMessage,httpStatus로 구성된 Json타입으로 보내줘야 한다는 이야기가 된다..
{
  "errorMessage":"중복된 폴더명을 제거해 주세요! 폴더명: 신발",
  "httpStatus":"BAD_REQUEST"
}
  • 그 전 프로젝트에서도 했었지만, 저러한 Json형태로 오류 메세지와 상태코드를 응답으로 내려주기 위해서는
    JavaClass객체에 변수를 초기화 한 상태로 반환해줘야 했었다.
    -> 그래서 ResponseMsgStatusDto를 만들어서 반환해줬었다.

public ResponseEntity randomLogic(){

try{

....비지니스 로직 수행
  } catch(IllegalArgumentExcetion e){

...비지니스 로직 수행 중 오류 발생 
return new ResponseEntity(ResponseMsgStatusDto,HttpStatus.BAD_REQUEST)
  }

}
  • 이런식으로 반환해주자...!
  • 근데 이렇게 비즈니스 로직마다 다 이렇게 넣어주기에는 코드의 중복도 많고, 굉장히 비효율적이다..!!!

@ExceptionHandler

  • Exception을 모듈화 한 AOP라고 쉽게 생각하자!
  • 다음과 같은 코드를 해당 비즈니스 로직 수행하는 Controller에 추가하자!
@ExceptionHandler({ IllegalArgumentException.class })
public ResponseEntity randomLogic(){

try{

....비지니스 로직 수행
  } catch(IllegalArgumentExcetion e){

...비지니스 로직 수행 중 오류 발생 
return new ResponseEntity(ResponseMsgStatusDto,HttpStatus.BAD_REQUEST)
  }

}
  • 근데 이것도 많이 모듈화 되었지만, Controller는 한개가 아니다... 이것 마저 중복이 싫다!!!!

Global Exception

  • @ControllerAdvice
  • @RestControllerAdvice = @ControllerAdvice + @RestController
@RestControllerAdvice
public class RestApiExceptionHandler{

	@ExcetpionHandler(value = { IllegalArgumentException.class })
    public ResponseEntity<Object> handleApiRequestException(IllegalArgumentException e){
    		return new ResponseEntity(ResponseMsgStatusDto,HttpStatus.BAD_REQUEST)
    }

}

2. Spring Transaction

  • 우리는 항상 비즈니스 로직 즉 DB와의 입출력을 하는 부분의 함수에 @Transactional을 사용했음.
  • 만약 데이터를 5개를 저장하는 중 3번째 데이터에서 Exception이 터졌다면 어떻게 될까?라는 의문에서 시작

Transaction

  • 데이터베이스에서 데이터에 대한 하나의 논리적 실행단계
  • 더 이상 쪼갤 수 없는 최소단위의 작업
  • 하나의 최소 단위의 작업에 여러가지 데이터 변경을 넣으면, 모두 저장 Or 아무것도 저장 안됨을 보장해야함.
  • 어노테이션이 아닌 트렌젝션 매니저를 사용해서 폴더 생성하는 코드 예시
		public List<Folder> addFolders(List<String> folderNames, User user) {
				// 트랜잭션의 시작
        TransactionStatus status = this.transactionManager.getTransaction(new DefaultTransactionDefinition());
				try {
	        // 1) 입력으로 들어온 폴더 이름을 기준으로, 회원이 이미 생성한 폴더들을 조회합니다.
	        List<Folder> existFolderList = folderRepository.findAllByUserAndNameIn(user, folderNames);
	
	        List<Folder> savedFolderList = new ArrayList<>();
	        for (String folderName : folderNames) {
	            // 2) 이미 생성한 폴더가 아닌 경우만 폴더 생성
	            if (isExistFolderName(folderName, existFolderList)) {
	                // Exception 발생!
	                throw new IllegalArgumentException("중복된 폴더명을 제거해 주세요! 폴더명: " + folderName);
	            } else {
	                Folder folder = new Folder(folderName, user);
	                // 폴더명 저장
	                folder = folderRepository.save(folder);
	                savedFolderList.add(folder);
	            }
	        }

					// 트랜잭션 commit
          transactionManager.commit(status);

	        return savedFolderList;
        } catch (Exception ex) {
            // 트랜잭션 rollback
            transactionManager.rollback(status);
            throw ex;
        }
    }
  • 우리는 어노테이션 하나로 트렌젝션의 원자성을 보장하는 Commit , Rollback을 쉽게 사용하고 있었던 것.
profile
기록하는 습관

0개의 댓글