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();
}
}
= Memo클래스이다. @들어가는 어노테이션들을 주의깊게보고, 실제 프로젝트에 사용해보자
package com.sparta.week03.domain;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;
@MappedSuperclass // Entity가 자동으로 컬럼으로 인식합니다.
@EntityListeners(AuditingEntityListener.class) // 생성/변경 시간을 자동으로 업데이트합니다.
public abstract class Timestamped { //abstract를 사용하면서 상속을 통해서만 사용할수있는 클래스다.
@CreatedDate //생성시간을 나타냄
private LocalDateTime createdAt;
@LastModifiedDate //수정시간을 나타냄
private LocalDateTime modifiedAt;
}
특별하게 추상클래스로 만들어줬는데, 상속을 통해서만 사용이 가능하도록 만들어주었다.
새로운@ 어노테이션들이 많이있다. 주석 달린것들을 토대로 이해해보자.
MemoRepository에서 JpaRepository의 메소드들을(findAll, delete, findById, save등등)을 사용할 것이라고 알려주는 것이고, 그 대상을 어디에 가져가 쓸것이냐에 대해서도 Memo라는 클래스고 Long이라는 id에 쓸것이라는 것도 알려준다.
단 여기서 List Memo findAllByOrderByModifiedAtDesc(); 요녀석은 뭘까 ?
JPA공식 사이트를 들어가보자. JPA규칙대로 메소드명만 잘 만들어주면 알아서 그 뒤의 로직을 다 만들어 준다.
findAll / By / OrderBy / ModifiedAt DESC 로 나눠서 볼수있는데
= 다 찾고 순서대로 정렬해줘라, 최신 수정된 날짜를 기준으로 ! 라는 뜻이다.
무언가를 변경시킬때 필요한 내용(내가 설정해준 정보)을 물고 돌아 다니는 녀석!
package com.sparta.week03.domain;
import lombok.Getter;
@Getter
public class MemoRequestDto {
private String username;
private String contents;
}
메모를 업데이트해주기 위해서는 두 단계가 필요한데, 1번은 필요한 녀석을 찾고, 2는 그녀석의 정보를 업데이트해줘야한다.
필요한 녀석을 찾으려면 find를 사용하게 되는데 이때는 repository가 필요하다.
그래서 rerpository를 생성해주고 findbyid를 사용하는데, 항상 스프링에는 이런 아이디가 없을때의 어떻게 할 것이냐를 스프링에게 알려줘야 한다. orElseThrow를 통해서 뭔가 없으면 오류를 발생 시키라고 한다.
public Long update(Long id, MemoRequestDto requestDto) {
Memo memo = memoRepository.findById(id).orElseThrow(
() -> new IllegalArgumentException("아이디가 존재하지 않습니다.")
);
memo.update(requestDto);
return memo.getId();
}
여기서 memoRepository를 그냥 둬버리면 spring에서는 애가 MemoService인지 아닌지를 잘 모르기때문에 final을 붙여서 꼭 필요한 녀석이라는 것을 알려줘야 한다. 또한 추가로
@RequiredArgsConstructor을 통해서 final로 선언된 녀석을 같이 넣어달라고 spring에게 얘기해주고 @Serivce를 통해서 spring에게 말해준다.
추가로 DB에 포함될수있도록 @Transactional을 사용하여 spring에게 말해준다.
repository service를 만들었으니 이제 controller을 만들 차례이다.
package com.sparta.week03.controller;
import com.sparta.week03.domain.Memo;
import com.sparta.week03.domain.MemoRepository;
import com.sparta.week03.domain.MemoRequestDto;
import com.sparta.week03.service.MemoService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RequiredArgsConstructor
@RestController
public class MemoController {
private final MemoRepository memoRepository; //CRD에는 레포가 필요
private final MemoService memoSerive; //업데이트에는 서비스가 필요
@PostMapping("/api/memos")
public Memo createMemo(@RequestBody MemoRequestDto requestDto){
Memo memo = new Memo(requestDto);
return memoRepository.save(memo);
}
@GetMapping("/api/memos")
public List<Memo> readMemo(){
return memoRepository.findAllByOrderByModifiedAtDesc();
}
@DeleteMapping("/api/memos/{id}")
public Long deleteMemo(@PathVariable Long id){
memoRepository.deleteById(id);
return id;
}
}
처음에 post를 할때 에러나 갔다. 왜냐 보았더니 요청이 왔을때 body안에 있는 내용을 DTO에 넣어 주는 @RequestBody(요청이들어왔을때 BODY안에 들어오는 REQUEST DTO에 넣어주는 녀석) 어노테이션이 빠졌기 때문이다. +실수가 많다니까 잘 생각해보자
자 다음으로는 아이디가 1인 녀석을 DELETE를 실행해보자
1이 나왔고, 다시 GET으로 요청하면 빈목록이 보인다. 잘 삭제됨을 확인할 수있다.