Light Blue Pointer
본문 바로가기
Developing/개발일지

2023-01-10, Today I Learned

by Greedy 2024. 1. 10.

오늘 한 일

모아요이츠

1. 모든 에러를 GlobalHandler로 AOP처리해봄

2. Swqgger 연결

3. 글 단독조회(상세페이지 조회) 기능 구현

4. 글 카테고리별 전체조회 기능 구현

 

 

1. 모든 에러를 GlobalHandler로 AOP 처리해봄

모든 에러를 받는 ErrorHandler를 만들어보고 싶어짐!

//    @ExceptionHandler(MethodArgumentNotValidException.class)
//    public ApiResponse<List<String>> handleMethodArgumentNotValidException(
//        BindingResult bindingResult) {
//        List<String> errors = bindingResult.getFieldErrors().stream()
//            .map((FieldError fieldError) -> fieldError.getField() +" "+ fieldError.getDefaultMessage())
//            .toList();
//        return new ApiResponse<>(HttpStatus.BAD_REQUEST.value(), "입력값이 잘못되었습니다", errors);
//    }

    @ExceptionHandler(Exception.class)
    public ApiResponse<String> handleALLException(Exception ex){
        return new ApiResponse<>(HttpStatus.BAD_REQUEST.value(), "입력값이 잘못되었습니다", ex.getMessage());
    }

이렇게 하고 이메일 형식이 아닌걸로 가입하려 하니까 이렇게 뜬다!

{
    "email":"emaildot.com",
    "password":"passPASS123",
    "checkPassword":"passPASS123",
    "nickname":"가나다라"
}
{
    "status": 400,
    "message": "입력값이 잘못되었습니다",
    "data": "Validation failed for argument [0] in public com.moayo.moayoeats.global.dto.ApiResponse<java.lang.Void> com.moayo.moayoeats.domain.user.controller.UserController.signup(com.moayo.moayoeats.domain.user.dto.request.SignupRequest): [Field error in object 'signupRequest' on field 'email': rejected value [emaildot.com]; codes [Email.signupRequest.email,Email.email,Email.java.lang.String,Email]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [signupRequest.email,email]; arguments []; default message [email],[Ljakarta.validation.constraints.Pattern$Flag;@3abe50dd,.*]; default message [must be a well-formed email address]] "
}

다시 돌리면 다른 에러들은 밑의것으로 받아지고 MethodArgumentNotValidException 은 원래대로 처리될까?

더 하위의 것이 있으면 그 Handler로 들어가고 구현 안 된 것들만 Exception.class로 들어갔으면 좋겠다!

@ExceptionHandler(MethodArgumentNotValidException.class)
    public ApiResponse<List<String>> handleMethodArgumentNotValidException(
        BindingResult bindingResult) {
        List<String> errors = bindingResult.getFieldErrors().stream()
            .map((FieldError fieldError) -> fieldError.getField() +" "+ fieldError.getDefaultMessage())
            .toList();
        return new ApiResponse<>(HttpStatus.BAD_REQUEST.value(), "입력값이 잘못되었습니다", errors);
    }

    @ExceptionHandler(Exception.class)
    public ApiResponse<String> handleALLException(Exception ex){
        return new ApiResponse<>(HttpStatus.BAD_REQUEST.value(), "입력값이 잘못되었습니다", ex.getMessage());
    }

주석 다시 풀어봄

{
    "status": 400,
    "message": "입력값이 잘못되었습니다",
    "data": [
        "email must be a well-formed email address"
    ]
}

오 이번에는 잘 뜸

 

2. Swqgger 연결

Swagger 추가함

build.gradle에 추가하기

//Swagger
    implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2'

인증 필터에서 Swagger api 걸러주기

.requestMatchers("/").permitAll() // 메인 페이지 요청 허가
                .requestMatchers("/api/v1/users/sign-up/**").permitAll() // singup이후로 접근 허가
                .requestMatchers("/api/v1/users/login/**").permitAll() // singup이후로 접근 허가
                .requestMatchers("/v3/api-docs/**", "/swagger-ui/**").permitAll()
                .anyRequest().authenticated() // 그 외 모든 요청 인증처리

 

 

 

 

3. 글 상세 조회 페이지 만들기

public record DetailedPostResponse (
    String author,
    String address,
    String store,
    Integer minPrice,
    Integer deliveryCost,
    List<User> people,
    List<List<Menu>> menus,
    List<Menu> myMenus,
    Integer sumPrice,
    LocalDateTime deadline
){
}
//글 단독 조회, 글 상세페이지
    @GetMapping("/posts/{postId}")
    public ApiResponse<DetailedPostResponse> getPost(
        @AuthenticationPrincipal UserDetailsImpl userDetails,
        @PathVariable(name = "postId") Long postId
    ){
        return new ApiResponse<>(HttpStatus.OK.value(), "글 상세페이지 조회에 성공했습니다.",postService.getPost(postId, userDetails.getUser()));
    }
@Builder
public record DetailedPostResponse (
    String author,
    String address,
    String store,
    Integer minPrice,
    Integer deliveryCost,
    List<Menu> myMenus,
    List<String> participants,
    List<List<Menu>> menus,
    Integer sumPrice,
    LocalDateTime deadline
){
}

List 순회하면서 Role이 Host아닌 유저의 닉네임만 걸러낼건데 stream filter쓰고싶어짐!!

https://www.baeldung.com/java-stream-filter-lambda

private List<String> getParticipants(List<UserPost> userPosts){
        return userPosts.stream()
            .filter((UserPost userPost)->userPost.getRole()==UserPostRole.PARTICIPANT)
            .map((UserPost userPost)->userPost.getUser().getNickname()).toList();
    }

stream filter 처음 써보는데 엄청 편리한듯!

음 일단 participant는 제대로 되나 찍어봤는데 그것도 null이 돌아가고 있음

{
    "status": 200,
    "message": "글 상세페이지 조회에 성공했습니다.",
    "data": {
        "author": "가나다라",
        "address": "주소주소",
        "store": "storestore",
        "minPrice": 20000,
        "deliveryCost": 2000,
        "participants": [], -> 이러시면 안되거든요...

private List<String> getParticipants(List<UserPost> userPosts){
        return userPosts.stream()
            .filter((UserPost userPost)->userPost.getRole()==UserPostRole.PARTICIPANT)
            .map((UserPost userPost)->userPost.getUser().getNickname()).toList();
    }

다시보니 ==이라 틀린거같음 equals를 넣어줘야 하는데

equals로 바꿔봄

private List<String> getParticipants(List<UserPost> userPosts){
        return userPosts.stream()
            .filter((UserPost userPost)->userPost.getRole().equals(UserPostRole.PARTICIPANT))
            .map((UserPost userPost)->userPost.getUser().getNickname()).toList();
    }

아직도 null값이 돌아감

Collectors.toList() 넣어봄

private List<String> getParticipants(List<UserPost> userPosts){
        return userPosts.stream()
            .filter((UserPost userPost)->userPost.getRole().equals(UserPostRole.PARTICIPANT))
            .map((UserPost userPost)->userPost.getUser().getNickname()).collect(Collectors.toList());
    }

"participants": [],

아직도 이래

익명함수 말고 함수를 따로 뺴는 방법)

We can also use a method reference, which is shorthand for a lambda expression:

List<Customer> customersWithMoreThan100Points = customers
  .stream()
  .filter(Customer::hasOverHundredPoints)
  .collect(Collectors.toList());Copy

In this case, we added the hasOverHundredPoints method to our Customer class:

public boolean hasOverHundredPoints() {
return this.points > 100;
}

해봤는데

private List<String> getParticipants(List<UserPost> userPosts){
        return userPosts.stream()
            .filter(UserPost::isParticipant)
            .map((UserPost userPost)->userPost.getUser().getNickname()).toList();
    }
    
    public boolean isParticipant(UserPost userpost){
        return userpost.getRole().equals(UserPostRole.PARTICIPANT);

    }

isParticipant가 빨간색으로 뜸 ㅜㅜ

걍 for문으로 합니다

private List<String> getParticipants(List<UserPost> userPosts){
        List<String> participants = new ArrayList<>();
        for(UserPost userpost : userPosts){
            participants.add(userpost.getUser().getNickname());
        }
        return participants;
    }

음 해결됨

{
    "status": 200,
    "message": "글 상세페이지 조회에 성공했습니다.",
    "data": {
        "author": "가나다라",
        "address": "주소주소",
        "store": "storestore",
        "minPrice": 20000,
        "deliveryCost": 2000,
        "participants": [
            "가나다라"
        ],

author은 그냥 빼고 participants에다 host까지 들어가게 바꿈

@Override
    public DetailedPostResponse getPost(Long postId, User user) {
        Post post = getPostById(postId);
        List<UserPost> userPosts = getUserPostsByPost(post);
        List<List<Menu>> allMenus = getAllMenus(userPosts,post);

        return DetailedPostResponse.builder()
            .address(post.getAddress())
            .store(post.getStore())
            .minPrice(post.getMinPrice())
            .deliveryCost(post.getDeliveryCost())
            .participants(getParticipants(userPosts))
            .menus(allMenus)
            .myMenus(getMyMenus(user, allMenus))
            .sumPrice(getSumPrice(getUserPostsByPost(post),post))
            .deadline(getDeadline(post))
            .build();
    }
{
    "status": 200,
    "message": "글 상세페이지 조회에 성공했습니다.",
    "data": {
        "address": "주소주소",
        "store": "storestore",
        "minPrice": 20000,
        "deliveryCost": 2000,
        "participants": [
            "가나다라"
        ],

여기까진 잘 나온다

 

⛳문제 발생 : 재귀가 끝나지 않음

@Override
    public DetailedPostResponse getPost(Long postId, User user) {
        Post post = getPostById(postId);
        List<UserPost> userPosts = getUserPostsByPost(post);
        List<List<Menu>> allMenus = getMenus(userPosts,post);

        return DetailedPostResponse.builder()
            .author(getAuthor(userPosts))
            .address(post.getAddress())
            .store(post.getStore())
            .minPrice(post.getMinPrice())
            .deliveryCost(post.getDeliveryCost())
            .participants(getParticipants(userPosts))
            .myMenus(getMyMenus(user, allMenus))
            .menus(allMenus)
            .sumPrice(getSumPrice(getUserPostsByPost(post),post))
            .deadline(getDeadline(post))
            .build();
    }
{
    "status": 200,
    "message": "글 상세페이지 조회에 성공했습니다.",
    "data": {
        "author": "가나다라",
        "address": "주소주소",
        "store": "storestore",
        "minPrice": 20000,
        "deliveryCost": 2000,
        "myMenus": [
            {
                "id": 1,
                "post": {
                    "id": 1,
                    "address": "주소주소",
                    "store": "storestore",
                    "minPrice": 20000,
                    "deliveryCost": 2000,
                    "category": "KOREAN",
                    "menus": [
                        {
                            "id": 1,
                            "post": {
                                "id": 1,
                                "address": "주소주소",
                                "store": "storestore",
                                "minPrice": 20000,
                                "deliveryCost": 2000,
                                "category": "KOREAN",
                                "menus": [
                                    {
                                        "id": 1,
                                        "post": {
                                            "id": 1,
                                            "address": "주소주소",
                                            "store": "storestore",
                                            "minPrice": 20000,
                                            "deliveryCost": 2000,
                                            "category": "KOREAN",
                                            "menus": [
                                                {
                                                    "id": 1,
                                                    "post": {
                                                        "id": 1,
                                                        "address": "주소주소",
                                                        "store": "storestore",
                                                        "minPrice": 20000,
                                                        "deliveryCost": 2000,
                                                        "category": "KOREAN",
                                                        "menus": [
                                                            {
                                                                "id": 1,
                                                                "post": {
                                                                    "id": 1,
                                                                    "address": "주소주소",
                                                                    "store": "storestore",
                                                                    "minPrice": 20000,
                                                                    "deliveryCost": 2000,
                                                                    "category": "KOREAN",
                                                                    "menus": [
                                                                        {
                                                                            "id": 1,
                                                                            "post": {
                                                                                "id": 1,
                                                                                "address": "주소주소",
                                                                                "store": "storestore",
                                                                                "minPrice": 20000,
                                                                                "deliveryCost": 2000,
                                                                                "category": "KOREAN",
                                                                                "menus": [
                                                                                    {
                                                                                        "id": 1,
                                                                                        "post": {
                                                                                            "id": 1,
                                                                                            "address": "주소주소",
                                                                                            "store": "storestore",
                                                                                            "minPrice": 20000,
                                                                                            "deliveryCost": 2000,
                                                                                            "category": "KOREAN",
                                                                                            "menus": [
                                                                                                {
                                                                                                    "id": 1,
                                                                                                    "post": {
                                                                                                        "id": 1,
                                                                                                        "address": "주소주소",
                                                                                                        "store": "storestore",
                                                                                                        "minPrice": 20000,
                                                                                                        "deliveryCost": 2000,
                                                                                                        "category": "KOREAN",
                                                                                                        "menus": [
                                                                                                                                                                     "deliveryCost": 2000,
                                                                                                                                                                                "category": "KOREAN",
... 이하 반복 후 에러메시지가 출력됨                                                                                                                                                                                "menus": [

{
    "status": 400,
    "message": "에러가 발생했습니다",
    "data": "Could not write JSON: Infinite recursion (StackOverflowError)"
}

myMenus가 문제임

private List<Menu> getMyMenus(User user, List<List<Menu>> allMenus){
        List<Menu> myMenus = null;

        for(List<Menu> menus : allMenus){
            if(menus.size()>0){
                if(menus.get(0).getUser().getId().equals(user.getId())){
                    myMenus = menus;
                    break;
                }
            }
        }

        return myMenus;
    }

저기에서 뭐가 오류가 나는지 모르겠네?

break가 안 되는건가 싶어서 break대신 return을 해봄

private List<Menu> getMyMenus(User user, List<List<Menu>> allMenus){
        for(List<Menu> menus : allMenus){
            if(menus.size()>0){
                if(menus.get(0).getUser().getId().equals(user.getId())){
                    return menus;
                }
            }
        }

        return null;
    }

상황이 똑같음

mymenus가 아니라 allmenus가 문제인가 싶어서 순서를 한번 바꿔봄

@Builder
public record DetailedPostResponse (
    String author,
    String address,
    String store,
    Integer minPrice,
    Integer deliveryCost,
    List<List<Menu>> menus,
    List<Menu> myMenus,
    List<String> participants,
    
    Integer sumPrice,
    LocalDateTime deadline
){
}
return DetailedPostResponse.builder()
            .author(getAuthor(userPosts))
            .address(post.getAddress())
            .store(post.getStore())
            .minPrice(post.getMinPrice())
            .deliveryCost(post.getDeliveryCost())
            .participants(getParticipants(userPosts))
            .menus(allMenus)
            .myMenus(getMyMenus(user, allMenus))
            .sumPrice(getSumPrice(getUserPostsByPost(post),post))
            .deadline(getDeadline(post))
            .build();

 

 

음 바꾸니까 allMenus가 문제였다는 걸 알게됨

{
    "status": 200,
    "message": "글 상세페이지 조회에 성공했습니다.",
    "data": {
        "author": "가나다라",
        "address": "주소주소",
        "store": "storestore",
        "minPrice": 20000,
        "deliveryCost": 2000,
        "menus": [
            [
                {
                    "id": 1,
                    "post": {
                        "id": 1,
                        "address": "주소주소",
                        "store": "storestore",
                        "minPrice": 20000,
                        "deliveryCost": 2000,
                        "category": "KOREAN",
                        "menus": [
                            {
                                "id": 1,
                                "post": {
                                    "id": 1,
                                    "address": "주소주소",
                                    "store": "storestore",
                                    "minPrice": 20000,
                                    "deliveryCost": 2000,
                                    "category": "KOREAN",
                                    "menus": [
                                        {
                                            "id": 1,
                                            "post": {
                                                "id": 1,
                                                "address": "주소주소",
                                                "store": "storestore",
                                                "minPrice": 20000,
                                                "deliveryCost": 2000,
                                                "category": "KOREAN",
                                                "menus": [

 

 

지금 allMenus가 어떻게 되고 있냐면

List<List<Menu>> allMenus = getMenus(userPosts,post);
private List<List<Menu>> getMenus(List<UserPost> userposts, Post post){

        List<List<Menu>> menus = new ArrayList<>();

        for(UserPost userpost : userposts){
            List<Menu> myMenus = getUserMenus(userpost.getUser(),post);
            menus.add(myMenus);
        }

        return menus;
    }

private List<Menu> getUserMenus(User user, Post post){
        return menuRepository.findAllByUserAndPost(user,post);
    }

음… 왜 무한반복이 되는거지…

        List<List<Menu>> menus = new ArrayList<>(); -> 미부분을 이렇게 쓰면 알아서 안 되는건가?

List<List<Menu>> menus = new ArrayList<List<Menu>>(); 이렇게 바꿔봄

아무 상관 없었음~~

ArrayList 에 add하는게 맞나 싶어서 찾아봄

https://www.baeldung.com/java-list-of-lists

private List<List<Menu>> getAllMenus(List<UserPost> userposts, Post post){

        List<List<Menu>> menus = new ArrayList<>();

        for(UserPost userpost : userposts){
            List<Menu> userMenus = getUserMenus(userpost.getUser(),post);
            menus.add(userMenus);
        }

        return menus;
    }
private List<String> getParticipants(List<UserPost> userPosts){
        return userPosts.stream()
            .filter((UserPost userPost)->userPost.getRole().equals(UserPostRole.PARTICIPANT))
            .map((UserPost userPost)->userPost.getUser().getNickname()).toList();
    }
private List<List<Menu>> getAllMenus(List<UserPost> userposts, Post post){

        List<List<Menu>> menus = new ArrayList<>();

        for(UserPost userpost : userposts){
            List<Menu> userMenus = getUserMenus(userpost.getUser(),post);
            menus.add(userMenus);
        }

        return menus;
    }

다시봐도 뭐가 잘못되었는지 모르겠고 일단 스트림으로 해봄

stream으로 바꾸다보니 List<List<Menu>>에다가 List<ArrayList<Menu>> 넣지 말라고 해서 그 부분 다 수정함

@Builder
public record DetailedPostResponse (
    String author,
    String address,
    String store,
    Integer minPrice,
    Integer deliveryCost,
    List<String> participants,
    List<ArrayList<Menu>> menus,
    List<Menu> myMenus,
    Integer sumPrice,
    LocalDateTime deadline
){
}
private List<Menu> getMyMenus(User user, List<ArrayList<Menu>> allMenus){
        for(List<Menu> menus : allMenus){
            if(menus.size()>0){
                if(menus.get(0).getUser().getId().equals(user.getId())){
                    return menus;
                }
            }
        }
        return null;
    }
private List<ArrayList<Menu>> getAllMenus(List<UserPost> userposts, Post post){
        
        List<ArrayList<Menu>> menus = userposts.stream().map((UserPost userpost)->new ArrayList<>(getUserMenus(userpost.getUser(),userpost.getPost()))).toList();
        return menus;
    }
{
    "status": 200,
    "message": "글 상세페이지 조회에 성공했습니다.",
    "data": {
        "author": "가나다라",
        "address": "주소주소",
        "store": "storestore",
        "minPrice": 20000,
        "deliveryCost": 2000,
        "participants": [],
        "menus": [
            [
                {
                    "id": 1,
                    "post": {
                        "id": 1,
                        "address": "주소주소",
                        "store": "storestore",
                        "minPrice": 20000,
                        "deliveryCost": 2000,
                        "category": "KOREAN",
                        "menus": [
                            {
                                "id": 1,
                                "post": {
                                    "id": 1,
                                    "address": "주소주소",
                                    "store": "storestore",
                                    "minPrice": 20000,
                                    "deliveryCost": 2000,
                                    "category": "KOREAN",
                                    "menus": [
                                        {

오 ~~ 여러가지 시도 다 해봐도 menus는 스트림으로 하나마나 무한반복임

private List<List<Menu>> getAllMenus(List<UserPost> userposts, Post post){

        List<List<Menu>> menus = userposts.stream().map((UserPost userpost)->getUserMenus(userpost.getUser(),userpost.getPost())).toList();
        return menus;
    }

이렇게 해봄

상황 똑같음

for문으로 다시 돌아가봄

private List<List<Menu>> getAllMenus(List<UserPost> userposts, Post post){

        List<List<Menu>> menus = new ArrayList<>();

        for(UserPost userpost : userposts){
            List<Menu> userMenus = getUserMenus(userpost.getUser(),post);
            menus.add(userMenus);
        }

        return menus;
    }
"menus": [
            [
                {
                    "id": 1,
                    "post": {
                        "id": 1,
                        "address": "주소주소",
                        "store": "storestore",
                        "minPrice": 20000,
                        "deliveryCost": 2000,
                        "category": "KOREAN",
                        "menus": [
                            {
                                "id": 1,
                                "post": {
                                    "id": 1,
                                    "address": "주소주소",
                                    "store": "storestore",
                                    "minPrice": 20000,
                                    "deliveryCost": 2000,
                                    "category": "KOREAN",
                                    "menus": [

 

💡참조에 문제가 있다고 함

menu를 가져올때 post를 가져오고 다시 menu를 가져오고 무한반복의 루프에 빠짐

Post entity에 JSON Ignore를 붙였더니 끝나긴 끝났다 아직 상호참조를 하고있지만…

@OneToMany(mappedBy = "post")
    @JsonIgnore//상호참조문제?
    private List<Menu> menus;
{
    "status": 200,
    "message": "글 상세페이지 조회에 성공했습니다.",
    "data": {
        "address": "주소주소",
        "store": "storestore",
        "minPrice": 20000,
        "deliveryCost": 2000,
        "participants": [
            "가나다라"
        ],
        "menus": [
            [
                {
                    "id": 1,
                    "post": {
                        "id": 1,
                        "address": "주소주소",
                        "store": "storestore",
                        "minPrice": 20000,
                        "deliveryCost": 2000,
                        "category": "KOREAN",
                        "sumPrice": null,
                        "deadline": "2024-01-09T23:03:49.701351"
                    },
                    "user": {
                        "id": 1,
                        "email": "email@dot.com",
                        "password": "$2a$10$lGhYCvjkDNzZyq8RkanrZ.3NRctUwVvZAbS8c9sFepIFz7U6wJUUq",
                        "nickname": "가나다라"
                    },
                    "menuname": "통새우버거",
                    "price": 5000
                },
                {
                    "id": 2,
                    "post": {
                        "id": 1,
                        "address": "주소주소",
                        "store": "storestore",
                        "minPrice": 20000,
                        "deliveryCost": 2000,
                        "category": "KOREAN",
                        "sumPrice": null,
                        "deadline": "2024-01-09T23:03:49.701351"
                    },
                    "user": {
                        "id": 1,
                        "email": "email@dot.com",
                        "password": "$2a$10$lGhYCvjkDNzZyq8RkanrZ.3NRctUwVvZAbS8c9sFepIFz7U6wJUUq",
                        "nickname": "가나다라"
                    },
                    "menuname": "통새우버거",
                    "price": 5000
                },
                {
                    "id": 3,
                    "post": {
                        "id": 1,
                        "address": "주소주소",
                        "store": "storestore",
                        "minPrice": 20000,
                        "deliveryCost": 2000,
                        "category": "KOREAN",
                        "sumPrice": null,
                        "deadline": "2024-01-09T23:03:49.701351"
                    },
                    "user": {
                        "id": 1,
                        "email": "email@dot.com",
                        "password": "$2a$10$lGhYCvjkDNzZyq8RkanrZ.3NRctUwVvZAbS8c9sFepIFz7U6wJUUq",
                        "nickname": "가나다라"
                    },
                    "menuname": "통새우버거",
                    "price": 5000
                }
            ]
        ],
        "myMenus": [
            {
                "id": 1,
                "post": {
                    "id": 1,
                    "address": "주소주소",
                    "store": "storestore",
                    "minPrice": 20000,
                    "deliveryCost": 2000,
                    "category": "KOREAN",
                    "sumPrice": null,
                    "deadline": "2024-01-09T23:03:49.701351"
                },
                "user": {
                    "id": 1,
                    "email": "email@dot.com",
                    "password": "$2a$10$lGhYCvjkDNzZyq8RkanrZ.3NRctUwVvZAbS8c9sFepIFz7U6wJUUq",
                    "nickname": "가나다라"
                },
                "menuname": "통새우버거",
                "price": 5000
            },
            {
                "id": 2,
                "post": {
                    "id": 1,
                    "address": "주소주소",
                    "store": "storestore",
                    "minPrice": 20000,
                    "deliveryCost": 2000,
                    "category": "KOREAN",
                    "sumPrice": null,
                    "deadline": "2024-01-09T23:03:49.701351"
                },
                "user": {
                    "id": 1,
                    "email": "email@dot.com",
                    "password": "$2a$10$lGhYCvjkDNzZyq8RkanrZ.3NRctUwVvZAbS8c9sFepIFz7U6wJUUq",
                    "nickname": "가나다라"
                },
                "menuname": "통새우버거",
                "price": 5000
            },
            {
                "id": 3,
                "post": {
                    "id": 1,
                    "address": "주소주소",
                    "store": "storestore",
                    "minPrice": 20000,
                    "deliveryCost": 2000,
                    "category": "KOREAN",
                    "sumPrice": null,
                    "deadline": "2024-01-09T23:03:49.701351"
                },
                "user": {
                    "id": 1,
                    "email": "email@dot.com",
                    "password": "$2a$10$lGhYCvjkDNzZyq8RkanrZ.3NRctUwVvZAbS8c9sFepIFz7U6wJUUq",
                    "nickname": "가나다라"
                },
                "menuname": "통새우버거",
                "price": 5000
            }
        ],
        "sumPrice": 15000,
        "deadline": "2024-01-09T23:03:49"
    }
}

 

Post entity에서 menus를 그냥 참조해올수 있는데 menu repository에서 해서 문제가 됐던걸까!

private List<List<Menu>> getAllMenus(List<UserPost> userposts, Post post){

        List<List<Menu>> menus = new ArrayList<>();

        for(UserPost userpost : userposts){
            List<Menu> userMenus = getUserMenus(userpost.getUser(),post);
            menus.add(userMenus);
        }

        return menus;
    }

    private List<Menu> getUserMenus(User user, Post post){
        return menuRepository.findAllByUserAndPost(user,post);
    }

private List<List<Menu>> getAllMenus(List<UserPost> userposts, Post post){

        List<List<Menu>> menus = new ArrayList<>();

        for(UserPost userpost : userposts){
            List<Menu> userMenus = userpost.getPost().getMenus();
            menus.add(userMenus);
        }

        return menus;
    }

이렇게 바꿔봄

{
    "status": 200,
    "message": "글 상세페이지 조회에 성공했습니다.",
    "data": {
        "address": "주소주소",
        "store": "storestore",
        "minPrice": 20000,
        "deliveryCost": 2000,
        "participants": [
            "가나다라"
        ],
        "menus": [
            [
                {
                    "id": 1,
                    "post": {
                        "id": 1,
                        "address": "주소주소",
                        "store": "storestore",
                        "minPrice": 20000,
                        "deliveryCost": 2000,
                        "category": "KOREAN",
                        "menus": [
                            {
                                "id": 1,
                                "post": {
                                    "id": 1,
                                    "address": "주소주소",
                                    "store": "storestore",
                                    "minPrice": 20000,
                                    "deliveryCost": 2000,
                                    "category": "KOREAN",
                                    "menus": [
                                        {

음 똑같은 문제가 일어난다

 

⚠️Spring Data JPA, @OneToMany 무한 반복 오류

 

@OneToMany Entity을 RestAPI로 리턴할때 부한 반복 오류

양방향 관계의 Entity에서 @OneToMany를 사용하면, 엔티티를 리턴할 때 순환 참조(Circular Reference) 문제가 발생할 수 있다고 함!

JSON 직렬화 시 무한 루프 -> StackOverflowError가 발생함 ( 나도 저거 발생했음! )

 

💡순환참조 해결법

  1. @JsonIgnore : 이 어노테이션을 붙이면 JSON 데이터에 해당 property는 null로 들어가게 된다. 즉, 데이터에 아예 포함시키지 않는다.
  2. @JsonManagedReference 와 @JsonBackReference : 부모 클래스(Posts entity)의 Comment 필드에 @JsonManagedReference를, 자식 클래스(Comment entity)의 Posts 필드에 @JsonBackReference를 추가해주면 순환 참조를 막을 수 있다.
  3. @JsonIgnoreProperties : 부모 클래스(Posts entity)의 Comment 필드에 @JsonIgnoreProperties({"posts"}) 를 붙여주면 순환 참조를 막을 수 있다.
  4. DTO 사용 : 위와 같은 상황이 발생하게된 주원인은 '양방향 매핑'이기도 하지만, 더 정확하게는 Entity 자체를 response로 리턴한데에 있다. entity 자체를 return 하지 말고, DTO 객체를 만들어 필요한 데이터만 옮겨담아 Client로 리턴하면 순환 참조 관련 문제는 애초에 방지 할 수 있다.
  5. 양방향 매핑을 단방향 매핑으로

🚩해결 : @JsonManagedReference 와 @JsonBackReference 달아서 해결함!!

public class Menu {

    @JsonBackReference
    @ManyToOne
    @OnDelete(action = OnDeleteAction.CASCADE)
    @JoinColumn(name = "post_id", nullable = false)
    private Post post;
public class Post {

    @JsonManagedReference
    @OneToMany(mappedBy = "post")
    private List<Menu> menus;
{
    "status": 200,
    "message": "글 상세페이지 조회에 성공했습니다.",
    "data": {
        "address": "주소주소",
        "store": "storestore",
        "minPrice": 20000,
        "deliveryCost": 2000,
        "participants": [
            "가나다라"
        ],
        "menus": [
            [
                {
                    "id": 1,
                    "user": {
                        "id": 1,
                        "email": "email@dot.com",
                        "password": "$2a$10$lGhYCvjkDNzZyq8RkanrZ.3NRctUwVvZAbS8c9sFepIFz7U6wJUUq",
                        "nickname": "가나다라"
                    },
                    "menuname": "통새우버거",
                    "price": 5000
                },
                {
                    "id": 2,
                    "user": {
                        "id": 1,
                        "email": "email@dot.com",
                        "password": "$2a$10$lGhYCvjkDNzZyq8RkanrZ.3NRctUwVvZAbS8c9sFepIFz7U6wJUUq",
                        "nickname": "가나다라"
                    },
                    "menuname": "통새우버거",
                    "price": 5000
                },
                {
                    "id": 3,
                    "user": {
                        "id": 1,
                        "email": "email@dot.com",
                        "password": "$2a$10$lGhYCvjkDNzZyq8RkanrZ.3NRctUwVvZAbS8c9sFepIFz7U6wJUUq",
                        "nickname": "가나다라"
                    },
                    "menuname": "통새우버거",
                    "price": 5000
                }
            ]
        ],
        "myMenus": [
            {
                "id": 1,
                "user": {
                    "id": 1,
                    "email": "email@dot.com",
                    "password": "$2a$10$lGhYCvjkDNzZyq8RkanrZ.3NRctUwVvZAbS8c9sFepIFz7U6wJUUq",
                    "nickname": "가나다라"
                },
                "menuname": "통새우버거",
                "price": 5000
            },
            {
                "id": 2,
                "user": {
                    "id": 1,
                    "email": "email@dot.com",
                    "password": "$2a$10$lGhYCvjkDNzZyq8RkanrZ.3NRctUwVvZAbS8c9sFepIFz7U6wJUUq",
                    "nickname": "가나다라"
                },
                "menuname": "통새우버거",
                "price": 5000
            },
            {
                "id": 3,
                "user": {
                    "id": 1,
                    "email": "email@dot.com",
                    "password": "$2a$10$lGhYCvjkDNzZyq8RkanrZ.3NRctUwVvZAbS8c9sFepIFz7U6wJUUq",
                    "nickname": "가나다라"
                },
                "menuname": "통새우버거",
                "price": 5000
            }
        ],
        "sumPrice": 15000,
        "deadline": "2024-01-09T23:03:49"
    }
}

잘 나온다!!

다시 Stream으로 바꿔봄

private List<List<Menu>> getAllMenus(List<UserPost> userposts, Post post){

        List<List<Menu>> menus = userposts.stream().map((UserPost userpost)->getUserMenus(userpost.getUser(),userpost.getPost())).toList();
        return menus;
    }

post 필요없는거 같아서 삭제함

private List<List<Menu>> getAllMenus(List<UserPost> userposts){

        List<List<Menu>> menus = userposts.stream().map((UserPost userpost)->userpost.getPost().getMenus()).toList();
        return menus;
    }

잘된다!

 

💡생각해봄

userpost.getPost().getMenus()랑 post.getMenus()랑 JPA내부적으로 생각해보면 동일한듯

userpost에 있는 postId로 post를 찾아와서 그걸로 tb_menu에서 menu들 찾아오나

post에 있는 postId로 post를 찾아와서 그걸로 tb_menu에서 menu들 찾아오나

 

근데 애초에 dto를 쓰는데 이유가 있었네ㅋㅋ

Menu를 안 돌려보내고 Menu response를 돌려보냈으면 이럴 일이 애초에 없고 user 정보도 안 나올거잖아...

User 정보가 왜 써있나 했다

Menu에 User가 들어있으니까 그걸 또 쓴거구나

Menu에 Post가 들어있으니까 그거 정보 쓰다가 그 안에 Menu가 있으니까 그거 쓰다가 무한반복이 그래서 시작된거군….

뭔가 DetailedPostResponse 짜는 중 무의식중에 dto안 만들고 그냥 Menu를 돌려보냈었는데 앞으로는 절대 그럴 일이 없을듯 ㅋㅋㅋ 

 

🚩💡더 나은 해결책

public record MenuResponse(
    String menuname,
    Integer price
) {
}
public record MenusResponse(
    String nickname,
    List<MenuResponse> menus
) {

}

걍 참여자 이름도 따로 넣지 않고 메뉴에다 넣고 myMenus를 없애고 allMenus 하나로 하는게 좋을듯

@Builder
public record DetailedPostResponse (
    String address,
    String store,
    Integer minPrice,
    Integer deliveryCost,
    List<List<MenuResponse>> menus,
    Integer sumPrice,
    LocalDateTime deadline
){
}
private List<MenusResponse> getAllMenus(List<UserPost> userposts){
        
        List<MenusResponse> menus = userposts.stream().map((UserPost userpost)->
            new MenusResponse(userpost.getUser().getNickname(),
                userpost.getPost().getMenus()
            .stream().map((Menu menu)->new MenuResponse(menu.getMenuname(),menu.getPrice())).toList()
        )).toList();
        return menus;
    }
{
    "status": 200,
    "message": "글 상세페이지 조회에 성공했습니다.",
    "data": {
        "address": "주소주소",
        "store": "storestore",
        "minPrice": 20000,
        "deliveryCost": 2000,
        "menus": [
            {
                "nickname": "가나다라",
                "menus": [
                    {
                        "menuname": "통새우버거",
                        "price": 5000
                    },
                    {
                        "menuname": "통새우버거",
                        "price": 5000
                    },
                    {
                        "menuname": "통새우버거",
                        "price": 5000
                    }
                ]
            }
        ],
        "sumPrice": 15000,
        "deadline": "2024-01-09T23:03:49"
    }
}

잘 된다!!

4. 글 카테고리별 조회

public record PostCategorySearchRequest (
    CategoryEnum categoty
){
}
package com.moayo.moayoeats.domain.post.entity;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum CategoryEnum {

    ALL("전체"),
    BURGER("햄버거"),
    CHICKEN("치킨"),
    PIZZA("피자"),
    KOREAN("한식"),
    SNACK("분식"),
    WESTERN("양식"),
    ASIAN("아시안"),
    JAPANESE("일식"),
    CHINESE("중식"),
    LUNCHBOX("도시락");

    private final String category;

}

 

 

💡저 CategoryEnum을 Bean Validation하는 방법도 있을까??

저 Enum이 아닌 값이 날아오면 에러 던지는거임

찾아보니 개발자가 직접 정의한 Enum class의 경우는 Validation 방법 또한 개발자가 직접 추가해야 한다고 함

  1. 먼저 Enum annotation을 작성한다!
package com.moayo.moayoeats.domain.post.exception.validator;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Documented
@Target({METHOD,FIELD,ANNOTATION_TYPE,CONSTRUCTOR,PARAMETER,TYPE_USE})
@Retention(RUNTIME)
@Constraint(validatedBy = {EnumValidator.class})
public @interface Enum {
    String message() default "the value should be one of the Enum";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default { };
    Class<? extends java.lang.Enum<?>> enumClass();
    boolean ignoreCase() default false;
}
package com.moayo.moayoeats.domain.post.exception.validator;

import jakarta.validation.Constraint;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;

public class EnumValidator implements ConstraintValidator<Enum,String> {

    private Enum annotation;

    @Override
    public void initialize(Enum constraintAnnotation){
        this.annotation = constraintAnnotation;
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        Object[] enumValues = this.annotation.enumClass().getEnumConstants();
        if (enumValues != null) {
            for (Object enumValue : enumValues) {
                if (value.equals(enumValue.toString())
                    || (this.annotation.ignoreCase() && value.equalsIgnoreCase(enumValue.toString()))) {
                    return true;
                }
            }
        }
        return false;
    }

}

 

annotation적용해주기

public record PostCategorySearchRequest (
    @Enum(enumClass = CategoryEnum.class)
    CategoryEnum categoty
){
}

🚩문제 . 왜 @Enum에 빨간줄이 뜨나요?

예측 1. class는 되는데 record는 안 된다

예측 2. import가 안 되어서 안 된다

import com.moayo.moayoeats.domain.post.exception.validator.Enum;

내가 정의한 Enum annotation import문 추가해주니까 안 뜬다!!

 

🚩문제 : Bean creation error막 이러면서 난리남

Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'postController' method 
com.moayo.moayoeats.domain.post.controller.PostController#getPosts(UserDetailsImpl)
to {GET [/api/v1/posts]}: There is already 'postController' bean method
com.moayo.moayoeats.domain.post.controller.PostController#getPostsByCategory(UserDetailsImpl, PostCategoryRequest) mapped.
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry.validateMethodMapping(AbstractHandlerMethodMapping.java:667) ~[spring-webmvc-6.1.2.jar:6.1.2]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry.register(AbstractHandlerMethodMapping.java:633) ~[spring-webmvc-6.1.2.jar:6.1.2]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.registerHandlerMethod(AbstractHandlerMethodMapping.java:331) ~[spring-webmvc-6.1.2.jar:6.1.2]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.registerHandlerMethod(RequestMappingHandlerMapping.java:486) ~[spring-webmvc-6.1.2.jar:6.1.2]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.registerHandlerMethod(RequestMappingHandlerMapping.java:79) ~[spring-webmvc-6.1.2.jar:6.1.2]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lambda$detectHandlerMethods$2(AbstractHandlerMethodMapping.java:298) ~[spring-webmvc-6.1.2.jar:6.1.2]
	at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:721) ~[na:na]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.detectHandlerMethods(AbstractHandlerMethodMapping.java:296) ~[spring-webmvc-6.1.2.jar:6.1.2]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.processCandidateBean(AbstractHandlerMethodMapping.java:265) ~[spring-webmvc-6.1.2.jar:6.1.2]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.initHandlerMethods(AbstractHandlerMethodMapping.java:224) ~[spring-webmvc-6.1.2.jar:6.1.2]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.afterPropertiesSet(AbstractHandlerMethodMapping.java:212) ~[spring-webmvc-6.1.2.jar:6.1.2]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.afterPropertiesSet(RequestMappingHandlerMapping.java:233) ~[spring-webmvc-6.1.2.jar:6.1.2]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1820) ~[spring-beans-6.1.2.jar:6.1.2]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1769) ~[spring-beans-6.1.2.jar:6.1.2]
	... 67 common frames omitted

 

public record PostCategoryRequest(
    //@Enum(enumClass = CategoryEnum.class)
    CategoryEnum categoty
){
}

Enum 주석처리해봄

Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'postController' method 
com.moayo.moayoeats.domain.post.controller.PostController#getPostsByCategory(UserDetailsImpl, PostCategoryRequest)
to {GET [/api/v1/posts]}: There is already 'postController' bean method
com.moayo.moayoeats.domain.post.controller.PostController#getPosts(UserDetailsImpl) mapped.
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry.validateMethodMapping(AbstractHandlerMethodMapping.java:667) ~[spring-webmvc-6.1.2.jar:6.1.2]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry.register(AbstractHandlerMethodMapping.java:633) ~[spring-webmvc-6.1.2.jar:6.1.2]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.registerHandlerMethod(AbstractHandlerMethodMapping.java:331) ~[spring-webmvc-6.1.2.jar:6.1.2]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.registerHandlerMethod(RequestMappingHandlerMapping.java:486) ~[spring-webmvc-6.1.2.jar:6.1.2]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.registerHandlerMethod(RequestMappingHandlerMapping.java:79) ~[spring-webmvc-6.1.2.jar:6.1.2]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lambda$detectHandlerMethods$2(AbstractHandlerMethodMapping.java:298) ~[spring-webmvc-6.1.2.jar:6.1.2]
	at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:721) ~[na:na]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.detectHandlerMethods(AbstractHandlerMethodMapping.java:296) ~[spring-webmvc-6.1.2.jar:6.1.2]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.processCandidateBean(AbstractHandlerMethodMapping.java:265) ~[spring-webmvc-6.1.2.jar:6.1.2]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.initHandlerMethods(AbstractHandlerMethodMapping.java:224) ~[spring-webmvc-6.1.2.jar:6.1.2]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.afterPropertiesSet(AbstractHandlerMethodMapping.java:212) ~[spring-webmvc-6.1.2.jar:6.1.2]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.afterPropertiesSet(RequestMappingHandlerMapping.java:233) ~[spring-webmvc-6.1.2.jar:6.1.2]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1820) ~[spring-beans-6.1.2.jar:6.1.2]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1769) ~[spring-beans-6.1.2.jar:6.1.2]
	... 67 common frames omitted

똑같음

 

to {GET [/api/v1/posts]}: There is already 'postController' bean method

아 내가 다른 인텔리제이 창 실행시키고 있었나봄

아니었다

뭐가 문제일까

구글링해보니까 내가 PostController에서 똑같은 api, 똑같은 mapping으로 보내는게 두개라서 깨지는거라고 함

// 모든 글 조회하기
    @GetMapping("/posts")
    public ApiResponse<List<BriefPostResponse>> getPosts(
        @AuthenticationPrincipal UserDetailsImpl userDetails
    ){
        return new ApiResponse<>(HttpStatus.OK.value(), "모든 글 조회에 성공했습니다.",postService.getPosts(userDetails.getUser()));
    }

저기에서 이미 /posts를 쓰고있는데 또 쓰려고 했다…

 

⛳해결 : 중복되던 api 주소 서로 다르게 바꿔줌!

그리고 Custon Enum Validation도 해보게 @Valid도 달아봄~

//글 카테고리별 조회
    @GetMapping("/posts/category")
    public ApiResponse<List<BriefPostResponse>> getPostsByCategory(
        @AuthenticationPrincipal UserDetailsImpl userDetails,
        @Valid @RequestBody PostCategoryRequest postCategorySearchReq
    ){
        return new ApiResponse<>(HttpStatus.OK.value(), "글 카테고리별 조회에 성공했습니다.",postService.getPostsByCategory(postCategorySearchReq, userDetails.getUser()));
    }

 

{
    "status": 400,
    "message": "에러가 발생했습니다",
    "data": "HV000030: No validator could be found for constraint 'com.moayo.moayoeats.domain.post.exception.validator.Enum' validating type 'com.moayo.moayoeats.domain.post.entity.CategoryEnum'. Check configuration for 'categoty'"
}

ㅜㅜ 오류발생함

public record PostCategoryRequest(
//    @Enum(enumClass = CategoryEnum.class)
    CategoryEnum categoty
){
}

Enum 일단 주석처리함!

{
    "category":"All"
}
public record PostCategoryRequest(
//    @Enum(enumClass = CategoryEnum.class)
    CategoryEnum categoty
){
}
{
    "status": 400,
    "message": "에러가 발생했습니다",
    "data": "Cannot invoke \\"com.moayo.moayoeats.domain.post.entity.CategoryEnum.getCategory()\\" because the return value of \\"com.moayo.moayoeats.domain.post.dto.request.PostCategoryRequest.categoty()\\" is null"
}

왜 안돼..?

dto에 categoty로 오타남 ㅋㅋ

오타 수정하고 다시 해봄

{
    "category":"ALL"
}
{
    "status": 200,
    "message": "글 카테고리별 조회에 성공했습니다.",
    "data": []
}

 

 

🚩문제 : db조회가 안 됨

{
    "category":"KOREAN"
}
{
    "status": 200,
    "message": "글 카테고리별 조회에 성공했습니다.",
    "data": []
}
@Override
    public List<BriefPostResponse> getPostsByCategory(
        PostCategoryRequest postCategoryReq,
        User user
    ) {
        List<Post> posts;
        if(postCategoryReq.category().getCategory().equals(CategoryEnum.ALL)){
            posts = findAll();
        }else{
            posts = postRepository.findAllByCategoryEquals(postCategoryReq.category()).orElse(null);
        }
        return postsToBriefResponses(posts);
    }

이걸 들여다보면 if나 else가 제대로 동작을 안 했을때 

List<Post> posts;
return postsToBriefResponses(posts);

만 수행되면 null이 돌아감

 

Enum은 equals쓰는거 아닌가??

Enum 비교 ==인지 equals인지 갑자기 헷갈려서 찾아봄

둘 다 된다고 함

 

⭐Enum equals()와 == 의 차이점

== never throws NullPointerException

== is subject to type compatibility check at compile time

 

 

postCategoryReq.category().getCategory().equals(CategoryEnum.ALL

인텔리제이가 이 문장이 언제나 false라고 함

왜…??!!

posts = postRepository.findAllByCategoryEquals(postCategoryReq.category().getCategory())

else안도 이렇게 바꿔봤는데

postCategoryReq.category().getCategory())

여기에 빨간줄이 그어짐!

인텔리제이가 expected type이 CategoryEnum인데 provided가 String이라고 함

그리고 CateforyEnum.valueOf를 대신 써보라고 함

예전 프로젝트에서는 Enum 만들때

걍 이렇게 만들어서 썼었는데

public enum CategoryEnum {

    ALL,
    BURGER,
    CHICKEN),
    PIZZA,
    KOREAN,
    SNACK,
    WESTERN,
    ASIAN,
    JAPANESE,
    CHINESE,
    LUNCHBOX;

}

이번에는 String category를 만들어봐서 저런 문제가 발생한 거 같다..!

근데 아무데도 안 쓰는 저 String을 왜 해놨는지 의문이긴 함

public enum CategoryEnum {

    ALL("전체"),
    BURGER("햄버거"),
    CHICKEN("치킨"),
    PIZZA("피자"),
    KOREAN("한식"),
    SNACK("분식"),
    WESTERN("양식"),
    ASIAN("아시안"),
    JAPANESE("일식"),
    CHINESE("중식"),
    LUNCHBOX("도시락");

    private final String category;

}

db에 String을 저장하고 싶어서 저랬던 거 같은데

지금 db를 들어가서 보니 KOREAN으로 넣은게 3이라는 Enum으로 들어가있음

@Column
@Enumerated(EnumType.STRING)
private CategoryEnum category;

이렇게 바꿔봄

테이블 드랍하고 새로 Post 생성해봄

posts = postRepository.findAllByCategoryEquals(postCategoryReq.category().getCategory()).orElse(null);

여기서 에러나서 빌드가 안 됨

public interface PostRepository extends JpaRepository<Post, Long> {
    Optional<List<Post>> findAllByCategoryEquals(CategoryEnum category);
}

이걸 수정함

Optional<List<Post>> findAllByCategoryEquals(String category);

새로 Post 생성해서 넣어봄

KOREAN으로 잘 들어가있음!!

{
    "status": 400,
    "message": "에러가 발생했습니다",
    "data": "Argument [한식] of type [java.lang.String] did not match parameter type [com.moayo.moayoeats.domain.post.entity.CategoryEnum (n/a)]"
}

이렇게 해봄

{
    "category":"한식"
}
{
    "status": 400,
    "message": "에러가 발생했습니다",
    "data": "JSON parse error: Cannot deserialize value of type `com.moayo.moayoeats.domain.post.entity.CategoryEnum` from String \\"한식\\": not one of the values accepted for Enum class: [ALL, WESTERN, ASIAN, BURGER, PIZZA, CHINESE, SNACK, LUNCHBOX, CHICKEN, JAPANESE, KOREAN]"
}

ㅋㅋㅋㅋ

걍 “한식”부분 다 빼고 그냥 예전처럼 String 대신 그냥 Enum 이름만 있게 함

posts = postRepository.findAllByCategoryEquals(postCategoryReq.category().getCategory()).orElse(null);

posts = postRepository.findAllByCategoryEquals(postCategoryReq.category()).orElse(null);

이거 바꾸고

public interface PostRepository extends JpaRepository<Post, Long> {
    Optional<List<Post>> findAllByCategoryEquals(String category);
}

Optional<List<Post>> findAllByCategoryEquals(CategoryEnum category);

이것도 바꿈

 

 

이렇게 해두면 숫자일거같은데…

Enum 바뀌거나 db 변경사항 있을때 큰일나지 않나?

Post 생성하고 앞번호에 Enum하나 추가한다음에 다시 찾아봄

{
    "status": 200,
    "message": "글 카테고리별 조회에 성공했습니다.",
    "data": [
        {
            "id": 1,
            "author": "가나다라",
            "address": "주소주소",
            "store": "storestore",
            "minPrice": 20000,
            "sumPrice": 5000,
            "deadline": "2024-01-11T00:41:48"
        },
        {
            "id": 2,
            "author": "가나다라",
            "address": "주소주소",
            "store": "storestore",
            "minPrice": 20000,
            "sumPrice": 10000,
            "deadline": "2024-01-11T00:41:49"
        },
        {
            "id": 3,
            "author": "가나다라",
            "address": "주소주소",
            "store": "storestore",
            "minPrice": 20000,
            "sumPrice": 5000,
            "deadline": "2024-01-11T00:41:50"
        }
    ]
}

KOREAN으로 등록해둔거임

@Getter
@RequiredArgsConstructor
public enum CategoryEnum {

    TEST,
    ALL,
    BURGER,
    CHICKEN,
    PIZZA,
    KOREAN,
    SNACK,
    WESTERN,
    ASIAN,
    JAPANESE,
    CHINESE,
    LUNCHBOX;

}

TEST를 추가해봄

그리고 다시 조회해보니까 똑같이 나옴

{
    "status": 200,
    "message": "글 카테고리별 조회에 성공했습니다.",
    "data": [
        {
            "id": 1,
            "author": "가나다라",
            "address": "주소주소",
            "store": "storestore",
            "minPrice": 20000,
            "sumPrice": 5000,
            "deadline": "2024-01-11T00:41:48"
        },
        {
            "id": 2,
            "author": "가나다라",
            "address": "주소주소",
            "store": "storestore",
            "minPrice": 20000,
            "sumPrice": 10000,
            "deadline": "2024-01-11T00:41:49"
        },
        {
            "id": 3,
            "author": "가나다라",
            "address": "주소주소",
            "store": "storestore",
            "minPrice": 20000,
            "sumPrice": 5000,
            "deadline": "2024-01-11T00:41:50"
        }
    ]
}

String으로 등록했을때 Enum으로 equals하는건 숫자 대신 String으로 해주나봄!

'Developing > 개발일지' 카테고리의 다른 글

2024-01-12, Today I Learned  (0) 2024.01.12
2024-01-11, Today I Learned  (1) 2024.01.11
2024-01-09, Today I Learned @IdClass Composite key in Spring  (0) 2024.01.09
2024-01-08, Today I Learned  (1) 2024.01.08
2024-01-03, Today I Learned  (0) 2024.01.03