"과제 하기 전부터 트러블(Trouble) 일으키는 사람?"
"저요!"
오늘 사전캠프 기간부터 우수 TIL에 선정된 수강생 전원에게 5,000포인트씩 지급되었다. 주머니가 두둑해져서 기분이 좋기도 했지만, '필수로 구현해야 하는 과제를 전부 무사히 제출하면 꼭 우주 비행기랑 플라밍고 튜브 사야지!' 같은 의욕이 샘솟아서 포인트를 쓰기가 망설여졌다. 강의 5주 차부터 직접 메모장을 만드는 실습이 있어서 '모르지만 일단 따라 친다'는 마음으로 코딩했는데, 별의별 트러블(Trouble)을 일으키거나 머리에 쥐가 날 때 '꼭 사고 만다'는 생각으로 5주 차 학습을 마쳤다.
주말에 실습할 부분을 무작정 따라 작성하며 눈에 보이는 족족 다시 강의 자료에서 해당 용어를 찾아 공부했는데, 효과가 있긴 한 듯했다. 어제보다는 한 발짝 Spring과 가까워진 느낌이 들었다. 아직 손잡을 정도로 가까워지려면 까마득하긴 하지만.
어제 생성한 저장소는 조금 아쉽긴 했지만, 주석으로 필기한 내용은 모두 익혔다는 생각에 지우고 새로운 저장소를 생성했다. 원래 계획은 6주 차 강의까지 전부 듣기였으나, 5주 차 실습을 낑낑대면서 했더니 12시간 학습을 훌쩍 넘겨서 내일로 미뤄야 한다. 대신 내일 오전 중에 6주 차 강의를 모두 듣고 필수 과제 0단계부터 차근차근히 할 예정이다. '일단 박치기!' 전략에 가깝지만 우선 '차근차근히'라고 표현하련다.
깃허브(GitHub)에 올린 실습 내용을 복사해서 TIL에 붙여넣기로 하루를 마치련다. 아침 기상에 성공해야 거북목 스트레칭과 허리 근력 강화 운동으로 하루를 열 수 있다. 오늘 작성한 TIL은 과제를 할 때 정말 많이 참고할 듯하다.
1. 메모를 CRUD할 수 있는 Web Application
(1) 요구사항
- 통신 데이터 형태: JSON
- 각각의 메모 구성: 식별자(id), 제목(title), 내용(contents)
(2) 실습 결과
package com.example.memo.entity;
// [1/4] entity 패키지에 있는 Memo 클래스
import com.example.memo.dto.MemoRequestDto;
import com.example.memo.dto.MemoResponseDto;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class Memo {
private Long id;
private String title;
private String contents;
public void update(MemoRequestDto dto) {
this.title = dto.getTitle();
this.contents = dto.getTitle();
// 매개변수인 MemoResponseDto dto == 요청 정보
}
}
package com.example.memo.dto;
// [2/4] dto 패키지에 있는 MemoRequestDto 클래스
import lombok.Getter;
@Getter
public class MemoRequestDto {
// id는 서버에서 관리하기 때문에 요청받지 않는다.
private String title;
private String contents;
}
package com.example.memo.dto;
// [3/4] dto 패키지에 있는 MemoResponseDto 클래스
import com.example.memo.entity.Memo;
import lombok.Getter;
@Getter
public class MemoResponseDto {
private Long id;
private String title;
private String contents;
// MemoController 작성이 끝나면 생성자 만들기
public MemoResponseDto(Memo memo) {
this.id = memo.getId();
this.title = memo.getTitle();
this.contents = memo.getContents();
/*
memo 객체가 그대로 반횐되는 게 아니다.
MemoResponseDto 형태로 바뀌어서 응답되어야 한다.
*/
}
}
package com.example.memo.controller;
// [4/4] controller 패키지에 있는 MemoController 클래스
/*
[절대 잊으면 안 되는 것]
첫째, src>test>java에 클래스를 넣지 않았는지 확인하자
➡️src>main>java이다. 그렇게 안 하고 postman을 실행하면 404 오류 뜬다.
둘째, import가 두 번 되지 않았는지 꼭 살펴보자.
*/
import com.example.memo.dto.MemoRequestDto;
import com.example.memo.dto.MemoResponseDto;
import com.example.memo.entity.Memo;
import org.springframework.web.bind.annotation.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/memos")
/*
[@RequestMapping]
- @PostMapping 사용 후 @RequestMapping을 추가하자.
- prefix하는 URL을 설정할 때 사용한다.
== prefix처럼 하위 메서드 전체에 영향을 주기 때문에 'prefix'라고 표현함
- 공통적으로 들어가는 /memos라는 URL을 적어둔다.
*/
public class MemoController {
private final Map<Long, Memo> memoList = new HashMap<>();
// key 값 = Long
// ------------------------- Create -------------------------
@PostMapping
/*
- 생성이기 때문에 @PostMapping을 사용한다.
Q. @PostMapping("/healthy") 이렇게 적으면?
A. == localhost:8080/memos/healthy
영향 범위는 메서드의 블럭만 해당한다.
Q. 만약 다른 메서드에 영향을 주려면?
A. 해당 메서드 위에 다시 annotation을 써야 한다.
*/
/*
[해야 할 일]
[1] 식별자가 1씩 증가해야 함. 중복이 되면 안 되니까!
[2] 요청받은 데이터로 Memo를 생성해야 함
[3] Inmemory DB에 메모 저장
== 데이터베이스 대신 Java의 Map 자료구조를 이용한다.
== 자료구조라서 프로젝트를 종료하면 그 안의 모든 데이터가 지워진다.
이런 이유로 Inmemory라고 표현한다.
*/
public MemoResponseDto createMemo(@RequestBody MemoRequestDto dto) {
Long memoId = memoList.isEmpty() ? 1 : Collections.max(memoList.keySet()) + 1;
/*
[1] 식별자가 1씩 증가하도록 삼항연산자를 사용해서 구현하기
memoList.isEmpty()
▶ 비어 있는지 검사
물음표 뒤에 있는 1
▶ 비어 있다면 1로 초기 값 설정
Collections.max(memoList.keySet())
▶ memoList.keySet() 안에 든 값 중 최댓값을 뽑아내는 메서드
memoList.keySet()
▶ memoList 안에 있는 key 값을 전부 뽑아내는 메서드
== 모든 Long 값을 꺼내서 최댓값을 반환해주는 메서드
[설명] 우리는 1씩 증가해야 하므로 + 1 추가
*/
Memo memo = new Memo(memoId, dto.getTitle(), dto.getContents());
/*
[2] 요청받은 데이터로 Memo 객체 생성하기
- MemoRequestDto 형태로 요청받았으므로 Memo 객체로 바꿔줘야 한다.
- 첫 번째 인자로 memoId 값 전달
- 두 번째로 title을, 세 번째로 contents를 전달해 줘야 한다.
이때, 두 데이터 모두 dto 안에 있으므로 getter 사용
- 그다음 Memo 타입 변수로 받아주면 된다.
*/
memoList.put(memoId, memo);
/*
[3] 실제 데이터베이스 (현재는 자료구조) 안에 저장하기
key 값은 memoId
저장될 객체 형태는 memo
*/
return new MemoResponseDto(memo);
/*
[4] 저장된 데이터를 MemoResponseDto 형태로 반환하기
이후 MemoResponseDto 클래스로 돌아가서 생성자를 만들어준다.
return new MemoResponseDto();
그다음, 위와 같이 적은 곳의 () 안에 memo를 넣어준다.
*/
}
// -------------------------- Read --------------------------
@GetMapping("/{id}")
// 이미 prefix로 /memos를 적었으므로 식별자를 추가로 적는다.
public MemoResponseDto findMemoById(@PathVariable Long id) {
// 식별자를 매개변수로 바인딩할 때는 @PathVariable을 사용한다.
Memo memo = memoList.get(id);
return new MemoResponseDto(memo);
}
// ------------------------- Update -------------------------
@PutMapping("/{id}")
/*
[1] 전체 수정이므로 PutMapping이다.
[2] 단건을 수정해야 하므로 아까처럼 경로 변수가 필요하다.
[3] id값 뿐만 아니라 우리가 수정하려는 데이터도 요청받아야 한다.
➡️ RequestDto 형태로 받기로 한 점을 기억하자!
➡️ 지금은 title과 contents 둘 다 수정할 수 있다고 가정했다.
== 아래에 @RequestBody MemoRequestDto dto를 작성한 이유
*/
public MemoResponseDto updateMemoById(@PathVariable Long id, @RequestBody MemoRequestDto dto) {
Memo memo = memoList.get(id);
/*
- 수정하려면 저장된 메모부터 꺼내와야 하므로 위와 같이 작성한다.
- 이후 Memo 클래스로 돌아가서 update() 메서드를 새로 만든다.
*/
memo.update(dto);
return new MemoResponseDto(memo);
}
// ------------------------- Delete -------------------------
@DeleteMapping("/{id}")
public void deleteMemo (@PathVariable Long id) {
// 삭제라서 따로 반환할 값이 없으므로 void로 설정
memoList.remove(id);
}
}
2. 1에서 만든 Web Appilcation 수정하기 ▶ 깃허브(Github) 링크
'끝을 보는 용기' 카테고리의 다른 글
Spring 본캠프 Day 058 - 기초 Spring 6주차 완강, API 명세서 작성 시작 (0) | 2024.12.03 |
---|---|
Spring 본캠프 Day 056 - 책 『비전공이지만 개발자로 먹고삽니다』 추가 정리 (0) | 2024.12.01 |
Spring 본캠프 Day 055 - 속 터지기 일 초 전에 계획을 뜯어고쳤다. (0) | 2024.11.30 |
Spring 본캠프 Day 054 - 기초 Spring 2주차 및 3주차 완강, 공식 문서 읽는 연습하기 (0) | 2024.11.29 |
Spring 본캠프 Day 053 - 5단계 키오스크 완료, 과제 제출, 기초 Spring 1주차 완강, Transfer vs Transmit (0) | 2024.11.28 |