EFUB 백엔드 세션 5주차

xyzw·2023년 4월 11일
0

Spring

목록 보기
4/22

DELETE

문제

  • 세션에서 작성한 코드
@DeleteMapping("/{postId}/{accountId}")
@ResponseStatus(value = HttpStatus.OK)
public String postRemove(@PathVariable Long postId, @RequestParam Long accountId){
    postService.removePost(postId, accountId);
    return "성공적으로 삭제되었습니다.";
}

인텔리제이에서 경로 변수 'accountId'은(는) 사용되지 않습니다 라는 경고가 뜬다.

그리고 테스트를 위해 Postman에서 url을 http://localhost:8080/posts/3?accountId=2로 설정하고 DELETE를 보냈는데, 405 Method Not Allowed가 떴다.



해결

  • 수정한 코드
@DeleteMapping("/{postId}")
@ResponseStatus(value = HttpStatus.OK)
public String postRemove(@PathVariable Long postId, @RequestParam Long accountId){
    postService.removePost(postId, accountId);
    return "성공적으로 삭제되었습니다.";
}

RequestParam 사용에 문제가 있었다.

Controller에서 PathVariable과 RequestParam을 같이 사용할 때,
PathVariable만 url에 포함시켜주면 된다.

참고: https://github.com/im-yeobi/tip-storage/issues/9


Postman에서 동일한 url로 요청을 보냈고 성공했다!


PUT

문제

제목과 내용은 변경되는데 modifiedDate는 변경되지 않는 문제가 있었다.

  • 게시글 생성(POST)
  • 게시글 수정(PUT)

    PUT 메소드를 보내면 수정 시각이 자동으로 저장되어야 하는데, 사진에 나와있듯이 modifiedDate이 null이라고 뜬다.



해결

service 클래스에 @Transactional을 써주지 않았던 것이 문제였다.

@Transactional이란?

  • DB 등의 트랜잭션 처리를 위해 사용되는 어노테이션
  • 트랜잭션 begin, commit 해주고 특정 예외 발생 시 rollback해주는 역할
  • 우선순위: 클래스 메소드 > 클래스 > 인터페이스 메소드 > 인터페이스
  • @Transactional(readOnly = true): MySQL에서 SELECT문에 대해서만 기능을 지원하며, Transaction ID 설정에 대한 오버헤드를 해결할 수 있음. 조회의 경우에 주로 사용함.

Service 영역

  • 트랜잭션 처리를 담당하여 도메인의 상태 변경을 트랜잭션으로 처리하는 역할
  • 서비스 클래스에 @Transactional을 써주지 않으면, 엔티티가 변경되어도 트랜잭션 처리가 이루어지지 않아 데이터베이스에 반영되지 않음
@Service
@Transactional  // 어노테이션 추가
@RequiredArgsConstructor
public class PostService {

    private final PostRepository postRepository;
    private final AccountRepository accountRepository;

    public Post addPost(PostRequestDto requestDto) {
        Account writer = accountRepository.findById(requestDto.getAccountId())
                .orElseThrow(()-> new IllegalArgumentException("존재하지 않는 계정입니다."));

        return postRepository.save(
                Post.builder()
                        .title(requestDto.getTitle())
                        .content(requestDto.getContent())
                        .writer(writer)
                        .build()
        );
    }

    @Transactional(readOnly = true)   // 게시글 전체 조회
    public List<Post> findPostList() {
        return postRepository.findAll();  //List<Post>를 반환
    }

    @Transactional(readOnly = true)   // 게시글 개별 조회
    public Post findPost(Long postId) {
        return postRepository.findById(postId)
                .orElseThrow(()->new IllegalArgumentException("존재하지 않는 게시글입니다."));
    }

    public void removePost(Long postId, Long accountId) {
        Post post = postRepository.findByPostIdAndWriter_AccountId(postId, accountId)
                .orElseThrow(()->new IllegalArgumentException("잘못된 접근입니다."));

        postRepository.delete(post);
    }


    public Post modifyPost(Long postId, PostModifyRequestDto requestDto) {
        Post post = postRepository.findByPostIdAndWriter_AccountId(postId, requestDto.getAccountId())
                .orElseThrow(()->new IllegalArgumentException("잘못된 접근입니다."));
        post.updatePost(requestDto);
        return post;
    }
}

클래스에 @Transactional을 두고, 조회에 사용되는 메소드 findPostListfindPost에는 @Transactional(readOnly = true)을 두었다.


Postman에서 다시 PUT을 보내보았다.
수정 시각이 저장되었다!

0개의 댓글