Spring Todo-List 할 일 목록 여러개 만들기

춤인형의 개발일지·2024년 12월 26일

Spring실습

목록 보기
15/40

24/12/26(목)

todo-list 추가구현

할 일 목록 여러 개 만들기

오늘 할일 : 
[ 일찍 자기,
푹 자기,
대박 개운하게 자기
]

이렇게 만들고 싶음. title이 하나 있고, 그 안의 여러개의 content가 있는 상황

Api스펙 수정

  1. DTO 만들기
//요청
public record TodoTitleRequest(String title) {
}

//응답
public record TodoTitleResponse(String title, Long id) {
}
  1. 컨트롤러
@RestController
public class TodoTitleRestController {

    private TodoTitleService todoTitleService;

    public TodoTitleRestController(TodoTitleService todoTitleService) {
        this.todoTitleService = todoTitleService;
    }

    @PostMapping("/todoTitles")
    public TodoTitleResponse create(@RequestBody TodoTitleRequest todoTitleRequest){
        return todoTitleService.create(todoTitleRequest);
    }

    //제목들만 보기
    @GetMapping("/todoTitles")
    public List<TodoTitleResponse> read(){
        return todoTitleService.read();
    }

    @PutMapping("/todoTitles/{todoTitleId}")
    public TodoTitleResponse update(@PathVariable Long todoTitleId, @RequestBody TodoTitleRequest todoTitleRequest){
        return todoTitleService.update(todoTitleId, todoTitleRequest);
    }

    @DeleteMapping("/todoTitles/{todoTitleId}")
    public void delete(@PathVariable Long todoTitleId){
        todoTitleService.delete(todoTitleId);
    }
}
  1. 엔티티
    id, id뺀 생성자, 기본 생성자, getter
@Entity
public class TodoTitle {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;

    public TodoTitle() {
    }

    public TodoTitle(String title) {
        this.title = title;
    }

    public Long getId() {
        return id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}
  1. 리포지토리
//리포지토리
public interface TodoTitleRepository extends JpaRepository<TodoTitle, Long> {
}
  1. service
@Service
public class TodoTitleService {

    private TodoTitleRepository todoTitleRepository;

    public TodoTitleService(TodoTitleRepository todoTitleRepository) {
        this.todoTitleRepository = todoTitleRepository;
    }

    public TodoTitleResponse create(TodoTitleRequest todoTitleRequest) {
        TodoTitle todoTitle = todoTitleRepository.save(new TodoTitle(todoTitleRequest.title()));
        return new TodoTitleResponse(todoTitle.getTitle(), todoTitle.getId());
    }

    public List<TodoTitleResponse> read() {
        List<TodoTitle> titleAll = todoTitleRepository.findAll();
        return titleAll.stream().map(todoTitle -> new TodoTitleResponse(todoTitle.getTitle(), todoTitle.getId())).toList();
    }

    @Transactional
    public TodoTitleResponse update(Long todoTitleId, TodoTitleRequest todoTitleRequest) {
        TodoTitle todoTitle = todoTitleRepository.findById(todoTitleId).orElseThrow();
        todoTitle.setTitle(todoTitleRequest.title());
        return new TodoTitleResponse(todoTitleRequest.title(),todoTitleId);
    }

    public void delete(Long todoTitleId) {
        TodoTitle todoTitle = todoTitleRepository.findById(todoTitleId).orElseThrow();
        todoTitleRepository.delete(todoTitle);
    }
}

crud는 같은 내용이니까 패스!


일단 관계를 먼저 생각해보자

  • title | content
    하나의 title안에는 여러개의 content를 갖는다. (N)
    하나의 content는 하나의 title를 갖는다. (1)
    1:N관계네!

관계맺기

엔티티끼리 관계를 맺어줘야한다.
N인 쪽에 ManyToOne
1인 쪽에 OneToMany - 이건 근데 옵션이다. 해도되고 안해도되고

//Todo Entitiy
@Entity
public class Todo {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String content;
    private Boolean isCompleted = false;

//관계맺기
    @ManyToOne
    private TodoTitle todoTitle;
    
    public Todo(String content, TodoTitle todoTitle) {
        this.content = content;
        this.todoTitle = todoTitle;
    }

//TodoTitle Entity
@Entity
public class TodoTitle {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;

    //이거 그냥 옵션임 없어도됨
    @OneToMany(mappedBy = "todoTitle")
    private List<Todo> todo;
  1. 순서 정하기
    순서는
    1. 제목이 만들어진 후
    2. 그 안에 할일들을 만든다.

<나의 고민>
❓이걸 구현하기 위해서는 필요한 것들이 무엇이 있을까?
TodoRequest(요청)쪽에 title, content가 있어야한다.
그럼 요청이 들어올 때 title이 들어갈테니까 그걸 받아주는 애들(service를 수정한다.)

  1. TodoRequest수정
public record TodoRequest(
        Long titleId,
        String content
) {
}

request안에 titleId를 넣었으면, request를 사용하면 titleId가 사용될 것이다.

  1. service수정
  • todoRequest.titleId(); 이거는 지금 Long타입인데 데이터 타입 자체를 todoRequest형식으로 바꾸고 싶다. 왜냐하면 titleId은 todoRequest안에 있으니까 이걸로 접근하면 편하기 떄문이다.
  • 리포지토리도 추가. 왜냐면 todoRepository는 todo만 사용할 수 있는데 내가 가지고 있는건 todoTitle이니까 이거에 맞는 repository가 필요하다.
 private TodoRepository todoRepository;
    private final TodoTitleRepository todoTitleRepository;

    public TodoService(TodoRepository todoRepository, TodoTitleRepository todoTitleRepository) {
        this.todoRepository = todoRepository;
        this.todoTitleRepository = todoTitleRepository;
    }
    
   public TodoResponse create(TodoRequest todoRequest) {
        TodoTitle todoTitle = todoTitleRepository.findById(todoRequest.titleId()).orElseThrow(); //orElseThrow를 사용하는 이유(에러를 내주는이유): 제목이 없는 할일이 생겨버리니까
        Todo save = todoRepository.save(new Todo(todoRequest.content(), todoTitle));
        return new TodoResponse(save.getContent(), save.getId());
    }

그럼 이제 데이터를 넣을 때 titleId까지 같이 넣어줘야 에러가 나지 않는다.


😐 느낀점

todoTitleRepository.findById(todoRequest.titleId()).orElseThrow(); 
이 형식을 잘 기억해두자. 내가 아는 건 titleId밖에 없으니까 이걸 활용하는 수밖에 없다.
아이디를 찾아서, 그걸 todoTitle형식으로 바꾸면 다시 save할 수 있음
이 형식을 잘 기억해서 계속해서 써먹는 방법밖에 없다!

0개의 댓글