java/spring
Memo api 구현
일상코더
2022. 10. 7. 03:43
최대한 lombok 없이 구현해 보았다.
Memo.java
@Entity
public class Memo extends Timestamped{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(nullable = false)
private String username;
@Column(nullable = false)
private String contents;
// 파라미터가 있는 생성자를 하나라도 정의하게 되면
// 더이상 기본생성자를 생성하지 않기때문에 기본생성자를 꼭 만들어줘야한다.
// @NoArgsConstructor 을 사용하는 이유
public Memo(){
}
public Memo(MemoRequestDto requestDto){
this.username = requestDto.getUsername();
this.contents = requestDto.getContents();
}
//getter를 만들지 않으면 클라이언트에게 데이터를 전달할수 없다.
//@Gettor lombok을 사용하는 이유
public Long getId(){
return this.id;
}
public String getUsername(){
return this.username;
}
public String getContents(){
return this.contents;
}
public void update(MemoRequestDto requestDto){
this.username = requestDto.getUsername();
this.contents = requestDto.getContents();
}
}
Timestamped.java
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;
@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
public abstract class Timestamped {
@CreatedDate
private LocalDateTime createdAt;
@LastModifiedDate
private LocalDateTime modifiedAt;
public LocalDateTime getCreatedAt(){
return this.createdAt;
}
public LocalDateTime getModifiedAt(){
return this.modifiedAt;
}
}
MemoApplication.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@EnableJpaAuditing //생성하지 않으면 생성 / 수정 일자가 db에 들어가지 않는다.
@SpringBootApplication
public class MemoApplication {
public static void main(String[] args) {
SpringApplication.run(MemoApplication.class, args);
}
}
MemoRepository.java
import com.sparta.memo.entity.Memo;
import org.springframework.data.jpa.repository.JpaRepository;
public interface MemoRepository extends JpaRepository<Memo, Long> {
//인터페이스로 구현하는 이유
//실제로 메서드를 정의만 하고 구체적으로 구현하지 않기때문
}
MemoController.java
import com.sparta.memo.dto.MemoRequestDto;
import com.sparta.memo.dto.MemoResponseDto;
import com.sparta.memo.dto.MemoUsernameResponseDto;
import com.sparta.memo.entity.Memo;
import com.sparta.memo.repository.MemoRepository;
import com.sparta.memo.service.MemoService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;
@RestController //@ResponseBody @Controller를 포함하고있다
//@RestController를 입힌 @RequestMapping메서드(ex @GetMapping)가
//기본적을 @ResponseBody 의미 체계를 띠고 있고있는 컨트롤러로 처리한다.
public class MemoController {
//memoRepository, memoService 값이 변할수 없음을 나타냄
//final로 처리하게 되면 파라미터 생성자를 만들어줘야한다.
//@RequiredConstructor을 사용하는 이유
public final MemoRepository memoRepository;
public final MemoService memoService;
//MemoController생성자
public MemoController(MemoRepository memoRepository, MemoService memoService) {
this.memoRepository = memoRepository;
this.memoService = memoService;
}
//전체 메모 조회
@GetMapping("/api/memos")
public List<MemoResponseDto> getMemos(){
return memoRepository.findAll().stream()
.map(MemoResponseDto::new)
.collect(Collectors.toList());
}
//id로 user이름 조회
@GetMapping("/api/memos/user/{id}")
public List<MemoUsernameResponseDto> getUsername(@PathVariable Long id){
return memoRepository.findById(id).stream()
.map(MemoUsernameResponseDto::new)
.collect(Collectors.toList());
}
//id로 조회
@GetMapping("/api/memos/{id}")
public List<MemoResponseDto> getMemo(@PathVariable Long id){
return memoRepository.findById(id).stream()
.map(MemoResponseDto::new)
.collect(Collectors.toList());
}
//메모 등록
@PostMapping("/api/memos")
public MemoResponseDto createMemos(@RequestBody MemoRequestDto requestDto){
Memo memo = memoRepository.save(new Memo(requestDto));
return new MemoResponseDto(memo);
}
//id로 메모 수정
@PutMapping("/api/memos/{id}")
public Long update(@PathVariable Long id, @RequestBody MemoRequestDto requestDto){
return memoService.update(id, requestDto);
}
//id로 메모 삭제
@DeleteMapping("/api/memos/{id}")
public Long Delete(@PathVariable Long id){
memoRepository.deleteById(id);
return new MemoResponseDto().getId();
}
}
MemoRequestDto.java
// 클라이언트에서 메모를 등록할때 @RequestBody로 json형식의 데이터가 넘어오면
// MemoRequestDto를 통해 Entity테이블에 값이 변경되고 MemoResponseDto를 이용해서
// DB에서 받은 데이터를 client에 보내준다.
public class MemoRequestDto {
private String username;
private String contents;
public String getUsername(){
return this.username;
}
public String getContents(){
return this.contents;
}
}
MemoResponseDto.java
public class MemoResponseDto {
private Long id;
private String username;
private String contents;
private LocalDateTime createdAt;
private LocalDateTime modifiedAt;
//Memo entity 테이블에 있는 데이터들이 entity에서 바로 클라이언트에게 가는게아니라
//MemoResponseDto를 통해 전달된다. entity는 db와 가장 근접해있기 때문에
//entity를 직접 수정하는것보다 ResponseDto를 사용해서 넘겨주는것이 안정이나
//유지보수 측면에서 더 좋다.
public MemoResponseDto(Memo memo){
this.id = memo.getId();
this.username = memo.getUsername();
this.contents = memo.getContents();
this.createdAt = memo.getCreatedAt();
this.modifiedAt = memo.getModifiedAt();
}
//위에있는 파라미터가 있는 생성자가 있으면
//컴파일할때 자동으로 기본생성자가 생성되지 않기때문에
//기본생성자를 만들어줘야한다
//@NoArgsConstructor을 사용하는이유
public MemoResponseDto(){
}
//값이 클라이언트로 전달되어야기때문에 getter를 만들어줘야함
//@Getter를 사용하는 이유
public Long getId(){
return this.id;
}
public String getUsername(){
return this.username;
}
public String getContents(){
return this.contents;
}
public LocalDateTime getCreatedAt(){
return this.createdAt;
}
public LocalDateTime getModifiedAt(){
return this.modifiedAt;
}
}
MemoUsernameResponseDto.java
public class MemoUsernameResponseDto {
private String username;
public MemoUsernameResponseDto(Memo memo){
this.username = memo.getUsername();
}
public String getUsername(){
return this.username;
}
}
MemoService.java
import com.sparta.memo.dto.MemoRequestDto;
import com.sparta.memo.dto.MemoResponseDto;
import com.sparta.memo.entity.Memo;
import com.sparta.memo.repository.MemoRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;
@Service
public class MemoService {
private final MemoRepository memoRepository;
public MemoService(MemoRepository memoRepository){
this.memoRepository = memoRepository;
}
//현재 MemoController에서 구현된 모든 로직들은 아래와 같이
//service단에서 구현되어야한다.
//일부러 refacoring을 위해 MemoController에 구현했다.
@Transactional
public Long update(Long id, @RequestBody MemoRequestDto requestDto){
Memo memo = memoRepository.findById(id).orElseThrow(
() -> new IllegalArgumentException("해당아이디가 없습니다.")
);
memo.update(requestDto);
return new MemoResponseDto(memo).getId();
}
}
Lombok 없이 구현해서 알게된 오류
1. Memo Entity에 기본생성자가 없으면 컴파일시 오류가 난다.
- 매개변수가 있는 생성자를 만들면 컴파일러가 기본생성자를 자동으로 만들어주지 않기때문에 따로 만들어줘야함
- @NoArgsConstructor을 사용하는 이유
2. getter를 만들지 않으면 데이터가 클라이언트에게 전달이 되지 않는다
- @Getter을 사용하는 이유
3. final 상수 선언시 생성자를 무조건 생성해줘야한다.
- @RequiredArgsConstructor을 사용한이유
https://github.com/Liam-Genius/homework2/tree/master/spring%201st%20week/post01/memo
GitHub - Liam-Genius/homework2
Contribute to Liam-Genius/homework2 development by creating an account on GitHub.
github.com