[Spring] Memo API 만들기 (CRUD 기능 구현)

코린이·2021년 6월 28일
1

Spring

목록 보기
1/1
post-thumbnail

1. 목표

  • End to End 프로젝트

  • 3계층에 대한 이해

  • API 설계하기 (CRUD) 와 구현


2. Repository 만들기

1) Memo 클래스 만들기

왜 필요할가?
Memo라는 것을 구현하려면 필요한 Table을 만들어야 함
→ 이러한 기능을 Repository에서 domain이 담당하게됨
→ domain > Memo.java 클래스를 만들어 준다.

  • 메모는 1) 익명의 작성자 이름(username), 2) 메모내용(contents)로 이루어져 있다.
  • Memo.java
    @NoArgsConstructor // 기본생성자를 만듭니다.
    @Getter // getter를 lombok으로 쉽게 표현
    @Entity // 테이블과 연계됨을 스프링에게 알려줍니다. DB설계도로 할거야를 알려줌
    public class Memo extends Timestamped { // 생성,수정 시간을 자동으로 만들어줍니다.
    // Timestamped를 상속받아 기능을 추가(생성시간, 수정시간 변수화)

        @GeneratedValue(strategy = GenerationType.AUTO) // 1씩 증가하게 자동생성
        @Id // Primary key를 지정
        private Long id;                // 인스턴스 변수 1

        @Column(nullable = false)
        private String username;        // 인스턴스 변수 2

        @Column(nullable = false)
        private String contents;        // 인스턴스 변수 3

        public Memo(String username, String contents) { // 생성자를 만들어줌
            this.username = username; // 기본 생성자가 필요하지만 어노테이션 처리함
            this.contents = contents;
        }

        public Memo(MemoRequestDto requestDto) {
            this.username = requestDto.getUsername();
            this.contents = requestDto.getContents();
        }

        public void update(MemoRequestDto requestDto){ // 업데이트 메소드
            this.username = requestDto.getUsername();  // return 없음
            this.contents = requestDto.getContents();  // DTO를 통해서 update하게 됨
        }

    }
- DB를 직접 바꿀일은 없으므로 Setter는 필요 없음, Getter만 필요
- record를 생성할때 정해진 파라미터가 필요하므로 생성자가 필요함
- requestsDto를 통해서 데이터를 이동시키므로 생성자의 파라미터 타입 MemoRequestDto

2) MemoRepository 인터페이스 만들기

왜 필요할가?
SQL과 같은 기능을 하는 것은 Repository 따라서 MemoRepository를 만들어 줌
이때 JpaRepository의 메서드만 사용할 것이므로 상속후 인터페이스로 만들어 줌

  • MemoRepository.java

    public interface MemoRepository extends JpaRepository<Memo, Long> { // 상속 후 JPA 메서드 사용
        List<Memo> findAllByOrderByModifiedAtDesc(); // 수정시간 기준 오름차순으로 List안에 Memo 객체를 넣어줌
    }
- JPA 메서드만을 사용하는 인터페이스를 만드는데 Memo DB이므로 MemoRepository를 만듬

3) MemoRequestDto 클래스 만들기

왜 필요할가?
DB에 직접 접근하여 값을 수정하는 것은 데이터 분석에도 금기 되어 있는 사실!
따라서 값의 이동이 있을 때 DTO를 사용

  • MemoRequestDto.java

    @Getter
    public class MemoRequestDto {
        private String username;     // 컬럼 중 하나
        private String contents;     // 컬럼 중 하나

    }
- 자동생성되는 ID는 제외하고 memo table의 column을 멤버 변수로 갖는다.
- 또한 private 멤버 변수를 조회하기 위해 Getter 옵션을 사용한다.

3. MemoService 클래스 만들기

왜 필요할가?
일단은 Client에서 DB로 넘어가서 update를 해준다는 점에서 Service에 해당이 됨
추후 DB 관련 update는 모두 Service에서 구현하는지 궁금함
또한, 서비스에 대한 이해가 진짜 필요함

  • MemoService.java

    @RequiredArgsConstructor  // final은 꼭 필요한 녀석으로 생성자도 필요로 함
    @Service // Service임을 알려주고 있음
    public class MemoService {

        private final MemoRepository memoRepository;  //꼭 필요한 녀석

        @Transactional // 트랜젝션 기능
        public Long update(Long id, MemoRequestDto requestDto) {
            Memo memo = memoRepository.findById(id).orElseThrow(
                    () -> new IllegalArgumentException("아이디가 존재하지 않습니다.")
            );
            memo.update(requestDto);
            return memo.getId();
        }
    }
- 일단 Client단에서 DB로 데이터의 이동이기 때문에 Service에 update를 만들어 놓는 것임

4. Controller 클래스 만들기

왜 필요할가?
API 요청을 처리하기 위해 필요하다.
즉, API 설계도에 따라 적절한 GET, PUT, DELETE, POST에 따라 반환되는 값이 무엇인지 설정해주게 됨

  • MemoContoller.java
@RequiredArgsConstructor // final에 꼭 필요한 녀석들은 생성자를 필요로 함
@RestController // Json 형태로 객체 데이터를 반환하기 위함
public class MemoController {

    private final MemoRepository memoRepository; // 꼭 필요한 녀석들을 멤버 변수로 설정
    private final MemoService memoService;

    @PostMapping("/api/memos") // Post요청
    public Memo createMemo(@RequestBody MemoRequestDto requestDto) { // Json으로 입력받으면 
        Memo memo = new Memo(requestDto); // Memo 객체 생성 후
        return memoRepository.save(memo); // DB에 저장
    }

    @GetMapping("/api/memos") // Get 요청
    public List<Memo> getMemos() { // GET이므로 BODY에 json은 없음
        return memoRepository.findAllByOrderByModifiedAtDesc(); // 조회해줌
    }

    @DeleteMapping("/api/memos/{id}")
    public Long deleteMemo(@PathVariable Long id) { //URL path로 부터 파라미터를 받음
        memoRepository.deleteById(id);
        return id;
    }

    @PutMapping ("/api/memos/{id}")
    public Long updateMemo(@PathVariable Long id,@RequestBody MemoRequestDto requestDto){
        memoService.update(id,requestDto); //Service인 update를 이용
        return id;
    }
}
  • Client로 부터 시작되는 요청에 따라 어떻게 stack되는지 흐름을 파악할 필요가 있음
  • Client 요청으로 부터 해야될 일들이 Controller에 만들어져 있음을 확인

    느낀점!

    1. 객체 지향 개념을 모두 이해하면서 Spring에 대입하는 것이 완벽하게 되지 않는다는 것
      (기초가 부족)
    2. 아직도 Service의 모호한 개념이 머리에 있어서 추가 공부가 필요함
    3. Annotation은 그때그때 쓰임새를 알아둘 것
    4. 기본적으로 CRUD를 구현할 자신감은 생김!!
profile
백엔드 개발자를 목표로 공부하고 있습니다.

0개의 댓글