diff --git a/module-api/src/docs/asciidoc/index.adoc b/module-api/src/docs/asciidoc/index.adoc index e1dddb94..c744ccd4 100644 --- a/module-api/src/docs/asciidoc/index.adoc +++ b/module-api/src/docs/asciidoc/index.adoc @@ -7,5 +7,6 @@ :sectlinks: include::overview.adoc[] -include::sample-api.adoc[] -// FIXME :: 위 라인 1줄은 추후 삭제 예정입니다 \ No newline at end of file +// include::sample-api.adoc[] +include::main-api.adoc[] + diff --git a/module-api/src/docs/asciidoc/main-api.adoc b/module-api/src/docs/asciidoc/main-api.adoc new file mode 100644 index 00000000..88986823 --- /dev/null +++ b/module-api/src/docs/asciidoc/main-api.adoc @@ -0,0 +1,41 @@ +== Main API + +// [[]] 안에는 a 태그 이름 들어갑니다 (http://localhost:8080/docs/index#공통코드-조회) +[[Banner-조회]] +=== Banner 조회 + +===== HTTP Request +include::{snippets}/banner/get-banner/http-request.adoc[] + +==== Response +include::{snippets}/banner/get-banner/response-fields-value.adoc[] + +===== HTTP Response 예시 +include::{snippets}/banner/get-banner/http-response.adoc[] + + +[[Recommend-Product-조회]] +=== Recommend-Product-조회 + +===== HTTP Request +include::{snippets}/recommend-products/get-recommend-products/http-request.adoc[] + +==== Response +include::{snippets}/recommend-products/get-recommend-products/response-fields.adoc[] + +===== HTTP Response 예시 +include::{snippets}/recommend-products/get-recommend-products/http-response.adoc[] + + +[[Products-rank-최신순]] +== Products-rank-최신순 + +===== HTTP Request +include::{snippets}/products/get-products-view-count-order/http-request.adoc[] + +===== Response +include::{snippets}/products/get-products-view-count-order/response-fields.adoc[] + +===== HTTP Response 예시 +include::{snippets}/products/get-products-view-count-order/http-response.adoc[] + diff --git a/module-api/src/main/java/com/kernel360/commoncode/controller/CommonCodeController.java b/module-api/src/main/java/com/kernel360/commoncode/controller/CommonCodeController.java index 9c115a17..0f91dc38 100644 --- a/module-api/src/main/java/com/kernel360/commoncode/controller/CommonCodeController.java +++ b/module-api/src/main/java/com/kernel360/commoncode/controller/CommonCodeController.java @@ -4,7 +4,6 @@ import com.kernel360.commoncode.dto.CommonCodeDto; import com.kernel360.response.ApiResponse; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; diff --git a/module-api/src/main/java/com/kernel360/global/Interceptor/InterceptorConfig.java b/module-api/src/main/java/com/kernel360/global/Interceptor/InterceptorConfig.java index da531eae..818980a1 100644 --- a/module-api/src/main/java/com/kernel360/global/Interceptor/InterceptorConfig.java +++ b/module-api/src/main/java/com/kernel360/global/Interceptor/InterceptorConfig.java @@ -14,6 +14,7 @@ public class InterceptorConfig implements WebMvcConfigurer { public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(acceptInterceptor) .addPathPatterns("/member/testJwt"); +// .addPathPatterns("/mypage/**"); //.excludePathPatterns("/public/**"); // 제외할 URL 패턴 } diff --git a/module-api/src/main/java/com/kernel360/main/code/ConverterErrorCode.java b/module-api/src/main/java/com/kernel360/main/code/ConverterErrorCode.java new file mode 100644 index 00000000..b857fc22 --- /dev/null +++ b/module-api/src/main/java/com/kernel360/main/code/ConverterErrorCode.java @@ -0,0 +1,34 @@ +package com.kernel360.main.code; + +import com.kernel360.code.ErrorCode; +import org.springframework.http.HttpStatus; + +public enum ConverterErrorCode implements ErrorCode { + + NOT_FOUND_CONVERTER(HttpStatus.BAD_REQUEST.value(), "CMB001", "적절한 조회타입이 존재하지 않습니다."); + + private final int status; + private final String code; + private final String message; + + ConverterErrorCode(int status, String code, String message) { + this.status = status; + this.code = code; + this.message = message; + } + + @Override + public int getStatus() { + return status; + } + + @Override + public String getCode() { + return code; + } + + @Override + public String getMessage() { + return message; + } + } diff --git a/module-api/src/main/java/com/kernel360/main/config/WebConfig.java b/module-api/src/main/java/com/kernel360/main/config/WebConfig.java new file mode 100644 index 00000000..78413a41 --- /dev/null +++ b/module-api/src/main/java/com/kernel360/main/config/WebConfig.java @@ -0,0 +1,15 @@ +package com.kernel360.main.config; + +import com.kernel360.main.conveter.StringToSortConverter; +import org.springframework.context.annotation.Configuration; +import org.springframework.format.FormatterRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebConfig implements WebMvcConfigurer { + + @Override + public void addFormatters(FormatterRegistry registry) { + registry.addConverter(new StringToSortConverter()); + } +} diff --git a/module-api/src/main/java/com/kernel360/main/controller/MainContoller.java b/module-api/src/main/java/com/kernel360/main/controller/MainContoller.java index 4b324f36..859be2c3 100644 --- a/module-api/src/main/java/com/kernel360/main/controller/MainContoller.java +++ b/module-api/src/main/java/com/kernel360/main/controller/MainContoller.java @@ -20,22 +20,23 @@ @RequiredArgsConstructor public class MainContoller { private final ProductService productService; + private final MainService mainService; @GetMapping("/banner") ResponseEntity> getBanner() { - return ApiResponse.toResponseEntity(BannerBusinessCode.GET_BANNER_DATA_SUCCESS, MainService.getSampleBanner()); + return ApiResponse.toResponseEntity(BannerBusinessCode.GET_BANNER_DATA_SUCCESS, mainService.getSampleBanner()); } - @GetMapping("/recommend_products") + @GetMapping("/recommend-products") ResponseEntity>> getRecommendProducts() { List recommendProductList = productService.getRecommendProductList(); return ApiResponse.toResponseEntity(ProductsBusinessCode.GET_RECOMMEND_PRODUCT_DATA_SUCCESS, recommendProductList); } - @GetMapping("/products/") - ResponseEntity>> getProducts(@RequestParam(name ="sortType", defaultValue = "viewCnt_order") Sort sortType){ + @GetMapping("/products/rank") + ResponseEntity>> getProducts(@RequestParam(name ="sortType", defaultValue = "viewCnt-order") Sort sortType){ List productDtos = sortType.sort(productService); return ApiResponse.toResponseEntity(ProductsBusinessCode.GET_PRODUCT_DATA_SUCCESS, productDtos); diff --git a/module-api/src/main/java/com/kernel360/main/controller/Sort.java b/module-api/src/main/java/com/kernel360/main/controller/Sort.java index 226c1a6e..9e3df48a 100644 --- a/module-api/src/main/java/com/kernel360/main/controller/Sort.java +++ b/module-api/src/main/java/com/kernel360/main/controller/Sort.java @@ -7,21 +7,21 @@ public enum Sort { - VIEW_COUNT_PRODUCT_ORDER("viewCnt_order") { + VIEW_COUNT_PRODUCT_ORDER("viewCnt-order") { @Override List sort(ProductService productService) { return productService.getProductListOrderByViewCount(); } }, - SAFE_PRODUCT_LIST("violation_product") { + VIOLATION_PRODUCT_LIST("violation-products") { @Override List sort(ProductService productService) { return productService.getViolationProducts(); } }, - RECOMMENDATION_PRODUCT_ORDER("recommend_order") { + RECOMMENDATION_PRODUCT_ORDER("recommend-order") { @Override List sort(ProductService productService) { //Fixme :: 향후 Like Table 구현후, 정렬메소드 변경이 필요합니다.(임시로 violationProduct 리턴으로 구현) @@ -29,7 +29,7 @@ List sort(ProductService productService) { return productService.getViolationProducts(); } }, - RECENT_PRODUCT_ORDER("recent_order") { + RECENT_PRODUCT_ORDER("recent-order") { @Override List sort(ProductService productService) { @@ -43,5 +43,9 @@ List sort(ProductService productService) { this.orderType = orderType; } + public String getOrderType() { + return orderType; + } + abstract List sort(ProductService productService); } diff --git a/module-api/src/main/java/com/kernel360/main/conveter/StringToSortConverter.java b/module-api/src/main/java/com/kernel360/main/conveter/StringToSortConverter.java new file mode 100644 index 00000000..956cb688 --- /dev/null +++ b/module-api/src/main/java/com/kernel360/main/conveter/StringToSortConverter.java @@ -0,0 +1,21 @@ +package com.kernel360.main.conveter; + +import com.kernel360.exception.BusinessException; +import com.kernel360.main.code.ConverterErrorCode; +import com.kernel360.main.controller.Sort; +import org.springframework.core.convert.converter.Converter; +import org.springframework.stereotype.Component; + +@Component +public class StringToSortConverter implements Converter { + + @Override + public Sort convert(String source) { + for (Sort sort : Sort.values()) { + if (sort.getOrderType().equalsIgnoreCase(source)) { + return sort; + } + } + throw new BusinessException(ConverterErrorCode.NOT_FOUND_CONVERTER); + } +} diff --git a/module-api/src/main/java/com/kernel360/main/dto/BannerDto.java b/module-api/src/main/java/com/kernel360/main/dto/BannerDto.java index 5ead983e..42496227 100644 --- a/module-api/src/main/java/com/kernel360/main/dto/BannerDto.java +++ b/module-api/src/main/java/com/kernel360/main/dto/BannerDto.java @@ -2,7 +2,7 @@ public record BannerDto ( Long id, - String src, + String image, String alt ) { public static BannerDto of( diff --git a/module-api/src/main/java/com/kernel360/main/service/MainService.java b/module-api/src/main/java/com/kernel360/main/service/MainService.java index a19fb53a..072ea0fc 100644 --- a/module-api/src/main/java/com/kernel360/main/service/MainService.java +++ b/module-api/src/main/java/com/kernel360/main/service/MainService.java @@ -7,10 +7,8 @@ public class MainService { - public static BannerDto getSampleBanner() { - - return BannerDto.of(1L, - "classpath:static/bannerSample.png", - "Banner Image"); + public BannerDto getSampleBanner() { + return BannerDto.of(1L, "classpath:static/bannerSample.png", "Banner Image"); } + } diff --git a/module-api/src/main/java/com/kernel360/member/code/MemberBusinessCode.java b/module-api/src/main/java/com/kernel360/member/code/MemberBusinessCode.java index bf23b5f8..5862d7cc 100644 --- a/module-api/src/main/java/com/kernel360/member/code/MemberBusinessCode.java +++ b/module-api/src/main/java/com/kernel360/member/code/MemberBusinessCode.java @@ -8,7 +8,12 @@ public enum MemberBusinessCode implements BusinessCode { SUCCESS_REQUEST_JOIN_MEMBER_CREATED(HttpStatus.CREATED.value(), "BMC001", "회원가입 성공"), - SUCCESS_REQUEST_LOGIN_MEMBER(HttpStatus.OK.value(), "BMC002", "로그인 성공"); + SUCCESS_REQUEST_LOGIN_MEMBER(HttpStatus.OK.value(), "BMC002", "로그인 성공"), + SUCCESS_FIND_REQUEST_MEMBER(HttpStatus.OK.value(), "BMC003", "회원 조회 성공"), + SUCCESS_FIND_CAR_INFO_IN_MEMBER(HttpStatus.OK.value(), "BMC004", "차량정보 조회 성공"), + SUCCESS_REQUEST_DELETE_MEMBER(HttpStatus.OK.value(), "BMC005", "회원이 탈퇴 되었습니다."), + SUCCESS_REQUEST_UPDATE_MEMBER(HttpStatus.OK.value(), "BMC006", "회원정보가 변경 되었습니다."), + SUCCESS_REQUEST_CHANGE_PASSWORD_MEMBER(HttpStatus.OK.value(), "BMC007", "비밀번호가 변경 되었습니다."); private final int status; diff --git a/module-api/src/main/java/com/kernel360/member/code/MemberErrorCode.java b/module-api/src/main/java/com/kernel360/member/code/MemberErrorCode.java index 1ffd512c..2aecc075 100644 --- a/module-api/src/main/java/com/kernel360/member/code/MemberErrorCode.java +++ b/module-api/src/main/java/com/kernel360/member/code/MemberErrorCode.java @@ -4,6 +4,8 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; +import java.util.EnumSet; + @RequiredArgsConstructor public enum MemberErrorCode implements ErrorCode { @@ -12,8 +14,8 @@ public enum MemberErrorCode implements ErrorCode { FAILED_NOT_MAPPING_ENUM_VALUEOF(HttpStatus.INTERNAL_SERVER_ERROR.value(), "EMC003", "PARAMETER 값과 ENUM의 NAME이 불일치함."), FAILED_GENERATE_JOIN_MEMBER_INFO(HttpStatus.INTERNAL_SERVER_ERROR.value(), "EMC004", "회원가입에 필요한 정보 생성 실패"), FAILED_GENERATE_LOGIN_REQUEST_INFO(HttpStatus.INTERNAL_SERVER_ERROR.value(), "EMC005", "정보 불일치로 인한 로그인 정보 생성 실패"), - FAILED_REQUEST_LOGIN(HttpStatus.BAD_REQUEST.value(), "EMC006", "정보 불일치로 인한 로그인 실패"); - + FAILED_REQUEST_LOGIN(HttpStatus.BAD_REQUEST.value(), "EMC006", "정보 불일치로 인한 로그인 실패"), + FAILED_FIND_MEMBER_INFO(HttpStatus.BAD_REQUEST.value(), "EMC007", "요청 회원정보가 존재하지 않습니다."); private final int status; diff --git a/module-api/src/main/java/com/kernel360/member/dto/MemberInfo.java b/module-api/src/main/java/com/kernel360/member/dto/MemberInfo.java new file mode 100644 index 00000000..1a4c8de2 --- /dev/null +++ b/module-api/src/main/java/com/kernel360/member/dto/MemberInfo.java @@ -0,0 +1,12 @@ +package com.kernel360.member.dto; + +public record MemberInfo( String id, + String password +) { + static MemberInfo of( + String id, + String password + ) { + return new MemberInfo(id, password); + } +} \ No newline at end of file diff --git a/module-api/src/main/java/com/kernel360/member/service/MemberService.java b/module-api/src/main/java/com/kernel360/member/service/MemberService.java index 25885991..58f89ea4 100644 --- a/module-api/src/main/java/com/kernel360/member/service/MemberService.java +++ b/module-api/src/main/java/com/kernel360/member/service/MemberService.java @@ -2,6 +2,8 @@ import com.kernel360.auth.entity.Auth; import com.kernel360.auth.repository.AuthRepository; +import com.kernel360.carinfo.entity.CarInfo; +import com.kernel360.commoncode.service.CommonCodeService; import com.kernel360.exception.BusinessException; import com.kernel360.member.code.MemberErrorCode; import com.kernel360.member.dto.MemberDto; @@ -13,9 +15,11 @@ import com.kernel360.utils.JWT; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.RequestEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.Map; import java.util.Optional; @@ -27,6 +31,8 @@ public class MemberService { private final JWT jwt; private final AuthRepository authRepository; private final MemberRepository memberRepository; + private final CommonCodeService commonCodeService; + /** * 가입 @@ -35,7 +41,9 @@ public class MemberService { public void joinMember(MemberDto requestDto) { Member entity = getNewJoinMemberEntity(requestDto); - if(entity == null) { throw new BusinessException(MemberErrorCode.FAILED_GENERATE_JOIN_MEMBER_INFO); } + if (entity == null) { + throw new BusinessException(MemberErrorCode.FAILED_GENERATE_JOIN_MEMBER_INFO); + } memberRepository.save(entity); } @@ -46,10 +54,10 @@ protected Member getNewJoinMemberEntity(MemberDto requestDto) { int genderOrdinal; int ageOrdinal; - try{ + try { genderOrdinal = Gender.valueOf(requestDto.gender()).ordinal(); ageOrdinal = Age.valueOf(requestDto.age()).ordinal(); - }catch (Exception e){ + } catch (Exception e) { throw new BusinessException(MemberErrorCode.FAILED_NOT_MAPPING_ENUM_VALUEOF); } @@ -63,10 +71,14 @@ protected Member getNewJoinMemberEntity(MemberDto requestDto) { public MemberDto login(MemberDto loginDto) { Member loginEntity = getReqeustLoginEntity(loginDto); - if(loginEntity == null) { throw new BusinessException(MemberErrorCode.FAILED_GENERATE_LOGIN_REQUEST_INFO); } + if (loginEntity == null) { + throw new BusinessException(MemberErrorCode.FAILED_GENERATE_LOGIN_REQUEST_INFO); + } Member memberEntity = memberRepository.findOneByIdAndPassword(loginEntity.getId(), loginEntity.getPassword()); - if(memberEntity == null) { throw new BusinessException(MemberErrorCode.FAILED_REQUEST_LOGIN); } + if (memberEntity == null) { + throw new BusinessException(MemberErrorCode.FAILED_REQUEST_LOGIN); + } String token = jwt.generateToken(memberEntity.getId()); @@ -76,8 +88,8 @@ public MemberDto login(MemberDto loginDto) { //결과 없으면 entity로 신규 생성 authJwt = Optional.ofNullable(authJwt) - .map(modifyAuth -> modifyAuthJwt(modifyAuth, encryptToken)) - .orElseGet(() -> createAuthJwt(memberEntity.getMemberNo(), encryptToken)); + .map(modifyAuth -> modifyAuthJwt(modifyAuth, encryptToken)) + .orElseGet(() -> createAuthJwt(memberEntity.getMemberNo(), encryptToken)); authRepository.save(authJwt); @@ -101,25 +113,75 @@ private Member getReqeustLoginEntity(MemberDto loginDto) { return Member.loginMember(loginDto.id(), encodePassword); } + @Transactional(readOnly = true) - public boolean idDuplicationCheck (String id) { + public boolean idDuplicationCheck(String id) { Member member = memberRepository.findOneById(id); return member != null; } @Transactional(readOnly = true) - public boolean emailDuplicationCheck (String email) { + public boolean emailDuplicationCheck(String email) { Member member = memberRepository.findOneByEmail(email); return member != null; } - public Auth findOneAuthByJwt(String encryptToken){ + public Auth findOneAuthByJwt(String encryptToken) { return authRepository.findOneByJwtToken(encryptToken); } public void reissuanceJwt(Auth storedAuthInfo) { authRepository.save(storedAuthInfo); } + + + public MemberDto findMemberByToken(RequestEntity request) { + String token = request.getHeaders().getFirst("Authorization"); + String id = JWT.ownerId(token); + + return MemberDto.from(memberRepository.findOneById(id)); + } + + public CarInfo findCarInfoByToken(RequestEntity request) { + MemberDto memberDto = findMemberByToken(request); + + return memberDto.toEntity().getCarInfo(); + } + + @Transactional + public void deleteMember(String id) { + memberRepository.deleteMemberById(id); + } + + + @Transactional + public void changePassword(MemberDto memberDto) { + memberRepository.updatePasswordById(memberDto.id(), memberDto.password()); + } + + @Transactional + public void updateMember(MemberDto memberDto) { + Member member = + Member.of(memberDto.memberNo(), memberDto.id(), memberDto.email(), memberDto.password(), + Integer.parseInt(memberDto.gender()), Integer.parseInt(memberDto.age())); + + memberRepository.save(member); + } + + @Transactional(readOnly = true) + public Map getCarInfo(RequestEntity request) { + // CarInfo carInfo = memberService.findCarInfoByToken(request); + //FIXME :: CarInfo Data 없어서 에러발생 주석 처리해둠 + + return Map.of( +// "car_info", carInfo, + "segment_options", commonCodeService.getCodes("segment"), + "carType_options", commonCodeService.getCodes("cartype"), + "color_options", commonCodeService.getCodes("color"), + "driving_options", commonCodeService.getCodes("driving"), + "parking_options", commonCodeService.getCodes("parking") + ); + } } diff --git a/module-api/src/main/java/com/kernel360/mypage/controller/MyPageController.java b/module-api/src/main/java/com/kernel360/mypage/controller/MyPageController.java index a8222dad..d62d9227 100644 --- a/module-api/src/main/java/com/kernel360/mypage/controller/MyPageController.java +++ b/module-api/src/main/java/com/kernel360/mypage/controller/MyPageController.java @@ -1,16 +1,15 @@ package com.kernel360.mypage.controller; +import com.kernel360.member.code.MemberBusinessCode; import com.kernel360.member.dto.MemberDto; import com.kernel360.member.service.MemberService; -import com.kernel360.product.dto.ProductDto; import com.kernel360.product.service.ProductService; +import com.kernel360.response.ApiResponse; import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; import org.springframework.http.ResponseEntity; -import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; -import java.util.List; import java.util.Map; @RestController @@ -19,43 +18,44 @@ public class MyPageController { private final MemberService memberService; private final ProductService productService; - @GetMapping("/main") - ResponseEntity main(Model model) { - List productDtoList = productService.getProductListOrderByViewCount(); - String bannerImageUrl = "http://localhost:8080/bannersample.png"; - String suggestImageUrl = "http://localhost:8080/suggestsample.png"; - - model.addAllAttributes(Map.of("Banner" , bannerImageUrl, - "Suggest", suggestImageUrl, - "Product", productDtoList)); - - return ResponseEntity.status(HttpStatus.OK).body(model); - } @GetMapping("/member") - ResponseEntity myInfo() { - return ResponseEntity.status(HttpStatus.OK).body("mypage 내정보 page입니다."); + ResponseEntity> myInfo(RequestEntity request) { + MemberDto dto = memberService.findMemberByToken(request); + + return ApiResponse.toResponseEntity(MemberBusinessCode.SUCCESS_FIND_REQUEST_MEMBER, dto); } @GetMapping("/car") - ResponseEntity myCar() { - return ResponseEntity.status(HttpStatus.OK).body("mypage 차량정보 page입니다."); + ResponseEntity>> myCar(RequestEntity request) { + Map carInfo = memberService.getCarInfo(request); + + return ApiResponse.toResponseEntity(MemberBusinessCode.SUCCESS_FIND_CAR_INFO_IN_MEMBER, carInfo); } + @DeleteMapping("/member") - ResponseEntity memberDelete(@RequestBody MemberDto memberDto) { - return ResponseEntity.status(HttpStatus.OK).body(memberDto.id() + " 회원이 탈퇴되었습니다."); + ResponseEntity> memberDelete(@RequestBody MemberDto memberDto) { + memberService.deleteMember(memberDto.id()); + + return ApiResponse.toResponseEntity(MemberBusinessCode.SUCCESS_REQUEST_DELETE_MEMBER); } + @PostMapping("/member") - ResponseEntity memberInfoAdd(@RequestBody MemberDto memberDto) { - return ResponseEntity.status(HttpStatus.OK).body(memberDto.id() + "회원의 회원정보가 추가되었습니다."); - } + ResponseEntity> changePassword(@RequestBody MemberDto memberDto) { + MemberDto dto = MemberDto.of(memberDto.id(), memberDto.password()); + memberService.changePassword(dto); - @PatchMapping("/member") - ResponseEntity changePassword(@RequestBody MemberDto memberDto) { - return ResponseEntity.status(HttpStatus.OK).body(memberDto.id() + "회원의 비밀번호가 변경 되었습니다."); + return ApiResponse.toResponseEntity(MemberBusinessCode.SUCCESS_REQUEST_CHANGE_PASSWORD_MEMBER); } + @PutMapping("/member") + ResponseEntity> updateMember(@RequestBody MemberDto memberDto) { + memberService.updateMember(memberDto); + + return ApiResponse.toResponseEntity(MemberBusinessCode.SUCCESS_REQUEST_UPDATE_MEMBER); + + } } diff --git a/module-api/src/main/java/com/kernel360/mypage/enumset/CarColor.java b/module-api/src/main/java/com/kernel360/mypage/enumset/CarColor.java new file mode 100644 index 00000000..24795e01 --- /dev/null +++ b/module-api/src/main/java/com/kernel360/mypage/enumset/CarColor.java @@ -0,0 +1,34 @@ +package com.kernel360.mypage.enumset; + +import java.util.List; + +public enum CarColor { + + WHITE("white", "#FFFFFF"), + RAT_COLOR("rat color", "#808080"), + BLACK("black", "#37383C"), + RED("red", "#FF4500"), + YELLOW("yellow", "#FFD400"), + GREEN("green", "#2F4F4F"), + BLUE("blue", "#145B7D"), + OTHER("Other", "#6E0000"); + + private final String label; + private final String value; + + CarColor(String label, String value) { + this.label = label; + this.value = value; + } + + public String getLabel() { + return label; + } + + public String getValue() { + return value; + } + + public static List getAllColors() { + return List.of(values()); + }} diff --git a/module-api/src/main/java/com/kernel360/mypage/enumset/CarDriving.java b/module-api/src/main/java/com/kernel360/mypage/enumset/CarDriving.java new file mode 100644 index 00000000..6226bdfd --- /dev/null +++ b/module-api/src/main/java/com/kernel360/mypage/enumset/CarDriving.java @@ -0,0 +1,30 @@ +package com.kernel360.mypage.enumset; + +import java.util.List; + +public enum CarDriving { + + CITY_CENTER("city center", "comport"), + HIGH_SPEED("High speed", "highway"), + COMPOSITE("composite", "complex"); + + private final String label; + private final String value; + + CarDriving(String label, String value) { + this.label = label; + this.value = value; + } + + public String getLabel() { + return label; + } + + public String getValue() { + return value; + } + + public static List getAllDrivings() { + return List.of(values()); + } +} diff --git a/module-api/src/main/java/com/kernel360/mypage/enumset/CarParking.java b/module-api/src/main/java/com/kernel360/mypage/enumset/CarParking.java new file mode 100644 index 00000000..20d0c16f --- /dev/null +++ b/module-api/src/main/java/com/kernel360/mypage/enumset/CarParking.java @@ -0,0 +1,31 @@ +package com.kernel360.mypage.enumset; + +import java.util.List; + +public enum CarParking { + + HOUSE("Indoor/Underground", "house"), + ROAD("노상", "road"), + PILOTI("Piloti", "piloti"); + + private final String label; + private final String value; + + CarParking(String label, String value) { + this.label = label; + this.value = value; + } + + // Getters + public String getLabel() { + return label; + } + + public String getValue() { + return value; + } + + public static List getAllParkings() { + return List.of(values()); + } +} diff --git a/module-api/src/main/java/com/kernel360/mypage/enumset/CarSegment.java b/module-api/src/main/java/com/kernel360/mypage/enumset/CarSegment.java new file mode 100644 index 00000000..c56b9ef7 --- /dev/null +++ b/module-api/src/main/java/com/kernel360/mypage/enumset/CarSegment.java @@ -0,0 +1,30 @@ +package com.kernel360.mypage.enumset; + +import java.util.List; + +public enum CarSegment { + + SEDAN("세단", "sedan"), + HATCHBACK("해치백", "hatchback"), + SUV("SUV", "suv"), + ETC("기타", "etc"); + private final String label; + private final String value; + + CarSegment(String label, String value) { + this.label = label; + this.value = value; + } + + public String getLabel() { + return label; + } + + public String getValue() { + return value; + } + + public static List getAllSegments() { + return List.of(values()); + } +} diff --git a/module-api/src/main/java/com/kernel360/mypage/enumset/CarType.java b/module-api/src/main/java/com/kernel360/mypage/enumset/CarType.java new file mode 100644 index 00000000..9148bc90 --- /dev/null +++ b/module-api/src/main/java/com/kernel360/mypage/enumset/CarType.java @@ -0,0 +1,31 @@ +package com.kernel360.mypage.enumset; + +import java.util.List; + +public enum CarType { + + COMPACT_CAR("compact car", "micro"), + SMALL("small", "subcompact"), + MEDIUM("medium", "compact"), + LARGE("large", "fullsize"); + + private final String label; + private final String value; + + CarType(String label, String value) { + this.label = label; + this.value = value; + } + + public String getLabel() { + return label; + } + + public String getValue() { + return value; + } + + public static List getAllTypes() { + return List.of(values()); + } +} diff --git a/module-api/src/main/java/com/kernel360/product/service/ProductService.java b/module-api/src/main/java/com/kernel360/product/service/ProductService.java index 9dbea385..50bd33d3 100644 --- a/module-api/src/main/java/com/kernel360/product/service/ProductService.java +++ b/module-api/src/main/java/com/kernel360/product/service/ProductService.java @@ -46,7 +46,9 @@ public List getProductListByKeyword(String keyword) { @Transactional(readOnly = true) public List getProductListOrderByViewCount() { - List products = productRepository.findAllByOrderByViewCountDesc(); + List products = productRepository.findTop5ByOrderByProductNameDesc(); +// List products = productRepository.findAllByOrderByViewCountDesc(); + //FIXME:: viewCount 값이 존재하지 않아,제품이룸순 데이터를 샘플로 전달한 후 향후 변경 return products.stream().map(ProductDto::from).toList(); } diff --git a/module-api/src/test/java/com/kernel360/common/ControllerTest.java b/module-api/src/test/java/com/kernel360/common/ControllerTest.java index 9b02a9e9..fce52ff9 100644 --- a/module-api/src/test/java/com/kernel360/common/ControllerTest.java +++ b/module-api/src/test/java/com/kernel360/common/ControllerTest.java @@ -4,6 +4,8 @@ import com.kernel360.commoncode.controller.CommonCodeController; import com.kernel360.commoncode.service.CommonCodeService; import com.kernel360.global.Interceptor.AcceptInterceptor; +import com.kernel360.main.controller.MainContoller; +import com.kernel360.main.service.MainService; import com.kernel360.member.controller.MemberController; import com.kernel360.member.service.MemberService; import com.kernel360.mypage.controller.MyPageController; @@ -18,8 +20,9 @@ @WebMvcTest({ CommonCodeController.class, MemberController.class, - MyPageController.class, - ProductController.class + ProductController.class, + MainContoller.class, + MyPageController.class }) @AutoConfigureRestDocs public abstract class ControllerTest { @@ -41,4 +44,7 @@ public abstract class ControllerTest { @MockBean protected ProductService productService; + + @MockBean + protected MainService mainService; } diff --git a/module-api/src/test/java/com/kernel360/main/controller/MainContollerTest.java b/module-api/src/test/java/com/kernel360/main/controller/MainContollerTest.java new file mode 100644 index 00000000..4a55382a --- /dev/null +++ b/module-api/src/test/java/com/kernel360/main/controller/MainContollerTest.java @@ -0,0 +1,200 @@ +package com.kernel360.main.controller; + +import com.kernel360.common.ControllerTest; +import com.kernel360.main.dto.BannerDto; +import com.kernel360.main.dto.RecommendProductsDto; +import com.kernel360.product.dto.ProductDto; +import com.navercorp.fixturemonkey.FixtureMonkey; +import com.navercorp.fixturemonkey.api.introspector.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.springframework.http.MediaType; +import org.springframework.restdocs.payload.JsonFieldType; + +import java.util.Arrays; +import java.util.List; + +import static com.kernel360.common.utils.RestDocumentUtils.getDocumentRequest; +import static com.kernel360.common.utils.RestDocumentUtils.getDocumentResponse; +import static org.mockito.Mockito.when; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.payload.PayloadDocumentation.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import static org.hamcrest.collection.IsCollectionWithSize.hasSize; +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +class MainContollerTest extends ControllerTest { + private FixtureMonkey fixtureMonkey; + + @BeforeEach + void 준비() { + fixtureMonkey = FixtureMonkey.builder() + .objectIntrospector(new FailoverIntrospector( + Arrays.asList( + BuilderArbitraryIntrospector.INSTANCE, + FieldReflectionArbitraryIntrospector.INSTANCE, + ConstructorPropertiesArbitraryIntrospector.INSTANCE, + BeanArbitraryIntrospector.INSTANCE + ) + )) + .build(); + } + + @Test + void 메인페이지_배너요청이_왔을때_200_응답이_잘반환되는지() throws Exception { + //given + BannerDto bannerDto = BannerDto.of(1L, "classpath:static/bannerSample.png", "Banner Image"); + when(mainService.getSampleBanner()).thenReturn(bannerDto); + + //when & then + mockMvc.perform(get("/banner")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.status").value(200)) + .andExpect(jsonPath("$.value.id").value(1L)) + .andExpect(jsonPath("$.value.image").value("classpath:static/bannerSample.png")) + .andExpect(jsonPath("$.value.alt").value("Banner Image")) + .andDo(document( + "banner/get-banner", + getDocumentRequest(), + getDocumentResponse(), + responseFields(beneathPath("value").withSubsectionId("value"), + fieldWithPath("id").type(JsonFieldType.NUMBER).description("배너 ID"), + fieldWithPath("image").type(JsonFieldType.STRING).description("배너 이미지 경로"), + fieldWithPath("alt").type(JsonFieldType.STRING).description("배너 대체 텍스트") + ) + )); + + verify(mainService, times(1)).getSampleBanner(); + } + + + @Test + void 메인페이지_추천상품을_호출할때_200응답과_데이터가_잘보내지는지() throws Exception { + //given + List recommendProductsDtos = fixtureMonkey.giveMeBuilder(RecommendProductsDto.class) + .setNotNull("id").setNotNull("image").setNotNull("alt").setNotNull("productName") + .sampleList(5); + when(productService.getRecommendProductList()).thenReturn(recommendProductsDtos); + + //when & then + mockMvc.perform(get("/recommend-products")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.status").value(200)) + .andExpect(jsonPath("$.code").value("PMB001")) + .andExpect(jsonPath("$.message").value("추천제품정보 조회 성공")) + .andExpect(jsonPath("$.value", hasSize(5))) + .andExpect(jsonPath("$.value[0].id").isNotEmpty()) + .andExpect(jsonPath("$.value[0].image").isNotEmpty()) + .andExpect(jsonPath("$.value[0].alt").isNotEmpty()) + .andExpect(jsonPath("$.value[0].productName").isNotEmpty()) + .andDo(document( + "recommend-products/get-recommend-products", + getDocumentRequest(), + getDocumentResponse(), + responseFields( + fieldWithPath("status").type(JsonFieldType.NUMBER).description("상태 코드"), + fieldWithPath("code").type(JsonFieldType.STRING).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답메세지"), + fieldWithPath("value").type(JsonFieldType.ARRAY).description("제품 리스트"), + fieldWithPath("value[].id").type(JsonFieldType.NUMBER).description("제품 ID"), + fieldWithPath("value[].image").type(JsonFieldType.STRING).description("이미지 URL"), + fieldWithPath("value[].alt").type(JsonFieldType.STRING).description("이미지 대체 텍스트"), + fieldWithPath("value[].productName").type(JsonFieldType.STRING).description("제품명") + ) + )); + } + @ParameterizedTest + @EnumSource(value = Sort.class, names = {"VIEW_COUNT_PRODUCT_ORDER", "VIOLATION_PRODUCT_LIST", "RECENT_PRODUCT_ORDER"}) + void 메인페이지_조회순으로_제품리스트_요청시_200응답과_데이터가_잘_반환되는지(Sort sortType) throws Exception { + // given + List productDtos = fixtureMonkey.giveMeBuilder(ProductDto.class) + .setNotNull("productNo") + .setNotNull("productName") + .setNotNull("viewCount") + .setNotNull("reportNumber") + .setNotNull("safetyStatus") + .setNotNull("createdAt") + .setNotNull("createdBy") + .sampleList(5); + + + if (sortType == Sort.VIEW_COUNT_PRODUCT_ORDER) { + when(productService.getProductListOrderByViewCount()).thenReturn(productDtos); + } else if (sortType == Sort.VIOLATION_PRODUCT_LIST) { + when(productService.getViolationProducts()).thenReturn(productDtos); + } else if (sortType == Sort.RECENT_PRODUCT_ORDER) { + when(productService.getRecentProducts()).thenReturn(productDtos); + } + + // when & then + mockMvc.perform(get("/products/rank") + .queryParam("sortType", sortType.getOrderType())) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.status").value(200)) + .andExpect(jsonPath("$.value", hasSize(5))) + .andExpect(jsonPath("$.value[0].productNo").isNotEmpty()) + .andExpect(jsonPath("$.value[0].productName").isNotEmpty()) + .andExpect(jsonPath("$.value[0].viewCount").isNotEmpty()) + .andDo(document( + "products/get-products-view-count-order", + getDocumentRequest(), + getDocumentResponse(), + responseFields( + fieldWithPath("status").type(JsonFieldType.NUMBER).description("상태 코드"), + fieldWithPath("code").type(JsonFieldType.STRING).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답메세지"), + fieldWithPath("value").type(JsonFieldType.ARRAY).description("제품 리스트"), + fieldWithPath("value[].productNo").type(JsonFieldType.NUMBER).description("제품 ID"), + fieldWithPath("value[].productName").type(JsonFieldType.STRING).description("제품명"), + fieldWithPath("value[].barcode").type(JsonFieldType.STRING).optional().description("바코드"), + fieldWithPath("value[].imageSource").type(JsonFieldType.STRING).optional().description("이미지 소스"), + fieldWithPath("value[].reportNumber").type(JsonFieldType.STRING).description("신고 번호"), + fieldWithPath("value[].safetyStatus").type(JsonFieldType.STRING).description("안전 상태"), + fieldWithPath("value[].viewCount").type(JsonFieldType.NUMBER).description("조회수"), + fieldWithPath("value[].createdAt").type(JsonFieldType.STRING).description("생성날짜"), + fieldWithPath("value[].createdBy").type(JsonFieldType.STRING).description("생성자"), + fieldWithPath("value[].modifiedAt").type(JsonFieldType.STRING).optional().description("수정날짜"), + fieldWithPath("value[].modifiedBy").type(JsonFieldType.STRING).optional().description("수정자") + ) + )); + + if (sortType == Sort.VIEW_COUNT_PRODUCT_ORDER) { + verify(productService, times(1)).getProductListOrderByViewCount(); + } else if (sortType == Sort.VIOLATION_PRODUCT_LIST) { + verify(productService, times(1)).getViolationProducts(); + } else if (sortType == Sort.RECENT_PRODUCT_ORDER) { + verify(productService, times(1)).getRecentProducts(); + } + + } + + +//FIXME:: 좋아요 기능구현후, 데이터를 바탕으로 추천기능구현후, 테스트코드 변경예정 +// @Test +// void 메인페이지_추천제품_정렬_옵션으로_요청시_200응답과_데이터가_잘_반환되는지() throws Exception { +// // given +// List recommendProducts = fixtureMonkey.giveMeBuilder(RecommendProductsDto.class) +// .sampleList(5); +// when(productService.getRecommendProductList()).thenReturn(recommendProducts); +// +// // when & then +// mockMvc.perform(get("/products/rank") +// .queryParam("sortType", "recommend-order")) +// .andExpect(status().isOk()) +// .andExpect(content().contentType(MediaType.APPLICATION_JSON)) +// .andExpect(jsonPath("$.status").value(200)); +//// .andExpect(jsonPath("$.value", hasSize(5))); +// ; +// +// verify(productService, times(1)).getRecommendProductList(); +// +// } +} \ No newline at end of file diff --git a/module-api/src/test/java/com/kernel360/mypage/controller/MyPageControllerTest.java b/module-api/src/test/java/com/kernel360/mypage/controller/MyPageControllerTest.java index 4da4295c..2584e3db 100644 --- a/module-api/src/test/java/com/kernel360/mypage/controller/MyPageControllerTest.java +++ b/module-api/src/test/java/com/kernel360/mypage/controller/MyPageControllerTest.java @@ -33,25 +33,25 @@ class MyPageControllerTest extends ControllerTest { )) .build(); } - - @Test - void 마이페이지_메인요청이왔을때_200요청과_응답이_잘반환되는지() throws Exception { - //given - List productDtoList = fixtureMonkey.giveMeBuilder(ProductDto.class).sampleList(5); - - //when - when(productService.getProductListOrderByViewCount()).thenReturn(productDtoList); - - //then - mockMvc.perform(get("/mypage/main")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.Banner").value("http://localhost:8080/bannersample.png")) - .andExpect(jsonPath("$.Suggest").value("http://localhost:8080/suggestsample.png")) - .andExpect(jsonPath("$.Product", hasSize(5))); - - verify(productService, times(1)).getProductListOrderByViewCount(); - } +// +// @Test +// void 마이페이지_메인요청이왔을때_200_응답이_잘반환되는지() throws Exception { +// //given +// List productDtoList = fixtureMonkey.giveMeBuilder(ProductDto.class).sampleList(5); +// +// //when +// when(productService.getProductListOrderByViewCount()).thenReturn(productDtoList); +// +// //then +// mockMvc.perform(get("/mypage/main")) +// .andExpect(status().isOk()) +// .andExpect(content().contentType(MediaType.APPLICATION_JSON)) +// .andExpect(jsonPath("$.Banner").value("http://localhost:8080/bannersample.png")) +// .andExpect(jsonPath("$.Suggest").value("http://localhost:8080/suggestsample.png")) +// .andExpect(jsonPath("$.Product", hasSize(5))); +// +// verify(productService, times(1)).getProductListOrderByViewCount(); +// } } \ No newline at end of file diff --git a/module-common/src/main/java/com/kernel360/utils/JWT.java b/module-common/src/main/java/com/kernel360/utils/JWT.java index 24021cfe..bdb72d04 100644 --- a/module-common/src/main/java/com/kernel360/utils/JWT.java +++ b/module-common/src/main/java/com/kernel360/utils/JWT.java @@ -3,7 +3,6 @@ import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.security.Keys; -import lombok.SneakyThrows; import org.springframework.stereotype.Component; import java.security.Key; @@ -43,7 +42,7 @@ public Date extractTime(String token) { return claims.getExpiration(); } - public String ownerId(String token) { + public static String ownerId(String token) { Claims claims = Jwts.parserBuilder().setSigningKey(SECRET_KEY).build().parseClaimsJws(token).getBody(); return claims.getId(); } diff --git a/module-domain/src/main/java/com/kernel360/member/entity/Member.java b/module-domain/src/main/java/com/kernel360/member/entity/Member.java index 43ee67b9..485ce059 100644 --- a/module-domain/src/main/java/com/kernel360/member/entity/Member.java +++ b/module-domain/src/main/java/com/kernel360/member/entity/Member.java @@ -99,4 +99,5 @@ private Member(String id, String password) { this.password = password; } + } \ No newline at end of file diff --git a/module-domain/src/main/java/com/kernel360/member/repository/MemberRepository.java b/module-domain/src/main/java/com/kernel360/member/repository/MemberRepository.java index b668ea79..988b09df 100644 --- a/module-domain/src/main/java/com/kernel360/member/repository/MemberRepository.java +++ b/module-domain/src/main/java/com/kernel360/member/repository/MemberRepository.java @@ -3,6 +3,10 @@ import com.kernel360.member.entity.Member; import jakarta.persistence.Id; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + public interface MemberRepository extends JpaRepository { @@ -11,4 +15,11 @@ public interface MemberRepository extends JpaRepository { Member findOneById(String id); Member findOneByEmail(String email); + + void deleteMemberById(String id); + + @Modifying + @Query("update Member m set m.password = :password where m.id = :id") + void updatePasswordById(@Param("id") String id, @Param("password") String password); + }