코드 그라데이션

230217 최종프로젝트 Board단 코드 설명 본문

Spring/부트캠프

230217 최종프로젝트 Board단 코드 설명

완벽한 장면 2023. 2. 25. 22:47
일반적으로 컨트롤러에는 별도의 로직이 없다.
서비스를 부르는 게 그냥 단순함.

스프링은 컨테이너다.
@Conponent 는 스프링 보고, "이 객체를 관리해줘" 라고 말하는 것이다.

객체는 일반적으로 new 붙이고 사용하는데, 여기서는 그냥 쓰고 있다.
private final SetHttpHeaders httpHeaders;
이게 스프링의 역할.
스프링이 객체를 만들어서 넣어줬어.

setHeaderTypeJson() 이걸 매번 쓰고 있으니까 
아예 클래스로까지 빼서 이것만 사용하게 만들 수 있도록 해 둔 것 같다.

이걸 클래스에서 객체로 만들지 않고 그냥 static으로 만들면 어디서든 쓸 수 있으니까,
static으로 리펙토링 하는 것을 고려해보도록.

UserDetails는 사용자 정보 관련 시큐리티다.
유저 관련한 정보들을 다 들고 있을 것이다. 사용자 정보를 암호화해서 들고 다닌다.

Return은 "나는 응답 본문을 이걸로 하고 싶다" 라고 말하는 것
본문 말고도 내가 다양한 정보를 주고싶을 수가 있지. Status나 헤더까지
본문 말고도 세 개의 요소를 다 조작하고 싶다고 할 때, ResponseEntity를 쓰게 되는 것

사실 return ResponseEntity.ok() 이것만 써도,
상태는 ok이고 본문은 비워둘꺼야. 이러한 의미가 된다.
이제 헤더까지 설정하고 싶으면 헤더 적어주고, 본문도 적어주고 
return ResponseEntity.ok().headers(httpHeaders.setHeaderTypeJson()).body(boardService.getBoard(boardId));

Dto에선 @NoArgsConstructor도 중요하지만 @AllArgsConstructor도 매우 중요하다.

Timestamped는 워낙 중요해서 별도의 클래스로 뺀다.
그런데 얘 자체가 하나의 엔티티는 아니거든요. 별도의 테이블은 없다.(중복제거용)
그래서 @MappedSuperclass 를 써주는 것.

@CreatedDate @LastModifiedDate는 스프링이 값이 생성되고 수정될 때 자동으로 들어가게 만드는 것.
그렇기 위해서는 늘 보고(주시하고) 있어야 하겠지.
그래서 어노테이션 @EntityListeners를 쓴다. 늘 듣고있다는 느낌이지.
AuditingEntityListener 감시 느낌.

*fetch 타입.
(fetch = FetchType.LAZY) : 지연 로딩.
늦게~ 마지막이 될 때서야 일 하겠다 뭐 요런 느낌이랄까.

내가 여러개고 상대방이 하나다. 그러면 가져오는 것 자체가 문제가 되진 않지만,
내가 하나고 상대방이 여러개면 가져오는데 성가신 일들이 있을 수 있지,
그럴 때 쓰는 것이 LAZY

실제 세부 문서 까보면, ManytoOne의 기본값은 EAGER.
EAGER은 바로 가져오겠다는 소리
OneToMany는 한번에 여러개를 가져오면 성능에 문제가 생길 수 있으니,
기본값이 LAZY

CASCADE는 지울 때 설정
연쇄적인 삭제를 어떻게 할 것이냐. 이거 따로 찾아보기
orphanremoval은 나와 연관관계가 없는 공허한 관계일 때 지우겠다는 설정 의미
BoardRepository에서 하는 save나 update 같은 것은
"얘를 데이터베이스에 저장하겠다"는 뜻

그런데 board.update(boardRequestDto);는 
"이 객체의 상태만 바꾸겠다"는 뜻.
그래서 이 메서드 선언한 부분(Board 엔티티)에 들어가서 확인해봐도, 필드의 내용만 바꾸는 로직 수행하고 있어.
어디에도 "데이터베이스의 값을 바꾸겠다"라는 것은 없음.

"그럼 데이터베이스에 반영은 어떻게 되는 거냐?" 묻는다면,
이게 JPA의 재밌는 점이다.
JPA에 한 번 저장이 되면 걔는 JPA에서 관리하는 객체가 된다.
그럼 걔를 JPA가 최초 저장 상태를 사진 찍어놓는다.
그리고 요청한 작업이 끝날 때 이 객체 상태(들어오기 전)와 
들어와있는 최초의 객체 상태(사진찍어놓은 것)를 비교해서 달라졌으면, 그 때 update가 일어난다.

즉, board는 JPA가 관심있게 보고있는 객체 중에 하나고,
따라서 board의 "상태가 변하면", update가 자동으로 일어난다.
마치 boardRepository.update(board); 가 현재 없지만 있는 것처럼.

 

그리고 지금 이 메서드는 잘못됨.

public boolean checkBoardWriter(User user) {
	return this.user.equals(user);
}

 

id를 비교하면 서로 동등하다고 볼 수 있음.

따라서 @EqualsAndHashCode(of = "id") 와 같은 어노테이션이 필요하다.
User 엔티티에...

 

 

마지막으로 Service단

builder 관련.
Dto를 바로 save할 수 없으니까,
Dto라는 바구니에 담긴 정보들을 실제 board로 옮기고 저장하는 과정이 어쩔 수 없이 필요하다.
엔티티를 다 들고다니면 위험하니까.

게시글 수정에서는 문제 터짐.
chaekBoardWriter가 본인임을 확인할 수 있는 부분이 아니니까 현재는 예외 던짐(적중)

@Transactional(readOnly = true)
: 내가 이 테이블에 접근을 할 때, 수정할 의도가 없어 말해주는 것.
데이터베이스에서는 데이터가 동시에 수정되거나 하면 위험하기 때문에
수정하려면 lock을 얻어야 한다. 그렇게 하면 사실 성능이 저하됨. 느려지고.
근데 이 어노테이션을 걸면, 나 읽기만 할거니까 lock 안 줘도 돼 말하는 것.
그럼 성능저하 없음. 가독성도 좋지
728x90

'Spring > 부트캠프' 카테고리의 다른 글

Day11-2 메소드 도입  (0) 2023.03.29
200220 API 테스트해보기  (0) 2023.02.21
[스파르타] SpringData JPA 페이징 심화  (0) 2023.02.20
Spring 입문 과제 수행 관련  (0) 2023.01.15
Comments