Self Code Review/(sparta) Spring 기초 - CRUD API
[Spring] Spring 구조와 API 흐름 이해하기2 (스파르타코딩클럽 - 웹개발의 봄, Spring 3주차)
밍굥잉
2022. 5. 26. 20:54
{ ⭐ 더 정리된 노션 버전 ⭐}
❗API 설계하기 (CRUD)
✔️ Repository 만들기
- domain 패키지 (Repo 영역) 만들기
- domain - Memo.java 클래스 생성
package com.sparta.week03.domain;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@NoArgsConstructor // 기본생성자를 만듭니다.
@Getter
@Entity // 테이블과 연계됨을 스프링에게 알려줍니다.
public class Memo extends Timestamped { // 생성,수정 시간을 자동으로 만들어줍니다.
@GeneratedValue(strategy = GenerationType.AUTO)
@Id
private Long id;
@Column(nullable = false)
private String username;
@Column(nullable = false)
private String contents;
public Memo(String username, String contents) {
this.username = username;
this.contents = contents;
}
public Memo(MemoRequestDto requestDto) {
this.username = requestDto.getUsername();
this.contents = requestDto.getContents();
}
}
- lombok을 이용해 기본 생성자를 만드는 @NoArgsConstructor, Getter를 생성해주는 @Getter를 추가
- 테이블과 이어지는 파일이라는 것을 알려주기 위해 @Entity를 추가
- 메모는 1) 익명의 작성자 이름 (username), 2) 메모 내용 (contents)로 이루어짐
- 구별해주는 키 id를 생성하고, 자동으로 증가하도록 *@GeneratedValue*(strategy = *GenerationType*.AUTO) 추가
- 현재 상태 : (🥶)Timestamped, (😤)MemoRequestDto 가 생성되지 않았기 때문에 에러
3. domain - Timestemped.java 클래스 생성
@MappedSuperclass // Entity가 자동으로 컬럼으로 인식합니다.
@EntityListeners(AuditingEntityListener.class) // 생성/변경 시간을 자동으로 업데이트합니다.
public abstract class Timestamped {
@CreatedDate
private LocalDateTime createdAt; //생성시간
@LastModifiedDate
private LocalDateTime modifiedAt; //수정시간
}
- @MappedSuperclass : Timestamped를 상속한 클래스(이 프로젝트에서는 Memo.java)에 자동으로 생성 시간과 수정 시간을 colunm으로 인식하게 함.
- @EntityListeners : Entity(이 프로젝트에서는 Memo.java)가 변화하는 것을 항상 듣고 있다는 것.
- LocalDateTime : 시간을 나타내는 자료형
- abstract 추가해서 추상 클래스로 만들어줘야함.
- New Timestamped 로 사용할 수 없음,
- (빵 틀은 있지만 빵 못만들고, 상속이 되어야만 만들 수 있는 클래스다)
- (🥶) Timestamped 클래스 만들어서 에러 해결!
4. domain - MemoRequestDto.java 클래스 생성
@Getter
public class MemoRequestDto {
private String username;
private String contents;
}
- RequestDto는 계층간 데이터 교환을 위해 필요한 정보(username, contents)를 가지고 다님.
- private로 설정하고, 가져오기 위해 @Getter 추가
- (😤) MemoRequestDto 클래스 만들어서 에러 해결!
5. domain - MemoRepository.java 인터페이스 생성
public interface MemoRepository extends JpaRepository<Memo, Long> {
List<Memo> findAllByOrderByModifiedAtDesc();
}
- (extends) MemoRepository는 미리 작성된 JpaRepository(findAll, delete, findById, sava …)를 / Memo라는 클래스의 id가 Long인 것에 대해서 가져다가 쓸거야
- findAllByOrderByModifiedAtDesc
- *️⃣ JPA 공식 홈페이지 문서 참고
- https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods
- findAll By OrderBy ModifiedAt Des
- 다 찾아서 정렬해줘 수정된 날짜 기준으로 내림차순(최신순)
- ⇒ 다 찾아서 수정된 날짜 기준으로 최신순으로 정렬해줘
✔️ Service 만들기
- service 패키지 생성하기
- service - MemoService.java 클래스 생성
@Service
public class MemoService {
@Transactional
public Long update(Long id, MemoRequestDto requestDto) {
Memo memo = memoRepository.findById(id).orElseThrow(
() -> new NullPointerException("아이디가 존재하지 않습니다. ")
);
memo.update(requestDto);
return id;
}
- update 시 service 가 필요하기 때문에 update 메소드를 생성해줌.
- public 반환타입 메소드이름(파라미터) { }
- id를 가져와서 해당하는 id의 Dto를 변경해줘야하기 때문에 (Long id, MemoRequestDto requestDto)을 파라미터로 설정
- return 하는 id의 반환타입인 Long
1) id로 해당하는 메모 찾기
-
Memo memo = memoRepository.findById(id).orElseThrow( () -> new NullPointerException("아이디가 존재하지 않습니다. ") );
- memoRepository의 findId로 id를 기준으로 찾을 건데, 만약에 없으면 오류 발생 시켜줘
- NullPointerException : 가리킨 게 비어있으면 예외 처리 해줘
- IllegalArgumentException : Argument(파라미터)가 뭔가 잘못됐으면 예외처리 해줘
- id로 메모를 찾았거나 오류를 보냈으면 memo에 반환해줘.
- memoRepository의 findId로 id를 기준으로 찾을 건데, 만약에 없으면 오류 발생 시켜줘
2) update 하기
-
memo.update(requestDto); return id;
- memo에 requestDto를 update 하고, id 값으로 넘겨줘
3. domain - Memo.java 클래스에 update 메소드 추가하기
public void update(MemoRequestDto requestDto) {
this.username = requestDto.getUsername();
this.contents = requestDto.getContents();
}
- MemoService에서 requestDto를 전달받기 때문에 update 메소드의 파라미터는 requestDto
- 변경할 값을 실어나르는 Dto의 값이 Memo 안에 저장됨.
4. MemoService.java 완성시키기
@RequiredArgsConstructor
@Service
public classMemoService{
private final MemoRepository memoRepository;
@Transactional
publicLongupdate(Longid,MemoRequestDtorequestDto) {
Memomemo = memoRepository.findById(id).orElseThrow(
() -> new NullPointerException("아이디가 존재하지 않습니다. ")
);
memo.update(requestDto);
returnid;
}
}
- memoRepository 꼭 필요하니까 final 적어주기
- @RequiredArgsConstructor : fianl이 있으면 알아서 생성자를 만들어주는 권한을 줘야함
- @Service : 서비스라고 알려주기
- @Transactional : 업데이트 할 때 DB에 진짜 반영되야한다고 알려줌.
✔️ Controller 만들기
- Controller 패키지 생성하기
- MemoController.java 클래스 생성
@RequiredArgsConstructor
@RestController
public classMemoController{
private final MemoRepository memoRepository;
private final MemoService memoService;
}
- MemoRepository랑 memoService 사용하건데 꼭 필요하니까 final 추가해줘
- 원래는 요청이 들어오면 new memoController ~ 라고 생성이 된 후 사용해야하는데, @RequiredArgsConstructor, @RestController 를 사용하면 스프링이 그 역할을 해줌.
POST - 생성
@PostMapping("/api/memos")
public Memo createMemo(@RequestBody MemoRequestDto requestDto) {
Memo memo = new Memo(requestDto);
return memoRepository.save(memo);
}
- requestDto라는 틀에 새로운 메모를 만들어서 memoRepository의 save를 활용해서 저장.
Get - 조회
@GetMapping("/api/memos")
public List<Memo> readMemo() {
return memoRepository.findAllByOrderByModifiedAtDesc();
}
- memoRepository에 있는 모든 데이터를 수정날짜 기준으로 최신순으로 정렬해 보여줌.
PUT - 변경
@PutMapping("/api/memos/{id}")
public Long updateMemo(@PathVariable Long id, @RequestBody MemoRequestDto requestDto) {
memoService.update(id, requestDto);
return id;
}
- 변경할 메모의 id를 받아서 memoService로 업데이트 하고 다시 id를 돌려줌
DELETE - 삭제
@DeleteMapping("/api/memo/{id}")
public Long deleteMemo(@PathVariable Long id) {
memoRepository.deleteById(id);
return id;
}
- 삭제할 메모의 id를 받아서 삭제하고 id를 돌려줌.