Skip to content

Commit

Permalink
[Feat] todo update와 toggle 분리 & 에러 처리 & api 명세서 작성
Browse files Browse the repository at this point in the history
  • Loading branch information
jiyunio committed Nov 15, 2024
1 parent 448bd77 commit acdbc80
Show file tree
Hide file tree
Showing 11 changed files with 137 additions and 44 deletions.
25 changes: 24 additions & 1 deletion src/main/java/com/basic/study/controller/MemberController.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,53 @@
import com.basic.study.dto.MemberReq;
import com.basic.study.dto.MemberRes;
import com.basic.study.service.MemberService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequiredArgsConstructor
@RequestMapping("api/members")
@Tag(name = "Member", description = "회원 API")
public class MemberController {
private final MemberService memberService;

@PostMapping("/signup")
@Operation(description = "회원가입")
@ApiResponse(responseCode = "200", description = "회원가입 성공", content = @Content(schema = @Schema(implementation = MemberRes.class)))
@ApiResponse(responseCode = "500", description = "이미 존재하는 아이디")
public ResponseEntity<MemberRes> signup(@RequestBody MemberReq memberReq) {
return ResponseEntity.ok(memberService.signup(memberReq));
}

@PostMapping("/login")
@Operation(description = "로그인")
@ApiResponse(responseCode = "200", description = "로그인 성공", content = @Content(schema = @Schema(implementation = MemberRes.class)))
@ApiResponse(responseCode = "500", description = "존재하지 않는 아이디 / 비밀번호 불일치")
public ResponseEntity<MemberRes> login(@RequestBody MemberReq memberReq) {
return ResponseEntity.ok(memberService.login(memberReq));
}

@GetMapping("/{memberId}")
@Operation(description = "memberId의 회원 조회")
@ApiResponse(responseCode = "200", description = "회원 조회 성공", content = @Content(schema = @Schema(implementation = MemberRes.class)))
@ApiResponse(responseCode = "500", description = "존재하지 않는 회원")
public ResponseEntity<MemberRes> getMember(@PathVariable Long memberId) {
return ResponseEntity.ok(memberService.getMember(memberId));
}

@DeleteMapping("/{memberId}")
@Operation(description = "회원 탈퇴")
@ApiResponse(responseCode = "200", description = "탈퇴 성공")
@ApiResponse(responseCode = "500", description = "존재하지 않는 회원")
public ResponseEntity<String> delete(@PathVariable Long memberId) {
return memberService.deleteMember(memberId)
? ResponseEntity.ok("탈퇴 성공")
: ResponseEntity.ok("탈퇴 실패");
: ResponseEntity.ok("탈퇴 실패, 회원이 존재하지 않습니다");
}
}
39 changes: 34 additions & 5 deletions src/main/java/com/basic/study/controller/TodoController.java
Original file line number Diff line number Diff line change
@@ -1,35 +1,64 @@
package com.basic.study.controller;

import com.basic.study.dto.TodoReq;
import com.basic.study.dto.TodoRes;
import com.basic.study.dto.TodoUpdateReq;
import com.basic.study.service.TodoService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequiredArgsConstructor
@RequestMapping("api/todos")
@Tag(name = "Todo", description = "Todo API")
public class TodoController {
final private TodoService todoService;

@PostMapping("")
public ResponseEntity<?> postTodo(@RequestBody TodoReq todoReq) {
@Operation(description = "todo 생성")
@ApiResponse(responseCode = "200", description = "todo 생성 성공", content = @Content(schema = @Schema(implementation = TodoRes.class)))
@ApiResponse(responseCode = "500", description = "존재하지 않는 memberId")
public ResponseEntity<TodoRes> postTodo(@RequestBody TodoReq todoReq) {
return ResponseEntity.ok(todoService.createTodo(todoReq));
}

@GetMapping("")
public ResponseEntity<?> getTodoes(@RequestParam Long memberId) {
return ResponseEntity.ok(todoService.readTodoes(memberId));
@Operation(description = "todo 조회")
@ApiResponse(responseCode = "200", description = "todo 조회 성공", content = @Content(schema = @Schema(implementation = TodoRes.class)))
@ApiResponse(responseCode = "200", description = "생성된 todo 없음", content = @Content(schema = @Schema(type = "array")))
public ResponseEntity<List<TodoRes>> getTodos(@RequestParam Long memberId) {
return ResponseEntity.ok(todoService.readTodos(memberId));
}

@PutMapping("/{todoId}")
public ResponseEntity<?> putTodo(@PathVariable Long todoId, @RequestBody TodoUpdateReq todoUpdateReq) {
@Operation(description = "todo 내용 및 기간 수정")
@ApiResponse(responseCode = "200", description = "todo 수정 성공", content = @Content(schema = @Schema(implementation = TodoRes.class)))
@ApiResponse(responseCode = "500", description = "존재하지 않는 todoId")
public ResponseEntity<TodoRes> putTodo(@PathVariable Long todoId, @RequestBody TodoUpdateReq todoUpdateReq) {
return ResponseEntity.ok(todoService.updateTodo(todoId, todoUpdateReq));
}

@PatchMapping("/{todoId}")
@Operation(description = "todo 완료 여부 수정")
@ApiResponse(responseCode = "200", description = "todo 수정 성공", content = @Content(schema = @Schema(implementation = TodoRes.class)))
@ApiResponse(responseCode = "500", description = "존재하지 않는 todoId")
public ResponseEntity<TodoRes> patchTodo(@PathVariable Long todoId) {
return ResponseEntity.ok(todoService.toggleTodo(todoId));
}

@DeleteMapping("/{todoId}")
public ResponseEntity<?> deleteTodo(@PathVariable Long todoId) {
@Operation(description = "todo 삭제")
@ApiResponse(responseCode = "200", description = "todo 삭제 성공", content = @Content(schema = @Schema(implementation = TodoRes.class)))
@ApiResponse(responseCode = "500", description = "존재하지 않는 todoId")
public ResponseEntity<String> deleteTodo(@PathVariable Long todoId) {
return todoService.deleteTodo(todoId)
? ResponseEntity.ok("todo 삭제 성공")
: ResponseEntity.ok("todo 삭제 실패");
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/com/basic/study/domain/Todo.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ private Todo(String content, LocalDate deadLine, Member member) {
public void update(TodoUpdateReq todoReq) {
this.content = todoReq.getContent();
this.deadLine = todoReq.getDeadLine();
this.isCompleted = todoReq.getIsCompleted();
}

public void toggle() {
this.isCompleted = !this.isCompleted;
}
}

4 changes: 4 additions & 0 deletions src/main/java/com/basic/study/dto/MemberReq.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.basic.study.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
Expand All @@ -8,7 +9,10 @@
@Getter
@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Schema(description = "회원가입 및 로그인")
public class MemberReq {
@Schema(description = "회원의 email", example = "asdf")
private String email;
@Schema(description = "회원의 password", example = "asdf")
private String password;
}
3 changes: 3 additions & 0 deletions src/main/java/com/basic/study/dto/MemberRes.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.basic.study.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
Expand All @@ -9,6 +10,8 @@
@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class MemberRes {
@Schema(description = "회원의 id", example = "1")
private Long memberId;
@Schema(description = "회원의 email", example = "asdf")
private String email;
}
9 changes: 5 additions & 4 deletions src/main/java/com/basic/study/dto/TodoReq.java
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
package com.basic.study.dto;

import com.basic.study.domain.Member;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;

import java.time.LocalDate;
import java.time.LocalDateTime;

@Getter
@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Schema(description = "todo 생성")
public class TodoReq {
@Schema(description = "회원의 id", example = "1")
private Long memberId;

@Schema(description = "todo 내용", example = "할 일")
private String content;

@Schema(description = "todo 끝나는 날짜", example = "2024-12-25")
private LocalDate deadLine;
}
5 changes: 5 additions & 0 deletions src/main/java/com/basic/study/dto/TodoRes.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.basic.study.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
Expand All @@ -11,9 +12,13 @@
@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class TodoRes {
@Schema(description = "todo의 id", example = "1")
private Long todoId;
@Schema(description = "todo 내용", example = "할 일")
private String content;
@Schema(description = "todo 끝나는 날짜", example = "2024-12-25")
private LocalDate deadLine;
@Builder.Default
@Schema(description = "todo 완료 여부 / 기본값 = false", example = "false")
private Boolean isCompleted = false;
}
7 changes: 4 additions & 3 deletions src/main/java/com/basic/study/dto/TodoUpdateReq.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.basic.study.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
Expand All @@ -10,10 +11,10 @@
@Getter
@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Schema(description = "todo 업데이트")
public class TodoUpdateReq {
@Schema(description = "todo 내용", example = "할 일")
private String content;

@Schema(description = "todo 끝나는 날짜", example = "2024-12-25")
private LocalDate deadLine;

private Boolean isCompleted;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import com.basic.study.domain.Member;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.Optional;

public interface MemberRepository extends JpaRepository<Member, Long> {
@Query("select m.id from Member m where m.email = :email")
Long findByEmail(String email);
Optional<Member> findByEmail(String email);

boolean existsByEmail(String email);
}
25 changes: 20 additions & 5 deletions src/main/java/com/basic/study/service/MemberService.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,31 @@
public class MemberService {
private final MemberRepository memberRepository;

public MemberRes login(MemberReq memberReq) {
public MemberRes signup(MemberReq memberReq) {
// 이미 존재하는 회원
if (memberRepository.existsByEmail(memberReq.getEmail())) throw new NullPointerException();

Member member = Member.builder()
.email(memberReq.getEmail())
.password(memberReq.getPassword())
.build();
memberRepository.save(member);
return MemberRes.builder()
.memberId(member.getId())
.email(memberReq.getEmail())
.email(member.getEmail())
.build();
}

public MemberRes login(MemberReq memberReq) {
Member member = memberRepository.findByEmail(memberReq.getEmail()).orElseThrow(
// 해당 회원 존재 X
NullPointerException::new
);
// 비밀번호 불일치
if (!memberReq.getPassword().equals(member.getPassword())) throw new NullPointerException();
return MemberRes.builder()
.memberId(member.getId())
.email(member.getEmail())
.build();
}

Expand All @@ -36,9 +52,8 @@ public MemberRes getMember(Long memberId) {
}

public boolean deleteMember(Long memberId) {
if (!memberRepository.existsById(memberId)) return false;
Member member = memberRepository.findById(memberId).get();
memberRepository.delete(member);
if (!memberRepository.existsById(memberId)) throw new NullPointerException();
memberRepository.deleteById(memberId);
return true;
}

Expand Down
51 changes: 29 additions & 22 deletions src/main/java/com/basic/study/service/TodoService.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
Expand All @@ -18,8 +17,8 @@ public class TodoService {
final private MemberRepository memberRepository;
final private TodoRepository todoRepository;

// CRUD
public TodoRes createTodo(TodoReq todoReq) {
if(!memberRepository.existsById(todoReq.getMemberId())) throw new NullPointerException();
Todo todo = Todo.builder()
.content(todoReq.getContent())
.deadLine(todoReq.getDeadLine())
Expand All @@ -34,24 +33,20 @@ public TodoRes createTodo(TodoReq todoReq) {
.build();
}

public List<TodoRes> readTodoes(Long memberId) {
List<Todo> todoList = todoRepository.findAllByMemberId(memberId);
ArrayList<TodoRes> todoResList = new ArrayList<>();

for (Todo todo : todoList) {
TodoRes todoRes = TodoRes.builder()
.todoId(todo.getId())
.content(todo.getContent())
.deadLine(todo.getDeadLine())
.isCompleted(todo.getIsCompleted())
.build();
todoResList.add(todoRes);
}
return todoResList;
public List<TodoRes> readTodos(Long memberId) {
return todoRepository.findAllByMemberId(memberId).stream()
.map(todo -> TodoRes.builder()
.todoId(todo.getId())
.content(todo.getContent())
.deadLine(todo.getDeadLine())
.isCompleted(todo.getIsCompleted())
.build()).toList();
}

public TodoRes updateTodo(Long todoId, TodoUpdateReq todoUpdateReq) {
Todo todo = todoRepository.findById(todoId).get();
Todo todo = todoRepository.findById(todoId).orElseThrow(
NullPointerException::new
);
todo.update(todoUpdateReq);
todoRepository.save(todo);
return TodoRes.builder()
Expand All @@ -62,11 +57,23 @@ public TodoRes updateTodo(Long todoId, TodoUpdateReq todoUpdateReq) {
.build();
}

public TodoRes toggleTodo(Long todoId) {
Todo todo = todoRepository.findById(todoId).orElseThrow(
NullPointerException::new
);
todo.toggle();
todoRepository.save(todo);
return TodoRes.builder()
.todoId(todo.getId())
.content(todo.getContent())
.deadLine(todo.getDeadLine())
.isCompleted(todo.getIsCompleted())
.build();
}

public boolean deleteTodo(Long todoId) {
if (todoRepository.existsById(todoId)) {
todoRepository.deleteById(todoId);
return true;
}
return false;
if (!todoRepository.existsById(todoId)) throw new NullPointerException();
todoRepository.deleteById(todoId);
return true;
}
}

0 comments on commit acdbc80

Please sign in to comment.