From 90db46b85a6c823e696252c13f2289c55777c743 Mon Sep 17 00:00:00 2001 From: priverg163 Date: Thu, 10 Oct 2024 20:57:40 +0900 Subject: [PATCH 1/4] Feat :: Damage Create, Read, Delete --- .../domain/damage/entity/Damage.java | 53 +++++++++++++++ .../domain/damage/mapper/DamageMapper.java | 30 +++++++++ .../payload/request/DamageCreateRequest.java | 19 ++++++ .../payload/response/DamageResponseDto.java | 15 +++++ .../damage/presentation/DamageController.java | 38 +++++++++++ .../damage/repository/DamageRepository.java | 10 +++ .../domain/damage/service/DamageService.java | 13 ++++ .../damage/service/DamageServiceImpl.java | 65 +++++++++++++++++++ .../global/exception/damage/DamageError.java | 15 +++++ .../exception/damage/DamageException.java | 20 ++++++ 10 files changed, 278 insertions(+) create mode 100644 src/main/java/com/keepgoing/keepserver/domain/damage/entity/Damage.java create mode 100644 src/main/java/com/keepgoing/keepserver/domain/damage/mapper/DamageMapper.java create mode 100644 src/main/java/com/keepgoing/keepserver/domain/damage/payload/request/DamageCreateRequest.java create mode 100644 src/main/java/com/keepgoing/keepserver/domain/damage/payload/response/DamageResponseDto.java create mode 100644 src/main/java/com/keepgoing/keepserver/domain/damage/presentation/DamageController.java create mode 100644 src/main/java/com/keepgoing/keepserver/domain/damage/repository/DamageRepository.java create mode 100644 src/main/java/com/keepgoing/keepserver/domain/damage/service/DamageService.java create mode 100644 src/main/java/com/keepgoing/keepserver/domain/damage/service/DamageServiceImpl.java create mode 100644 src/main/java/com/keepgoing/keepserver/global/exception/damage/DamageError.java create mode 100644 src/main/java/com/keepgoing/keepserver/global/exception/damage/DamageException.java diff --git a/src/main/java/com/keepgoing/keepserver/domain/damage/entity/Damage.java b/src/main/java/com/keepgoing/keepserver/domain/damage/entity/Damage.java new file mode 100644 index 0000000..f71906e --- /dev/null +++ b/src/main/java/com/keepgoing/keepserver/domain/damage/entity/Damage.java @@ -0,0 +1,53 @@ +package com.keepgoing.keepserver.domain.damage.entity; + +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.time.LocalDateTime; + +@Entity +@Getter +@Setter +@SuperBuilder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@EntityListeners(AuditingEntityListener.class) +@Table(name = "damage") +public class Damage { + /* + id + */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + /* + 기기 식별 코드 (nfc/이름) + */ + @Column(nullable = false) + private String code; + + /* + 문제 유형 + */ + @Column(nullable = false) + private String issueType; + + /* + 유형에 맞는 자세한 내용 + */ + @Lob + @Column(nullable = false, columnDefinition = "MEDIUMTEXT") + private String description; + + /* + 신고 날짜 + */ + @Column(nullable = false) + private LocalDateTime reportDate; + +} diff --git a/src/main/java/com/keepgoing/keepserver/domain/damage/mapper/DamageMapper.java b/src/main/java/com/keepgoing/keepserver/domain/damage/mapper/DamageMapper.java new file mode 100644 index 0000000..c368754 --- /dev/null +++ b/src/main/java/com/keepgoing/keepserver/domain/damage/mapper/DamageMapper.java @@ -0,0 +1,30 @@ +package com.keepgoing.keepserver.domain.damage.mapper; + +import com.keepgoing.keepserver.domain.damage.entity.Damage; +import com.keepgoing.keepserver.domain.damage.payload.request.DamageCreateRequest; +import com.keepgoing.keepserver.domain.damage.payload.response.DamageResponseDto; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; + +@Component +public class DamageMapper { + public DamageResponseDto entityToDto(Damage entity) { + return DamageResponseDto.builder() + .id(entity.getId()) + .code(entity.getCode()) + .issueType(entity.getIssueType()) + .description(entity.getDescription()) + .reportDate(entity.getReportDate()) + .build(); + } + + public Damage dtoToEntity(DamageCreateRequest dto) { + return Damage.builder() + .code(dto.getCode()) + .issueType(dto.getIssueType()) + .description(dto.getDescription()) + .reportDate(LocalDateTime.now()) + .build(); + } +} diff --git a/src/main/java/com/keepgoing/keepserver/domain/damage/payload/request/DamageCreateRequest.java b/src/main/java/com/keepgoing/keepserver/domain/damage/payload/request/DamageCreateRequest.java new file mode 100644 index 0000000..b4c8dbc --- /dev/null +++ b/src/main/java/com/keepgoing/keepserver/domain/damage/payload/request/DamageCreateRequest.java @@ -0,0 +1,19 @@ +package com.keepgoing.keepserver.domain.damage.payload.request; + +import jakarta.validation.constraints.NotBlank; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class DamageCreateRequest { + @NotBlank(message = "Code cannot be blank") + private String code; + + @NotBlank(message = "Issue type cannot be blank") + private String issueType; + + @NotBlank(message = "Description cannot be blank") + private final String description; + +} \ No newline at end of file diff --git a/src/main/java/com/keepgoing/keepserver/domain/damage/payload/response/DamageResponseDto.java b/src/main/java/com/keepgoing/keepserver/domain/damage/payload/response/DamageResponseDto.java new file mode 100644 index 0000000..8afa7cb --- /dev/null +++ b/src/main/java/com/keepgoing/keepserver/domain/damage/payload/response/DamageResponseDto.java @@ -0,0 +1,15 @@ +package com.keepgoing.keepserver.domain.damage.payload.response; + +import lombok.Builder; + +import java.time.LocalDateTime; + +@Builder +public record DamageResponseDto( + Long id, + String code, + String issueType, + String description, + LocalDateTime reportDate +) { +} diff --git a/src/main/java/com/keepgoing/keepserver/domain/damage/presentation/DamageController.java b/src/main/java/com/keepgoing/keepserver/domain/damage/presentation/DamageController.java new file mode 100644 index 0000000..5b914f1 --- /dev/null +++ b/src/main/java/com/keepgoing/keepserver/domain/damage/presentation/DamageController.java @@ -0,0 +1,38 @@ +package com.keepgoing.keepserver.domain.damage.presentation; + +import com.keepgoing.keepserver.domain.damage.payload.request.DamageCreateRequest; +import com.keepgoing.keepserver.domain.damage.service.DamageService; +import com.keepgoing.keepserver.global.common.BaseResponse; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +@Slf4j +@Tag(name = "파손", description = " 관련 api 입니다.") +@RequiredArgsConstructor +@RestController +@RequestMapping("/damage") +public class DamageController { + private final DamageService damageService; + + @Operation(summary = "파손 등록", description = "파손된 항목 등록을 진행합니다.") + @PostMapping("/report") + public BaseResponse reportDamage(@Valid @RequestBody DamageCreateRequest request) { + return damageService.reportDamage(request); + } + + @Operation(summary = "파손 정보 불러오기", description = "파손된 항목들을 불러옵니다.") + @GetMapping("/all") + public BaseResponse getAllDamages() { + return damageService.getAllDamages(); + } + + @Operation(summary = "파손 정보 삭제하기", description = "파손된 항목을 삭제합니다.") + @DeleteMapping("/{id}") + public BaseResponse deleteDamage(@PathVariable Long id) { + return damageService.deleteDamage(id); + } +} diff --git a/src/main/java/com/keepgoing/keepserver/domain/damage/repository/DamageRepository.java b/src/main/java/com/keepgoing/keepserver/domain/damage/repository/DamageRepository.java new file mode 100644 index 0000000..1ae6e8f --- /dev/null +++ b/src/main/java/com/keepgoing/keepserver/domain/damage/repository/DamageRepository.java @@ -0,0 +1,10 @@ +package com.keepgoing.keepserver.domain.damage.repository; + +import com.keepgoing.keepserver.domain.damage.entity.Damage; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface DamageRepository extends JpaRepository { + boolean existsByCodeAndIssueType(String code, String issueType); +} diff --git a/src/main/java/com/keepgoing/keepserver/domain/damage/service/DamageService.java b/src/main/java/com/keepgoing/keepserver/domain/damage/service/DamageService.java new file mode 100644 index 0000000..8c3f3f0 --- /dev/null +++ b/src/main/java/com/keepgoing/keepserver/domain/damage/service/DamageService.java @@ -0,0 +1,13 @@ +package com.keepgoing.keepserver.domain.damage.service; + +import com.keepgoing.keepserver.domain.damage.payload.request.DamageCreateRequest; +import com.keepgoing.keepserver.global.common.BaseResponse; + +public interface DamageService { + + BaseResponse reportDamage(DamageCreateRequest request); + + BaseResponse getAllDamages(); + + BaseResponse deleteDamage(Long id); +} diff --git a/src/main/java/com/keepgoing/keepserver/domain/damage/service/DamageServiceImpl.java b/src/main/java/com/keepgoing/keepserver/domain/damage/service/DamageServiceImpl.java new file mode 100644 index 0000000..10cb4aa --- /dev/null +++ b/src/main/java/com/keepgoing/keepserver/domain/damage/service/DamageServiceImpl.java @@ -0,0 +1,65 @@ +package com.keepgoing.keepserver.domain.damage.service; + +import com.keepgoing.keepserver.domain.damage.entity.Damage; +import com.keepgoing.keepserver.domain.damage.mapper.DamageMapper; +import com.keepgoing.keepserver.domain.damage.payload.request.DamageCreateRequest; +import com.keepgoing.keepserver.domain.damage.payload.response.DamageResponseDto; +import com.keepgoing.keepserver.domain.damage.repository.DamageRepository; +import com.keepgoing.keepserver.global.common.BaseResponse; +import com.keepgoing.keepserver.global.exception.damage.DamageError; +import com.keepgoing.keepserver.global.exception.damage.DamageException; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class DamageServiceImpl implements DamageService { + + private final DamageRepository damageRepository; + private final DamageMapper damageMapper; + + @Override + @Transactional + public BaseResponse reportDamage(DamageCreateRequest request) { + validateDuplicate(request.getCode(), request.getIssueType()); + Damage damage = damageMapper.dtoToEntity(request); + damageRepository.save(damage); + return new BaseResponse(HttpStatus.OK, "파손 정보 등록 성공", damage); + } + + @Override + @Transactional(readOnly = true) + public BaseResponse getAllDamages() { + List damages = damageRepository.findAll().stream() + .map(damageMapper::entityToDto) + .toList(); + if (damages.isEmpty()) { + throw new DamageException(DamageError.INVALID_DAMAGE); + } + return new BaseResponse(HttpStatus.OK, "파손 정보 불러오기 성공", damages); + } + + @Override + @Transactional + public BaseResponse deleteDamage(Long id) { + Damage damage = findDamageById(id); + damageRepository.deleteById(id); + return new BaseResponse(HttpStatus.OK, "파손 정보 삭제 성공"); + } + + private void validateDuplicate(String code, String issueType) { + boolean isDuplicate = damageRepository.existsByCodeAndIssueType(code, issueType); + if (isDuplicate) { + throw new DamageException(DamageError.DUPLICATE); + } + } + + private Damage findDamageById(Long id) { + return damageRepository.findById(id) + .orElseThrow(() -> new DamageException(DamageError.INVALID_DAMAGE)); + } +} diff --git a/src/main/java/com/keepgoing/keepserver/global/exception/damage/DamageError.java b/src/main/java/com/keepgoing/keepserver/global/exception/damage/DamageError.java new file mode 100644 index 0000000..fd97b63 --- /dev/null +++ b/src/main/java/com/keepgoing/keepserver/global/exception/damage/DamageError.java @@ -0,0 +1,15 @@ +package com.keepgoing.keepserver.global.exception.damage; + +import com.keepgoing.keepserver.global.exception.error.ErrorProperty; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; + +@Getter +@RequiredArgsConstructor +public enum DamageError implements ErrorProperty { + INVALID_DAMAGE(HttpStatus.NOT_FOUND, "파손 정보가 없습니다."), + DUPLICATE(HttpStatus.NOT_FOUND, "이미 같은 문제로 신고된 기기입니다."); + private final HttpStatus status; + private final String message; +} diff --git a/src/main/java/com/keepgoing/keepserver/global/exception/damage/DamageException.java b/src/main/java/com/keepgoing/keepserver/global/exception/damage/DamageException.java new file mode 100644 index 0000000..8e5c84c --- /dev/null +++ b/src/main/java/com/keepgoing/keepserver/global/exception/damage/DamageException.java @@ -0,0 +1,20 @@ +package com.keepgoing.keepserver.global.exception.damage; + +import com.keepgoing.keepserver.global.exception.BusinessException; + +public class DamageException extends BusinessException { + private static final DamageException INVALID_DAMAGE = new DamageException(DamageError.INVALID_DAMAGE); + private static final DamageException DUPLICATE = new DamageException(DamageError.DUPLICATE); + + public DamageException(DamageError error) { + super(error); + } + + public static DamageException invalidDamage() { + return INVALID_DAMAGE; + } + + public static DamageException duplicate() { + return DUPLICATE; + } +} From cb1fa7f8a9ced1a19732307691ae8e4e98efbea5 Mon Sep 17 00:00:00 2001 From: priverg163 Date: Fri, 11 Oct 2024 11:32:58 +0900 Subject: [PATCH 2/4] Edit :: Mapper annotation in DamageMapper --- .../domain/damage/entity/Damage.java | 2 +- .../domain/damage/mapper/DamageMapper.java | 29 +++++-------------- .../payload/response/DamageResponseDto.java | 2 +- 3 files changed, 10 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/keepgoing/keepserver/domain/damage/entity/Damage.java b/src/main/java/com/keepgoing/keepserver/domain/damage/entity/Damage.java index f71906e..b1cf332 100644 --- a/src/main/java/com/keepgoing/keepserver/domain/damage/entity/Damage.java +++ b/src/main/java/com/keepgoing/keepserver/domain/damage/entity/Damage.java @@ -23,7 +23,7 @@ public class Damage { */ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + private Long idx; /* 기기 식별 코드 (nfc/이름) diff --git a/src/main/java/com/keepgoing/keepserver/domain/damage/mapper/DamageMapper.java b/src/main/java/com/keepgoing/keepserver/domain/damage/mapper/DamageMapper.java index c368754..335a209 100644 --- a/src/main/java/com/keepgoing/keepserver/domain/damage/mapper/DamageMapper.java +++ b/src/main/java/com/keepgoing/keepserver/domain/damage/mapper/DamageMapper.java @@ -3,28 +3,15 @@ import com.keepgoing.keepserver.domain.damage.entity.Damage; import com.keepgoing.keepserver.domain.damage.payload.request.DamageCreateRequest; import com.keepgoing.keepserver.domain.damage.payload.response.DamageResponseDto; -import org.springframework.stereotype.Component; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; -import java.time.LocalDateTime; +@Mapper(componentModel = "spring") +public interface DamageMapper { -@Component -public class DamageMapper { - public DamageResponseDto entityToDto(Damage entity) { - return DamageResponseDto.builder() - .id(entity.getId()) - .code(entity.getCode()) - .issueType(entity.getIssueType()) - .description(entity.getDescription()) - .reportDate(entity.getReportDate()) - .build(); - } + DamageResponseDto entityToDto(Damage damage); - public Damage dtoToEntity(DamageCreateRequest dto) { - return Damage.builder() - .code(dto.getCode()) - .issueType(dto.getIssueType()) - .description(dto.getDescription()) - .reportDate(LocalDateTime.now()) - .build(); - } + @Mapping(target = "reportDate", expression = "java(java.time.LocalDateTime.now())") + Damage dtoToEntity(DamageCreateRequest damageCreateRequest); } + diff --git a/src/main/java/com/keepgoing/keepserver/domain/damage/payload/response/DamageResponseDto.java b/src/main/java/com/keepgoing/keepserver/domain/damage/payload/response/DamageResponseDto.java index 8afa7cb..4774ce5 100644 --- a/src/main/java/com/keepgoing/keepserver/domain/damage/payload/response/DamageResponseDto.java +++ b/src/main/java/com/keepgoing/keepserver/domain/damage/payload/response/DamageResponseDto.java @@ -6,7 +6,7 @@ @Builder public record DamageResponseDto( - Long id, + Long idx, String code, String issueType, String description, From 60e3675df460749033286cb6caf912a1e0f14920 Mon Sep 17 00:00:00 2001 From: priverg163 Date: Fri, 11 Oct 2024 11:34:32 +0900 Subject: [PATCH 3/4] Refactor :: convert function to void in damage --- .../keepserver/domain/damage/service/DamageServiceImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/keepgoing/keepserver/domain/damage/service/DamageServiceImpl.java b/src/main/java/com/keepgoing/keepserver/domain/damage/service/DamageServiceImpl.java index 10cb4aa..4645811 100644 --- a/src/main/java/com/keepgoing/keepserver/domain/damage/service/DamageServiceImpl.java +++ b/src/main/java/com/keepgoing/keepserver/domain/damage/service/DamageServiceImpl.java @@ -46,7 +46,7 @@ public BaseResponse getAllDamages() { @Override @Transactional public BaseResponse deleteDamage(Long id) { - Damage damage = findDamageById(id); + findDamageById(id); damageRepository.deleteById(id); return new BaseResponse(HttpStatus.OK, "파손 정보 삭제 성공"); } @@ -58,8 +58,8 @@ private void validateDuplicate(String code, String issueType) { } } - private Damage findDamageById(Long id) { - return damageRepository.findById(id) + private void findDamageById(Long id) { + damageRepository.findById(id) .orElseThrow(() -> new DamageException(DamageError.INVALID_DAMAGE)); } } From bf0891aef6a5a112826c5a0e59d23bf50ed2e709 Mon Sep 17 00:00:00 2001 From: priverg163 Date: Fri, 11 Oct 2024 11:34:57 +0900 Subject: [PATCH 4/4] Fix :: remove readonly in deleteBook --- .../keepserver/domain/book/service/BookServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/keepgoing/keepserver/domain/book/service/BookServiceImpl.java b/src/main/java/com/keepgoing/keepserver/domain/book/service/BookServiceImpl.java index 282848d..a0482fd 100644 --- a/src/main/java/com/keepgoing/keepserver/domain/book/service/BookServiceImpl.java +++ b/src/main/java/com/keepgoing/keepserver/domain/book/service/BookServiceImpl.java @@ -42,7 +42,7 @@ public BaseResponse selectAllBook() { } @Override - @Transactional(readOnly = true) + @Transactional public BaseResponse deleteBook(String nfcCode, Authentication auth) { if (nfcCode == null || nfcCode.isEmpty()) { return new BaseResponse(HttpStatus.NOT_FOUND, "Invalid NFC code");