web layer

service layer

package com.springbootaws.book.springboot.service.posts;

import com.springbootaws.book.springboot.domain.posts.PostRepository;
import com.springbootaws.book.springboot.domain.posts.Posts;
import com.springbootaws.book.springboot.web.dto.PostResponseDto;
import com.springbootaws.book.springboot.web.dto.PostSaveRequestDto;
import com.springbootaws.book.springboot.web.dto.PostUpdateRequestDto;
import com.springbootaws.book.springboot.web.dto.PostsListResponseDto;
import javafx.geometry.Pos;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class PostsService {
    // 생성자로 PostRepository를 DI받을 수 있도록 해서 확장성을 높임.
    private final PostRepository postRepository;

    @Transactional
    public Long save(PostSaveRequestDto postSaveRequestDto){
        // 결국 요청으로 받는 데이터는 Posts가 아닌 PostSaveRequestDto 형태이다.
            // --> Posts 테이블 정보가 수정되면 PostSaveRequestDto만을 수정하면 됨.
        // postRepository.save()가 저장된 객체를 반환함.
        return postRepository.save(postSaveRequestDto.toEntity()).getId();
    }

    @Transactional
    public Long update(Long id, PostUpdateRequestDto postUpdateRequestDto){
        // jpa의 영속성 컨텍스트 덕분에 entity를 수정하는 것만으로 @Transactional이 종료된 후 변경된 entity값을 반영한다.
        Posts posts = postRepository.findById(id).orElseThrow(()-> new IllegalArgumentException("해당 데이터가 없습니다 id=" + id));
        posts.update(postUpdateRequestDto.getTitle(), postUpdateRequestDto.getContent());
        return id;
    }

    public PostResponseDto findById(Long id){
        Posts posts = postRepository.findById(id).orElseThrow(()->new IllegalArgumentException("해당 데이터 없음 id=" + id));
        return new PostResponseDto(posts);
    }

    @Transactional
    public List<PostsListResponseDto> findAllDesc(){
        return postRepository.findAllDesc().stream()
                .map(PostsListResponseDto::new)// .map(posts -> new PostsListResponseDto(posts))
                .collect(Collectors.toList());
    }

    @Transactional
    public void delete(Long id){
        Posts posts = postRepository.findById(id).orElseThrow(()->new IllegalArgumentException("해당 게시글이 없음 id=" + id));
        postRepository.delete(posts);
    }
}

repository layer (dao)

// Post CRUD를 위한 repository 인터페이스 (MyBatis에서는 Dao라고 불림)

package com.springbootaws.book.springboot.domain.posts;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;

// JpaRepository<Entity 클래스, PK 타입> 상속시 기본적인 CRUD 기능 제공
// @Repository 어노테이션은 추가할 필요 없음. (단, Entity 클래스와 Entity 레포지토리는 저장 디렉터리가 같아야 한다.)
public interface PostRepository extends JpaRepository<Posts, Long> {
    @Query("SELECT p FROM Posts p ORDER BY p.id DESC")
    List<Posts> findAllDesc();
}

JpaRepository는 Repository 인터페이스를 상속받기 때문에 새로 bean을 만들지 않도록 @NoRepositoryBean가 있다

dto