From 6dc53fc29dfb0d5be0b74d1d021f39b827c0422f Mon Sep 17 00:00:00 2001 From: psj Date: Fri, 23 May 2025 10:15:02 +0900 Subject: [PATCH 1/6] =?UTF-8?q?=EC=98=B7=20=EC=A1=B0=ED=9A=8C=20(=EC=88=98?= =?UTF-8?q?=EC=A0=95=EC=9A=A9=20)=20API=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gradle/8.13/checksums/checksums.lock | Bin 17 -> 17 bytes .gradle/8.13/checksums/md5-checksums.bin | Bin 26047 -> 28197 bytes .gradle/8.13/checksums/sha1-checksums.bin | Bin 40475 -> 72221 bytes .../executionHistory/executionHistory.lock | Bin 17 -> 17 bytes .gradle/8.13/fileHashes/fileHashes.bin | Bin 25447 -> 26347 bytes .gradle/8.13/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../buildOutputCleanup.lock | Bin 17 -> 17 bytes build.gradle | 1 + .../domain/cloth/api/ClothRestController.java | 38 ++++++++++++++++ .../cloth/application/ClothService.java | 8 ++++ .../cloth/application/ClothServiceImpl.java | 43 ++++++++++++++++++ .../cloth/converter/ClothConverter.java | 22 +++++++++ .../repository/ClothImageRepository.java | 5 ++ .../domain/cloth/dto/ClothRequestDTO.java | 4 ++ .../domain/cloth/dto/ClothResponseDTO.java | 29 ++++++++++++ .../cloth/exception/ClothException.java | 12 +++++ .../goorm/global/config/SwaggerConfig.java | 37 +++++++++++++++ .../global/error/code/status/ErrorStatus.java | 8 +++- .../error/code/status/SuccessStatus.java | 5 +- .../exception/GlobalExceptionAdvice.java | 24 +++++----- 20 files changed, 222 insertions(+), 14 deletions(-) create mode 100644 src/main/java/study/goorm/domain/cloth/api/ClothRestController.java create mode 100644 src/main/java/study/goorm/domain/cloth/application/ClothService.java create mode 100644 src/main/java/study/goorm/domain/cloth/application/ClothServiceImpl.java create mode 100644 src/main/java/study/goorm/domain/cloth/converter/ClothConverter.java create mode 100644 src/main/java/study/goorm/domain/cloth/dto/ClothRequestDTO.java create mode 100644 src/main/java/study/goorm/domain/cloth/dto/ClothResponseDTO.java create mode 100644 src/main/java/study/goorm/domain/cloth/exception/ClothException.java create mode 100644 src/main/java/study/goorm/global/config/SwaggerConfig.java diff --git a/.gradle/8.13/checksums/checksums.lock b/.gradle/8.13/checksums/checksums.lock index 943f8b00944f0cfe4b052a4b2b18f71cdcfec7b8..2623f2b46d5165d1b4a2ee7911dbf8f5874a6979 100644 GIT binary patch literal 17 VcmZQRynUyB`kMNS3}C?Y763ga1-JkJ literal 17 VcmZQRynUyB`kMNS3}C=y1pqvA1qA>A diff --git a/.gradle/8.13/checksums/md5-checksums.bin b/.gradle/8.13/checksums/md5-checksums.bin index 47ef681448ec327e45020b54da8007a0190d29f3..877b0477b0cff4a0c0f80cf535844b9b65c0abaa 100644 GIT binary patch delta 2963 zcmZXW3pmv29>-@wD8}CAQI5 zP&^R|r%*q!4tUfIY~}Fw(2@b!St!QHfj_A>*qYPgL{`853*D0;hRFR{P~>QVN!?79wp+4~%-vj(@d5DE%T(#w`82Jw=MmJR$3dT-52k#`ly6^g z-5827Q9zkS!_-W>QiE*4DMS|oCd~)aN}Bp6=omu zNpu>f?=iTd)Ra;H#po(QK0ThuvX0mlQrp3tgDR&<+`e^R(NNqwFR|MW{H{;KY>B`& z;rHKapgCp(C^LLmd#BqC3mU|AMQ;^naQ1gh8}=L@KxQ^L%&=j(T#tC;ws?$%#9^`7 zbw2FNmJ3TnsK*8Z9)pIt55!FOENj!D7*!7{7`7^j9v<1*;T2GeoCm{OM+WTe~N|_1L zm^3VI^OW)Wh$9CT0dJHQslW zG{8UPK|^SsId`}+ayAHwgb3418u7TwH_=P* zU-WDFKx<>&#;*`zS;goe*qo3iX7*H*TzxCuU)r5q@9S9Gf(W#6OrMJh?q9t>RkZ9( zPRkDJ9#7>RU9UcZkaw^wdWIPJi!jy1f_{v7TfAHl9kTH#kpzhnCL)C8N%ZdX#J+hi ze~)f{a%-hwznKidR@6y}8bnmDOC$BasQJ&`NHuHth<41F5E+Li@d9z)+FSvBn@NH^ z_o{&xyHVr#rJHE*98Bl+v2?mWltxT|UE7Bbyiev9{M)+`kpKzxVQFG?-DS_mIgQPe zOcFgw@FWBgZMc(*f5L@#qC}gE3w39*8~<*nJLlfr{N|_&M6MX&PCQho_(Os?raMa< zSDo8!9AD}Xs5sM!2qzIhP~=M!XDYuA)nF|58aVtzw?n|^C?g~ol=*0rSHrSWeyw~R z@!x#4yAMXHHPK)$81~Vo@%}74mwF*(BO2_5ld%lIa)3HF%F5uUwvl1d z2)tN4If0;^`@+U_Y!%_L(_*_SaS zKjTQo^HDS?JWzO0HSmYTvg_53#A#ip-h6xGmt@G}zDV}6GK$i(Fjo5s5x%%nxbt>wl1482A9H3l-Ou}v z!nZF>XeOZ$;VNIrGY{;p;qds!hH5@qPmiJF--!FW;Yr>LqlTd83zA>=45OBugiB+GILz^1-G{LCy*=k?p5$zA1$sD#94G-;y5 ziLI!?HPHHlqp#*YH~;K0LM}jLn{W*zdas;S_+*~#*L=ex*S~(OGz1YiDGX)dH!eX` zoSO{=RUga)?mvkG9Wvh`Vp;?cl!k>HL;}ei4S1zwa^C))kB4IrrUIofUpfh~_AUb0`b% HD3kvI(*RVl delta 179 zcmV;k08Ia-+yTGK0kAX}0hg0C7+{mF7+{kn85omQ85xs?85fha8F;fr8VCWCWg9S) zts7vIB^-E@wH%PMbsabXlieP8lWiX`leHhHlXW0@lLjGpla?Vzll37OlO-ZZvxOoE z0h6U87_-$QXaSRLB^Z;PB}kJMCNPtACK!{YCNY!lCa9CHCohxrCoq#eD5#VDC>WD1 hDHxM=DR`3|Dj1VZDk1_7Ik6%57qKwl39~^+ejP25L7)Ht diff --git a/.gradle/8.13/checksums/sha1-checksums.bin b/.gradle/8.13/checksums/sha1-checksums.bin index 35da322241e6a311725f14b072188d3a1f7addd7..e88d72e9b9ef12cf92168a3a9c3430bcf397e363 100644 GIT binary patch delta 9369 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 diff --git a/.gradle/8.13/executionHistory/executionHistory.lock b/.gradle/8.13/executionHistory/executionHistory.lock index 2e74c8c71b6deca14fd2851ce58163766f2a3bf4..bad597e2857ab25d9708ad3b001f48fbb732b90c 100644 GIT binary patch literal 17 UcmZQRtXo+5@vdep0|Y1n05vrPQvd(} literal 17 UcmZQRtXo+5@vdep0|W>I05vBBMF0Q* diff --git a/.gradle/8.13/fileHashes/fileHashes.bin b/.gradle/8.13/fileHashes/fileHashes.bin index 1a348dde98acbbecfcbedc686a0805ff656c2ae9..a831f698fee338fb511ebb8d1bf686ef8e83bcf1 100644 GIT binary patch delta 2260 zcmZvcc~DbV6o>P|BC?pIFa`oh*sQ3a2m2EwAEXt4^Y6bmTG7Uhhn zQxOmmsamk9QlKnKK@iX?;vnM|pkN1?n$i)dEWPjD*MCCK%)9qD=brDJ^X|RxjkFP? z-9)vcp;1v}W$$k^7aNW@8NYGg$;I_%PEODM9@`%!a z_O*hwse+aHi=gYPhKJZE?SvWAcWm9h6NhuJ9$bW-F_zG~M8szOGbENyG>y?T$W6^S z1k1s$sBQg$BHB3t*8Dwe$9_*%)Pv(J?2J~*Pw_(tw&3=VFZ=uM4D6N0La%u>J3OJu z-PNFH3+}Jr7BWc3;ym2N;xde2QG(u> z2M$40scRqzqR2`}p@h>cR8hkD6)3Pc3;MxijB_t+#^M?z2HUxgyRGxVhoEMLW;+Ko z*r3OpeAs8+tqH8Ux8_Un>%_p3#VxC;V=EJRqD5q{e}lnb^4MHD`86#qldk`L0Az^jd(sp#8A zap{T=7}V56vr1z@{TIq+kB)?XcA7}M_{pZ5B38N;V?x~)IFhC6=z=|h4HBx*V>p1t zQz(}3{IlBEPM&zoiH}H39n?}Ln^3%rJAnB`uJbD@>>G!3pS;}K8P9(bbGns76CW|5 zQw};2H~6be8ai3+k2w0Lduvi6nN-^M!l{cm$kY{jB0|XbABI(tR9k%zfki(67H^?7 z(oPq}C@`dv4$3fn_(H0mikyF7r&<}BRkq|s`NIqKvn3{T7GWO3nvQ1Npy5VLI4S27 z#kvNi6>}XW`O363Nu@gagAj$|>yPSVLL)(iutXQ)T=3Ad7mUBw9oAUfp042OP>7og znH-sR77+gWshU0-&AFfMapt<7ai_^|9DVC$E3bU~Q#*+Um9|P73+k?hYjbS($7R2Nbs7Dj5n+^0|5F+0nyM1RCRJ@? zzM1DvX;prHAo$fNhe9m)2T>?8H48MT6v>*+4)9D-#@;Gyu6$zRiw+nS*=IaN0Ssa} zwWGzO%lEZki4|SCw0XiOlt;ysZNH9Vw5{i7t@k}FoDMCXGLw!Qk1Dp{4_C(J(pmfF z6CJ5tVNM0XOr7V2TGe;EL#Y}vZaGPy9cBGEAMtxDJ$tlv+JiZe|7M^r&!0wWNd#Sn z5HzT~te$^P@7kNpzG|t+Rk-6ib$!rR+CTveg8UPy5L`8}mtktxRC$U0g_#px-|nJ| z1Ym@dJReyWujW<6E`GPL+e)m%t(l<-vK?f)|I=3fq|x~^0Z~>PFCwRJT!YS*EF_11gsG#Hf=It*Vn3*5%`#$qNGc(r7Mjx`4Xca4k zNo5xvsEQbD>L8&^J%OP)cs3MM^H4nX1Ijdeq1EJLy;LMHNJ`POfG1{3WEDQT~FypxJA)GydzK{ zB#R54AcNp34iP+qlb{cy1TOK$Y8aRERzpZ#&XptB$DyPPmnovh5CMZSo7ZTNK;VPj z*@jrr=@@;2dx*FjjN&p=oO)^c_0I3lo@r<(X!oghZ6vw?3yvd&K z(fv(+N>HrW!*q2y-IIFktU0V+iR)(&S2GZUM*wZLPL(5m-IM=XtHrP`{A+; zTb_P2I+Goj%dCS{ejb2YWPsz(TW1ok&Yf9}A2TE3*J?B?mmqv<%PExqv zguk5|E5bs%L2`Hon+R%f-mbQoj|_I*_x$aBtR=vjpI}na#pI);S1kU&GI^pbHPy7<|Q=9uj#T!l%_r1gurYi@|;hy4Q>QxF;zr+R!^=BYq05p~001XP13dr$ diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 8bc68f86f0de793920ac40f302dc30edd80075f1..de3d77d18bed12ff5853a317bc25ef7735f82f6c 100644 GIT binary patch literal 17 TcmZSfny)7yTG{!G0Rn0OC8PtS literal 17 TcmZSfny)7yTG{!G0Rn;nC3^#V diff --git a/build.gradle b/build.gradle index 9592344..86da822 100644 --- a/build.gradle +++ b/build.gradle @@ -28,6 +28,7 @@ dependencies { //implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' annotationProcessor 'org.projectlombok:lombok' diff --git a/src/main/java/study/goorm/domain/cloth/api/ClothRestController.java b/src/main/java/study/goorm/domain/cloth/api/ClothRestController.java new file mode 100644 index 0000000..cb3b730 --- /dev/null +++ b/src/main/java/study/goorm/domain/cloth/api/ClothRestController.java @@ -0,0 +1,38 @@ +package study.goorm.domain.cloth.api; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import study.goorm.domain.cloth.application.ClothService; +import study.goorm.domain.cloth.dto.ClothResponseDTO; +import study.goorm.global.common.response.BaseResponse; +import study.goorm.global.error.code.status.SuccessStatus; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/cloth") //원래 cloth-였는데 cloth로 바꿨음 +@Validated +public class ClothRestController { + + private final ClothService clothService; + + @GetMapping("/{cloth-id}/edit-view") + @Operation(summary = "특정 Cloth에 대한 정보를 수정용으로 조회하는 API",description = "Path Variable로 clothId를 던져주세요.") + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "CLOTH_200", description = "OK, 성공적으로 조회되었습니다."), + }) + public BaseResponse getClothEditView( + @PathVariable(name = "cloth-id") Long clothId + ){ + ClothResponseDTO.ClothEditViewResult result=clothService.getClothEditView(clothId); + return BaseResponse.onSuccess(SuccessStatus.CLOTH_VIEW_SUCCESS,result); + } + + +} + diff --git a/src/main/java/study/goorm/domain/cloth/application/ClothService.java b/src/main/java/study/goorm/domain/cloth/application/ClothService.java new file mode 100644 index 0000000..77840fa --- /dev/null +++ b/src/main/java/study/goorm/domain/cloth/application/ClothService.java @@ -0,0 +1,8 @@ +package study.goorm.domain.cloth.application; + +import study.goorm.domain.cloth.dto.ClothResponseDTO; + +public interface ClothService { + ClothResponseDTO.ClothEditViewResult getClothEditView(Long clothId); + +} diff --git a/src/main/java/study/goorm/domain/cloth/application/ClothServiceImpl.java b/src/main/java/study/goorm/domain/cloth/application/ClothServiceImpl.java new file mode 100644 index 0000000..889be3f --- /dev/null +++ b/src/main/java/study/goorm/domain/cloth/application/ClothServiceImpl.java @@ -0,0 +1,43 @@ +package study.goorm.domain.cloth.application; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import study.goorm.domain.cloth.converter.ClothConverter; +import study.goorm.domain.cloth.domain.entity.Cloth; +import study.goorm.domain.cloth.domain.entity.ClothImage; +import study.goorm.domain.cloth.domain.repository.ClothImageRepository; +import study.goorm.domain.cloth.domain.repository.ClothRepository; +import study.goorm.domain.cloth.dto.ClothResponseDTO; +import study.goorm.domain.cloth.exception.ClothException; +import study.goorm.global.error.code.status.ErrorStatus; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class ClothServiceImpl implements ClothService { + + private final ClothRepository clothRepository; + private final ClothImageRepository clothImageRepository; + + @Override + @Transactional(readOnly = true) + public ClothResponseDTO.ClothEditViewResult getClothEditView(Long clothId){ + + Cloth cloth = clothRepository.findById(clothId) + .orElseThrow(() -> new ClothException(ErrorStatus.NO_SUCH_CLOTH)); + + List clothImageUrls=clothImageRepository.findAllByCloth(cloth); + + String firstImageUrl=clothImageUrls.stream() + .findFirst() + .map(ClothImage::getImageUrl) + .orElseThrow(()->new ClothException(ErrorStatus.NO_ClOTH_IMAGE)); + + + + return ClothConverter.toClothEditViewResult(cloth,firstImageUrl ); + } + +} diff --git a/src/main/java/study/goorm/domain/cloth/converter/ClothConverter.java b/src/main/java/study/goorm/domain/cloth/converter/ClothConverter.java new file mode 100644 index 0000000..fc8f0c1 --- /dev/null +++ b/src/main/java/study/goorm/domain/cloth/converter/ClothConverter.java @@ -0,0 +1,22 @@ +package study.goorm.domain.cloth.converter; + +import study.goorm.domain.cloth.domain.entity.Cloth; +import study.goorm.domain.cloth.dto.ClothResponseDTO; + +public class ClothConverter { + public static ClothResponseDTO.ClothEditViewResult toClothEditViewResult(Cloth cloth, String clothImageUrl){ + return ClothResponseDTO.ClothEditViewResult.builder() + .id(cloth.getId()) + .brand(cloth.getBrand()) + .categoryId(cloth.getCategory().getId()) + .clothUrl(cloth.getClothUrl()) + .imageUrl(clothImageUrl) + .name(cloth.getName()) + .seasons(cloth.getSeason()) + .tempLowerBound(cloth.getTempLowerBound()) + .tempUpperBound(cloth.getTempUpperBound()) + .thicknessLevel(cloth.getThicknessLevel()) + .build(); + + } +} diff --git a/src/main/java/study/goorm/domain/cloth/domain/repository/ClothImageRepository.java b/src/main/java/study/goorm/domain/cloth/domain/repository/ClothImageRepository.java index 1b5a7f1..ebaafd3 100644 --- a/src/main/java/study/goorm/domain/cloth/domain/repository/ClothImageRepository.java +++ b/src/main/java/study/goorm/domain/cloth/domain/repository/ClothImageRepository.java @@ -1,7 +1,12 @@ package study.goorm.domain.cloth.domain.repository; import org.springframework.data.jpa.repository.JpaRepository; +import study.goorm.domain.cloth.domain.entity.Cloth; import study.goorm.domain.cloth.domain.entity.ClothImage; +import java.util.List; + public interface ClothImageRepository extends JpaRepository { + + List findAllByCloth(Cloth cloth); } diff --git a/src/main/java/study/goorm/domain/cloth/dto/ClothRequestDTO.java b/src/main/java/study/goorm/domain/cloth/dto/ClothRequestDTO.java new file mode 100644 index 0000000..d30c9ca --- /dev/null +++ b/src/main/java/study/goorm/domain/cloth/dto/ClothRequestDTO.java @@ -0,0 +1,4 @@ +package study.goorm.domain.cloth.dto; + +public class ClothRequestDTO { +} diff --git a/src/main/java/study/goorm/domain/cloth/dto/ClothResponseDTO.java b/src/main/java/study/goorm/domain/cloth/dto/ClothResponseDTO.java new file mode 100644 index 0000000..82f09f0 --- /dev/null +++ b/src/main/java/study/goorm/domain/cloth/dto/ClothResponseDTO.java @@ -0,0 +1,29 @@ +package study.goorm.domain.cloth.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import study.goorm.domain.model.enums.Season; +import study.goorm.domain.model.enums.ThicknessLevel; +import java.util.List; + +public class ClothResponseDTO { + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class ClothEditViewResult{ + private Long id; + private String name; + private List seasons; + private int tempUpperBound; + private int tempLowerBound; + private ThicknessLevel thicknessLevel; + private String clothUrl; + private String brand; + private String imageUrl; + private Long categoryId; + + } +} diff --git a/src/main/java/study/goorm/domain/cloth/exception/ClothException.java b/src/main/java/study/goorm/domain/cloth/exception/ClothException.java new file mode 100644 index 0000000..e4e7be9 --- /dev/null +++ b/src/main/java/study/goorm/domain/cloth/exception/ClothException.java @@ -0,0 +1,12 @@ +package study.goorm.domain.cloth.exception; + +import study.goorm.global.error.code.BaseErrorCode; +import study.goorm.global.exception.GeneralException; + +public class ClothException extends GeneralException { + + public ClothException(BaseErrorCode code) { + super(code); + } + +} diff --git a/src/main/java/study/goorm/global/config/SwaggerConfig.java b/src/main/java/study/goorm/global/config/SwaggerConfig.java new file mode 100644 index 0000000..1939cb7 --- /dev/null +++ b/src/main/java/study/goorm/global/config/SwaggerConfig.java @@ -0,0 +1,37 @@ +package study.goorm.global.config; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; +import io.swagger.v3.oas.models.servers.Server; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SwaggerConfig { + + @Bean + public OpenAPI goormStudyAPI(){ + Info info = new Info() + .title("GOORM API") + .description("GOORM API 명세서") + .version("1.0.0"); + + String jwtSchemeName="JWT TOKEN"; + SecurityRequirement securityRequirement=new SecurityRequirement().addList(jwtSchemeName); + Components components = new Components() + .addSecuritySchemes(jwtSchemeName,new SecurityScheme() + .name(jwtSchemeName) + .type(SecurityScheme.Type.HTTP) + .scheme("bearer") + .bearerFormat("JWT")); + return new OpenAPI() + .addServersItem(new Server().url("/")) + .info(info) + .addSecurityItem(securityRequirement) + .components(components); + + } +} diff --git a/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java b/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java index 5e1f9b3..807de6a 100644 --- a/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java +++ b/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java @@ -14,7 +14,13 @@ public enum ErrorStatus implements BaseErrorCode { _INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "COMMON500", "서버 에러, 관리자에게 문의 바랍니다."), _BAD_REQUEST(HttpStatus.BAD_REQUEST, "COMMON400", "잘못된 요청입니다."), _UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "COMMON401", "인증이 필요합니다."), - _FORBIDDEN(HttpStatus.FORBIDDEN, "COMMON403", "금지된 요청입니다."); + _FORBIDDEN(HttpStatus.FORBIDDEN, "COMMON403", "금지된 요청입니다."), + + //Cloth + NO_SUCH_CLOTH(HttpStatus.BAD_REQUEST,"CLOTH_4001","옷이 존재하지 않습니다"), + + //bug data + NO_ClOTH_IMAGE(HttpStatus.BAD_REQUEST,"CLOTH_4002","옷의 사진이 존재하지 않습니다."); private final HttpStatus httpStatus; private final String code; diff --git a/src/main/java/study/goorm/global/error/code/status/SuccessStatus.java b/src/main/java/study/goorm/global/error/code/status/SuccessStatus.java index 71d54d6..50f58a0 100644 --- a/src/main/java/study/goorm/global/error/code/status/SuccessStatus.java +++ b/src/main/java/study/goorm/global/error/code/status/SuccessStatus.java @@ -11,7 +11,10 @@ public enum SuccessStatus implements BaseCode { //Common - OK(HttpStatus.OK, "COMMON_200", "성공입니다."); + OK(HttpStatus.OK, "COMMON_200", "성공입니다."), + + //Cloth + CLOTH_VIEW_SUCCESS(HttpStatus.OK,"CLOTH_200","옷이 성공적으로 조회되었습니다."); private final HttpStatus httpStatus; private final String code; diff --git a/src/main/java/study/goorm/global/exception/GlobalExceptionAdvice.java b/src/main/java/study/goorm/global/exception/GlobalExceptionAdvice.java index 05f6cf3..1698dcd 100644 --- a/src/main/java/study/goorm/global/exception/GlobalExceptionAdvice.java +++ b/src/main/java/study/goorm/global/exception/GlobalExceptionAdvice.java @@ -3,7 +3,8 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.ConstraintViolationException; import lombok.extern.slf4j.Slf4j; -import org.hibernate.TypeMismatchException; + +import org.springframework.beans.TypeMismatchException; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode; @@ -28,18 +29,17 @@ @RestControllerAdvice(annotations = {RestController.class}) public class GlobalExceptionAdvice extends ResponseEntityExceptionHandler { - //주석처리한 코드는 override가 안됨, getPropertyName()도 문제가 있음 -// @Override -// protected ResponseEntity handleTypeMismatch( -// TypeMismatchException e, -// HttpHeaders headers, -// HttpStatusCode status, -// WebRequest request) { -// String errorMessage = e.getPropertyName() + ": 올바른 값이 아닙니다."; -// -// return handleExceptionInternalMessage(e, headers, request, errorMessage); -// } + @Override + protected ResponseEntity handleTypeMismatch( + TypeMismatchException e, + HttpHeaders headers, + HttpStatusCode status, + WebRequest request) { + String errorMessage = e.getPropertyName() + ": 올바른 값이 아닙니다."; + + return handleExceptionInternalMessage(e, headers, request, errorMessage); + } @Override protected ResponseEntity handleMissingServletRequestParameter( From 1250016a037e71096887913435423de47cccddc2 Mon Sep 17 00:00:00 2001 From: psj Date: Sat, 24 May 2025 11:04:20 +0900 Subject: [PATCH 2/6] =?UTF-8?q?=EC=9C=A0=EC=A0=80=EC=9D=98=20=EC=98=B7?= =?UTF-8?q?=EC=9E=A5=20=EC=A1=B0=ED=9A=8C=20API=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../executionHistory/executionHistory.lock | Bin 17 -> 17 bytes .gradle/8.13/fileHashes/fileHashes.bin | Bin 26347 -> 27447 bytes .gradle/8.13/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .../domain/cloth/api/ClothRestController.java | 35 ++++++++++++++-- .../application/ClothImageQueryService.java | 9 ++++ .../ClothImageQueryServiceImpl.java | 34 +++++++++++++++ .../cloth/application/ClothService.java | 3 ++ .../cloth/application/ClothServiceImpl.java | 39 +++++++++++++++++- .../cloth/converter/ClothConverter.java | 34 +++++++++++++++ .../repository/ClothImageRepository.java | 15 +++++++ .../domain/repository/ClothRepository.java | 9 ++++ .../domain/cloth/dto/ClothResponseDTO.java | 34 +++++++++++++++ .../domain/exception/MemberException.java | 12 ++++++ .../domain/repository/MemberRepository.java | 4 ++ .../goorm/domain/model/enums/ClothSort.java | 9 ++++ .../model/exception/annotation/CheckPage.java | 20 +++++++++ .../exception/annotation/CheckPageSize.java | 19 +++++++++ .../validator/CheckPageSizeValidator.java | 30 ++++++++++++++ .../validator/CheckPageValidator.java | 30 ++++++++++++++ .../global/error/code/status/ErrorStatus.java | 12 +++++- 21 files changed, 342 insertions(+), 6 deletions(-) create mode 100644 src/main/java/study/goorm/domain/cloth/application/ClothImageQueryService.java create mode 100644 src/main/java/study/goorm/domain/cloth/application/ClothImageQueryServiceImpl.java create mode 100644 src/main/java/study/goorm/domain/member/domain/exception/MemberException.java create mode 100644 src/main/java/study/goorm/domain/model/enums/ClothSort.java create mode 100644 src/main/java/study/goorm/domain/model/exception/annotation/CheckPage.java create mode 100644 src/main/java/study/goorm/domain/model/exception/annotation/CheckPageSize.java create mode 100644 src/main/java/study/goorm/domain/model/exception/validator/CheckPageSizeValidator.java create mode 100644 src/main/java/study/goorm/domain/model/exception/validator/CheckPageValidator.java diff --git a/.gradle/8.13/executionHistory/executionHistory.lock b/.gradle/8.13/executionHistory/executionHistory.lock index bad597e2857ab25d9708ad3b001f48fbb732b90c..abec310068e8be93f54fb7301b2d29bbdadaccd5 100644 GIT binary patch literal 17 UcmZQRtXo+5@vdep0|e*;05wAdVE_OC literal 17 UcmZQRtXo+5@vdep0|Y1n05vrPQvd(} diff --git a/.gradle/8.13/fileHashes/fileHashes.bin b/.gradle/8.13/fileHashes/fileHashes.bin index a831f698fee338fb511ebb8d1bf686ef8e83bcf1..7840b468d011a19940d7e40e8cca89e36a3d401e 100644 GIT binary patch delta 2476 zcmZvedo)yA7{F(SkusBERA}Uk^wg~oSy!G-T`WSSOOjEBN$&?KF}WVqnu^-YEpNJA zrBqB(B6{gLii##mqLfFul@fQx-RGR`k2}*|>zuvTH^1Mvzi(!reWqJREpMb=m}f|p z0vp2`=ffFy=T;QV*hL{mc>FLLsh!pi`PXd}WPDxZNc@Ot6+dwnrJsyP=zw0sz0;4K zw?24es*4wb3rFDNh0`712Z#;ZkY3Q8bNJ+snRHGniaA2olfCQ}l?ELsxSkG}CO)i| zAy>z=dtKp()B}DdTwMVrCE2w7AQ=<3f{i8^t0S91-+r(87qpHyNHV$0`WV3T`_!N{ z4UsX@MU(QWxOO6U$waxvB%9qs6VBuf)A7}gD{xIQeKj3lkc z?Jd^c=JC{PCN)!ztD@chx5ze!%;cW)IxcJ5DlN&cC%<5ix?T)d5leRrTMk@Re4viPm z*d>WtSo#Kqy|dCaVbAXNQ}dWBHz4XbNzs-_xqbyyENpUHvaYrBZ#NPyb$O%=Ht=VBcm^i<*0P?pCkGB0(xbaGG@4Qm(* zaoN~(MrVg(#sq^fqfbPQy|Olv8WjavgZ(v!l@Z3ko*##mEuSsYZ%VoE$xGYdAP<5o z;vGdSC28GGshl52!*MYPTpK64ZkOaWTf96Y+v>6`xAdrlz!fPUNSt8`XO-4m8xrL| znm8{xPaXt+n_TmeC_1?;m^7#{>c&6jaSZRL^=A~4bJ>$i*zk#=N|cmlCrHkR7o$R5 zscxw^WzOL|wf!-(yN$`O#ubIKLkE&@jIISKp*(EA-n-}Q?!UG3vabt6Gb1(;m26!Z zL_%6l;7ce^l-R7yw0h+qzTj;|fPV;|jYGrAb>$?)dIo2e1~qiFt(?acHdlJynN-Wo zt|8WL;BO@j4Lx-u=j=ZH$Ss&vCjGX{mGHAY0kW-I#tv&QTx?kiS? zT717gv*@5_{X#t7P_7O9s_{Xc2X87BBx^N|^YRh97yOXb?K`BfCyWHaRYIUp_NW`a z%?B=7?~^&Mb|{z<#O}M+O%z>GcNi&OfgYbN+I`r>?L=2h6j+w`X#O8|1aotLG|6b@ zs;3PWpD%f@Z)NL$d%Rg-_^l&^(ZK&q8q_>>L*`3SP|7V<*`IF_)U0>1B8?C?+z?SH zOt^7XyB!kG67Jv`xdu9Wx+u!b;2yzGFa8T$f%~)w-c-IH$t&}g7i*auy-LCJHP@oj zknxHTC|VZk#>bVM>eC|d)vTL3tv9W@7@oYuB9BOg8LzH%Bw=yFlfgZVn_Ha=^9rUT z1K;d$Xe;4Or7VW~g`$g%+cb*Kn*Ga3t9^@%n}k3a-3-{?`l3&axyN3|dd+Ck9G@+2 zkiJIHT@up5cZEt?bDfXJGp%iIoL%4fVZjwQVmH9ky^u6$`szm4{-M=Qs~OIH0~LmA zb_T+iCebWB_3+<-LjQ>}5b)rUD6lU!z28yc+cEwQt_=6(x}rsXvgM9!zt|Ra^{?7{ z)2c&P{kjL97|+TPt70X?`(CX9W%%vl%YiQ??DrPJ*)KIKl(D8 z)>edV5f<0RB+*Y3#GuW8=k>kmdWJVuS&$@2#wDFQD VRyKK67nsjLYbMHSiwq%d{0A3s?{NSC delta 1026 zcmdmfjq&wa#tkMCjB_WON*tJMD_Jr5sieVXU8w@5$y;R-C+o?&PwtgXn9M5YF*#LE za`H4e@ySQ!4s4z)Ka+8?pQ6O%I>i-}?Uc$VpH-SLxl~zV@=|4w&8#XXStdWzP-Nme zxl!?l_(p>O&drV;z$Kt<#E3NiXzm-+#|L{jq9!SS$d-Fd)Ng!Y>-(2h0!Y1+K`@DS(|J7T*mNIHO zcK(ZmsIpivd7;15X5-Kaj0&9(j6&9LGg6PcTORUU?63jY=EVUn5OeNc*!(zb5o1uV z;ai74Ra;DWdM?Jy*wwELR#oo}QN+O517x7N@6efq11ANpO`X5T-gtZP`m-P%d+*Kq z3f1ys^YsWF76nd6jhwnK*Z*&wJ^7E6;?tvGRgYK7Lsk9VtQw1OhDxlwv(fi>+0FrJXjC(eA_1Y|I8)vKcHX-2LEE6E~o{-U_s@PF4hI$`>`ORhyv}|8H?WTQsvQs=47V_KwB(3Oy{K3oDpq;Yu0Y!l93VfsPksif zGzVff2TUzo-aZRAySur_Xrwp1Zef`Lwxr?^P$38~H%#tNaZz|Cv;NrI_KB?=D}NvI zJ|fu-R-~km4^^Zz`Cy9hWVTepdiMFRwX#mkOAnYi)AhSYloZ61{>vZ=xm1BPS{&~7 zE%y5pHUFo4@@MJS4?Q7iqhDMcqJ!}UrjC>KXJX7Ig)wnonZ~hU>)9x<9sS}V-FvjFHwda_Cr~92a79dho9f~v&K&0^apvdJ1%}iA*0?oB zLlp%>6bV)WX*9QM#)vCaP2kiA{y R08|p_To7Q&n7lR33;_KFN&Nr- diff --git a/.gradle/8.13/fileHashes/fileHashes.lock b/.gradle/8.13/fileHashes/fileHashes.lock index 654fa71d8ab72e0b336f70e8241d9abb6fcd3db5..b304fc84a5d2903456926e9aa97f100844f5eb0b 100644 GIT binary patch literal 17 VcmZR6%*1`2-RO=50~jzV0RSgQ13Ul# literal 17 VcmZR6%*1`2-RO=50~j!_1OO+@1Hu3R diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index de3d77d18bed12ff5853a317bc25ef7735f82f6c..844b29e6b47019c962d551e1b24e4c8c122b0f78 100644 GIT binary patch literal 17 UcmZSfny)7yTG{!G0RlDv043N1*Z=?k literal 17 TcmZSfny)7yTG{!G0Rn0OC8PtS diff --git a/src/main/java/study/goorm/domain/cloth/api/ClothRestController.java b/src/main/java/study/goorm/domain/cloth/api/ClothRestController.java index cb3b730..812bba8 100644 --- a/src/main/java/study/goorm/domain/cloth/api/ClothRestController.java +++ b/src/main/java/study/goorm/domain/cloth/api/ClothRestController.java @@ -1,15 +1,17 @@ package study.goorm.domain.cloth.api; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.responses.ApiResponses; import lombok.RequiredArgsConstructor; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import study.goorm.domain.cloth.application.ClothService; import study.goorm.domain.cloth.dto.ClothResponseDTO; +import study.goorm.domain.model.enums.ClothSort; +import study.goorm.domain.model.exception.annotation.CheckPage; +import study.goorm.domain.model.exception.annotation.CheckPageSize; import study.goorm.global.common.response.BaseResponse; import study.goorm.global.error.code.status.SuccessStatus; @@ -34,5 +36,30 @@ public BaseResponse getClothEditView( } + + @GetMapping("/closet-view") + @Operation(summary = "유저의 옷장을 조회하는 API",description = "query string으로 sort,page,size를 넘겨주세요.") + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "CLOTH_200",description = "OK, 성공적으로 조회되었습니다.") + }) + @Parameters({ + @Parameter(name = "clokey-id", description = "클로키 유저의 clokey id, query string 입니다."), + @Parameter(name = "sort", description = "정렬(Sort) ENUM 값 { WEAR, NOT_WEAR, LATEST, OLDEST }, query string 입니다."), + @Parameter(name = "page", description = "페이지 값, query string 입니다."), + @Parameter(name = "size", description = "페이지에 표시할 요소 개수 값, query string 입니다.") + }) + public BaseResponsegetMemberCloset( + @RequestParam(value="clokey-id") String clokeyId, + @RequestParam ClothSort sort, + @RequestParam @CheckPage int page, + @RequestParam @CheckPageSize int size + ){ + + ClothResponseDTO.MemberClosetResult result=clothService.getMemberCloset(clokeyId,sort,page-1,size); + return BaseResponse.onSuccess(SuccessStatus.CLOTH_VIEW_SUCCESS,result); + + } + + } diff --git a/src/main/java/study/goorm/domain/cloth/application/ClothImageQueryService.java b/src/main/java/study/goorm/domain/cloth/application/ClothImageQueryService.java new file mode 100644 index 0000000..f1a8e71 --- /dev/null +++ b/src/main/java/study/goorm/domain/cloth/application/ClothImageQueryService.java @@ -0,0 +1,9 @@ +package study.goorm.domain.cloth.application; + +import study.goorm.domain.cloth.domain.entity.Cloth; + +import java.util.Map; + +public interface ClothImageQueryService { + Map getFirstImageUrlMap(Iterable clothes); +} diff --git a/src/main/java/study/goorm/domain/cloth/application/ClothImageQueryServiceImpl.java b/src/main/java/study/goorm/domain/cloth/application/ClothImageQueryServiceImpl.java new file mode 100644 index 0000000..43128fa --- /dev/null +++ b/src/main/java/study/goorm/domain/cloth/application/ClothImageQueryServiceImpl.java @@ -0,0 +1,34 @@ +package study.goorm.domain.cloth.application; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import study.goorm.domain.cloth.domain.entity.Cloth; +import study.goorm.domain.cloth.domain.entity.ClothImage; +import study.goorm.domain.cloth.domain.repository.ClothImageRepository; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +@Service +@RequiredArgsConstructor +public class ClothImageQueryServiceImpl implements ClothImageQueryService { + private final ClothImageRepository clothImageRepository; + + @Override + public Map getFirstImageUrlMap(Iterable clothes){ + List clothIds= StreamSupport.stream(clothes.spliterator(),false) + .map(Cloth::getId) + .toList(); + + List firstImages=clothImageRepository.findFirstImagesByClothIds(clothIds); + + return firstImages.stream() + .collect(Collectors.toMap( + image->image.getCloth().getId(), + ClothImage::getImageUrl + )); + + } +} diff --git a/src/main/java/study/goorm/domain/cloth/application/ClothService.java b/src/main/java/study/goorm/domain/cloth/application/ClothService.java index 77840fa..09efc6b 100644 --- a/src/main/java/study/goorm/domain/cloth/application/ClothService.java +++ b/src/main/java/study/goorm/domain/cloth/application/ClothService.java @@ -1,8 +1,11 @@ package study.goorm.domain.cloth.application; import study.goorm.domain.cloth.dto.ClothResponseDTO; +import study.goorm.domain.model.enums.ClothSort; public interface ClothService { ClothResponseDTO.ClothEditViewResult getClothEditView(Long clothId); + ClothResponseDTO.MemberClosetResult getMemberCloset(String clokeyId, ClothSort sort,int page,int size); + } diff --git a/src/main/java/study/goorm/domain/cloth/application/ClothServiceImpl.java b/src/main/java/study/goorm/domain/cloth/application/ClothServiceImpl.java index 889be3f..b00922f 100644 --- a/src/main/java/study/goorm/domain/cloth/application/ClothServiceImpl.java +++ b/src/main/java/study/goorm/domain/cloth/application/ClothServiceImpl.java @@ -1,6 +1,8 @@ package study.goorm.domain.cloth.application; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import study.goorm.domain.cloth.converter.ClothConverter; @@ -10,9 +12,14 @@ import study.goorm.domain.cloth.domain.repository.ClothRepository; import study.goorm.domain.cloth.dto.ClothResponseDTO; import study.goorm.domain.cloth.exception.ClothException; +import study.goorm.domain.member.domain.entity.Member; +import study.goorm.domain.member.domain.exception.MemberException; +import study.goorm.domain.member.domain.repository.MemberRepository; +import study.goorm.domain.model.enums.ClothSort; import study.goorm.global.error.code.status.ErrorStatus; import java.util.List; +import java.util.Map; @Service @RequiredArgsConstructor @@ -20,6 +27,8 @@ public class ClothServiceImpl implements ClothService { private final ClothRepository clothRepository; private final ClothImageRepository clothImageRepository; + private final MemberRepository memberRepository; + private final ClothImageQueryService clothImageQueryService; @Override @Transactional(readOnly = true) @@ -37,7 +46,35 @@ public ClothResponseDTO.ClothEditViewResult getClothEditView(Long clothId){ - return ClothConverter.toClothEditViewResult(cloth,firstImageUrl ); + return ClothConverter.toClothEditViewResult(cloth,firstImageUrl); + } + + @Override + @Transactional(readOnly = true) + public ClothResponseDTO.MemberClosetResult getMemberCloset(String clokeyId, ClothSort sort, int page, int size){ + Member member=memberRepository.findByClokeyId(clokeyId) + .orElseThrow(()->new MemberException(ErrorStatus.NO_SUCH_MEMBER)); + + PageRequest pageRequest=PageRequest .of(page,size); + Page clothes; + + if(sort.equals(ClothSort.LATEST)){ + clothes=clothRepository.findByMemberOrderByCreatedAtDesc(member,pageRequest); + } + else if (sort.equals(ClothSort.OLDEST)){ + clothes=clothRepository.findByMemberOrderByCreatedAtAsc(member,pageRequest); + + } + else if(sort.equals(ClothSort.WEAR)){ + clothes=clothRepository.findByMemberOrderByWearNumDesc(member,pageRequest); + + } + else{ + clothes=clothRepository.findByMemberOrderByWearNumAsc(member,pageRequest); + } + Map firstImagesOfCloth=clothImageQueryService.getFirstImageUrlMap(clothes); + + return ClothConverter.toMemberClosetResult(member,firstImagesOfCloth,clothes); } } diff --git a/src/main/java/study/goorm/domain/cloth/converter/ClothConverter.java b/src/main/java/study/goorm/domain/cloth/converter/ClothConverter.java index fc8f0c1..2d7a9e0 100644 --- a/src/main/java/study/goorm/domain/cloth/converter/ClothConverter.java +++ b/src/main/java/study/goorm/domain/cloth/converter/ClothConverter.java @@ -1,7 +1,15 @@ package study.goorm.domain.cloth.converter; + +import org.springframework.data.domain.Page; import study.goorm.domain.cloth.domain.entity.Cloth; import study.goorm.domain.cloth.dto.ClothResponseDTO; +import study.goorm.domain.member.domain.entity.Member; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + public class ClothConverter { public static ClothResponseDTO.ClothEditViewResult toClothEditViewResult(Cloth cloth, String clothImageUrl){ @@ -19,4 +27,30 @@ public static ClothResponseDTO.ClothEditViewResult toClothEditViewResult(Cloth c .build(); } + public static ClothResponseDTO.MemberClosetResult toMemberClosetResult(Member member, Map firstImagesOfCloth, Page clothes){ + return ClothResponseDTO.MemberClosetResult.builder() + .nickName(member.getNickname()) + .clothPreviewListResult(toClothPreviewListResult(firstImagesOfCloth,clothes)) + .build(); + } + private static ClothResponseDTO.ClothPreviewListResult toClothPreviewListResult(Map firstImagesOfCloth,Page clothes){ + return ClothResponseDTO.ClothPreviewListResult.builder() + .clothPreviews(toClothPreview(firstImagesOfCloth,clothes)) + .isFirst(clothes.isFirst()) + .isLast(clothes.isLast()) + .totalElements(clothes.getTotalElements()) + .totalPage(clothes.getTotalPages()) + .build(); + } + private static List toClothPreview(Map firstImagesOfCloth, Page clothes){ + return clothes.stream() + .map(cloth->ClothResponseDTO.ClothPreview.builder() + .id(cloth.getId()) + .name(cloth.getName()) + .wearNum(cloth.getWearNum()) + .imageUrl(firstImagesOfCloth.get(cloth.getId())) + .build()) + .collect(Collectors.toList()); + } + } diff --git a/src/main/java/study/goorm/domain/cloth/domain/repository/ClothImageRepository.java b/src/main/java/study/goorm/domain/cloth/domain/repository/ClothImageRepository.java index ebaafd3..4958c9b 100644 --- a/src/main/java/study/goorm/domain/cloth/domain/repository/ClothImageRepository.java +++ b/src/main/java/study/goorm/domain/cloth/domain/repository/ClothImageRepository.java @@ -1,6 +1,8 @@ package study.goorm.domain.cloth.domain.repository; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import study.goorm.domain.cloth.domain.entity.Cloth; import study.goorm.domain.cloth.domain.entity.ClothImage; @@ -9,4 +11,17 @@ public interface ClothImageRepository extends JpaRepository { List findAllByCloth(Cloth cloth); + + @Query(value = """ + SELECT ci.* + FROM cloth_image ci + INNER JOIN( + SELECT cloth_id, MIN(id) AS min_id + FROM cloth_image + WHERE cloth_id IN (:clothIds) + GROUP BY cloth_id + ) AS firsts ON ci.id=firsts.min_id +""",nativeQuery = true) + List findFirstImagesByClothIds(@Param("clothIds") List clothIds); + } diff --git a/src/main/java/study/goorm/domain/cloth/domain/repository/ClothRepository.java b/src/main/java/study/goorm/domain/cloth/domain/repository/ClothRepository.java index e27b013..ee14452 100644 --- a/src/main/java/study/goorm/domain/cloth/domain/repository/ClothRepository.java +++ b/src/main/java/study/goorm/domain/cloth/domain/repository/ClothRepository.java @@ -1,7 +1,16 @@ package study.goorm.domain.cloth.domain.repository; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import study.goorm.domain.cloth.domain.entity.Cloth; +import study.goorm.domain.member.domain.entity.Member; + public interface ClothRepository extends JpaRepository { + Page findByMemberOrderByWearNumAsc(Member member, Pageable pageable); + Page findByMemberOrderByWearNumDesc(Member member, Pageable pageable); + Page findByMemberOrderByCreatedAtAsc(Member member, Pageable pageable); + Page findByMemberOrderByCreatedAtDesc(Member member, Pageable pageable); + } diff --git a/src/main/java/study/goorm/domain/cloth/dto/ClothResponseDTO.java b/src/main/java/study/goorm/domain/cloth/dto/ClothResponseDTO.java index 82f09f0..c3e19ce 100644 --- a/src/main/java/study/goorm/domain/cloth/dto/ClothResponseDTO.java +++ b/src/main/java/study/goorm/domain/cloth/dto/ClothResponseDTO.java @@ -9,6 +9,7 @@ import java.util.List; public class ClothResponseDTO { + @Builder @Getter @NoArgsConstructor @@ -26,4 +27,37 @@ public static class ClothEditViewResult{ private Long categoryId; } + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class MemberClosetResult{ + private String nickName; + private ClothPreviewListResult clothPreviewListResult; + } + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class ClothPreviewListResult{ + private List clothPreviews; + private int totalPage; + private long totalElements; + private Boolean isFirst; + private Boolean isLast; + } + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class ClothPreview{ + private Long id; + private String name; + private String imageUrl; + private int wearNum; + } + } diff --git a/src/main/java/study/goorm/domain/member/domain/exception/MemberException.java b/src/main/java/study/goorm/domain/member/domain/exception/MemberException.java new file mode 100644 index 0000000..e5ccfa4 --- /dev/null +++ b/src/main/java/study/goorm/domain/member/domain/exception/MemberException.java @@ -0,0 +1,12 @@ +package study.goorm.domain.member.domain.exception; + +import study.goorm.global.error.code.BaseErrorCode; +import study.goorm.global.exception.GeneralException; + +public class MemberException extends GeneralException { + + public MemberException(BaseErrorCode code) { + super(code); + } + +} diff --git a/src/main/java/study/goorm/domain/member/domain/repository/MemberRepository.java b/src/main/java/study/goorm/domain/member/domain/repository/MemberRepository.java index d095876..94b9110 100644 --- a/src/main/java/study/goorm/domain/member/domain/repository/MemberRepository.java +++ b/src/main/java/study/goorm/domain/member/domain/repository/MemberRepository.java @@ -3,5 +3,9 @@ import org.springframework.data.jpa.repository.JpaRepository; import study.goorm.domain.member.domain.entity.Member; +import java.util.Optional; + public interface MemberRepository extends JpaRepository { + + Optional findByClokeyId(String clokeyId); } diff --git a/src/main/java/study/goorm/domain/model/enums/ClothSort.java b/src/main/java/study/goorm/domain/model/enums/ClothSort.java new file mode 100644 index 0000000..ba569b0 --- /dev/null +++ b/src/main/java/study/goorm/domain/model/enums/ClothSort.java @@ -0,0 +1,9 @@ +package study.goorm.domain.model.enums; + +public enum ClothSort { + + WEAR, + NOT_WEAR, + LATEST, + OLDEST +} diff --git a/src/main/java/study/goorm/domain/model/exception/annotation/CheckPage.java b/src/main/java/study/goorm/domain/model/exception/annotation/CheckPage.java new file mode 100644 index 0000000..9411134 --- /dev/null +++ b/src/main/java/study/goorm/domain/model/exception/annotation/CheckPage.java @@ -0,0 +1,20 @@ +package study.goorm.domain.model.exception.annotation; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; +import study.goorm.domain.model.exception.validator.CheckPageValidator; + +import java.lang.annotation.*; + +@Documented +@Constraint(validatedBy = CheckPageValidator.class) +@Target({ElementType.METHOD, ElementType.FIELD,ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +public @interface CheckPage { + + String message() default "페이지는 1이상 부터 입력이 가능합니다."; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/src/main/java/study/goorm/domain/model/exception/annotation/CheckPageSize.java b/src/main/java/study/goorm/domain/model/exception/annotation/CheckPageSize.java new file mode 100644 index 0000000..7b7cfaf --- /dev/null +++ b/src/main/java/study/goorm/domain/model/exception/annotation/CheckPageSize.java @@ -0,0 +1,19 @@ +package study.goorm.domain.model.exception.annotation; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; +import study.goorm.domain.model.exception.validator.CheckPageSizeValidator; + +import java.lang.annotation.*; + +@Documented +@Constraint(validatedBy= CheckPageSizeValidator.class) +@Target({ElementType.METHOD,ElementType.FIELD,ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +public @interface CheckPageSize { + String message() default "페이지 크기는 1이상 부터 입력이 가능합니다."; + + Class[] groups() default {}; + Class[] payload() default {}; + +} diff --git a/src/main/java/study/goorm/domain/model/exception/validator/CheckPageSizeValidator.java b/src/main/java/study/goorm/domain/model/exception/validator/CheckPageSizeValidator.java new file mode 100644 index 0000000..b01f662 --- /dev/null +++ b/src/main/java/study/goorm/domain/model/exception/validator/CheckPageSizeValidator.java @@ -0,0 +1,30 @@ +package study.goorm.domain.model.exception.validator; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import study.goorm.domain.model.exception.annotation.CheckPageSize; +import study.goorm.global.error.code.status.ErrorStatus; + +@Component +@RequiredArgsConstructor +public class CheckPageSizeValidator implements ConstraintValidator { + + @Override + public void initialize(CheckPageSize constraintAnnotation) { + ConstraintValidator.super.initialize(constraintAnnotation); + } + + @Override + public boolean isValid(Integer pageSize, ConstraintValidatorContext context){ + boolean isValid = pageSize>=1; + + if(!isValid){ + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(ErrorStatus.PAGE_SIZE_UNDER_ONE.toString()).addConstraintViolation(); + + } + return isValid; + } +} diff --git a/src/main/java/study/goorm/domain/model/exception/validator/CheckPageValidator.java b/src/main/java/study/goorm/domain/model/exception/validator/CheckPageValidator.java new file mode 100644 index 0000000..ec4cf1f --- /dev/null +++ b/src/main/java/study/goorm/domain/model/exception/validator/CheckPageValidator.java @@ -0,0 +1,30 @@ +package study.goorm.domain.model.exception.validator; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import study.goorm.domain.model.exception.annotation.CheckPage; +import study.goorm.global.error.code.status.ErrorStatus; + +@Component +@RequiredArgsConstructor +public class CheckPageValidator implements ConstraintValidator { + + @Override + public void initialize(CheckPage constraintAnnotation){ + ConstraintValidator.super.initialize(constraintAnnotation); + } + @Override + public boolean isValid(Integer page, ConstraintValidatorContext context){ + boolean isValid=page>=1; + if(!isValid){ + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(ErrorStatus.PAGE_UNDER_ONE.toString()).addConstraintViolation(); + + + } + return isValid; + } + +} diff --git a/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java b/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java index 807de6a..4b8d21f 100644 --- a/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java +++ b/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java @@ -20,7 +20,17 @@ public enum ErrorStatus implements BaseErrorCode { NO_SUCH_CLOTH(HttpStatus.BAD_REQUEST,"CLOTH_4001","옷이 존재하지 않습니다"), //bug data - NO_ClOTH_IMAGE(HttpStatus.BAD_REQUEST,"CLOTH_4002","옷의 사진이 존재하지 않습니다."); + NO_ClOTH_IMAGE(HttpStatus.BAD_REQUEST,"CLOTH_4002","옷의 사진이 존재하지 않습니다."), + + //Member + NO_SUCH_MEMBER(HttpStatus.BAD_REQUEST,"MEMBER_4001","멤버가 존재하지 않습니다."), + + //Page + PAGE_UNDER_ONE(HttpStatus.BAD_REQUEST,"PAGE_4001","페이지는 1이상으로 입력해야 합니다."), + PAGE_SIZE_UNDER_ONE(HttpStatus.BAD_REQUEST,"PAGE_4002","페이지 사이즈는 1이상으로 입력해야합니다."); + + + private final HttpStatus httpStatus; private final String code; From d2b4f9ed077c96115adc4ea0bda4cdb4ef4f1126 Mon Sep 17 00:00:00 2001 From: psj Date: Sat, 24 May 2025 17:55:51 +0900 Subject: [PATCH 3/6] =?UTF-8?q?=EC=98=B7=20=EC=B6=94=EA=B0=80=20API?= =?UTF-8?q?=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gradle/8.13/checksums/checksums.lock | Bin 17 -> 17 bytes .gradle/8.13/checksums/sha1-checksums.bin | Bin 72221 -> 72275 bytes .../executionHistory/executionHistory.lock | Bin 17 -> 17 bytes .gradle/8.13/fileHashes/fileHashes.bin | Bin 27447 -> 27897 bytes .gradle/8.13/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .../domain/cloth/api/ClothRestController.java | 21 +++++++++ .../cloth/application/ClothService.java | 3 ++ .../cloth/application/ClothServiceImpl.java | 40 ++++++++++++++++++ .../cloth/converter/ClothConverter.java | 6 +++ .../domain/cloth/dto/ClothRequestDTO.java | 34 +++++++++++++++ .../domain/cloth/dto/ClothResponseDTO.java | 9 ++++ .../annotation/CheckLowerUpperTempBound.java | 18 ++++++++ .../CheckLowerUpperTempBoundValidator.java | 32 ++++++++++++++ .../goorm/global/config/SwaggerConfig.java | 17 ++++++++ .../global/error/code/status/ErrorStatus.java | 5 ++- .../error/code/status/SuccessStatus.java | 5 ++- .../exception/GlobalExceptionAdvice.java | 14 +++++- 18 files changed, 200 insertions(+), 4 deletions(-) create mode 100644 src/main/java/study/goorm/domain/cloth/exception/annotation/CheckLowerUpperTempBound.java create mode 100644 src/main/java/study/goorm/domain/cloth/exception/validator/CheckLowerUpperTempBoundValidator.java diff --git a/.gradle/8.13/checksums/checksums.lock b/.gradle/8.13/checksums/checksums.lock index 2623f2b46d5165d1b4a2ee7911dbf8f5874a6979..3fa8343595de8fb3fb2e4c45d3330b7ca3a67658 100644 GIT binary patch literal 17 VcmZQRynUyB`kMNS3}C?Y0RTNI1-k$M literal 17 VcmZQRynUyB`kMNS3}C?Y763ga1-JkJ diff --git a/.gradle/8.13/checksums/sha1-checksums.bin b/.gradle/8.13/checksums/sha1-checksums.bin index e88d72e9b9ef12cf92168a3a9c3430bcf397e363..c8e90bcba1619d934cc28fac9947cbc70df3f8fb 100644 GIT binary patch delta 103 zcmbQch2`=VmJKEnjQpETB`$LCzd03Hwta^p0|+om$!`9uFj;`HabeV`zp3?%8}v&UvAb#KAv)%F#xDm86P4Q>WExcaG00!Bao0m#xGV;&5`q0)N4$Q#a?T&0=B_+_+KkhxkT=47SaV9!-1-_1Cn+O18Sr;gk!J|5aTU z$-uxkov~*B3$QLm^@W=shuz@_N-?={k~^+y`KvG4lGStbLcps0b1y^8=12$9dd5IP z6NnW-SYW#Gy$HSTmFI#B*1GK7ZMqAjgTd@{HBb@=Sf))DOi*Q=&KPlF>SXJLx*#Uj zDw|eoM#0T19*3$0d_M!WAmYM4h;l&*AdO~0z0S%-w*tHO&wnQPt=6xE2dqQx-8zU4 z9=plhi7OO#zWr@s#;bk2TL14>SB5!9!HQ}cx*&=aoHt)iEMQc~N#@Ad-FtR&LQ7rC zl1*o0A*%LkKvY@rO>T@64s2Mx@@3f?iN`4$_UpXeatW-)q<0xa4M!7@MsuJ<*wU|a zmRiRxHEQasY+5A_(Xp`)qJuAE^22mtc`^N#15fN$g={;?Ic-hFL$DgF@J$dk0s+8K z60YAi`Li^)mVzw9;~O$7_G|~MVgGXuqJ}98(`Mnb7DuH1vTXSnxGE{!HxZZufN?5U zZwApJ3^W1Vt+tJ?&lco94Zd%%k-s`Oml>pkLFCv*kd6!n2Cl`JTCRlsF4n7e^QsFr zI&IZG59kb_B@qWVgR}r67?cXo0wm>rio*7*J;yr5K3rvWJ-Huj370i6xIuvJ&g6qB z!jsuj4eOch%=Vl7Hk`OrY2n((Ue{Y7MxTEIQ7AqaNTV6O`q_)OP6frAvk;ZCZKr)wHZ# zzgx~+11bdt>$_Z_N+3`LrGGSM^}P=0KO|Okrt7nul1|wr1*j!*AoUCkOmUOt(?FR( z?(Ou+o@u&Z*1XBpX;KQTUl!Lt{ArykZBS;VH%CbqV%6L85RGiCo42MlGlJFcn{1l_ z(Rp}sK9sd_@Z|= zj_#4;ET#3O|86I|j$L*3m&f)}s7HWl8UzG+fdrb@XV?TDx9oOKKeS_>(PF(>K$nBV zR~qOvse0$Rv0rxAcrTc_rsUb-wYp_c@0|pj#=!Oy(>S>^flrr;y6C5DdMkRKeG9NW z0EPYAvk)CDIhZ)wSEPyH#ftYCrrj{q}FZ|zoZi&1Z zTp)9bdwu}K&6*d0DuDo7D(aIqT)x<6Ui7R}3r^hqwg^~a0G$>7v|=)2q*U0skN^ET z|1o^Ox$?-3o2?fig=WMB6^L=nw}3QSply5STs~VhMQ?J;!FnfF`Qs1=TpqCRh4>fOljwub1{3tjI&<>N9X$M$Ay55&@} zAc%4N&w;d_F_6#%Vnq-ZcxbrqS~SCgLHhhDien2U@gMbF){4PrE3hIEQ?viPBcH1 z;s)!mw*Z-455!y@m|6~6wEF6Ghs>I5wBzjjO_Qd9o%Of>B~T?0@W=xRG-o+oYPtFI zy3Adf%ctYNDIa(T(($`(Ydly317kI&j*lvJJoWxpF0TGNZQWeujlw%YTK+NIwuflp z*@dZP|DB8Sy!tX%%zkRUe#o1!AEe{&zb8N+fdJ<*Ac5wrh5IJ$S`^DAsGF1B_2SMP zK9G(dlFcn(4Gav%KA2iM1fSgye!Yxi!Q6uxDYLWkz&i!Iu0N zb_A*f0woI|ffhi#LETqPS2Nw%kQ`v=7rqRfIDYht?*(gMVDy+QpQg$>?eC?89g{uN zbiu5>ldIFD6y97pF diff --git a/.gradle/8.13/fileHashes/fileHashes.lock b/.gradle/8.13/fileHashes/fileHashes.lock index b304fc84a5d2903456926e9aa97f100844f5eb0b..eef3103f6d3b85838c906580ae682c2e0cef6ade 100644 GIT binary patch literal 17 VcmZR6%*1`2-RO=50~jzZ0RSh-1HJ$N literal 17 VcmZR6%*1`2-RO=50~jzV0RSgQ13Ul# diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 844b29e6b47019c962d551e1b24e4c8c122b0f78..c6893e330170c8df12480c6caccd9283e05c1f59 100644 GIT binary patch literal 17 UcmZSfny)7yTG{!G0Rlb)045s*8vp getClothEditView( } + + @PostMapping(value = "",consumes= MediaType.MULTIPART_FORM_DATA_VALUE) + @Operation(summary = "새로운 옷을 생성하는 API", description = "request body에 ClothCreateRequest 형식의 데이터를 전달해주세요.") + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "CLOTH_201",description = "CREATED,성공적으로 생성되었습니다."), + + }) + public BaseResponse createCloth( + @RequestPart("clothCreateRequest") @Valid ClothRequestDTO.ClothCreateRequest clothCreateRequest, + @RequestPart("imageFile") MultipartFile imageFile + ){ + ClothResponseDTO.ClothCreateResult result=clothService.createCloth(clothCreateRequest,imageFile); + return BaseResponse.onSuccess(SuccessStatus.CLOTH_CREATED,result); + } + + + } diff --git a/src/main/java/study/goorm/domain/cloth/application/ClothService.java b/src/main/java/study/goorm/domain/cloth/application/ClothService.java index 09efc6b..4ca06fb 100644 --- a/src/main/java/study/goorm/domain/cloth/application/ClothService.java +++ b/src/main/java/study/goorm/domain/cloth/application/ClothService.java @@ -1,11 +1,14 @@ package study.goorm.domain.cloth.application; +import org.springframework.web.multipart.MultipartFile; +import study.goorm.domain.cloth.dto.ClothRequestDTO; import study.goorm.domain.cloth.dto.ClothResponseDTO; import study.goorm.domain.model.enums.ClothSort; public interface ClothService { ClothResponseDTO.ClothEditViewResult getClothEditView(Long clothId); ClothResponseDTO.MemberClosetResult getMemberCloset(String clokeyId, ClothSort sort,int page,int size); + ClothResponseDTO.ClothCreateResult createCloth(ClothRequestDTO.ClothCreateRequest clothCreateResult ,MultipartFile image); } diff --git a/src/main/java/study/goorm/domain/cloth/application/ClothServiceImpl.java b/src/main/java/study/goorm/domain/cloth/application/ClothServiceImpl.java index b00922f..819d598 100644 --- a/src/main/java/study/goorm/domain/cloth/application/ClothServiceImpl.java +++ b/src/main/java/study/goorm/domain/cloth/application/ClothServiceImpl.java @@ -5,11 +5,15 @@ import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; import study.goorm.domain.cloth.converter.ClothConverter; +import study.goorm.domain.cloth.domain.entity.Category; import study.goorm.domain.cloth.domain.entity.Cloth; import study.goorm.domain.cloth.domain.entity.ClothImage; +import study.goorm.domain.cloth.domain.repository.CategoryRepository; import study.goorm.domain.cloth.domain.repository.ClothImageRepository; import study.goorm.domain.cloth.domain.repository.ClothRepository; +import study.goorm.domain.cloth.dto.ClothRequestDTO; import study.goorm.domain.cloth.dto.ClothResponseDTO; import study.goorm.domain.cloth.exception.ClothException; import study.goorm.domain.member.domain.entity.Member; @@ -29,6 +33,7 @@ public class ClothServiceImpl implements ClothService { private final ClothImageRepository clothImageRepository; private final MemberRepository memberRepository; private final ClothImageQueryService clothImageQueryService; + private final CategoryRepository categoryRepository; @Override @Transactional(readOnly = true) @@ -77,4 +82,39 @@ else if(sort.equals(ClothSort.WEAR)){ return ClothConverter.toMemberClosetResult(member,firstImagesOfCloth,clothes); } + @Override + @Transactional + public ClothResponseDTO.ClothCreateResult createCloth(ClothRequestDTO.ClothCreateRequest clothCreateResult, MultipartFile image){ + Member member=memberRepository.findById(clothCreateResult.getMemberId()) + .orElseThrow(()->new MemberException(ErrorStatus.NO_SUCH_MEMBER)); + + Category category=categoryRepository.findById(clothCreateResult.getCategoryId()) + .orElseThrow(()->new ClothException(ErrorStatus.NO_SUCH_CATEGORY)); + + Cloth newCloth=Cloth.builder() + .name(clothCreateResult.getName()) + .wearNum(0) + .season(clothCreateResult.getSeasons()) + .tempUpperBound(clothCreateResult.getTempUpperBound()) + .tempLowerBound(clothCreateResult.getTempLowerBound()) + .thicknessLevel(clothCreateResult.getThicknessLevel()) + .clothUrl(clothCreateResult.getClothUrl()) + .brand(clothCreateResult.getBrand()) + .category(category) + .member(member) + .build(); + + clothRepository.save(newCloth); + + ClothImage newClothImage=ClothImage.builder() + .cloth(newCloth) + .imageUrl("아직 S3를 구현하지 않아서 url이 없어용") + .build(); + clothImageRepository.save(newClothImage); + + return ClothConverter.toClothCreateResult(newCloth); + + + } + } diff --git a/src/main/java/study/goorm/domain/cloth/converter/ClothConverter.java b/src/main/java/study/goorm/domain/cloth/converter/ClothConverter.java index 2d7a9e0..ec948e3 100644 --- a/src/main/java/study/goorm/domain/cloth/converter/ClothConverter.java +++ b/src/main/java/study/goorm/domain/cloth/converter/ClothConverter.java @@ -53,4 +53,10 @@ private static List toClothPreview(Map seasons; + @Max(40) + @Min(-20) + private Integer tempUpperBound; + @Max(40) + @Min(-20) + private Integer tempLowerBound; + private ThicknessLevel thicknessLevel; + private String clothUrl; + private String brand; + + } } diff --git a/src/main/java/study/goorm/domain/cloth/dto/ClothResponseDTO.java b/src/main/java/study/goorm/domain/cloth/dto/ClothResponseDTO.java index c3e19ce..15e991e 100644 --- a/src/main/java/study/goorm/domain/cloth/dto/ClothResponseDTO.java +++ b/src/main/java/study/goorm/domain/cloth/dto/ClothResponseDTO.java @@ -60,4 +60,13 @@ public static class ClothPreview{ private int wearNum; } + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class ClothCreateResult{ + private Long id; + } + + } diff --git a/src/main/java/study/goorm/domain/cloth/exception/annotation/CheckLowerUpperTempBound.java b/src/main/java/study/goorm/domain/cloth/exception/annotation/CheckLowerUpperTempBound.java new file mode 100644 index 0000000..bee7914 --- /dev/null +++ b/src/main/java/study/goorm/domain/cloth/exception/annotation/CheckLowerUpperTempBound.java @@ -0,0 +1,18 @@ +package study.goorm.domain.cloth.exception.annotation; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; +import study.goorm.domain.cloth.exception.validator.CheckLowerUpperTempBoundValidator; + +import java.lang.annotation.*; + +@Documented +@Constraint(validatedBy = CheckLowerUpperTempBoundValidator.class) +@Target({ElementType.TYPE, ElementType.METHOD,ElementType.FIELD,ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +public @interface CheckLowerUpperTempBound { + + String message() default "상한 온도는 하한 온도보다 높아야 합니다."; + Class[] groups() default {}; + Class[] payload() default {}; +} diff --git a/src/main/java/study/goorm/domain/cloth/exception/validator/CheckLowerUpperTempBoundValidator.java b/src/main/java/study/goorm/domain/cloth/exception/validator/CheckLowerUpperTempBoundValidator.java new file mode 100644 index 0000000..f0971ea --- /dev/null +++ b/src/main/java/study/goorm/domain/cloth/exception/validator/CheckLowerUpperTempBoundValidator.java @@ -0,0 +1,32 @@ +package study.goorm.domain.cloth.exception.validator; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import study.goorm.domain.cloth.dto.ClothRequestDTO; +import study.goorm.domain.cloth.exception.annotation.CheckLowerUpperTempBound; +import study.goorm.global.error.code.status.ErrorStatus; + +@Component +@RequiredArgsConstructor +public class CheckLowerUpperTempBoundValidator implements ConstraintValidator { + + @Override + public void initialize(CheckLowerUpperTempBound constraintAnnotation){ + ConstraintValidator.super.initialize(constraintAnnotation); + } + + @Override + public boolean isValid(ClothRequestDTO.ClothCreateRequest request, ConstraintValidatorContext context) { + boolean isValid=request.getTempLowerBound()<=request.getTempUpperBound(); + + if(!isValid){ + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(ErrorStatus.LOWER_TEMP_BIGGER_THAN_UPPER_TEMP.toString()).addConstraintViolation(); + + + } + return isValid; + } +} diff --git a/src/main/java/study/goorm/global/config/SwaggerConfig.java b/src/main/java/study/goorm/global/config/SwaggerConfig.java index 1939cb7..5d267d4 100644 --- a/src/main/java/study/goorm/global/config/SwaggerConfig.java +++ b/src/main/java/study/goorm/global/config/SwaggerConfig.java @@ -6,11 +6,28 @@ import io.swagger.v3.oas.models.security.SecurityRequirement; import io.swagger.v3.oas.models.security.SecurityScheme; import io.swagger.v3.oas.models.servers.Server; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; + +import java.util.ArrayList; +import java.util.List; @Configuration public class SwaggerConfig { + /* + Multipart+JSON동시에 Swagger에서 테스트할떄 + content-type null -> application/octet-stream으로 처리되어 Jackson에서 인식 못하는 문제 해결 + */ + + @Autowired + public void configureMessageConverter(MappingJackson2HttpMessageConverter converter) { + List supportMediaTypes = new ArrayList<>(converter.getSupportedMediaTypes()); + supportMediaTypes.add(MediaType.APPLICATION_OCTET_STREAM); + converter.setSupportedMediaTypes(supportMediaTypes); + } @Bean public OpenAPI goormStudyAPI(){ diff --git a/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java b/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java index 4b8d21f..ae21bc4 100644 --- a/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java +++ b/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java @@ -27,10 +27,11 @@ public enum ErrorStatus implements BaseErrorCode { //Page PAGE_UNDER_ONE(HttpStatus.BAD_REQUEST,"PAGE_4001","페이지는 1이상으로 입력해야 합니다."), - PAGE_SIZE_UNDER_ONE(HttpStatus.BAD_REQUEST,"PAGE_4002","페이지 사이즈는 1이상으로 입력해야합니다."); - + PAGE_SIZE_UNDER_ONE(HttpStatus.BAD_REQUEST,"PAGE_4002","페이지 사이즈는 1이상으로 입력해야합니다."), + NO_SUCH_CATEGORY(HttpStatus.BAD_REQUEST,"CLOTH_4003","카테고리가 존재하지 않습니다."), + LOWER_TEMP_BIGGER_THAN_UPPER_TEMP(HttpStatus.BAD_REQUEST,"CLOTH_4004","옷의 하한 온도가 상한 온도 보다 높습니다."); private final HttpStatus httpStatus; private final String code; diff --git a/src/main/java/study/goorm/global/error/code/status/SuccessStatus.java b/src/main/java/study/goorm/global/error/code/status/SuccessStatus.java index 50f58a0..f9f00be 100644 --- a/src/main/java/study/goorm/global/error/code/status/SuccessStatus.java +++ b/src/main/java/study/goorm/global/error/code/status/SuccessStatus.java @@ -14,7 +14,10 @@ public enum SuccessStatus implements BaseCode { OK(HttpStatus.OK, "COMMON_200", "성공입니다."), //Cloth - CLOTH_VIEW_SUCCESS(HttpStatus.OK,"CLOTH_200","옷이 성공적으로 조회되었습니다."); + CLOTH_VIEW_SUCCESS(HttpStatus.OK,"CLOTH_200","옷이 성공적으로 조회되었습니다."), + + CLOTH_CREATED(HttpStatus.CREATED, "CLOTH_201","옷이 성공적으로 생성되었습니다."); + private final HttpStatus httpStatus; private final String code; diff --git a/src/main/java/study/goorm/global/exception/GlobalExceptionAdvice.java b/src/main/java/study/goorm/global/exception/GlobalExceptionAdvice.java index 1698dcd..2568ee7 100644 --- a/src/main/java/study/goorm/global/exception/GlobalExceptionAdvice.java +++ b/src/main/java/study/goorm/global/exception/GlobalExceptionAdvice.java @@ -77,7 +77,7 @@ public ResponseEntity handleMethodArgumentNotValid( WebRequest request) { Map errors = new LinkedHashMap<>(); - + //필드에러처리 e.getBindingResult().getFieldErrors().stream() .forEach( fieldError -> { @@ -94,6 +94,18 @@ public ResponseEntity handleMethodArgumentNotValid( (existingErrorMessage, newErrorMessage) -> existingErrorMessage + ", " + newErrorMessage); }); + //클래스 레벨 에러 처리(ObjectError) + e.getBindingResult().getGlobalErrors().forEach(objectError ->{ + String objectName=objectError.getObjectName(); + String errorMessage; + try{ + errorMessage = Optional.ofNullable(ErrorStatus.valueOf(objectError.getDefaultMessage()).getMessage()).orElse(""); + } catch (IllegalArgumentException ex) { + errorMessage = Optional.ofNullable(ErrorStatus.valueOf(objectError.getDefaultMessage()).getMessage()).orElse(""); + } + errors.merge("message :",errorMessage, + (existingErrorMessage, newErrorMessage) ->existingErrorMessage+ ", " + newErrorMessage); + } ); return handleExceptionInternalArgs( e, HttpHeaders.EMPTY, ErrorStatus.valueOf("_BAD_REQUEST"), request, errors); From 224d7dd1e14571e5d5933b7698f1913af4864437 Mon Sep 17 00:00:00 2001 From: psj Date: Mon, 2 Jun 2025 19:39:35 +0900 Subject: [PATCH 4/6] history get patch delete --- .../executionHistory/executionHistory.lock | Bin 17 -> 17 bytes .gradle/8.13/fileHashes/fileHashes.bin | Bin 27897 -> 28997 bytes .gradle/8.13/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .../domain/cloth/api/ClothRestController.java | 10 ++ .../cloth/application/ClothService.java | 2 +- .../cloth/application/ClothServiceImpl.java | 18 ++++ .../domain/repository/CategoryRepository.java | 2 + .../repository/ClothImageRepository.java | 2 +- .../repository/ClothFolderRepository.java | 2 + .../history/api/HistoryRestController.java | 63 +++++++++++++ .../history/application/HistoryService.java | 15 +++ .../application/HistoryServiceImpl.java | 89 ++++++++++++++++++ .../history/converter/HistoryConverter.java | 48 ++++++++++ .../domain/repository/CommentRepository.java | 2 + .../repository/HashtagHistoryRepository.java | 6 ++ .../repository/HistoryClothRepository.java | 12 +++ .../repository/HistoryImageRepository.java | 2 + .../domain/history/dto/HistoryRequestDTO.java | 18 ++++ .../history/dto/HistoryResponseDTO.java | 51 ++++++++++ .../history/exception/HistoryException.java | 11 +++ .../domain/repository/MemberRepository.java | 2 + .../repository/MemberTermRepository.java | 2 + .../domain/repository/TermRepository.java | 2 + .../goorm/domain/model/enums/Visibility.java | 5 + .../global/error/code/status/ErrorStatus.java | 9 +- .../error/code/status/SuccessStatus.java | 10 +- 27 files changed, 379 insertions(+), 4 deletions(-) create mode 100644 src/main/java/study/goorm/domain/history/api/HistoryRestController.java create mode 100644 src/main/java/study/goorm/domain/history/application/HistoryService.java create mode 100644 src/main/java/study/goorm/domain/history/application/HistoryServiceImpl.java create mode 100644 src/main/java/study/goorm/domain/history/converter/HistoryConverter.java create mode 100644 src/main/java/study/goorm/domain/history/dto/HistoryRequestDTO.java create mode 100644 src/main/java/study/goorm/domain/history/dto/HistoryResponseDTO.java create mode 100644 src/main/java/study/goorm/domain/history/exception/HistoryException.java create mode 100644 src/main/java/study/goorm/domain/model/enums/Visibility.java diff --git a/.gradle/8.13/executionHistory/executionHistory.lock b/.gradle/8.13/executionHistory/executionHistory.lock index d5322613eeb61840de3e4aa06d59fdafeaadd001..7720f922561be1b5932bed2e1db646040031f0f8 100644 GIT binary patch literal 17 UcmZQRtXo+5@vdep0|X=j05x?4lK=n! literal 17 UcmZQRtXo+5@vdep0|Yn%05w$va{vGU diff --git a/.gradle/8.13/fileHashes/fileHashes.bin b/.gradle/8.13/fileHashes/fileHashes.bin index cbd3f48d64b5cb09508e520496fadc99500f0126..7907f76bb9f4a9b95b928dd28cba4a61281c360c 100644 GIT binary patch delta 2856 zcmZvcdpuO>AIIm6k?V{pOv8jhZeg!vbl^Vk}fue@O#cY$3HXsyk6%#=k-0G_viVZ=X}49vJ1J> zhmB9an)I%}Nozd}3VUaX(T8xS88W#(A+AHUtr8sv zkNHw-{`4M(K|%PO_@$i3Yj`jE9maPm(RizJBl<@NR+e%uhZiW7y_!C?t0gsd;D=Gd zpbGV5Kc{Q6!gHexe3!tWFaR^PjzH-2Ci&kFLK*Hv^cOVV<~f}uH)8z!IxPVPlMkVu zwq=g?qOe=si&vf!rde}YIn@PjNvEwZAmSsa+?Gw}99L}Zb9U$_9KJ-SZA0kpovUv7 z_}7sMr5(0$@dkwM=bqe^$I<(fkXE2+cK7IE_42)=TgrW4ke`Qn+B+ij1VPpO{*H4I zFuKba<2fi0$GzPt{jUbj|3PTq&m|`6PVT8P9bmz@Fb(x|x=c2%E4Q9lSnd`m>16wNgO=txI_Ml`S6g3NTRXqvN0OBbX zOAGTu*iDI+((8(wM!c#@nrrsUG-#53Q{{oUq+tDD2@$S1@^h@atRhbACRv-Xfh5OO z$fc?(m5PL{0kc|id|BnlJR3^sa*xd>q=t=_D&ivl6eP4xpx;N>fsBfG*r2TuVzzIK z_k+ZN1CM$RUK;LrZ9AZnmy{Cqj3lA_$SiHC-I>@jY%0a2^WK>HwfYhx;4s|`E|YrwNGz6 zf6TkFCED7*gAfVP+5efdMWMHwZSrQUJV$n(B1eB6LcGi-9QI@5QHF@bdIE_}`7vPZ(ydRt(|5$8$6)RxDZV z)m7WR?A;aXr2MxX@`wYt9FfHm@&$MUsr}`k#6-uGWRhqX|1!C3JFQ$rT&N@Jf}EpC z>=tmY?qU7(q3Ur*W}j!*3KbzW0VS^5OGXFEi|dxG)YlhuzKOrzzck>~t+f-jFmZ7( zOxz5tqn=5dMW5F*tp@6cdRMf&AQ>DFAor5~T1aT)TdJ0OozQ!4?pq;gecg<@*mWq8ip&nm_ad$+(3Lk?Wa| zz;{?Zt%dg{I}{P?k<6%~!H>7Kz?q0h7pIT!fds4QT@4aN+!wKiH+A&BlDm95m4==6UZqRDDw@C3g z`%3s6k%tqYSjqb}k=fQuqE|P5WG?efXxmfR5bMlG%VTrEqo4W#DHBBY&dT6AcAwF!@AnJW%nV81ldR8)_)mao7I?yc{uF delta 1360 zcmX^5i1Fu5#tkMCjC(elN<3totS9whvYB-J=C#s0m?qcCeV9B~K4G%1!ph0-6!a&X zD&E+vsuaLDxmWqdd!ViMfA zQSpcPMuQBt&5j4F`t2faoXQYiD3+2 zz$(4j+mDA);Ub5H(7WuL&dXEx$GA;BeF&uLv%Q5BL=|KA;&OlHpi1URS&xP4?Ai8z zu=JmIf(fc96RM~YNb4B`2~8kY1Yv>P}8<*n>+%UxM{>)KzaqDrWu2|yan*l>qCCysJwid3~YJ(hoZa0ygL9ZbjM zjrqcxi-H$1vVy!ibFyTpE+|ASmQ41BvQ}=c4RvEwsK2HiR$vZ$nOyhTc+Rl^6krO zU<>Y@(SusRGdVZ1lXcqOSJt~W|Be)4lsNrAE#+)=)T~LX-xtZc-|qpdzwbR|vSN&s zf|sb23QJyFn(2qrOGS!(PCz6l+<_V|K{51J8!~WQ!KYu69NaI`pHuv$B>63F4q!f;~2hgZjZHK3Q94#agsZ(YWb@#*^5r>h}4Sf))DOi*KCjJPm$vUNgT5EE;aO{+Dd;N}&N zL)8Mlp8=a6abX`swV(v1`Sm(07u^c%-ar4D;I~@85+1M)xp(UzI(Y0hb0_*Ru>ez= z#^mVaI)$@h`Yi{Z*sTiLc9L`2nu>>DDi zrG;xBdtGk1OO-?1QY-O literal 17 VcmZR6%*1`2-RO=50~jzZ0RSh-1HJ$N diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index c6893e330170c8df12480c6caccd9283e05c1f59..d2c563d17cf127c5db086e2ba76f824a0e105888 100644 GIT binary patch literal 17 UcmZSfny)7yTG{!G0Sp-X042Bsw*UYD literal 17 UcmZSfny)7yTG{!G0Rlb)045s*8vp createCloth( return BaseResponse.onSuccess(SuccessStatus.CLOTH_CREATED,result); } + @DeleteMapping("/{cloth-id}") + @Operation(summary = "특정 옷을 삭제하는 API",description = "path variable로 cloth_id를 넘겨주세요.") + @Parameters({@Parameter(name = "cloth-id",description = "옷의 id,path variable입니다.")}) + public BaseResponse deleteCloth ( + @PathVariable(value="cloth-id") Long clothId + ){ + clothService.deleteCloth(clothId); + return BaseResponse.onSuccess(SuccessStatus.CLOTH_DELETED,null); + } + } diff --git a/src/main/java/study/goorm/domain/cloth/application/ClothService.java b/src/main/java/study/goorm/domain/cloth/application/ClothService.java index 4ca06fb..822b1c1 100644 --- a/src/main/java/study/goorm/domain/cloth/application/ClothService.java +++ b/src/main/java/study/goorm/domain/cloth/application/ClothService.java @@ -9,6 +9,6 @@ public interface ClothService { ClothResponseDTO.ClothEditViewResult getClothEditView(Long clothId); ClothResponseDTO.MemberClosetResult getMemberCloset(String clokeyId, ClothSort sort,int page,int size); ClothResponseDTO.ClothCreateResult createCloth(ClothRequestDTO.ClothCreateRequest clothCreateResult ,MultipartFile image); - + void deleteCloth(Long clothId); } diff --git a/src/main/java/study/goorm/domain/cloth/application/ClothServiceImpl.java b/src/main/java/study/goorm/domain/cloth/application/ClothServiceImpl.java index 819d598..f7efd3e 100644 --- a/src/main/java/study/goorm/domain/cloth/application/ClothServiceImpl.java +++ b/src/main/java/study/goorm/domain/cloth/application/ClothServiceImpl.java @@ -16,6 +16,8 @@ import study.goorm.domain.cloth.dto.ClothRequestDTO; import study.goorm.domain.cloth.dto.ClothResponseDTO; import study.goorm.domain.cloth.exception.ClothException; +import study.goorm.domain.folder.domain.repository.ClothFolderRepository; +import study.goorm.domain.history.domain.repository.HistoryClothRepository; import study.goorm.domain.member.domain.entity.Member; import study.goorm.domain.member.domain.exception.MemberException; import study.goorm.domain.member.domain.repository.MemberRepository; @@ -34,6 +36,8 @@ public class ClothServiceImpl implements ClothService { private final MemberRepository memberRepository; private final ClothImageQueryService clothImageQueryService; private final CategoryRepository categoryRepository; + private final ClothFolderRepository clothFolderRepository; + private final HistoryClothRepository historyClothRepository; @Override @Transactional(readOnly = true) @@ -116,5 +120,19 @@ public ClothResponseDTO.ClothCreateResult createCloth(ClothRequestDTO.ClothCreat } + + @Override + @Transactional + public void deleteCloth(Long clothId){ + Cloth cloth=clothRepository.findById(clothId) + .orElseThrow(()->new ClothException(ErrorStatus.NO_SUCH_CLOTH)); + //매핑 테이블 삭제 + clothImageRepository.deleteAllByCloth(cloth); + clothFolderRepository.deleteAllByCloth(cloth); + historyClothRepository.deleteAllByCloth(cloth); + + //최종 옷 삭제 + clothRepository.delete(cloth); + } } diff --git a/src/main/java/study/goorm/domain/cloth/domain/repository/CategoryRepository.java b/src/main/java/study/goorm/domain/cloth/domain/repository/CategoryRepository.java index 66bc9fd..efd5455 100644 --- a/src/main/java/study/goorm/domain/cloth/domain/repository/CategoryRepository.java +++ b/src/main/java/study/goorm/domain/cloth/domain/repository/CategoryRepository.java @@ -2,6 +2,8 @@ import org.springframework.data.jpa.repository.JpaRepository; import study.goorm.domain.cloth.domain.entity.Category; +import study.goorm.domain.cloth.domain.entity.Cloth; public interface CategoryRepository extends JpaRepository { + } diff --git a/src/main/java/study/goorm/domain/cloth/domain/repository/ClothImageRepository.java b/src/main/java/study/goorm/domain/cloth/domain/repository/ClothImageRepository.java index 4958c9b..a665717 100644 --- a/src/main/java/study/goorm/domain/cloth/domain/repository/ClothImageRepository.java +++ b/src/main/java/study/goorm/domain/cloth/domain/repository/ClothImageRepository.java @@ -9,7 +9,7 @@ import java.util.List; public interface ClothImageRepository extends JpaRepository { - + void deleteAllByCloth(Cloth cloth); List findAllByCloth(Cloth cloth); @Query(value = """ diff --git a/src/main/java/study/goorm/domain/folder/domain/repository/ClothFolderRepository.java b/src/main/java/study/goorm/domain/folder/domain/repository/ClothFolderRepository.java index 143587d..f135bb0 100644 --- a/src/main/java/study/goorm/domain/folder/domain/repository/ClothFolderRepository.java +++ b/src/main/java/study/goorm/domain/folder/domain/repository/ClothFolderRepository.java @@ -1,7 +1,9 @@ package study.goorm.domain.folder.domain.repository; import org.springframework.data.jpa.repository.JpaRepository; +import study.goorm.domain.cloth.domain.entity.Cloth; import study.goorm.domain.folder.domain.entity.ClothFolder; public interface ClothFolderRepository extends JpaRepository { + void deleteAllByCloth(Cloth cloth); } diff --git a/src/main/java/study/goorm/domain/history/api/HistoryRestController.java b/src/main/java/study/goorm/domain/history/api/HistoryRestController.java new file mode 100644 index 0000000..b625d05 --- /dev/null +++ b/src/main/java/study/goorm/domain/history/api/HistoryRestController.java @@ -0,0 +1,63 @@ +package study.goorm.domain.history.api; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import study.goorm.domain.history.application.HistoryService; +import study.goorm.domain.history.dto.HistoryRequestDTO; +import study.goorm.domain.history.dto.HistoryResponseDTO; +import study.goorm.global.common.response.BaseResponse; +import study.goorm.global.error.code.status.SuccessStatus; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/histories") +@Validated +public class HistoryRestController { + private final HistoryService historyService; + + @GetMapping("/{history-id}") + @Operation(summary ="일별 기록을 조회하는 API",description = "Path Variable로 historyId를 던져주세요.") + @ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "HISTORY_200", description = "OK, 성공적으로 조회되었습니다.")}) + public BaseResponse getDailyHistoryView( + @PathVariable(name="history-id") Long historyId + ){ + HistoryResponseDTO.HistoryDailyViewResult result=historyService.getDailyHistoryView(historyId); + return BaseResponse.onSuccess(SuccessStatus.HISTORY_DAILY_VIEW_SUCCESS, result); + } + + @PatchMapping(value = "/{history-id}",consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + @Operation(summary = "기록을 수정하는 API",description = "request body에 HistoryUpdateRequest 형식의 데이터를 전달해주세요.") + @ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "HISTORY_200", description = "UPDATED, 기록이 성공적으로 수정되었습니다."),}) + public BaseResponse updateHistory( + @RequestPart("historyUpdateRequest")HistoryRequestDTO.HistoryUpdateRequest historyUpdateRequest + + ){ + HistoryResponseDTO.HistoryUpdateResult result=historyService.updateHistory(historyUpdateRequest); + return BaseResponse.onSuccess(SuccessStatus.HISTORY_UPDATED,result); + } + + @DeleteMapping("{history-id}") + @Operation(summary="특정 기록을 삭제하는 API",description = "path variable로 history_id를 넘겨주세요.") + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "HISTORY_200", description = "기록이 성공적으로 삭제되었습니다."), + }) + @Parameters({ + @Parameter(name = "history-id", description = "기록의 id, path variable 입니다.") + }) + public BaseResponse deleteHistory( + @PathVariable(value = "history-id") Long historyId + ) { + + historyService.deleteHistory(historyId); + + return BaseResponse.onSuccess(SuccessStatus.HISTORY_DELETED, null); + } + + +} diff --git a/src/main/java/study/goorm/domain/history/application/HistoryService.java b/src/main/java/study/goorm/domain/history/application/HistoryService.java new file mode 100644 index 0000000..93d393a --- /dev/null +++ b/src/main/java/study/goorm/domain/history/application/HistoryService.java @@ -0,0 +1,15 @@ +package study.goorm.domain.history.application; + +import study.goorm.domain.cloth.domain.entity.Cloth; +import study.goorm.domain.history.domain.entity.Hashtag; +import study.goorm.domain.history.dto.HistoryRequestDTO; +import study.goorm.domain.history.dto.HistoryResponseDTO; +import study.goorm.domain.model.enums.Visibility; + +public interface HistoryService { + HistoryResponseDTO.HistoryDailyViewResult getDailyHistoryView(Long historyId); + HistoryResponseDTO.HistoryUpdateResult updateHistory(HistoryRequestDTO.HistoryUpdateRequest historyUpdateResult); + public void deleteHistory(Long historyId); + +} + diff --git a/src/main/java/study/goorm/domain/history/application/HistoryServiceImpl.java b/src/main/java/study/goorm/domain/history/application/HistoryServiceImpl.java new file mode 100644 index 0000000..66e3614 --- /dev/null +++ b/src/main/java/study/goorm/domain/history/application/HistoryServiceImpl.java @@ -0,0 +1,89 @@ +package study.goorm.domain.history.application; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import study.goorm.domain.cloth.domain.entity.Cloth; +import study.goorm.domain.history.converter.HistoryConverter; +import study.goorm.domain.history.domain.entity.Hashtag; +import study.goorm.domain.history.domain.entity.History; +import study.goorm.domain.history.domain.repository.*; +import study.goorm.domain.history.dto.HistoryRequestDTO; +import study.goorm.domain.history.dto.HistoryResponseDTO; +import study.goorm.domain.history.exception.HistoryException; +import study.goorm.domain.model.enums.Visibility; +import study.goorm.global.error.code.status.ErrorStatus; +import java.util.List; + +@Service +@RequiredArgsConstructor +public class HistoryServiceImpl implements HistoryService { + private final HistoryRepository historyRepository; + private final HashtagRepository hashtagRepository; + private final CommentRepository commentRepository; + private final HistoryClothRepository historyClothRepository; + private final HashtagHistoryRepository historyHashtagRepository; + private final HashtagHistoryRepository hashtagHistoryRepository; + private final HistoryImageRepository historyImageRepository; + + @Override + @Transactional(readOnly = true) + public HistoryResponseDTO.HistoryDailyViewResult getDailyHistoryView(Long historyId){ + + History history=historyRepository.findById(historyId) + .orElseThrow(()->new HistoryException(ErrorStatus.NO_SUCH_HISTORY)); + + //List hashtag와 List clothes 차이 + List hashtag = historyHashtagRepository.findAllByHistory_Id(historyId) + .stream() + .map(hc->hc.getHashtag().getName()) + .toList(); + + + List clothes=historyClothRepository.findAllByHistory(history) + .stream() + .map(hc->hc.getCloth().getName()) + .toList(); + + int commentCount=commentRepository.countByHistory(history); + + + boolean liked= false; + return HistoryConverter.toHistoryDailyViewResult(history,hashtag,clothes,commentCount,liked); + } + + //매우 어렵다 + @Override + public HistoryResponseDTO.HistoryUpdateResult updateHistory( + HistoryRequestDTO.HistoryUpdateRequest historyUpdateResult + ) + { +// History history=historyRepository.findById(historyUpdateResult.getHistoryId()) +// .orElseThrow(()->new HistoryException(ErrorStatus.NO_SUCH_HISTORY)); +// History newHistory=History.builder() +// .content(history.getContent()) +// .clothes(cloth.getName()) +// .hashtags(hashtag.getName()) +// .visibility(visibility) +// .build(); +// historyRepository.save(newHistory); +// return HistoryConverter.toHistoryUpdateResult(newHistory); + return null; + } + + @Override + @Transactional + public void deleteHistory(Long historyId) { + History history=historyRepository.findById(historyId) + .orElseThrow(()->new HistoryException(ErrorStatus.NO_SUCH_HISTORY)); + + hashtagHistoryRepository.deleteAllByHistory(history); + historyClothRepository.deleteAllByHistory(history); + historyImageRepository.deleteAllByHistory(history); + + + historyRepository.delete(history); + } + +} + diff --git a/src/main/java/study/goorm/domain/history/converter/HistoryConverter.java b/src/main/java/study/goorm/domain/history/converter/HistoryConverter.java new file mode 100644 index 0000000..b54bf97 --- /dev/null +++ b/src/main/java/study/goorm/domain/history/converter/HistoryConverter.java @@ -0,0 +1,48 @@ +package study.goorm.domain.history.converter; + +import study.goorm.domain.cloth.domain.entity.Cloth; +import study.goorm.domain.history.domain.entity.History; +import study.goorm.domain.history.domain.entity.Hashtag; +import study.goorm.domain.history.dto.HistoryRequestDTO; +import study.goorm.domain.history.dto.HistoryResponseDTO; +import study.goorm.domain.model.enums.Visibility; + +import java.util.List; +//List에서 List로 바꿈 +public class HistoryConverter { + public static HistoryResponseDTO.HistoryDailyViewResult toHistoryDailyViewResult( + History history, List hashtag, List clothes, int commentCount, boolean liked + ) { + return HistoryResponseDTO.HistoryDailyViewResult.builder() + .memberId(history.getMember().getId()) + .historyId(history.getId()) + .memberImageUrl(history.getMember().getProfileImageUrl()) + .nickName(history.getMember().getNickname()) + .clokeyId(history.getMember().getClokeyId()) + .contents(history.getContent()) + .hashtags(hashtag) + .likeCount(history.getLikes()) + .commentCount(commentCount) + .date(history.getHistoryDate()) + .clothes(clothes) + .liked(liked) + .build(); + + } + + public static HistoryRequestDTO.HistoryUpdateRequest toHistoryUpdateRequest(History history) { + return HistoryRequestDTO.HistoryUpdateRequest.builder() + .historyId(history.getId()) + .build(); + } + public static HistoryResponseDTO.HistoryUpdateResult toHistoryUpdateResult( + History history, List clothes, List hashtags, Visibility visibility) { + return HistoryResponseDTO.HistoryUpdateResult.builder() + .content(history.getContent()) + .clothes(clothes) + .hashtags(hashtags) + .visibility(visibility) + .build(); + } + +} diff --git a/src/main/java/study/goorm/domain/history/domain/repository/CommentRepository.java b/src/main/java/study/goorm/domain/history/domain/repository/CommentRepository.java index 3ce29c9..4f98b16 100644 --- a/src/main/java/study/goorm/domain/history/domain/repository/CommentRepository.java +++ b/src/main/java/study/goorm/domain/history/domain/repository/CommentRepository.java @@ -2,6 +2,8 @@ import org.springframework.data.jpa.repository.JpaRepository; import study.goorm.domain.history.domain.entity.Comment; +import study.goorm.domain.history.domain.entity.History; public interface CommentRepository extends JpaRepository { + int countByHistory(History history); } diff --git a/src/main/java/study/goorm/domain/history/domain/repository/HashtagHistoryRepository.java b/src/main/java/study/goorm/domain/history/domain/repository/HashtagHistoryRepository.java index 571b65b..1e608bb 100644 --- a/src/main/java/study/goorm/domain/history/domain/repository/HashtagHistoryRepository.java +++ b/src/main/java/study/goorm/domain/history/domain/repository/HashtagHistoryRepository.java @@ -2,6 +2,12 @@ import org.springframework.data.jpa.repository.JpaRepository; import study.goorm.domain.history.domain.entity.HashtagHistory; +import study.goorm.domain.history.domain.entity.History; + +import java.util.List; public interface HashtagHistoryRepository extends JpaRepository { + List findAllByHistory_Id(Long historyId); + + void deleteAllByHistory(History history); } diff --git a/src/main/java/study/goorm/domain/history/domain/repository/HistoryClothRepository.java b/src/main/java/study/goorm/domain/history/domain/repository/HistoryClothRepository.java index 1042019..7fa3aef 100644 --- a/src/main/java/study/goorm/domain/history/domain/repository/HistoryClothRepository.java +++ b/src/main/java/study/goorm/domain/history/domain/repository/HistoryClothRepository.java @@ -1,7 +1,19 @@ package study.goorm.domain.history.domain.repository; import org.springframework.data.jpa.repository.JpaRepository; +import study.goorm.domain.cloth.domain.entity.Cloth; +import study.goorm.domain.history.domain.entity.History; import study.goorm.domain.history.domain.entity.HistoryCloth; +import java.util.List; +import java.util.Optional; + public interface HistoryClothRepository extends JpaRepository { + void deleteAllByCloth(Cloth cloth); + + Optional findAllByHistory_Id(Long historyId); + + List findAllByHistory(History history); + + void deleteAllByHistory(History history); } diff --git a/src/main/java/study/goorm/domain/history/domain/repository/HistoryImageRepository.java b/src/main/java/study/goorm/domain/history/domain/repository/HistoryImageRepository.java index 52881cb..abcce1f 100644 --- a/src/main/java/study/goorm/domain/history/domain/repository/HistoryImageRepository.java +++ b/src/main/java/study/goorm/domain/history/domain/repository/HistoryImageRepository.java @@ -1,7 +1,9 @@ package study.goorm.domain.history.domain.repository; import org.springframework.data.jpa.repository.JpaRepository; +import study.goorm.domain.history.domain.entity.History; import study.goorm.domain.history.domain.entity.HistoryImage; public interface HistoryImageRepository extends JpaRepository { + void deleteAllByHistory(History history); } diff --git a/src/main/java/study/goorm/domain/history/dto/HistoryRequestDTO.java b/src/main/java/study/goorm/domain/history/dto/HistoryRequestDTO.java new file mode 100644 index 0000000..93e7877 --- /dev/null +++ b/src/main/java/study/goorm/domain/history/dto/HistoryRequestDTO.java @@ -0,0 +1,18 @@ +package study.goorm.domain.history.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + + +public class HistoryRequestDTO { + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class HistoryUpdateRequest{ + private Long historyId; + } +} diff --git a/src/main/java/study/goorm/domain/history/dto/HistoryResponseDTO.java b/src/main/java/study/goorm/domain/history/dto/HistoryResponseDTO.java new file mode 100644 index 0000000..acb16a4 --- /dev/null +++ b/src/main/java/study/goorm/domain/history/dto/HistoryResponseDTO.java @@ -0,0 +1,51 @@ +package study.goorm.domain.history.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import study.goorm.domain.cloth.domain.entity.ClothImage; +import study.goorm.domain.model.enums.Visibility; + + +import java.time.LocalDate; +import java.util.List; + +public class HistoryResponseDTO { + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class HistoryDailyViewResult{ + private Long memberId; + private String memberImageUrl; + private String nickName; + private String clokeyId; + private String contents; + private List images; + private List hashtags; + private int likeCount; + private Boolean liked; + private LocalDate date; + private List clothes; + private Long ClothId; + private int commentCount; + private Long historyId; + + + } + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class HistoryUpdateResult{ + private String content; + private List clothes; + private List hashtags; + private Visibility visibility; + } + + +} diff --git a/src/main/java/study/goorm/domain/history/exception/HistoryException.java b/src/main/java/study/goorm/domain/history/exception/HistoryException.java new file mode 100644 index 0000000..b3307a2 --- /dev/null +++ b/src/main/java/study/goorm/domain/history/exception/HistoryException.java @@ -0,0 +1,11 @@ +package study.goorm.domain.history.exception; + +import study.goorm.global.error.code.BaseErrorCode; +import study.goorm.global.exception.GeneralException; + +public class HistoryException extends GeneralException { + public HistoryException(BaseErrorCode code) { + super(code); + } + +} diff --git a/src/main/java/study/goorm/domain/member/domain/repository/MemberRepository.java b/src/main/java/study/goorm/domain/member/domain/repository/MemberRepository.java index 94b9110..61f4aa2 100644 --- a/src/main/java/study/goorm/domain/member/domain/repository/MemberRepository.java +++ b/src/main/java/study/goorm/domain/member/domain/repository/MemberRepository.java @@ -1,6 +1,7 @@ package study.goorm.domain.member.domain.repository; import org.springframework.data.jpa.repository.JpaRepository; +import study.goorm.domain.cloth.domain.entity.Cloth; import study.goorm.domain.member.domain.entity.Member; import java.util.Optional; @@ -8,4 +9,5 @@ public interface MemberRepository extends JpaRepository { Optional findByClokeyId(String clokeyId); + } diff --git a/src/main/java/study/goorm/domain/member/domain/repository/MemberTermRepository.java b/src/main/java/study/goorm/domain/member/domain/repository/MemberTermRepository.java index 92c726c..1af3a38 100644 --- a/src/main/java/study/goorm/domain/member/domain/repository/MemberTermRepository.java +++ b/src/main/java/study/goorm/domain/member/domain/repository/MemberTermRepository.java @@ -1,7 +1,9 @@ package study.goorm.domain.member.domain.repository; import org.springframework.data.jpa.repository.JpaRepository; +import study.goorm.domain.cloth.domain.entity.Cloth; import study.goorm.domain.member.domain.entity.MemberTerm; public interface MemberTermRepository extends JpaRepository { + } diff --git a/src/main/java/study/goorm/domain/member/domain/repository/TermRepository.java b/src/main/java/study/goorm/domain/member/domain/repository/TermRepository.java index bcc6edb..13651e2 100644 --- a/src/main/java/study/goorm/domain/member/domain/repository/TermRepository.java +++ b/src/main/java/study/goorm/domain/member/domain/repository/TermRepository.java @@ -1,7 +1,9 @@ package study.goorm.domain.member.domain.repository; import org.springframework.data.jpa.repository.JpaRepository; +import study.goorm.domain.cloth.domain.entity.Cloth; import study.goorm.domain.member.domain.entity.Term; public interface TermRepository extends JpaRepository { + } diff --git a/src/main/java/study/goorm/domain/model/enums/Visibility.java b/src/main/java/study/goorm/domain/model/enums/Visibility.java new file mode 100644 index 0000000..080be15 --- /dev/null +++ b/src/main/java/study/goorm/domain/model/enums/Visibility.java @@ -0,0 +1,5 @@ +package study.goorm.domain.model.enums; + +public enum Visibility { + PUBLIC,PRIAVTE +} diff --git a/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java b/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java index ae21bc4..61fe69b 100644 --- a/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java +++ b/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java @@ -31,7 +31,14 @@ public enum ErrorStatus implements BaseErrorCode { NO_SUCH_CATEGORY(HttpStatus.BAD_REQUEST,"CLOTH_4003","카테고리가 존재하지 않습니다."), - LOWER_TEMP_BIGGER_THAN_UPPER_TEMP(HttpStatus.BAD_REQUEST,"CLOTH_4004","옷의 하한 온도가 상한 온도 보다 높습니다."); + LOWER_TEMP_BIGGER_THAN_UPPER_TEMP(HttpStatus.BAD_REQUEST,"CLOTH_4004","옷의 하한 온도가 상한 온도 보다 높습니다."), + + + //History + NO_SUCH_HISTORY(HttpStatus.NOT_FOUND, "HISTORY_4002","존재하지 않는 기록ID입니다"), + + NO_AUTHORITY_HISTORY(HttpStatus.FORBIDDEN,"HISTORY_4006","기록에 접근 권한이 없습니다."); + private final HttpStatus httpStatus; private final String code; diff --git a/src/main/java/study/goorm/global/error/code/status/SuccessStatus.java b/src/main/java/study/goorm/global/error/code/status/SuccessStatus.java index f9f00be..5e430e9 100644 --- a/src/main/java/study/goorm/global/error/code/status/SuccessStatus.java +++ b/src/main/java/study/goorm/global/error/code/status/SuccessStatus.java @@ -16,7 +16,15 @@ public enum SuccessStatus implements BaseCode { //Cloth CLOTH_VIEW_SUCCESS(HttpStatus.OK,"CLOTH_200","옷이 성공적으로 조회되었습니다."), - CLOTH_CREATED(HttpStatus.CREATED, "CLOTH_201","옷이 성공적으로 생성되었습니다."); + CLOTH_CREATED(HttpStatus.CREATED, "CLOTH_201","옷이 성공적으로 생성되었습니다."), + + CLOTH_DELETED(HttpStatus.NO_CONTENT,"CLOTH_202","옷이 성공적으로 삭제되었습니다."), + + HISTORY_DAILY_VIEW_SUCCESS(HttpStatus.OK,"HISTORY_200","성공적으로 조회되었습니다."), + + HISTORY_UPDATED(HttpStatus.OK,"HISTORY_200","기록이 성공적으로 수정되었습니다."), + + HISTORY_DELETED(HttpStatus.NO_CONTENT,"HISTORY_200","기록이 성공적으로 삭제되었습니다."); private final HttpStatus httpStatus; From 2fd0c4669e57284a6ee65d192c12ac1412efcc16 Mon Sep 17 00:00:00 2001 From: psj Date: Tue, 24 Jun 2025 19:57:38 +0900 Subject: [PATCH 5/6] =?UTF-8?q?history=EC=97=90=EC=84=9C=20post=20patch?= =?UTF-8?q?=EC=9D=98=20serviceImpl=EB=B6=80=EB=B6=84=20=EC=A0=9C=EC=99=B8?= =?UTF-8?q?=ED=95=98=EA=B3=A0=20=EA=B5=AC=ED=98=84=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../executionHistory/executionHistory.lock | Bin 17 -> 17 bytes .gradle/8.13/fileHashes/fileHashes.bin | Bin 28997 -> 29547 bytes .gradle/8.13/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .../history/api/HistoryRestController.java | 27 ++++++++++ .../application/HistoryImageQueryService.java | 10 ++++ .../HistoryImageQueryServiceImpl.java | 32 ++++++++++++ .../history/application/HistoryService.java | 5 ++ .../application/HistoryServiceImpl.java | 40 +++++++++++++++ .../history/converter/HistoryConverter.java | 48 ++++++++++++++++++ .../repository/HistoryImageRepository.java | 22 ++++++++ .../domain/repository/HistoryRepository.java | 7 +++ .../domain/history/dto/HistoryRequestDTO.java | 15 ++++++ .../history/dto/HistoryResponseDTO.java | 31 +++++++++++ .../global/error/code/status/ErrorStatus.java | 3 +- .../error/code/status/SuccessStatus.java | 2 + 16 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 src/main/java/study/goorm/domain/history/application/HistoryImageQueryService.java create mode 100644 src/main/java/study/goorm/domain/history/application/HistoryImageQueryServiceImpl.java diff --git a/.gradle/8.13/executionHistory/executionHistory.lock b/.gradle/8.13/executionHistory/executionHistory.lock index 7720f922561be1b5932bed2e1db646040031f0f8..4c9a1b74418b9e4503d84078e615c880cb83f828 100644 GIT binary patch literal 17 UcmZQRtXo+5@vdep0|b-+05ymNrT_o{ literal 17 UcmZQRtXo+5@vdep0|X=j05x?4lK=n! diff --git a/.gradle/8.13/fileHashes/fileHashes.bin b/.gradle/8.13/fileHashes/fileHashes.bin index 7907f76bb9f4a9b95b928dd28cba4a61281c360c..9193126aed419cb8911446e8e31c9a2bec08a927 100644 GIT binary patch delta 2407 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 diff --git a/.gradle/8.13/fileHashes/fileHashes.lock b/.gradle/8.13/fileHashes/fileHashes.lock index 65a6d37c31f8f593f41496a0127d001a52e72f9f..17aa435a0cd1990ab46040607456d83fe5069891 100644 GIT binary patch literal 17 VcmZR6%*1`2-RO=50~oL@0stq=1HJ$N literal 17 VcmZR6%*1`2-RO=50~j#>1OO-?1QY-O diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index d2c563d17cf127c5db086e2ba76f824a0e105888..a7d29172914d76620f821d120fbefc962aa3b684 100644 GIT binary patch literal 17 VcmZSfny)7yTG{!G0Sp+A0RScN1MdI; literal 17 UcmZSfny)7yTG{!G0Sp-X042Bsw*UYD diff --git a/src/main/java/study/goorm/domain/history/api/HistoryRestController.java b/src/main/java/study/goorm/domain/history/api/HistoryRestController.java index b625d05..579058c 100644 --- a/src/main/java/study/goorm/domain/history/api/HistoryRestController.java +++ b/src/main/java/study/goorm/domain/history/api/HistoryRestController.java @@ -5,6 +5,7 @@ import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.responses.ApiResponses; import lombok.RequiredArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.MediaType; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -14,6 +15,8 @@ import study.goorm.global.common.response.BaseResponse; import study.goorm.global.error.code.status.SuccessStatus; +import java.time.YearMonth; + @RestController @RequiredArgsConstructor @RequestMapping("/histories") @@ -21,6 +24,17 @@ public class HistoryRestController { private final HistoryService historyService; + @GetMapping("/monthly") + @Operation(summary ="월별 기록을 조회하는 API",description = "Query Parameter로 clokeyId와 month(YYYY-MM)를 전달해주세요. clokeyId를 생략하면 본인기록을 조회합니다.") + @ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "HISTORY_200", description = "OK, 성공적으로 조회되었습니다.")}) + public BaseResponse getMonthlyHistoryView( + @RequestParam(required = false) String clokeyId, + @RequestParam @DateTimeFormat(pattern = "yyyy-MM") YearMonth month + ){ + HistoryResponseDTO.HistoryMonthlyViewResult result=historyService.getMonthlyHistoryView(clokeyId,month); + return BaseResponse.onSuccess(SuccessStatus.HISTORY_MONTHLY_VIEW_SUCCESS, result); + } + @GetMapping("/{history-id}") @Operation(summary ="일별 기록을 조회하는 API",description = "Path Variable로 historyId를 던져주세요.") @ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "HISTORY_200", description = "OK, 성공적으로 조회되었습니다.")}) @@ -31,6 +45,19 @@ public BaseResponse getDailyHistoryVi return BaseResponse.onSuccess(SuccessStatus.HISTORY_DAILY_VIEW_SUCCESS, result); } + @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + @Operation(summary = "기록을 추가하는 API",description = "request body에 HistoryCreateRequest 형식의 데이터를 전달해주세요.") + @ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "HISTORY_201", description = "CREATED, 기록이 성공적으로 추가되었습니다."),}) + public BaseResponse createHistory( + @RequestPart("historyCreateRequest")HistoryRequestDTO.HistoryCreateRequest historyCreateRequest + + ){ + HistoryResponseDTO.HistoryCreateResult result=historyService.createHistory(historyCreateRequest); + return BaseResponse.onSuccess(SuccessStatus.HISTORY_CREATED,result); + } + + + @PatchMapping(value = "/{history-id}",consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @Operation(summary = "기록을 수정하는 API",description = "request body에 HistoryUpdateRequest 형식의 데이터를 전달해주세요.") @ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "HISTORY_200", description = "UPDATED, 기록이 성공적으로 수정되었습니다."),}) diff --git a/src/main/java/study/goorm/domain/history/application/HistoryImageQueryService.java b/src/main/java/study/goorm/domain/history/application/HistoryImageQueryService.java new file mode 100644 index 0000000..9cdbd6e --- /dev/null +++ b/src/main/java/study/goorm/domain/history/application/HistoryImageQueryService.java @@ -0,0 +1,10 @@ +package study.goorm.domain.history.application; + +import study.goorm.domain.history.domain.entity.History; + +import java.util.List; +import java.util.Map; + +public interface HistoryImageQueryService { + Map getFirstImageUrlMap(List histories); +} diff --git a/src/main/java/study/goorm/domain/history/application/HistoryImageQueryServiceImpl.java b/src/main/java/study/goorm/domain/history/application/HistoryImageQueryServiceImpl.java new file mode 100644 index 0000000..8c014e2 --- /dev/null +++ b/src/main/java/study/goorm/domain/history/application/HistoryImageQueryServiceImpl.java @@ -0,0 +1,32 @@ +package study.goorm.domain.history.application; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import study.goorm.domain.history.domain.entity.History; +import study.goorm.domain.history.domain.entity.HistoryImage; +import study.goorm.domain.history.domain.repository.HistoryImageRepository; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class HistoryImageQueryServiceImpl implements HistoryImageQueryService { + private final HistoryImageRepository historyImageRepository; + + public Map getFirstImageUrlMap(List histories) { + List historyIds=histories.stream() + .map(History::getId) + .toList(); + List firstImages=historyImageRepository.findFirstImagesByHistoryIds(historyIds); + + return firstImages.stream() + .collect(Collectors.toMap( + image->image.getHistory().getId(), + HistoryImage::getImageUrl + )); + } + + +} diff --git a/src/main/java/study/goorm/domain/history/application/HistoryService.java b/src/main/java/study/goorm/domain/history/application/HistoryService.java index 93d393a..63803df 100644 --- a/src/main/java/study/goorm/domain/history/application/HistoryService.java +++ b/src/main/java/study/goorm/domain/history/application/HistoryService.java @@ -6,10 +6,15 @@ import study.goorm.domain.history.dto.HistoryResponseDTO; import study.goorm.domain.model.enums.Visibility; +import java.time.YearMonth; + public interface HistoryService { HistoryResponseDTO.HistoryDailyViewResult getDailyHistoryView(Long historyId); + HistoryResponseDTO.HistoryMonthlyViewResult getMonthlyHistoryView(String clokeyId, YearMonth month); HistoryResponseDTO.HistoryUpdateResult updateHistory(HistoryRequestDTO.HistoryUpdateRequest historyUpdateResult); public void deleteHistory(Long historyId); + HistoryResponseDTO.HistoryCreateResult createHistory(HistoryRequestDTO.HistoryCreateRequest historyCreateRequest); + } diff --git a/src/main/java/study/goorm/domain/history/application/HistoryServiceImpl.java b/src/main/java/study/goorm/domain/history/application/HistoryServiceImpl.java index 66e3614..1b2ba44 100644 --- a/src/main/java/study/goorm/domain/history/application/HistoryServiceImpl.java +++ b/src/main/java/study/goorm/domain/history/application/HistoryServiceImpl.java @@ -11,9 +11,17 @@ import study.goorm.domain.history.dto.HistoryRequestDTO; import study.goorm.domain.history.dto.HistoryResponseDTO; import study.goorm.domain.history.exception.HistoryException; +import study.goorm.domain.member.domain.entity.Member; +import study.goorm.domain.member.domain.repository.MemberRepository; import study.goorm.domain.model.enums.Visibility; import study.goorm.global.error.code.status.ErrorStatus; + +import java.time.LocalDate; +import java.time.Year; +import java.time.YearMonth; import java.util.List; +import java.util.Map; + @Service @RequiredArgsConstructor @@ -25,6 +33,28 @@ public class HistoryServiceImpl implements HistoryService { private final HashtagHistoryRepository historyHashtagRepository; private final HashtagHistoryRepository hashtagHistoryRepository; private final HistoryImageRepository historyImageRepository; + private final MemberRepository memberRepository; + private final HistoryImageQueryService historyImageQueryService; + + + @Override + @Transactional(readOnly = true) + public HistoryResponseDTO.HistoryMonthlyViewResult getMonthlyHistoryView(String clokeyId, YearMonth month){ + + String effectiveClokeyId=(clokeyId==null) ? "clo001" : clokeyId; + + Member member=memberRepository.findByClokeyId(effectiveClokeyId) + .orElseThrow(()->new HistoryException(ErrorStatus.NO_SUCH_HISTORY_MEMBER)); + + LocalDate start=month.atDay(1); + LocalDate end=month.atEndOfMonth(); + List histories=historyRepository.findByMemberIdAndHistoryDateBetween(member.getId(),start,end); + Map imageUrlMap=historyImageQueryService.getFirstImageUrlMap(histories); + return HistoryConverter.toHistoryMonthlyViewResult(histories,member,imageUrlMap); + + + + } @Override @Transactional(readOnly = true) @@ -51,6 +81,16 @@ public HistoryResponseDTO.HistoryDailyViewResult getDailyHistoryView(Long histor boolean liked= false; return HistoryConverter.toHistoryDailyViewResult(history,hashtag,clothes,commentCount,liked); } + + //매우 어렵다 + @Override + public HistoryResponseDTO.HistoryCreateResult createHistory( + HistoryRequestDTO.HistoryCreateRequest historyCreateResult + ) + { + + return null; + } //매우 어렵다 @Override diff --git a/src/main/java/study/goorm/domain/history/converter/HistoryConverter.java b/src/main/java/study/goorm/domain/history/converter/HistoryConverter.java index b54bf97..f931a04 100644 --- a/src/main/java/study/goorm/domain/history/converter/HistoryConverter.java +++ b/src/main/java/study/goorm/domain/history/converter/HistoryConverter.java @@ -5,11 +5,36 @@ import study.goorm.domain.history.domain.entity.Hashtag; import study.goorm.domain.history.dto.HistoryRequestDTO; import study.goorm.domain.history.dto.HistoryResponseDTO; +import study.goorm.domain.member.domain.entity.Member; import study.goorm.domain.model.enums.Visibility; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + //List에서 List로 바꿈 public class HistoryConverter { + + + public static HistoryResponseDTO.HistoryMonthlyViewResult toHistoryMonthlyViewResult( + List histories, Member member, Map imageUrlMap + ) { + + List historyItems = histories.stream() + .map(history -> new HistoryResponseDTO.HistoryMonthlyViewResult.HistoryItem( + history.getId(), + history.getHistoryDate(), + imageUrlMap.getOrDefault(history.getId(), null) // 존재하지 않으면 null + )) + .collect(Collectors.toList()); + + return HistoryResponseDTO.HistoryMonthlyViewResult.builder() + .memberId(member.getId()) + .nickname(member.getNickname()) + .histories(historyItems) + .build(); + } + public static HistoryResponseDTO.HistoryDailyViewResult toHistoryDailyViewResult( History history, List hashtag, List clothes, int commentCount, boolean liked ) { @@ -30,11 +55,34 @@ public static HistoryResponseDTO.HistoryDailyViewResult toHistoryDailyViewResult } + public static HistoryRequestDTO.HistoryCreateRequest toHistoryCreateRequest( + History history,List clothes, List hashtags + ) { + return HistoryRequestDTO.HistoryCreateRequest.builder() + .content(history.getContent()) + .clothes(clothes) + .hashtags(hashtags) + .date(history.getHistoryDate().toString()) + .build(); + } + + public static HistoryResponseDTO.HistoryCreateResult toHistoryCreateResult( + History history + ) + { + return HistoryResponseDTO.HistoryCreateResult.builder() + .historyId(history.getId()) + .build(); + } + public static HistoryRequestDTO.HistoryUpdateRequest toHistoryUpdateRequest(History history) { return HistoryRequestDTO.HistoryUpdateRequest.builder() .historyId(history.getId()) .build(); } + + + public static HistoryResponseDTO.HistoryUpdateResult toHistoryUpdateResult( History history, List clothes, List hashtags, Visibility visibility) { return HistoryResponseDTO.HistoryUpdateResult.builder() diff --git a/src/main/java/study/goorm/domain/history/domain/repository/HistoryImageRepository.java b/src/main/java/study/goorm/domain/history/domain/repository/HistoryImageRepository.java index abcce1f..09b6317 100644 --- a/src/main/java/study/goorm/domain/history/domain/repository/HistoryImageRepository.java +++ b/src/main/java/study/goorm/domain/history/domain/repository/HistoryImageRepository.java @@ -1,9 +1,31 @@ package study.goorm.domain.history.domain.repository; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import study.goorm.domain.history.domain.entity.History; import study.goorm.domain.history.domain.entity.HistoryImage; +import java.util.List; + public interface HistoryImageRepository extends JpaRepository { void deleteAllByHistory(History history); + + List findFirstImagesByHistory(History history); + + + History history(History history); + + @Query(""" + SELECT hi FROM HistoryImage hi + WHERE hi.id IN ( + SELECT MIN(hi2.id) + FROM HistoryImage hi2 + WHERE hi2.history.id IN :historyIds + GROUP BY hi2.history.id + ) +""") + List findFirstImagesByHistoryIds(@Param("historyIds") List historyIds); + + } diff --git a/src/main/java/study/goorm/domain/history/domain/repository/HistoryRepository.java b/src/main/java/study/goorm/domain/history/domain/repository/HistoryRepository.java index 5f66987..ff92152 100644 --- a/src/main/java/study/goorm/domain/history/domain/repository/HistoryRepository.java +++ b/src/main/java/study/goorm/domain/history/domain/repository/HistoryRepository.java @@ -3,5 +3,12 @@ import org.springframework.data.jpa.repository.JpaRepository; import study.goorm.domain.history.domain.entity.History; +import java.time.LocalDate; +import java.time.YearMonth; +import java.util.List; + public interface HistoryRepository extends JpaRepository { + //List findByClokeyIdAndMonth(String Id, YearMonth month); + + List findByMemberIdAndHistoryDateBetween(Long memberId, LocalDate historyDateAfter, LocalDate historyDateBefore); } diff --git a/src/main/java/study/goorm/domain/history/dto/HistoryRequestDTO.java b/src/main/java/study/goorm/domain/history/dto/HistoryRequestDTO.java index 93e7877..0f2f65b 100644 --- a/src/main/java/study/goorm/domain/history/dto/HistoryRequestDTO.java +++ b/src/main/java/study/goorm/domain/history/dto/HistoryRequestDTO.java @@ -5,6 +5,8 @@ import lombok.Getter; import lombok.NoArgsConstructor; +import java.util.List; + public class HistoryRequestDTO { @@ -15,4 +17,17 @@ public class HistoryRequestDTO { public static class HistoryUpdateRequest{ private Long historyId; } + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class HistoryCreateRequest{ + private String content; + private List clothes; + private List hashtags; + private String date; + } } + + diff --git a/src/main/java/study/goorm/domain/history/dto/HistoryResponseDTO.java b/src/main/java/study/goorm/domain/history/dto/HistoryResponseDTO.java index acb16a4..c29c1b1 100644 --- a/src/main/java/study/goorm/domain/history/dto/HistoryResponseDTO.java +++ b/src/main/java/study/goorm/domain/history/dto/HistoryResponseDTO.java @@ -5,6 +5,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import study.goorm.domain.cloth.domain.entity.ClothImage; +import study.goorm.domain.history.domain.entity.History; import study.goorm.domain.model.enums.Visibility; @@ -13,6 +14,25 @@ public class HistoryResponseDTO { + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class HistoryMonthlyViewResult{ + private Long memberId; + private String nickname; + private List histories; + + @Getter + @AllArgsConstructor + public static class HistoryItem{ + private Long historyId; + private LocalDate date; + private String imageUrl; + } + } + + @Builder @Getter @NoArgsConstructor @@ -36,6 +56,17 @@ public static class HistoryDailyViewResult{ } + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class HistoryCreateResult{ + private Long historyId; + } + + + + @Builder @Getter @NoArgsConstructor diff --git a/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java b/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java index 61fe69b..b79c9cd 100644 --- a/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java +++ b/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java @@ -37,7 +37,8 @@ public enum ErrorStatus implements BaseErrorCode { //History NO_SUCH_HISTORY(HttpStatus.NOT_FOUND, "HISTORY_4002","존재하지 않는 기록ID입니다"), - NO_AUTHORITY_HISTORY(HttpStatus.FORBIDDEN,"HISTORY_4006","기록에 접근 권한이 없습니다."); + NO_AUTHORITY_HISTORY(HttpStatus.FORBIDDEN,"HISTORY_4006","기록에 접근 권한이 없습니다."), + NO_SUCH_HISTORY_MEMBER(HttpStatus.BAD_REQUEST,"MEMBER_4001","존재하지 않는 ID멤버입니다."); private final HttpStatus httpStatus; diff --git a/src/main/java/study/goorm/global/error/code/status/SuccessStatus.java b/src/main/java/study/goorm/global/error/code/status/SuccessStatus.java index 5e430e9..cb192b4 100644 --- a/src/main/java/study/goorm/global/error/code/status/SuccessStatus.java +++ b/src/main/java/study/goorm/global/error/code/status/SuccessStatus.java @@ -21,8 +21,10 @@ public enum SuccessStatus implements BaseCode { CLOTH_DELETED(HttpStatus.NO_CONTENT,"CLOTH_202","옷이 성공적으로 삭제되었습니다."), HISTORY_DAILY_VIEW_SUCCESS(HttpStatus.OK,"HISTORY_200","성공적으로 조회되었습니다."), + HISTORY_MONTHLY_VIEW_SUCCESS(HttpStatus.OK,"HISTORY_201","월별기록이 성공적으로 조회되었습니다."), HISTORY_UPDATED(HttpStatus.OK,"HISTORY_200","기록이 성공적으로 수정되었습니다."), + HISTORY_CREATED(HttpStatus.OK,"HISTORY_201","기록이 성공적으로 추가되었습니다."), HISTORY_DELETED(HttpStatus.NO_CONTENT,"HISTORY_200","기록이 성공적으로 삭제되었습니다."); From 318af64873973122113375e742f5d97126ce6263 Mon Sep 17 00:00:00 2001 From: psj Date: Fri, 11 Jul 2025 21:03:13 +0900 Subject: [PATCH 6/6] =?UTF-8?q?=EB=8C=93=EA=B8=80=20=EC=A1=B0=ED=9A=8C,?= =?UTF-8?q?=EC=82=AD=EC=A0=9C,=EC=88=98=EC=A0=95=20=EB=B9=BC=EA=B3=A0=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=ED=96=88=EC=9D=8C.=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=ED=95=B4=EC=95=BC=ED=95=A0=20=EB=B6=80=EB=B6=84=EB=93=A4=20?= =?UTF-8?q?=EA=B5=B0=EB=8D=B0=EA=B5=B0=EB=8D=B0=20=EC=9E=88=EC=9D=8C.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gradle/8.13/checksums/checksums.lock | Bin 17 -> 17 bytes .gradle/8.13/checksums/md5-checksums.bin | Bin 28197 -> 29947 bytes .gradle/8.13/checksums/sha1-checksums.bin | Bin 72275 -> 75569 bytes .../executionHistory/executionHistory.lock | Bin 17 -> 17 bytes .gradle/8.13/fileHashes/fileHashes.bin | Bin 29547 -> 30947 bytes .gradle/8.13/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../buildOutputCleanup.lock | Bin 17 -> 17 bytes build.gradle | 1 + .../domain/cloth/domain/entity/Cloth.java | 5 + .../history/api/HistoryRestController.java | 76 ++++- .../history/application/HistoryService.java | 21 +- .../application/HistoryServiceImpl.java | 297 ++++++++++++++++-- .../history/converter/HistoryConverter.java | 104 +++++- .../domain/history/domain/entity/Follow.java | 16 + .../domain/history/domain/entity/History.java | 8 + .../history/domain/entity/HistoryImage.java | 2 +- .../domain/repository/CommentRepository.java | 9 + .../repository/HashtagHistoryRepository.java | 1 + .../domain/repository/HashtagRepository.java | 3 + .../repository/HistoryClothRepository.java | 2 + .../repository/HistoryImageRepository.java | 1 + .../domain/repository/HistoryRepository.java | 21 +- .../repository/MemberLikeRepository.java | 12 + .../domain/repository/followRepository.java | 9 + .../domain/history/dto/HistoryRequestDTO.java | 32 +- .../history/dto/HistoryResponseDTO.java | 75 ++++- .../global/common/utils/MinioUploader.java | 49 +++ .../goorm/global/config/MinioConfig.java | 29 ++ .../global/error/code/status/ErrorStatus.java | 27 +- .../error/code/status/SuccessStatus.java | 7 +- src/main/resources/application.yml | 5 + 31 files changed, 748 insertions(+), 64 deletions(-) create mode 100644 src/main/java/study/goorm/domain/history/domain/entity/Follow.java create mode 100644 src/main/java/study/goorm/domain/history/domain/repository/followRepository.java create mode 100644 src/main/java/study/goorm/global/common/utils/MinioUploader.java create mode 100644 src/main/java/study/goorm/global/config/MinioConfig.java diff --git a/.gradle/8.13/checksums/checksums.lock b/.gradle/8.13/checksums/checksums.lock index 3fa8343595de8fb3fb2e4c45d3330b7ca3a67658..a3194972a548d51a7fc6dbf1e6f18809c94f219a 100644 GIT binary patch literal 17 VcmZQRynUyB`kMNS3}C<<4gfro1tS0e literal 17 VcmZQRynUyB`kMNS3}C?Y0RTNI1-k$M diff --git a/.gradle/8.13/checksums/md5-checksums.bin b/.gradle/8.13/checksums/md5-checksums.bin index 877b0477b0cff4a0c0f80cf535844b9b65c0abaa..f47d8b2ef99835c198a23e2e19c8dc0d590c1e95 100644 GIT binary patch delta 2506 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 VumU(eN;oztYY-*C=a7@N=rEK0 z=-IPAG*++y43m}QNt5>EFS9-62?3K{=J1nd=P#4>=a93V=urW)2I^n~vxYZs0<$&n zAOW-eI$#5njrEbU);@;?vo-vI0h6vpFO&WKF|+nXI02KE|1Xn8NBRO8F|i@w7Pp}k G0kQ=Vv~gAd diff --git a/.gradle/8.13/executionHistory/executionHistory.lock b/.gradle/8.13/executionHistory/executionHistory.lock index 4c9a1b74418b9e4503d84078e615c880cb83f828..5c3450092ff34eeac320fcafd1cbe18a27be7ac0 100644 GIT binary patch literal 17 UcmZQRtXo+5@vdep0|cxC05!q{-~a#s literal 17 UcmZQRtXo+5@vdep0|b-+05ymNrT_o{ diff --git a/.gradle/8.13/fileHashes/fileHashes.bin b/.gradle/8.13/fileHashes/fileHashes.bin index 9193126aed419cb8911446e8e31c9a2bec08a927..4c8dcf5855118135056525ffc5c8ed19f9c632c5 100644 GIT binary patch delta 4964 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 aJovJ+(4uP9iU=zm`r{SsPm0{>CjSG8OaFxc delta 3133 zcmZ`*dpwj`AD?H8hSlUUBBRVuZ<0)uT(Y{L%gS{`*2=XAMJe5=S#5YfTZEtMTDLd4 zi+QK4wy5ONWv$YZYOQN(w@9T{^(pUp&UyZt+4uMPoO8Z&p5OO(JGU8pMLi#;YOH5a zJ@O?pM3g+mUOhlG~pQNiDtlR(Hf{1Wx{6T>#)p3AGVpC z0*l#J^4+uds=yS}HE_VxKz`oTivm5fWAb{lEfhGKuZ3dsF?r>JehNy&nXr1{!l{#t zuvogcWX2QvGD|NN`O3AW9M!xx%Wa;+6E_Qt#zEiRVmX?#UChFw-G~M;{lg43W4dWo z94#EKJDvj_V2sUtKKE^igUF%LcuaqKw6ih2?BNAjW3Lx;9xrv?vcZG^Nz!;>IgaP-8c zHbERSC4_PY&4>F8vH(@DEKFSkMP7vJ3T+Isfk`icsHV2rerUkv_J_170f&3@e;^sz z*^^kl&;omJoROUugnJVcK9K8;D`odJ6LAz86)Ke(w&Cu^X8%2JhF+*GdAqcgu^UJj z+$NwT#BL~gVZ0wX@Sc(!dITu;iF z4&Dqp2H!C#7cMgBM|ip(Zyg^n@Wmh&))9~Z2Yj&!o6k^9knQi#&!9};`w>^2u!=zy zu*VPY1pBolG!>z8HhP_+-1BC6nHL#8@Ar9EbVBdz_BJC@w0SnZ|vv?b7L8riI2-iNDu42MK+8{GmK0;HXS-8~mdXc+3~&+g6RqY&2@=|?eNXy| zyyl$8N@E`#7=M9qC%{D-^fA|7uQfG2e;~VYIM`_}Qp&gVjFS;1DguoPYv?NZ+O+sV zub!3e`KrQ2Z%i1*e;LMOWk&d_;-(B6gHEo-b5Gu-tm8P4-s@+P=0emcwlXCk$ALGX z{&&v!%3Hq#8h`a0QpYI;JYE#rfw0Zq`l~be4JbeUXchrYdTb zhWwkrb!>bEEr+u~WP>_EPmtjMtg}Ziq9H-+tRH+z!sTyoNuTRkzbmIlGcVGq3rBRW z`!!Kgzl27Gh0b>FAtan%VH<<) zL1~CU(ynQoqjqWkbeCF5=hetBe6fYrL+gnJojNos_-uG`CpkN|PL|SQo;2@f_XC=N zT=)@&=0UkesF1=%7>0#m#A`Q%GUyQigL1wa51N>^-wN+6CT2$tYsPU ztKml}ltbTa@Z3xv;lXQ=i~zcZgdnG9j7GP?6B_v6H3IzzdS)aaz9OIm5(#LBst6R! z#4-JA&>QiVevv|6!^240v{2~h-vyo91CJSn8)A*^kE|b zhRCe|PRC#;x8OQGYc$dZZ(^G0MCYKl6xYBRMz#v1?~I#xZP_fJ59eIQ2PWO-<2BK_ z;z*qGos?J6ZS|T<%@p8UH1`}q2G9$1$R_oz!{nK>jw7$~rNY24N zQvIWmCjETycPmr2shRbR$Ln%(Tx5Ncf)nYOA}MV|nn`#6IkpbWyUkB-uE-xyDwTBnf@oRrs?z*OySjhA{4G1jALD-Z*ERj zFOEo)n@g+wipSYvtaPN0KDtO|@ldA_Nn%p!km=Kzx?#PErNvblg$%<66IfI3D>KUH zzIzby@()?8FQ-TUT%$Q*^rLHnMgL_mrB_42$?0IRw0GyGGQ*mh0a+H;nxU*fnn)~k zP^Z9fS54E1aN}{S5>iHQr*1)aGJX2`nlOQ-k^t^;^oj3FgFSKLWe8-FFPi^wk}GHb zx!g8B%w=!V)9_DD;gGlZe~8ScgN;awb`V`iVN1-$KUu6429)pdGRO_o8@)X^LI z=w`y+FAxTIIT{t>mGqM7}Sg+w$e1bunM?(H)=4vJo;9@_kSmm&Sf zmo9QWVN5kuX86~oNMjOHv|c>FY1uvT?<9tCoiMnQ3JlQMsZU2$02VvNS_u3|6gg$I G;{O2u*6jKK diff --git a/.gradle/8.13/fileHashes/fileHashes.lock b/.gradle/8.13/fileHashes/fileHashes.lock index 17aa435a0cd1990ab46040607456d83fe5069891..805ecaade630ae1e69a701f66cd92e77bf7aeb87 100644 GIT binary patch literal 17 VcmZR6%*1`2-RO=50~oM(0RSht1E~N2 literal 17 VcmZR6%*1`2-RO=50~oL@0stq=1HJ$N diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index a7d29172914d76620f821d120fbefc962aa3b684..ef3c451f712c70381b309f01126a88d8fa76f2c4 100644 GIT binary patch literal 17 UcmZSfny)7yTG{!G0SuUm041ISoB#j- literal 17 VcmZSfny)7yTG{!G0Sp+A0RScN1MdI; diff --git a/build.gradle b/build.gradle index 86da822..f4c1f54 100644 --- a/build.gradle +++ b/build.gradle @@ -33,6 +33,7 @@ dependencies { runtimeOnly 'com.mysql:mysql-connector-j' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' + implementation 'io.minio:minio:8.5.7' //testImplementation 'org.springframework.security:spring-security-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } diff --git a/src/main/java/study/goorm/domain/cloth/domain/entity/Cloth.java b/src/main/java/study/goorm/domain/cloth/domain/entity/Cloth.java index fd8ad15..2bfe3ae 100644 --- a/src/main/java/study/goorm/domain/cloth/domain/entity/Cloth.java +++ b/src/main/java/study/goorm/domain/cloth/domain/entity/Cloth.java @@ -64,4 +64,9 @@ public class Cloth extends BaseEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id", nullable = false) private Member member; + + //hyowon + public void increaseWearCount(){ + this.wearNum++; + } } \ No newline at end of file diff --git a/src/main/java/study/goorm/domain/history/api/HistoryRestController.java b/src/main/java/study/goorm/domain/history/api/HistoryRestController.java index 579058c..2599774 100644 --- a/src/main/java/study/goorm/domain/history/api/HistoryRestController.java +++ b/src/main/java/study/goorm/domain/history/api/HistoryRestController.java @@ -9,6 +9,7 @@ import org.springframework.http.MediaType; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import study.goorm.domain.history.application.HistoryService; import study.goorm.domain.history.dto.HistoryRequestDTO; import study.goorm.domain.history.dto.HistoryResponseDTO; @@ -16,6 +17,7 @@ import study.goorm.global.error.code.status.SuccessStatus; import java.time.YearMonth; +import java.util.List; @RestController @RequiredArgsConstructor @@ -49,10 +51,11 @@ public BaseResponse getDailyHistoryVi @Operation(summary = "기록을 추가하는 API",description = "request body에 HistoryCreateRequest 형식의 데이터를 전달해주세요.") @ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "HISTORY_201", description = "CREATED, 기록이 성공적으로 추가되었습니다."),}) public BaseResponse createHistory( - @RequestPart("historyCreateRequest")HistoryRequestDTO.HistoryCreateRequest historyCreateRequest + @RequestPart("historyCreateRequest")HistoryRequestDTO.HistoryCreateRequest historyCreateRequest, + @RequestPart("imageFile") List imageFiles ){ - HistoryResponseDTO.HistoryCreateResult result=historyService.createHistory(historyCreateRequest); + HistoryResponseDTO.HistoryCreateResult result=historyService.createHistory(historyCreateRequest,imageFiles); return BaseResponse.onSuccess(SuccessStatus.HISTORY_CREATED,result); } @@ -62,14 +65,16 @@ public BaseResponse createHistory( @Operation(summary = "기록을 수정하는 API",description = "request body에 HistoryUpdateRequest 형식의 데이터를 전달해주세요.") @ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "HISTORY_200", description = "UPDATED, 기록이 성공적으로 수정되었습니다."),}) public BaseResponse updateHistory( - @RequestPart("historyUpdateRequest")HistoryRequestDTO.HistoryUpdateRequest historyUpdateRequest + @Parameter(description = "수정할 기록ID") @PathVariable Long historyId, + @RequestPart("historyUpdateRequest")HistoryRequestDTO.HistoryUpdateRequest historyUpdateRequest, + @RequestPart("imageFile")List imageFiles ){ - HistoryResponseDTO.HistoryUpdateResult result=historyService.updateHistory(historyUpdateRequest); + HistoryResponseDTO.HistoryUpdateResult result=historyService.updateHistory(historyId ,historyUpdateRequest ,imageFiles); return BaseResponse.onSuccess(SuccessStatus.HISTORY_UPDATED,result); } - @DeleteMapping("{history-id}") + @DeleteMapping("/{history-id}") @Operation(summary="특정 기록을 삭제하는 API",description = "path variable로 history_id를 넘겨주세요.") @ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "HISTORY_200", description = "기록이 성공적으로 삭제되었습니다."), @@ -80,11 +85,68 @@ public BaseResponse updateHistory( public BaseResponse deleteHistory( @PathVariable(value = "history-id") Long historyId ) { - historyService.deleteHistory(historyId); - return BaseResponse.onSuccess(SuccessStatus.HISTORY_DELETED, null); } + + @PostMapping("/like") + @Operation(summary="좋아요 누르기 / 취소 기능 API",description = "좋아요 기능입니다.") + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "HISTORY_200", description = "좋아요 상태가 성공적으로 변경되었습니다."), + }) + public BaseResponse likeHistory( + @RequestPart("likeRequest")HistoryRequestDTO.LikeRequest likeRequest + + ){ + HistoryResponseDTO.LikeResult result=historyService.likeHistory(likeRequest); + return BaseResponse.onSuccess(SuccessStatus.LIKE_UPDATED,result); + } + + + + @GetMapping("/{history-id}/likes") + @Operation(summary="특정 게시물에 좋아요를 누른 유저들의 정보를 확인 API",description = "path variable로 history_id를 넘겨주세요.") + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "HISTORY_200", description = "좋아요 상태가 성공적으로 변경되었습니다."), + }) + @Parameters({ + @Parameter(name = "history-id", description = "기록의 id, path variable 입니다.") + }) + public BaseResponse getLikedUsers( + @PathVariable(value = "history-id") Long historyId + ){ + HistoryResponseDTO.LikedUsersResult result=historyService.likedUser(historyId); + return BaseResponse.onSuccess(SuccessStatus.LIKED_USERS_VIEW_SUCCESS, result); + + } + + @PostMapping("/{historyId}/comments") + @Operation(summary="댓글을 작성하는 API",description = "path variable로 history_id를 넘겨주세요.") + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "HISTORY_200", description = "댓글이 성공적으로 추가되었습니다."), + }) + @Parameters({ + @Parameter(name = "history-id", description = "기록의 id, path variable 입니다.") + }) + public BaseResponse postWriteComment( + @PathVariable(value = "history-id") Long historyId, + @RequestPart("likeRequest")HistoryRequestDTO.WriteCommentRequest request + ){ + HistoryResponseDTO.writeCommentResult result=historyService.writeComment(historyId,request); + return BaseResponse.onSuccess(SuccessStatus.COMMENT_CREATED,result); + } + + + + + + + + + + + + } diff --git a/src/main/java/study/goorm/domain/history/application/HistoryService.java b/src/main/java/study/goorm/domain/history/application/HistoryService.java index 63803df..36f09c2 100644 --- a/src/main/java/study/goorm/domain/history/application/HistoryService.java +++ b/src/main/java/study/goorm/domain/history/application/HistoryService.java @@ -1,20 +1,31 @@ package study.goorm.domain.history.application; -import study.goorm.domain.cloth.domain.entity.Cloth; -import study.goorm.domain.history.domain.entity.Hashtag; +import org.springframework.data.domain.Page; +import org.springframework.web.multipart.MultipartFile; import study.goorm.domain.history.dto.HistoryRequestDTO; import study.goorm.domain.history.dto.HistoryResponseDTO; -import study.goorm.domain.model.enums.Visibility; + import java.time.YearMonth; +import java.util.List; public interface HistoryService { HistoryResponseDTO.HistoryDailyViewResult getDailyHistoryView(Long historyId); HistoryResponseDTO.HistoryMonthlyViewResult getMonthlyHistoryView(String clokeyId, YearMonth month); - HistoryResponseDTO.HistoryUpdateResult updateHistory(HistoryRequestDTO.HistoryUpdateRequest historyUpdateResult); + HistoryResponseDTO.HistoryUpdateResult updateHistory(Long historyId,HistoryRequestDTO.HistoryUpdateRequest historyUpdateRequest,List imageFiles); public void deleteHistory(Long historyId); - HistoryResponseDTO.HistoryCreateResult createHistory(HistoryRequestDTO.HistoryCreateRequest historyCreateRequest); + HistoryResponseDTO.HistoryCreateResult createHistory(HistoryRequestDTO.HistoryCreateRequest historyCreateRequest, List imageFiles); + + HistoryResponseDTO.LikeResult likeHistory(HistoryRequestDTO.LikeRequest likeRequest); + + HistoryResponseDTO.LikedUsersResult likedUser(Long historyId); + + HistoryResponseDTO.writeCommentResult writeComment(Long historyId,HistoryRequestDTO.WriteCommentRequest request); + + + + } diff --git a/src/main/java/study/goorm/domain/history/application/HistoryServiceImpl.java b/src/main/java/study/goorm/domain/history/application/HistoryServiceImpl.java index 1b2ba44..04d5422 100644 --- a/src/main/java/study/goorm/domain/history/application/HistoryServiceImpl.java +++ b/src/main/java/study/goorm/domain/history/application/HistoryServiceImpl.java @@ -1,23 +1,26 @@ package study.goorm.domain.history.application; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; import study.goorm.domain.cloth.domain.entity.Cloth; +import study.goorm.domain.cloth.domain.repository.ClothRepository; import study.goorm.domain.history.converter.HistoryConverter; -import study.goorm.domain.history.domain.entity.Hashtag; -import study.goorm.domain.history.domain.entity.History; +import study.goorm.domain.history.domain.entity.*; import study.goorm.domain.history.domain.repository.*; import study.goorm.domain.history.dto.HistoryRequestDTO; import study.goorm.domain.history.dto.HistoryResponseDTO; import study.goorm.domain.history.exception.HistoryException; import study.goorm.domain.member.domain.entity.Member; import study.goorm.domain.member.domain.repository.MemberRepository; -import study.goorm.domain.model.enums.Visibility; +import study.goorm.global.common.utils.MinioUploader; import study.goorm.global.error.code.status.ErrorStatus; import java.time.LocalDate; -import java.time.Year; import java.time.YearMonth; import java.util.List; import java.util.Map; @@ -27,7 +30,6 @@ @RequiredArgsConstructor public class HistoryServiceImpl implements HistoryService { private final HistoryRepository historyRepository; - private final HashtagRepository hashtagRepository; private final CommentRepository commentRepository; private final HistoryClothRepository historyClothRepository; private final HashtagHistoryRepository historyHashtagRepository; @@ -35,6 +37,11 @@ public class HistoryServiceImpl implements HistoryService { private final HistoryImageRepository historyImageRepository; private final MemberRepository memberRepository; private final HistoryImageQueryService historyImageQueryService; + private final ClothRepository clothRepository; + private final HashtagRepository hashtagRepository; + private final MinioUploader minioUploader; + private final MemberLikeRepository memberLikeRepository; + private final followRepository followRepository; @Override @@ -64,7 +71,7 @@ public HistoryResponseDTO.HistoryDailyViewResult getDailyHistoryView(Long histor .orElseThrow(()->new HistoryException(ErrorStatus.NO_SUCH_HISTORY)); //List hashtag와 List clothes 차이 - List hashtag = historyHashtagRepository.findAllByHistory_Id(historyId) + List hashtag = historyHashtagRepository.findAllByHistory_Id(historyId)//n+1발생할것임->fetchjoin hashtagtable같이 조인해서 가져오기 or hashtag repository에 jpql로 로직짜기!! .stream() .map(hc->hc.getHashtag().getName()) .toList(); @@ -82,33 +89,152 @@ public HistoryResponseDTO.HistoryDailyViewResult getDailyHistoryView(Long histor return HistoryConverter.toHistoryDailyViewResult(history,hashtag,clothes,commentCount,liked); } - //매우 어렵다 + //코드참고함 @Override public HistoryResponseDTO.HistoryCreateResult createHistory( - HistoryRequestDTO.HistoryCreateRequest historyCreateResult + HistoryRequestDTO.HistoryCreateRequest historyCreateRequest,List imageFiles ) + { + Member member=memberRepository.findById(1L) + .orElseThrow(()->new HistoryException(ErrorStatus.NO_SUCH_MEMBER)); + LocalDate date; + try{ + date= historyCreateRequest.getDate(); + + } catch(Exception e){ + throw new HistoryException(ErrorStatus.INVALID_HISTORY_DATE_FORTMAT); + } + History history = HistoryConverter.toHistoryEntity(historyCreateRequest, member); + historyRepository.save(history); + + if(imageFiles==null || imageFiles.isEmpty()){ + throw new HistoryException(ErrorStatus.EMPTY_HISTORY_IMAGE); + } + //minioUploader로 나중에 대체하기 + for(MultipartFile imageFile:imageFiles){ + HistoryImage image = HistoryImage.builder() + .history(history) + .imageUrl("지금은 url이 없음") + .build(); + historyImageRepository.save(image); + + } + + List clothIds=historyCreateRequest.getClothes(); + if(clothIds==null || clothIds.isEmpty()){ + throw new HistoryException(ErrorStatus.EMPTY_CLOTH); + } + if(clothIds.size()!= clothIds.stream().distinct().count()){ + throw new HistoryException(ErrorStatus.DUPLICATE_CLOTH); + } + for(Long clothId:clothIds){ + Cloth cloth = clothRepository.findById(clothId) + .orElseThrow(() -> new HistoryException(ErrorStatus.INVALID_CLOTH)); + cloth.increaseWearCount(); + HistoryCloth hc = HistoryCloth.builder(). + history(history) + .cloth(cloth) + .build(); + historyClothRepository.save(hc); + } + + List hashtags=historyCreateRequest.getHashtags(); + if(hashtags==null || hashtags.isEmpty()){ + throw new HistoryException(ErrorStatus.EMPTY_HASHTAGS); + } + if(hashtags.size()!= hashtags.stream().distinct().count()){ + throw new HistoryException(ErrorStatus.DUPLICATE_HASHTAGS); + } + for(String tag:hashtags){ + Hashtag hashtag = hashtagRepository.findByName(tag) + .orElseGet(() -> hashtagRepository.save(Hashtag.builder().name(tag).build())); + HashtagHistory hh = HashtagHistory.builder() + .history(history) + .hashtag(hashtag) + .build(); + hashtagHistoryRepository.save(hh); + + } + - return null; + + return HistoryConverter.toHistoryCreateResult(history); } - //매우 어렵다 + //코드참고함 @Override public HistoryResponseDTO.HistoryUpdateResult updateHistory( - HistoryRequestDTO.HistoryUpdateRequest historyUpdateResult - ) - { -// History history=historyRepository.findById(historyUpdateResult.getHistoryId()) -// .orElseThrow(()->new HistoryException(ErrorStatus.NO_SUCH_HISTORY)); -// History newHistory=History.builder() -// .content(history.getContent()) -// .clothes(cloth.getName()) -// .hashtags(hashtag.getName()) -// .visibility(visibility) -// .build(); -// historyRepository.save(newHistory); -// return HistoryConverter.toHistoryUpdateResult(newHistory); - return null; + Long historyId,HistoryRequestDTO.HistoryUpdateRequest historyUpdateRequest,List imageFiles + ) { + + Member member = memberRepository.findById(1L) + .orElseThrow(() -> new HistoryException(ErrorStatus.NO_SUCH_MEMBER)); + History history = historyRepository.findById(historyId) + .orElseThrow(() -> new HistoryException(ErrorStatus.NO_SUCH_HISTORY)); + + if (!history.getMember().getId().equals(member.getId())) { + throw new HistoryException(ErrorStatus.NO_AUTHORITY_HISTORY); + } + history.updateContent(historyUpdateRequest.getContent()); + if (historyUpdateRequest.getContent() != null + && historyUpdateRequest.getContent().length() > 200) { + throw new HistoryException(ErrorStatus.CONTENT_LENGTH_EXCEEDED); + } + if (imageFiles != null && imageFiles.size() > 10) { + throw new HistoryException(ErrorStatus.TOO_MANY_IMAGES); + } + historyImageRepository.deleteAllByHistoryId(historyId); + +// if(imageFiles!=null && !imageFiles.isEmpty()){ +// for(MultipartFile imageFile:imageFiles){ +// String url=minioUploader.uploadImage(file); +// historyImageRepository.save(HistoryImage.builder() +// .history(history) +// .imageUrl(url) +// .build()); +// } +// } else{ +// throw new HistoryException(ErrorStatus.EMPTY_HISTORY_IMAGE); +// } + + historyClothRepository.deleteAllByHistoryId(historyId); + List clothes = historyUpdateRequest.getClothes(); + if (clothes.size() != clothes.stream().distinct().count()) { + throw new HistoryException(ErrorStatus.DUPLICATE_CLOTH); + } + for (Long clothId : clothes) { + Cloth cloth = clothRepository.findById(clothId) + .orElseThrow(() -> new HistoryException(ErrorStatus.INVALID_CLOTH)); + if (!cloth.getMember().getId().equals(member.getId())) { + throw new HistoryException(ErrorStatus.INVALID_CLOTH); + } + cloth.increaseWearCount(); + historyClothRepository.save(HistoryCloth.builder() + .history(history) + .cloth(cloth) + .build()); + } + + hashtagHistoryRepository.deleteAllByHistoryId(historyId); + List hashtags = historyUpdateRequest.getHashtags(); + if (hashtags != null && !hashtags.isEmpty()) { + if (hashtags.size() != hashtags.stream().distinct().count()) { + throw new HistoryException(ErrorStatus.DUPLICATE_HASHTAGS); + } + for (String tag : hashtags) { + Hashtag hashtag = hashtagRepository.findByName(tag) + .orElseGet(() -> hashtagRepository.save(Hashtag.builder().name(tag).build())); + hashtagHistoryRepository.save(HashtagHistory.builder() + .history(history) + .hashtag(hashtag) + .build()); + } + } + history.updateContent(historyUpdateRequest.getContent()); + + return HistoryConverter.toHistoryUpdateResult(history); + } @Override @@ -121,9 +247,130 @@ public void deleteHistory(Long historyId) { historyClothRepository.deleteAllByHistory(history); historyImageRepository.deleteAllByHistory(history); - historyRepository.delete(history); } + + @Override + @Transactional(readOnly = true) + public HistoryResponseDTO.LikeResult likeHistory(HistoryRequestDTO.LikeRequest likeRequest){ + History history=historyRepository.findById(likeRequest.getHistoryId()) + .orElseThrow(()->new HistoryException(ErrorStatus.NO_SUCH_HISTORY)); + Member member=memberRepository.findById(1L) + .orElseThrow(()->new HistoryException(ErrorStatus.NO_SUCH_MEMBER)); + boolean isLiked=memberLikeRepository.existsByMemberAndHistory(member,history); + + if(likeRequest.isLiked()!=isLiked){ + throw new HistoryException(ErrorStatus.LIKE_STATE_MISMATCH); + } + + if(isLiked){ + MemberLike like=memberLikeRepository.findByMemberAndHistory(member,history) + .orElseThrow(()->new HistoryException(ErrorStatus.LIKE_NOT_FOUND)); + }else{ + MemberLike like=MemberLike.builder() + .member(member) + .history(history) + .build(); + memberLikeRepository.save(like); + history.setLikes(history.getLikes()+1); + } + + Long likeCount=memberLikeRepository.countByHistory(history); + boolean newState=!isLiked; + + + return HistoryConverter.toHistoryLikeResult(history,newState,likeCount); + + } + + + + @Override + @Transactional(readOnly = true) + public HistoryResponseDTO.LikedUsersResult likedUser(Long historyId){ + History history=historyRepository.findById(historyId) + .orElseThrow(()->new HistoryException(ErrorStatus.NO_SUCH_HISTORY)); + //실제 로그인한 1L대신 사용자id로 써야할것 + Member member=memberRepository.findById(1L) + .orElseThrow(()->new HistoryException(ErrorStatus.NO_SUCH_MEMBER)); + + List likes = memberLikeRepository.findAllByHistory(history); + + //코드 참고 + List likedUsers=likes.stream() + .map(like->{ + Member likedMember=like.getMember(); + boolean isFollowing = followRepository.existsByFollowerAndFollowing(member, likedMember); + boolean me=likedMember.getId().equals(member.getId()); + + return HistoryResponseDTO.LikedUser.builder() + .memberId(likedMember.getId()) + .nickName(likedMember.getNickname()) + .imageUrl(likedMember.getProfileImageUrl()) + .followStatus(isFollowing) + .me(me) + .clokeyId(likedMember.getClokeyId()) + .build(); + }) + .toList(); + + return HistoryConverter.toLikedUsersResult(likedUsers); + + } + + + + @Override + @Transactional(readOnly = true) + public HistoryResponseDTO.writeCommentResult writeComment( + Long historyId,HistoryRequestDTO.WriteCommentRequest request + ){ + + History history=historyRepository.findById(historyId) + .orElseThrow(()->new HistoryException(ErrorStatus.NO_SUCH_HISTORY)); + + Member member=memberRepository.findById(1L) + .orElseThrow(()->new HistoryException(ErrorStatus.NO_SUCH_MEMBER)); + + + String content=request.getContent(); + if(content==null || content.isEmpty()){ + throw new HistoryException(ErrorStatus.COMMENT_CONTENT_EMPTY); + } + if(content.length()>50){ + throw new HistoryException(ErrorStatus.COMMENT_CONTENT_TOO_LONG); + } + + Comment newComment=Comment.builder() + .content(content) + .history(history) + .member(member) + .history(history) + .build(); + commentRepository.save(newComment); + return HistoryConverter.toHistoryWriteCommentResult(newComment); + + } + + + + + + + + + + + + + + + + + + + + } diff --git a/src/main/java/study/goorm/domain/history/converter/HistoryConverter.java b/src/main/java/study/goorm/domain/history/converter/HistoryConverter.java index f931a04..619d6de 100644 --- a/src/main/java/study/goorm/domain/history/converter/HistoryConverter.java +++ b/src/main/java/study/goorm/domain/history/converter/HistoryConverter.java @@ -1,8 +1,8 @@ package study.goorm.domain.history.converter; -import study.goorm.domain.cloth.domain.entity.Cloth; + +import study.goorm.domain.history.domain.entity.Comment; import study.goorm.domain.history.domain.entity.History; -import study.goorm.domain.history.domain.entity.Hashtag; import study.goorm.domain.history.dto.HistoryRequestDTO; import study.goorm.domain.history.dto.HistoryResponseDTO; import study.goorm.domain.member.domain.entity.Member; @@ -55,14 +55,14 @@ public static HistoryResponseDTO.HistoryDailyViewResult toHistoryDailyViewResult } - public static HistoryRequestDTO.HistoryCreateRequest toHistoryCreateRequest( - History history,List clothes, List hashtags - ) { - return HistoryRequestDTO.HistoryCreateRequest.builder() - .content(history.getContent()) - .clothes(clothes) - .hashtags(hashtags) - .date(history.getHistoryDate().toString()) + + //코드 참고 + public static History toHistoryEntity(HistoryRequestDTO.HistoryCreateRequest historyRequestDTO,Member member) { + return History.builder() + .member(member) + .historyDate(historyRequestDTO.getDate()) + .likes(0) + .content(historyRequestDTO.getContent()) .build(); } @@ -75,22 +75,96 @@ public static HistoryResponseDTO.HistoryCreateResult toHistoryCreateResult( .build(); } - public static HistoryRequestDTO.HistoryUpdateRequest toHistoryUpdateRequest(History history) { - return HistoryRequestDTO.HistoryUpdateRequest.builder() + + + public static HistoryResponseDTO.HistoryUpdateResult toHistoryUpdateResult(History history){ + return HistoryResponseDTO.HistoryUpdateResult.builder() .historyId(history.getId()) .build(); } - public static HistoryResponseDTO.HistoryUpdateResult toHistoryUpdateResult( + //안쓰이나 남겨둠 + public static HistoryRequestDTO.HistoryCreateRequest toHistoryCreateRequest( + History history,List clothes, List hashtags + ) { + return HistoryRequestDTO.HistoryCreateRequest.builder() + .content(history.getContent()) + .clothes(clothes) + .hashtags(hashtags) + .date(history.getHistoryDate()) + .build(); + } + + + //안쓰이나 남겨둠 + public static HistoryRequestDTO.HistoryUpdateRequest toHistoryUpdateRequest( History history, List clothes, List hashtags, Visibility visibility) { - return HistoryResponseDTO.HistoryUpdateResult.builder() + return HistoryRequestDTO.HistoryUpdateRequest.builder() .content(history.getContent()) .clothes(clothes) .hashtags(hashtags) - .visibility(visibility) + .visibility(visibility.toString()) + .build(); + } + + public static HistoryResponseDTO.LikeResult toHistoryLikeResult( + History history,boolean newState, Long likeCount + + ){ + return HistoryResponseDTO.LikeResult.builder() + .historyId(history.getId()) + .isLiked(newState) + .likeCount(likeCount) + .build(); + + } + + public static HistoryResponseDTO.LikedUser toHistoryLikedUser( + Member member, boolean me, boolean followStatus + ){ + return HistoryResponseDTO.LikedUser.builder() + .memberId(member.getId()) + .clokeyId(member.getClokeyId()) + .nickName(member.getNickname()) + .imageUrl(member.getProfileImageUrl()) + .me(me) + .followStatus(followStatus) + .build(); + + } + + public static HistoryResponseDTO.LikedUsersResult toLikedUsersResult( + List likedUsers + ){ + + return HistoryResponseDTO.LikedUsersResult.builder() + .likedUsers(likedUsers) + .build(); + + } + + + public static HistoryResponseDTO.writeCommentResult toHistoryWriteCommentResult( + Comment comment + ){ + return HistoryResponseDTO.writeCommentResult.builder() + .commentId(comment.getId()) .build(); } + + + + + + + + + + + + + } diff --git a/src/main/java/study/goorm/domain/history/domain/entity/Follow.java b/src/main/java/study/goorm/domain/history/domain/entity/Follow.java new file mode 100644 index 0000000..94d0115 --- /dev/null +++ b/src/main/java/study/goorm/domain/history/domain/entity/Follow.java @@ -0,0 +1,16 @@ +package study.goorm.domain.history.domain.entity; + +import jakarta.persistence.*; +import study.goorm.domain.member.domain.entity.Member; + +@Entity +public class Follow { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + @ManyToOne + private Member follower; + + @ManyToOne + private Member following; +} diff --git a/src/main/java/study/goorm/domain/history/domain/entity/History.java b/src/main/java/study/goorm/domain/history/domain/entity/History.java index 2667b0c..422c541 100644 --- a/src/main/java/study/goorm/domain/history/domain/entity/History.java +++ b/src/main/java/study/goorm/domain/history/domain/entity/History.java @@ -37,4 +37,12 @@ public class History extends BaseEntity { @JoinColumn(name = "member_id", nullable = false) private Member member; + public void updateContent(String content) { + this.content = content; + } + + public void setLikes(int likes) { + this.likes = likes; + } + } diff --git a/src/main/java/study/goorm/domain/history/domain/entity/HistoryImage.java b/src/main/java/study/goorm/domain/history/domain/entity/HistoryImage.java index 93aec04..ebcba89 100644 --- a/src/main/java/study/goorm/domain/history/domain/entity/HistoryImage.java +++ b/src/main/java/study/goorm/domain/history/domain/entity/HistoryImage.java @@ -15,7 +15,7 @@ public class HistoryImage extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(nullable = false, unique = true) + @Column(nullable = false, unique = true,length=1000) private String imageUrl; @ManyToOne(fetch = FetchType.LAZY) diff --git a/src/main/java/study/goorm/domain/history/domain/repository/CommentRepository.java b/src/main/java/study/goorm/domain/history/domain/repository/CommentRepository.java index 4f98b16..f6c662a 100644 --- a/src/main/java/study/goorm/domain/history/domain/repository/CommentRepository.java +++ b/src/main/java/study/goorm/domain/history/domain/repository/CommentRepository.java @@ -1,9 +1,18 @@ package study.goorm.domain.history.domain.repository; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import study.goorm.domain.history.domain.entity.Comment; import study.goorm.domain.history.domain.entity.History; +import java.util.List; + public interface CommentRepository extends JpaRepository { int countByHistory(History history); + + + + + } diff --git a/src/main/java/study/goorm/domain/history/domain/repository/HashtagHistoryRepository.java b/src/main/java/study/goorm/domain/history/domain/repository/HashtagHistoryRepository.java index 1e608bb..79f849c 100644 --- a/src/main/java/study/goorm/domain/history/domain/repository/HashtagHistoryRepository.java +++ b/src/main/java/study/goorm/domain/history/domain/repository/HashtagHistoryRepository.java @@ -10,4 +10,5 @@ public interface HashtagHistoryRepository extends JpaRepository findAllByHistory_Id(Long historyId); void deleteAllByHistory(History history); + void deleteAllByHistoryId(Long historyId); } diff --git a/src/main/java/study/goorm/domain/history/domain/repository/HashtagRepository.java b/src/main/java/study/goorm/domain/history/domain/repository/HashtagRepository.java index d149c62..d37eaed 100644 --- a/src/main/java/study/goorm/domain/history/domain/repository/HashtagRepository.java +++ b/src/main/java/study/goorm/domain/history/domain/repository/HashtagRepository.java @@ -3,5 +3,8 @@ import org.springframework.data.jpa.repository.JpaRepository; import study.goorm.domain.history.domain.entity.Hashtag; +import java.util.Optional; + public interface HashtagRepository extends JpaRepository { + Optional findByName(String name); } diff --git a/src/main/java/study/goorm/domain/history/domain/repository/HistoryClothRepository.java b/src/main/java/study/goorm/domain/history/domain/repository/HistoryClothRepository.java index 7fa3aef..44c5799 100644 --- a/src/main/java/study/goorm/domain/history/domain/repository/HistoryClothRepository.java +++ b/src/main/java/study/goorm/domain/history/domain/repository/HistoryClothRepository.java @@ -16,4 +16,6 @@ public interface HistoryClothRepository extends JpaRepository findAllByHistory(History history); void deleteAllByHistory(History history); + + void deleteAllByHistoryId(Long historyId); } diff --git a/src/main/java/study/goorm/domain/history/domain/repository/HistoryImageRepository.java b/src/main/java/study/goorm/domain/history/domain/repository/HistoryImageRepository.java index 09b6317..8da7c8b 100644 --- a/src/main/java/study/goorm/domain/history/domain/repository/HistoryImageRepository.java +++ b/src/main/java/study/goorm/domain/history/domain/repository/HistoryImageRepository.java @@ -26,6 +26,7 @@ SELECT MIN(hi2.id) ) """) List findFirstImagesByHistoryIds(@Param("historyIds") List historyIds); + void deleteAllByHistoryId(Long historyId); } diff --git a/src/main/java/study/goorm/domain/history/domain/repository/HistoryRepository.java b/src/main/java/study/goorm/domain/history/domain/repository/HistoryRepository.java index ff92152..ccd486b 100644 --- a/src/main/java/study/goorm/domain/history/domain/repository/HistoryRepository.java +++ b/src/main/java/study/goorm/domain/history/domain/repository/HistoryRepository.java @@ -1,14 +1,33 @@ package study.goorm.domain.history.domain.repository; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; import study.goorm.domain.history.domain.entity.History; +import study.goorm.domain.history.dto.HistoryResponseDTO; +import java.awt.print.Pageable; import java.time.LocalDate; import java.time.YearMonth; import java.util.List; +import java.util.Optional; public interface HistoryRepository extends JpaRepository { - //List findByClokeyIdAndMonth(String Id, YearMonth month); + List findByMemberIdAndHistoryDateBetween(Long memberId, LocalDate historyDateAfter, LocalDate historyDateBefore); + + @Query("SELECT h FROM History h JOIN FETCH h.member WHERE h.id=:historyId") + Optional findByIdWithMember(@Param("historyId") Long historyId); + + + + + + + + + + } diff --git a/src/main/java/study/goorm/domain/history/domain/repository/MemberLikeRepository.java b/src/main/java/study/goorm/domain/history/domain/repository/MemberLikeRepository.java index b9f1634..6845bb8 100644 --- a/src/main/java/study/goorm/domain/history/domain/repository/MemberLikeRepository.java +++ b/src/main/java/study/goorm/domain/history/domain/repository/MemberLikeRepository.java @@ -1,7 +1,19 @@ package study.goorm.domain.history.domain.repository; import org.springframework.data.jpa.repository.JpaRepository; +import study.goorm.domain.history.domain.entity.History; import study.goorm.domain.history.domain.entity.MemberLike; +import study.goorm.domain.member.domain.entity.Member; + +import java.util.List; +import java.util.Optional; public interface MemberLikeRepository extends JpaRepository { + boolean existsByMemberAndHistory(Member member, History history); + Optional findByMemberAndHistory(Member member, History history); + Long countByHistory(History history); + + List findAllByHistoryId(Long historyId); + + List findAllByHistory(History history); } diff --git a/src/main/java/study/goorm/domain/history/domain/repository/followRepository.java b/src/main/java/study/goorm/domain/history/domain/repository/followRepository.java new file mode 100644 index 0000000..93d5197 --- /dev/null +++ b/src/main/java/study/goorm/domain/history/domain/repository/followRepository.java @@ -0,0 +1,9 @@ +package study.goorm.domain.history.domain.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import study.goorm.domain.history.domain.entity.Follow; +import study.goorm.domain.member.domain.entity.Member; + +public interface followRepository extends JpaRepository { + boolean existsByFollowerAndFollowing(Member follower, Member following); +} diff --git a/src/main/java/study/goorm/domain/history/dto/HistoryRequestDTO.java b/src/main/java/study/goorm/domain/history/dto/HistoryRequestDTO.java index 0f2f65b..3c7a017 100644 --- a/src/main/java/study/goorm/domain/history/dto/HistoryRequestDTO.java +++ b/src/main/java/study/goorm/domain/history/dto/HistoryRequestDTO.java @@ -5,6 +5,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; +import java.time.LocalDate; import java.util.List; @@ -15,7 +16,10 @@ public class HistoryRequestDTO { @NoArgsConstructor @AllArgsConstructor public static class HistoryUpdateRequest{ - private Long historyId; + private String content; + private List clothes; + private List hashtags; + private String visibility; } @Builder @@ -26,8 +30,32 @@ public static class HistoryCreateRequest{ private String content; private List clothes; private List hashtags; - private String date; + private LocalDate date; + } + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class LikeRequest{ + private Long historyId; + private boolean liked; + } + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class WriteCommentRequest{ + private String content; + private Long commentId; + } + + + + + } diff --git a/src/main/java/study/goorm/domain/history/dto/HistoryResponseDTO.java b/src/main/java/study/goorm/domain/history/dto/HistoryResponseDTO.java index c29c1b1..7a13c22 100644 --- a/src/main/java/study/goorm/domain/history/dto/HistoryResponseDTO.java +++ b/src/main/java/study/goorm/domain/history/dto/HistoryResponseDTO.java @@ -1,15 +1,15 @@ package study.goorm.domain.history.dto; - import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import study.goorm.domain.cloth.domain.entity.ClothImage; -import study.goorm.domain.history.domain.entity.History; -import study.goorm.domain.model.enums.Visibility; + + import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.List; public class HistoryResponseDTO { @@ -72,11 +72,74 @@ public static class HistoryCreateResult{ @NoArgsConstructor @AllArgsConstructor public static class HistoryUpdateResult{ + private Long historyId; + + } + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class LikeResult{ + private Long historyId; + private boolean isLiked; + private long likeCount; + } + + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class LikedUser{ + private Long memberId; + private String clokeyId; + private String nickName; + private boolean followStatus; + private String imageUrl; + private Boolean me; + + } + + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class LikedUsersResult{ + private List likedUsers; + } + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class writeCommentResult{ + private Long commentId; + } + + @Builder + @Getter + @AllArgsConstructor + @NoArgsConstructor + public static class HistoryCommentProjectionDTO { + private Long commentId; private String content; - private List clothes; - private List hashtags; - private Visibility visibility; + private boolean isRoot; + private Long parentId; + private String clokeyId; + private String nickname; + private String profileImageUrl; + private LocalDateTime createdAt; } + + + + + + + + } diff --git a/src/main/java/study/goorm/global/common/utils/MinioUploader.java b/src/main/java/study/goorm/global/common/utils/MinioUploader.java new file mode 100644 index 0000000..6125f47 --- /dev/null +++ b/src/main/java/study/goorm/global/common/utils/MinioUploader.java @@ -0,0 +1,49 @@ +package study.goorm.global.common.utils; + +import lombok.RequiredArgsConstructor; +import lombok.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import java.util.UUID; + +@Component +@RequiredArgsConstructor +public class MinioUploader { + +// private final MinioClient minioClient; +// +// @Value("${minio.bucket}") +// private String bucket; +// +// public String uploadImage(MultipartFile file) { +// String objectName= UUID.randomUUID() + "_" + file.getOriginalFilename(); +// +// try{ +// minioClient.putObject( +// putObjectArgs.builder() +// .bucket(bucket) +// .object(objectName) +// .stream(file.getInputStream(),file.getSize(),-1) +// .contentType(file.getContentType) +// .build() +// ); +// return minioClient.getPresignedObjectUrl( +// GetPresignObjectUrlArgs.builder() +// .method(Method.GET) +// .bucket(bucket) +// .object(objectName) +// .expire(60*30) +// .build() +// ); +// +// +// +// }catch(Exception e) +// { +// throw new RuntimeException("MiniO 이미지 업로드 실패",e); +// +// } +// +// } +} diff --git a/src/main/java/study/goorm/global/config/MinioConfig.java b/src/main/java/study/goorm/global/config/MinioConfig.java new file mode 100644 index 0000000..3348d4c --- /dev/null +++ b/src/main/java/study/goorm/global/config/MinioConfig.java @@ -0,0 +1,29 @@ +package study.goorm.global.config; + +import lombok.Getter; +import lombok.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@Getter +public class MinioConfig { + +// @Value("${minio.url}") +// private String url; +// +// @Value("${minio.url}") +// private String accessKey; +// +// @Value("${minio.url}") +// private String secretKey; +// +// @Bean +// public MinioClient minioClient(){ +// return MinioClient.builder() +// .endpoint(url) +// .credentials(accessKey,secretKey) +// .build(); +// } + +} diff --git a/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java b/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java index b79c9cd..0be17da 100644 --- a/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java +++ b/src/main/java/study/goorm/global/error/code/status/ErrorStatus.java @@ -36,9 +36,34 @@ public enum ErrorStatus implements BaseErrorCode { //History NO_SUCH_HISTORY(HttpStatus.NOT_FOUND, "HISTORY_4002","존재하지 않는 기록ID입니다"), + //hyowon + INVALID_HISTORY_DATE_FORTMAT(HttpStatus.BAD_REQUEST,"HISTORY_4001","잘못된 날짜 형식입니다."), + EMPTY_HISTORY_IMAGE(HttpStatus.BAD_REQUEST,"HISTORY_4004","기록의 이미지는 필수입니다."), + EMPTY_CLOTH(HttpStatus.BAD_REQUEST,"CLOTH_4005","등록할 옷이 비어있습니다."), + DUPLICATE_CLOTH(HttpStatus.BAD_REQUEST,"CLOTH_4006","중복되는 옷이 있습니다."), + INVALID_CLOTH(HttpStatus.BAD_REQUEST,"CLOTH_4007","존재하지 않거나 소유하지 않은 옷id입니다."), NO_AUTHORITY_HISTORY(HttpStatus.FORBIDDEN,"HISTORY_4006","기록에 접근 권한이 없습니다."), - NO_SUCH_HISTORY_MEMBER(HttpStatus.BAD_REQUEST,"MEMBER_4001","존재하지 않는 ID멤버입니다."); + NO_SUCH_HISTORY_MEMBER(HttpStatus.BAD_REQUEST,"MEMBER_4001","존재하지 않는 ID멤버입니다."), + CONTENT_LENGTH_EXCEEDED(HttpStatus.BAD_REQUEST,"HISTORY_4007","내용은 200자 초과 불과합니다"), + TOO_MANY_IMAGES(HttpStatus.BAD_REQUEST,"HISTORY_4008","이미지는 최대 10장까지만 업로드할 수 있습니다."), + + + //Like + LIKE_STATE_MISMATCH(HttpStatus.BAD_REQUEST,"LIKE_4001","유효하지 않은 좋아요상태입니다"), + LIKE_NOT_FOUND(HttpStatus.BAD_REQUEST,"LIKE_4002","Like를 찾지 못했습니다."), + + //HASHTAG + EMPTY_HASHTAGS(HttpStatus.BAD_REQUEST,"HASHTAG_4001","해쉬태그가 없습니다."), + DUPLICATE_HASHTAGS(HttpStatus.BAD_REQUEST,"HASHTAG_4002","중복되는 해시태그가 있습니다."), + + + COMMENT_CONTENT_EMPTY(HttpStatus.BAD_REQUEST,"COMMENT_4001","댓글이 비어있습니다."), + COMMENT_CONTENT_TOO_LONG(HttpStatus.BAD_REQUEST,"COMMENT_4002","댓글 글자수 초과입니다."), + ; + + + private final HttpStatus httpStatus; diff --git a/src/main/java/study/goorm/global/error/code/status/SuccessStatus.java b/src/main/java/study/goorm/global/error/code/status/SuccessStatus.java index cb192b4..38a691b 100644 --- a/src/main/java/study/goorm/global/error/code/status/SuccessStatus.java +++ b/src/main/java/study/goorm/global/error/code/status/SuccessStatus.java @@ -26,7 +26,12 @@ public enum SuccessStatus implements BaseCode { HISTORY_UPDATED(HttpStatus.OK,"HISTORY_200","기록이 성공적으로 수정되었습니다."), HISTORY_CREATED(HttpStatus.OK,"HISTORY_201","기록이 성공적으로 추가되었습니다."), - HISTORY_DELETED(HttpStatus.NO_CONTENT,"HISTORY_200","기록이 성공적으로 삭제되었습니다."); + HISTORY_DELETED(HttpStatus.NO_CONTENT,"HISTORY_200","기록이 성공적으로 삭제되었습니다."), + LIKE_UPDATED(HttpStatus.OK,"LIKE_200","좋아요가 성공적으로 수정되었습니다"), + LIKED_USERS_VIEW_SUCCESS(HttpStatus.OK,"LIKE_201","좋아요 누른 유저들 성공적으로 확인되었습니다."), + + COMMENT_CREATED(HttpStatus.OK,"COMMENT_201","댓글이 성공적으로 추가되었습니다"),; + private final HttpStatus httpStatus; diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 252c411..305fc74 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -26,3 +26,8 @@ logging: org.hibernate.SQL: DEBUG org.hibernate.type.descriptor.sql.BasicBinder: TRACE org.springframework.jdbc.core: DEBUG +#minio: +# url:http://localhost:9000 +# access-key: +# secret-key: +# bucket: