-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: YSL-24 오늘의 다짐 CRUD 기능 추가 #16
base: develop
Are you sure you want to change the base?
Changes from 20 commits
25f5485
7175a0e
9cae178
b1f30d4
94f8fdd
eebce38
cae20b6
e134df8
9b8ffde
af6c019
d42981e
91fde0b
3694065
ebcd5ac
1d65e19
0eeb7a9
77093d7
367ce99
649c403
b2dfa7d
05f8817
6a29a5c
7f80143
47e3cd0
45fb635
f32b746
0127768
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package org.idiot.yesslave.global.exception; | ||
|
||
import lombok.Getter; | ||
|
||
public enum ErrorCode { | ||
ID_NOT_FOUND("해당 ID를 찾을 수 없습니다."), | ||
ID_DELETE("삭제된 ID입니다."); | ||
|
||
@Getter | ||
private String message; | ||
|
||
ErrorCode(String message) { | ||
this.message = message; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package org.idiot.yesslave.global.exception; | ||
|
||
import lombok.Getter; | ||
|
||
public class TodoIdHandler extends RuntimeException { | ||
|
||
@Getter | ||
private final ErrorCode errorCode; | ||
|
||
public TodoIdHandler(ErrorCode errorCode) { | ||
super(errorCode.getMessage()); | ||
this.errorCode = errorCode; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package org.idiot.yesslave.todo.application; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.idiot.yesslave.global.exception.TodoIdHandler; | ||
import org.idiot.yesslave.global.exception.ErrorCode; | ||
import org.idiot.yesslave.todo.domain.todo; | ||
import org.idiot.yesslave.todo.dto.SaveDto; | ||
import org.idiot.yesslave.todo.dto.UpdateDto; | ||
import org.idiot.yesslave.todo.repository.TodoRepository; | ||
import org.springframework.stereotype.Service; | ||
|
||
import javax.transaction.Transactional; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class TodoService { | ||
private final TodoRepository todoRepository ; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 변수명과 세미콜론 사이에 공백이 들어가 있습니다 🤤 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 공백 제거했습니다 |
||
|
||
@Transactional | ||
public void save(SaveDto saveDto) { | ||
todoRepository.save(todo.builder() | ||
.todo(saveDto.getTodo()) | ||
.build()); | ||
} | ||
|
||
@Transactional | ||
public void update(Long id, UpdateDto updateDto) { | ||
todo todo = existId(id); | ||
checkDeleteStatus(todo); | ||
todo.update(updateDto.getTodo()); | ||
} | ||
|
||
@Transactional | ||
public void changeCheck(Long id) { | ||
todo todo = existId(id); | ||
checkDeleteStatus(todo); | ||
todo.changeCheck(!todo.isTodoCheck()); | ||
} | ||
|
||
@Transactional | ||
public void delete(Long id) { | ||
todo todo = existId(id); | ||
checkDeleteStatus(todo); | ||
todo.delete(true); | ||
} | ||
|
||
private void checkDeleteStatus(todo todo) { | ||
if (todo.isDelete()) { | ||
throw new TodoIdHandler(ErrorCode.ID_DELETE); | ||
} | ||
} | ||
|
||
public todo existId(Long id) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @transactional에 readOnly 라는 옵션이 있습니다. |
||
todo todo = todoRepository.findById(id) | ||
.orElseThrow(() -> new TodoIdHandler(ErrorCode.ID_NOT_FOUND)); | ||
return todo; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package org.idiot.yesslave.todo.domain; | ||
|
||
import lombok.*; | ||
import org.hibernate.annotations.Comment; | ||
import org.idiot.yesslave.global.jpa.AuditInformation; | ||
|
||
import javax.persistence.*; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 와일드 카드가 사용이 되었는데, 한 번 아래 참고글 봐보시면 좋을 것 같아용 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 와일드카드가 컴파일 속도를 느리게 한다는 것은 알고 있었는데 인텔리제이 설정에서 바꿀 수 있는 건 처음 알았습니다. |
||
|
||
|
||
@Entity | ||
@Getter | ||
@Table(name = "TODO") | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
public class todo extends AuditInformation { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아직 이 부분은 소문자로 작성이 되어 있는 것 같아요 🥹 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 수정했습니다 😊 |
||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
@Column(name = "ID", nullable = false) | ||
@Comment("id는 todo 테이블의 pk 값 입니다") | ||
private Long id; | ||
|
||
@Column(name = "TODO", nullable = false) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 해당 칼럼에 Comment가 있다면 더 좋을 것 같아요. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comment 추가했습니다 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 훨씬 더 이해하기 좋은 코드가 된 것 같아요 👍🏻 감사합니다! |
||
@Comment("todo는 오늘의 다짐을 적는 부분입니다.") | ||
private String todo; | ||
|
||
@Column(name = "TODO_CHECK", nullable = false) | ||
@Comment("todoCheck는 실행 여부를 체크하는 부분입니다.") | ||
private boolean todoCheck = false; | ||
|
||
@Column(name = "DELETE", nullable = false) | ||
@Comment("delete는 삭제 여부를 체크하는 부분입니다.") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 실제 DB 설계하실 때에도 코멘트에 문장으로 작성하시는 편일까요..? 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 주석처럼 생각하고 문장으로 작성했습니다. |
||
private boolean delete = false; | ||
|
||
|
||
@Builder | ||
public todo(String todo) { | ||
this.todo = todo; | ||
} | ||
|
||
|
||
public void changeCheck(boolean todoCheck) { | ||
this.todoCheck = todoCheck; | ||
} | ||
|
||
public void update(String todo) { | ||
this.todo = todo; | ||
} | ||
public void delete (boolean delete) { | ||
this.delete = delete; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. delete 메서드는 "삭제"에 대한 상태를 "true"로만 바꿔주는 역할만을 할 것 같습니다. 외부에 의한 요인으로 내부 객체 상태가 바뀌는 경우가 있지만, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여기서 외부가 다른 클래스라는 의미일까요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
저의 경우는 해당 코드를 아래와 같이 작성할 것 같아요 public void delete() {
this.delete = true;
} 지금 주철님의 코드 경우에는 외부라는 건, 다른 클래스가 될 수도 있을 것 같네요. 혹시 질문에 답변이 되었을까요? |
||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package org.idiot.yesslave.todo.dto; | ||
|
||
import lombok.AccessLevel; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
// cannot deserialize from Object value (no delegate- or property-based Creator)에러로 인해 기본 생성자 필요 | ||
public class SaveDto { | ||
private String todo; | ||
@Builder | ||
public SaveDto(String todo) { | ||
this.todo = todo; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package org.idiot.yesslave.todo.dto; | ||
|
||
import lombok.AccessLevel; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
public class UpdateDto { | ||
private String todo; | ||
|
||
public UpdateDto(String todo) { | ||
this.todo = todo; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package org.idiot.yesslave.todo.repository; | ||
|
||
import org.idiot.yesslave.todo.domain.todo; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface TodoRepository extends JpaRepository<todo,Long>{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. JpaRepository<todo,Long>{ 중괄호 시작 전에 공백이 하나 있으면 좋을 것 같습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 항상 이런 실수를 못 보고 지나가네요 수정하겠습니다 |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package org.idiot.yesslave.todo.ui; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.idiot.yesslave.todo.application.TodoService; | ||
import org.idiot.yesslave.todo.dto.SaveDto; | ||
import org.idiot.yesslave.todo.dto.UpdateDto; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
@RestController | ||
@RequestMapping("/todo") | ||
@RequiredArgsConstructor | ||
public class TodoController { | ||
|
||
private final TodoService todoService; | ||
|
||
@PostMapping | ||
public ResponseEntity todoSave(@RequestBody SaveDto saveDto) { | ||
todoService.save(saveDto); | ||
return ResponseEntity.ok("Todo save successfully"); | ||
} | ||
|
||
@PatchMapping("/{id}") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저는 |
||
public ResponseEntity todoUpdate(@PathVariable Long id, @RequestBody UpdateDto updateDto) { | ||
todoService.update(id, updateDto); | ||
return ResponseEntity.ok("Todo updated successfully"); | ||
} | ||
|
||
@PostMapping("/{id}") | ||
public ResponseEntity changeCheck(@PathVariable Long id) { | ||
todoService.changeCheck(id); | ||
return ResponseEntity.ok("Todo change successfully"); | ||
} | ||
|
||
@DeleteMapping("/{id}") | ||
public ResponseEntity delete(@PathVariable Long id) { | ||
todoService.delete(id); | ||
return ResponseEntity.ok("Todo delete successfully"); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,4 +20,6 @@ spring: | |
add-mappings: false | ||
mvc: | ||
throw-exception-if-no-handler-found: true | ||
|
||
main: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 해당 옵션이 어떠한 역할을 하나요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 깃허브 빌드에서 발생하는 테스트 코드 에러를 없애려고 사용했는데 지금 보니까 제 테스트 자체에도 문제가 있어서 수정 중입니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 해당 부분은 수정이 되었나요? 👍🏻 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. main: |
||
allow-bean-definition-overriding: true | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
package org.idiot.yesslave.todo.ui; | ||
|
||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
|
||
import org.assertj.core.api.Assertions; | ||
import org.idiot.yesslave.todo.domain.todo; | ||
import org.idiot.yesslave.todo.dto.SaveDto; | ||
import org.idiot.yesslave.todo.repository.TodoRepository; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.test.web.servlet.MockMvc; | ||
|
||
import java.time.LocalDateTime; | ||
|
||
|
||
@SpringBootTest | ||
@AutoConfigureMockMvc | ||
public class TodoControllerTest { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 테스트 코드 작성 경험이 적으신 와중에 이렇게 짜주셔서 감사합니다! 제가 생각했을 때 테스트코드는 [ 성공 ] 보다는 [ 실패 ]에 대한 경우를 잡는게 더 중요하다고 생각하는데요. 아직 어색하시겠지만, 제가 곧 올리는 PR에서 "실패"의 경우는 어떻게 처리를 했는지 한 번 봐보시면 좋을 것 같습니다. |
||
@Autowired | ||
ObjectMapper mapper; | ||
|
||
@Autowired | ||
MockMvc mvc; | ||
|
||
@Autowired | ||
private TodoRepository todoRepository; | ||
|
||
private static final String BASE_URL = "/todo"; | ||
|
||
@Test | ||
@DisplayName("저장 테스트") | ||
void save_test() throws Exception { | ||
//given | ||
String text = "Test schedule"; | ||
|
||
//when | ||
String body = mapper.writeValueAsString( | ||
SaveDto.builder() | ||
.todo(text) | ||
.build() | ||
); | ||
|
||
//then | ||
mvc.perform(post(BASE_URL) | ||
.content(body) //HTTP Body에 데이터를 담는다 | ||
.contentType(MediaType.APPLICATION_JSON) //보내는 데이터의 타입을 명시 | ||
) | ||
.andExpect(status().isOk()) | ||
.andExpect(content().string("Todo save successfully")); | ||
} | ||
|
||
@Test | ||
@DisplayName("수정 테스트") | ||
void patch_test() throws Exception { | ||
|
||
//given | ||
String text = "Test schedule"; | ||
String change_text = "Change test schedule"; | ||
|
||
//when | ||
todoRepository.save(todo.builder() | ||
.todo(text) | ||
.build()); | ||
|
||
String body = mapper.writeValueAsString( | ||
SaveDto.builder() | ||
.todo(change_text) | ||
.build() | ||
); | ||
|
||
//then | ||
mvc.perform(patch(BASE_URL + "/2") | ||
.contentType(MediaType.APPLICATION_JSON) | ||
.content(body) | ||
) | ||
.andExpect(status().isOk()) | ||
.andExpect(content().string("Todo updated successfully")); | ||
|
||
} | ||
|
||
@Test | ||
@DisplayName("체크 변경 테스트") | ||
void change_check_test() throws Exception { | ||
|
||
//given | ||
String text = "Test schedule"; | ||
|
||
//when | ||
todoRepository.save(todo.builder() | ||
.todo(text) | ||
.build()); | ||
|
||
//then | ||
mvc.perform(post(BASE_URL + "/2") | ||
.contentType(MediaType.APPLICATION_JSON) | ||
) | ||
.andExpect(status().isOk()) | ||
.andExpect(content().string("Todo change successfully")); | ||
|
||
} | ||
|
||
@DisplayName("삭제 테스트") | ||
@Test | ||
public void delete_Test() throws Exception { | ||
|
||
//given | ||
String text = "Test schedule"; | ||
|
||
//when | ||
todoRepository.save(todo.builder() | ||
.todo(text) | ||
.build()); | ||
|
||
//then | ||
mvc.perform(delete(BASE_URL + "/1")) | ||
.andExpect(status().isOk()) | ||
.andExpect(content().string("Todo delete successfully")); | ||
|
||
Assertions.assertThat(todoRepository.findById(1L).isEmpty()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,7 +29,7 @@ | |
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; | ||
|
||
|
||
@WebMvcTest | ||
@WebMvcTest(WorkTimerController.class) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍🏻👍🏻👍🏻 이렇게 처리를 하면, 해댕 컨트롤러와, 관련 bean 들을 등록해서 스부테보다는 가볍게 테스트 환경을 꾸릴 수 있더라구요. |
||
@ExtendWith(SpringExtension.class) | ||
class WorkTimerControllerTest { | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
요거 JpaConfig에 작성 되어 있던 내용인데 앞으로 꺼내오신 이유가 있으실까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Auditing 사용하면서 오류가 발생해서 앞으로 꺼냈는데 다시 제거하고 확인해 보니까 정상적으로 동작하네요
코드를 작성하면서 뭔가 실수가 있었나 봐요. 지금은 지웠습니다