diff --git a/BE/src/main/java/com/codesquad/issuetracker/milestone/controller/MilestoneController.java b/BE/src/main/java/com/codesquad/issuetracker/milestone/controller/MilestoneController.java new file mode 100644 index 000000000..762c43111 --- /dev/null +++ b/BE/src/main/java/com/codesquad/issuetracker/milestone/controller/MilestoneController.java @@ -0,0 +1,49 @@ +package com.codesquad.issuetracker.milestone.controller; + + +import com.codesquad.issuetracker.milestone.dto.MilestoneRequestDto; +import com.codesquad.issuetracker.milestone.dto.MilestoneWrapper; +import com.codesquad.issuetracker.milestone.dto.MilestonesWrapper; +import com.codesquad.issuetracker.milestone.service.MilestoneService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; + +import java.util.UUID; + +@RestController +@RequestMapping("/api/milestones") +public class MilestoneController { + + private final Logger logger = LoggerFactory.getLogger(MilestoneController.class); + + private final MilestoneService milestoneService; + + public MilestoneController(MilestoneService milestoneService) { + this.milestoneService = milestoneService; + } + + @GetMapping + public MilestonesWrapper readAllMilestones() { + return milestoneService.readAllMilestones(); + } + + @PostMapping + public MilestoneWrapper createMilestone(@RequestBody MilestoneRequestDto milestoneRequestDto) { + logger.debug("{}", milestoneRequestDto); + return milestoneService.createMilestone(milestoneRequestDto); + } + + @PutMapping("/{id}") + public MilestoneWrapper updateMilestone(@PathVariable UUID id, @RequestBody MilestoneRequestDto milestoneRequestDto) { + logger.debug("{}", id); + return milestoneService.updateMilestone(id, milestoneRequestDto); + } + + @DeleteMapping("/{id}") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void deleteMilestone(@PathVariable UUID id) { + milestoneService.deleteMilestone(id); + } +} diff --git a/BE/src/main/java/com/codesquad/issuetracker/milestone/domain/Milestone.java b/BE/src/main/java/com/codesquad/issuetracker/milestone/domain/Milestone.java new file mode 100644 index 000000000..cd0bc86d9 --- /dev/null +++ b/BE/src/main/java/com/codesquad/issuetracker/milestone/domain/Milestone.java @@ -0,0 +1,50 @@ +package com.codesquad.issuetracker.milestone.domain; + +import com.codesquad.issuetracker.milestone.dto.MilestoneRequestDto; +import lombok.*; +import org.hibernate.annotations.GenericGenerator; + +import javax.persistence.*; +import java.time.LocalDate; +import java.util.UUID; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter +@ToString +public class Milestone { + + @Id + @GeneratedValue( generator = "uuid2" ) + @GenericGenerator( name = "uuid2", strategy = "uuid2" ) + @Column( name = "MILESTONE_ID", columnDefinition = "BINARY(16)" ) + private UUID id; + + @NonNull + @Column(name = "MILESTONE_TITLE", unique = true, nullable = false) + private String title; + + @NonNull + @Lob + @Column(name = "MILESTONE_DESCRIPTION", nullable = false) + private String description; + + @Column(name = "MILESTONE_DUE_DATE") + private LocalDate dueDate; + + private Milestone(@NonNull String title, @NonNull String description, LocalDate dueDate) { + this.title = title; + this.description = description; + this.dueDate = dueDate; + } + + public static Milestone create(String title, String description, LocalDate dueDate) { + return new Milestone(title, description, dueDate); + } + + public void update(MilestoneRequestDto milestoneRequest) { + this.title = milestoneRequest.getTitle(); + this.description = milestoneRequest.getDescription(); + this.dueDate = milestoneRequest.getDueDate(); + } +} diff --git a/BE/src/main/java/com/codesquad/issuetracker/milestone/dto/MilestoneRequestDto.java b/BE/src/main/java/com/codesquad/issuetracker/milestone/dto/MilestoneRequestDto.java new file mode 100644 index 000000000..a821d46b4 --- /dev/null +++ b/BE/src/main/java/com/codesquad/issuetracker/milestone/dto/MilestoneRequestDto.java @@ -0,0 +1,24 @@ +package com.codesquad.issuetracker.milestone.dto; + +import com.codesquad.issuetracker.milestone.domain.Milestone; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + +import java.time.LocalDate; + +@Getter +@RequiredArgsConstructor +@ToString +public class MilestoneRequestDto { + + private final String title; + + private final String description; + + private final LocalDate dueDate; + + public Milestone toEntity() { + return Milestone.create(title, description, dueDate); + } +} diff --git a/BE/src/main/java/com/codesquad/issuetracker/milestone/dto/MilestoneResponseDto.java b/BE/src/main/java/com/codesquad/issuetracker/milestone/dto/MilestoneResponseDto.java new file mode 100644 index 000000000..94f92016e --- /dev/null +++ b/BE/src/main/java/com/codesquad/issuetracker/milestone/dto/MilestoneResponseDto.java @@ -0,0 +1,46 @@ +package com.codesquad.issuetracker.milestone.dto; + +import com.codesquad.issuetracker.milestone.domain.Milestone; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.ToString; + +import java.time.LocalDate; +import java.util.Objects; +import java.util.UUID; + +@Getter +@ToString +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class MilestoneResponseDto { + + private final UUID id; + + private final String title; + + private final String description; + + private final LocalDate dueDate; + + public static MilestoneResponseDto fromEntity (Milestone entity) { + return new MilestoneResponseDto(entity.getId(), + entity.getTitle(), + entity.getDescription(), + entity.getDueDate()); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof MilestoneResponseDto)) return false; + MilestoneResponseDto that = (MilestoneResponseDto) o; + return Objects.equals(id, that.id) && Objects.equals(title, that.title) && + Objects.equals(description, that.description) && Objects.equals(dueDate, that.dueDate); + } + + @Override + public int hashCode() { + return Objects.hash(id, title, description, dueDate); + } +} diff --git a/BE/src/main/java/com/codesquad/issuetracker/milestone/dto/MilestoneWrapper.java b/BE/src/main/java/com/codesquad/issuetracker/milestone/dto/MilestoneWrapper.java new file mode 100644 index 000000000..aa86d9a83 --- /dev/null +++ b/BE/src/main/java/com/codesquad/issuetracker/milestone/dto/MilestoneWrapper.java @@ -0,0 +1,17 @@ +package com.codesquad.issuetracker.milestone.dto; + +import lombok.Getter; + +@Getter +public class MilestoneWrapper { + + private MilestoneResponseDto milestoneResponseDto; + + private MilestoneWrapper(MilestoneResponseDto milestoneResponseDto) { + this.milestoneResponseDto = milestoneResponseDto; + } + + public static MilestoneWrapper create(MilestoneResponseDto milestoneResponseDto) { + return new MilestoneWrapper(milestoneResponseDto); + } +} diff --git a/BE/src/main/java/com/codesquad/issuetracker/milestone/dto/MilestonesWrapper.java b/BE/src/main/java/com/codesquad/issuetracker/milestone/dto/MilestonesWrapper.java new file mode 100644 index 000000000..72576aa65 --- /dev/null +++ b/BE/src/main/java/com/codesquad/issuetracker/milestone/dto/MilestonesWrapper.java @@ -0,0 +1,18 @@ +package com.codesquad.issuetracker.milestone.dto; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.List; + +@Getter +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class MilestonesWrapper { + + private List milestoneResponseDtoList; + + public static MilestonesWrapper create(List milestoneResponseDtoList) { + return new MilestonesWrapper(milestoneResponseDtoList); + } +} diff --git a/BE/src/main/java/com/codesquad/issuetracker/milestone/infra/MilestoneRepository.java b/BE/src/main/java/com/codesquad/issuetracker/milestone/infra/MilestoneRepository.java new file mode 100644 index 000000000..0fc1d2142 --- /dev/null +++ b/BE/src/main/java/com/codesquad/issuetracker/milestone/infra/MilestoneRepository.java @@ -0,0 +1,12 @@ +package com.codesquad.issuetracker.milestone.infra; + +import com.codesquad.issuetracker.milestone.domain.Milestone; +import org.springframework.data.repository.CrudRepository; + +import java.util.List; +import java.util.UUID; + +public interface MilestoneRepository extends CrudRepository { + @Override + List findAll(); +} diff --git a/BE/src/main/java/com/codesquad/issuetracker/milestone/service/MilestoneService.java b/BE/src/main/java/com/codesquad/issuetracker/milestone/service/MilestoneService.java new file mode 100644 index 000000000..4aca966de --- /dev/null +++ b/BE/src/main/java/com/codesquad/issuetracker/milestone/service/MilestoneService.java @@ -0,0 +1,61 @@ +package com.codesquad.issuetracker.milestone.service; + +import com.codesquad.issuetracker.milestone.domain.Milestone; +import com.codesquad.issuetracker.milestone.dto.MilestoneRequestDto; +import com.codesquad.issuetracker.milestone.dto.MilestoneResponseDto; +import com.codesquad.issuetracker.milestone.dto.MilestoneWrapper; +import com.codesquad.issuetracker.milestone.dto.MilestonesWrapper; +import com.codesquad.issuetracker.milestone.infra.MilestoneRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +@Service +public class MilestoneService { + + private final Logger logger = LoggerFactory.getLogger(MilestoneService.class); + + private final MilestoneRepository milestoneRepository; + + public MilestoneService(MilestoneRepository milestoneRepository) { + this.milestoneRepository = milestoneRepository; + } + + public MilestoneWrapper createMilestone(MilestoneRequestDto milestoneRequest) { + Milestone milestone = milestoneRepository.save(milestoneRequest.toEntity()); + MilestoneResponseDto milestoneResponseDto = MilestoneResponseDto.fromEntity(milestone); + + logger.debug("{}", milestone); + + return MilestoneWrapper.create(milestoneResponseDto); + } + + public MilestonesWrapper readAllMilestones() { + List milestoneList = milestoneRepository.findAll(); + List milestoneResponseDtoList = milestoneList.stream() + .map(MilestoneResponseDto::fromEntity) + .collect(Collectors.toList()); + + return MilestonesWrapper.create(milestoneResponseDtoList); + } + + public MilestoneWrapper updateMilestone(UUID id, MilestoneRequestDto milestoneRequest) { + Milestone milestone = milestoneRepository.findById(id).orElseThrow(RuntimeException::new); + milestone.update(milestoneRequest); + Milestone updatedMilestone = milestoneRepository.save(milestone); + + logger.debug("{}", milestone); + + MilestoneResponseDto milestoneResponseDto = MilestoneResponseDto.fromEntity(updatedMilestone); + + return MilestoneWrapper.create(milestoneResponseDto); + } + + public void deleteMilestone(UUID id) { + milestoneRepository.deleteById(id); + } +} diff --git a/BE/src/main/resources/application.properties b/BE/src/main/resources/application.properties index d211bf3b9..65949eb29 100644 --- a/BE/src/main/resources/application.properties +++ b/BE/src/main/resources/application.properties @@ -1,4 +1,24 @@ spring.profiles.include=secret +# 실행 쿼리 보기 설정 spring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=true + +# DB DB connection 설정 +# DB_CLOSE_ON_EXIT : 인메모리 DB의 종료마저도 스프링 부트가 관리. +spring.datasource.url=jdbc:h2:mem://localhost/~/issuetracker;DB_CLOSE_ON_EXIT=FALSE +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password= + +spring.jpa.database-platform=org.hibernate.dialect.H2Dialect + +# 서버 시작 시점 db table drop후 다시 생성 +spring.jpa.hibernate.ddl-auto=create-drop + +# h2 db console 접근 설정 +spring.h2.console.enabled=true +spring.h2.console.path=/h2-console + +#logging level +logging.level.com.codesquad.issuetracker.milestone=DEBUG diff --git a/BE/src/test/java/com/codesquad/issuetracker/milestone/domain/MilestoneTest.java b/BE/src/test/java/com/codesquad/issuetracker/milestone/domain/MilestoneTest.java new file mode 100644 index 000000000..1ad9f7150 --- /dev/null +++ b/BE/src/test/java/com/codesquad/issuetracker/milestone/domain/MilestoneTest.java @@ -0,0 +1,46 @@ +package com.codesquad.issuetracker.milestone.domain; + + +import com.codesquad.issuetracker.milestone.infra.MilestoneRepository; +import org.junit.jupiter.api.AfterEach; +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.orm.jpa.DataJpaTest; + +import java.time.LocalDate; +import java.util.List; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +@DataJpaTest +public class MilestoneTest { + + @Autowired + MilestoneRepository milestoneRepository; + + @AfterEach + public void cleanup() { + milestoneRepository.deleteAll(); + + } + + @Test + @DisplayName("milestone이 추가되었는지를 확인한다.") + public void createMilestone() { + String name = "제목"; + String description = "세부설명"; + + Milestone milestone = Milestone + .create("제목", "세부설명", LocalDate.now()); + + milestoneRepository.save(milestone); + + List milestoneList = milestoneRepository.findAll(); + + Milestone milestoneInDb = milestoneList.get(0); + + assertThat(milestoneInDb.getTitle()).isEqualTo(name); + assertThat(milestoneInDb.getDescription()).isEqualTo(description); + } +}