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

2023-12-07, Today I Leanred

by Greedy 2023. 12. 7.

오늘 한 일

오늘도 유사 당근마켓(햇살마켓) 개발을 계속 했다

1. User → Seller로 변경

UserId를 Item에 넣어두고 있었는데 판매자 프로필과 구매자 프로필을 따로따로 하기로 해서 Item에는 User대신 Seller를 넣었다

2. 주문(구매 요청) 기능 만들기 주문 CRUD는 오늘 다 했다!

 

내일 할 일

주문 승인처리, 배송 완료처리

 

1. User → Seller로 변경

@ManyToOne
    @JoinColumn(name = "seller_id")
    private Seller seller;

전에 User였던 것을 Seller로 바꾸니까 그냥 됐음

 

2. 주문(구매 요청) 기능 만들기

2-1. Order Entity를 생성함

@Getter
@Entity
@Table(name = "orders")
public class Order {
    private final int ORDER_PENDING = 1;
    private final int ORDER_ACCEPTED = 2;
    private final int ORDER_REJECTED = 3;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @JoinColumn(name = "item_id")
    private Item item;

    @JoinColumn(name = "buyer_id")
    private Buyer buyer;

    private int orderStatus;

}

Order의 진행 상황을 어떻게 표시할지 생각하다가 상태 코드를 만들고 그걸 상수로 만들어서 상태 업데이트 함수로 orderStatus에 값 넣어주기로 함

아 근데 나는 Column 안 붙이면 db에 안 들어가는줄 알고

이래놨는데 db에 order_accepted, order_pending, order_rejected가 다 들어가있음ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

public class Order extends Timestamped {
//    private final String  ORDER_PENDING = "Pending";
//    private final String ORDER_ACCEPTED = "Accepted";
//    private final String ORDER_REJECTED = "Rejected";

그래서 그냥 삭제하고 String값으로 함 내일 Enum을 공부하고 다시 해보기로 했음

 

⛳문제 : 그렇게 하고 나니까 Item에 오류가 뜸

basic attribute type should not be ‘attribute entity’

🚩해결 : @ManyToOne 달아주니까 사라졌다

item이 삭제될때 그거에 딸린 orders도 삭제되어야 하니까 cascade를 Item에다 달아줌

@OneToMany
    @JoinColumn(name = "item_id")
    private List<Order> orders;
@OneToMany(mappedBy = "item",cascade = CascadeType.PERSIST,orphanRemoval = true)
    @JoinColumn(name = "item_id")
    private List<Order> orders;

이렇게 만들어줌!

item이 삭제되면 거기에 딸린 order들도 삭제되도록

 

🚩문제 : 실행이 안 됨

with name 'webSecurityConfig' defined in file [E:\Workspace\Temp\SunlightMarket\build\classes\java\main\com\raincloud\sunlightmarket\global\config\WebSecurityConfig.class]: Unsatisfied dependency expressed through constructor parameter 1: Error creating bean with name 'userDetailsServiceImpl' defined in file [E:\Workspace\Temp\SunlightMarket\build\classes\java\main\com\raincloud\sunlightmarket\global\security\UserDetailsServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'userRepository' defined in com.raincloud.sunlightmarket.user.repository.UserRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Cannot resolve reference to bean 'jpaSharedEM_entityManagerFactory' while setting bean property 'entityManager’

Cannot resolve reference to bean 'jpaSharedEM_entityManagerFactory' while setting bean property 'entityManager’

구글링함

Exception says that there is no bean with name entityManagerFactory, Place a debug point in

public LocalContainerEntityManagerFactoryBean entityManagerFactory(
            EntityManagerFactoryBuilder factoryBuilder)

method org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration.class and check why the bean is not getting initiated.

Oh, From discussion I came to the conclusion that mentioned issue is due to hibernate older dependencies. Also, the @Id which was imported needs to be from javax.persistence.id for all your entities.

Association 'com.raincloud.sunlightmarket.item.entity.Item.orders' is 'mappedBy' another entity and may not specify the '@JoinColumn' at org.hibernate.boot.model.internal.CollectionBinder.detectMappedByProblem(CollectionBinder.java:1239) ~[hibernate-core-6.2.13.Final.jar:6.2.13.Final] at org.hibernate.boot.model.internal.CollectionBinder.bind(CollectionBinder.java:1154) ~[hibernate-core-6.2.13.Final.jar:6.2.13.Final] at org.hibernate.boot.model.internal.CollectionBinder.bindCollection(CollectionBinder.java:353) ~[hibernate-core-6.2.13.Final.jar:6.2.13.Final] at org.hibernate.boot.model.internal.PropertyBinder.bindProperty(PropertyBinder.java:873) ~[hibernate-core-6.2.13.Final.jar:6.2.13.Final] at org.hibernate.boot.model.internal.PropertyBinder.buildProperty(PropertyBinder.java:787) ~[hibernate-core-6.2.13.Final.jar:6.2.13.Final] at org.hibernate.boot.model.internal.PropertyBinder.processElementAnnotations(PropertyBinder.java:708) ~[hibernate-core-6.2.13.Final.jar:6.2.13.Final] at org.hibernate.boot.model.internal.EntityBinder.processIdPropertiesIfNotAlready(EntityBinder.java:967) ~[hibernate-core-6.2.13.Final.jar:6.2.13.Final] at org.hibernate.boot.model.internal.EntityBinder.handleIdentifier(EntityBinder.java:302) ~[hibernate-core-6.2.13.Final.jar:6.2.13.Final] at org.hibernate.boot.model.internal.EntityBinder.bindEntityClass(EntityBinder.java:228) ~[hibernate-core-6.2.13.Final.jar:6.2.13.Final] at org.hibernate.boot.model.internal.AnnotationBinder.bindClass(AnnotationBinder.java:417) ~[hibernate-core-6.2.13.Final.jar:6.2.13.Final] at org.hibernate.boot.model.source.internal.annotations.AnnotationMetadataSourceProcessorImpl.processEntityHierarchies(AnnotationMetadataSourceProcessorImpl.java:255) ~[hibernate-core-6.2.13.Final.jar:6.2.13.Final] at org.hibernate.boot.model.process.spi.MetadataBuildingProcess$1.processEntityHierarchies(MetadataBuildingProcess.java:278) ~[hibernate-core-6.2.13.Final.jar:6.2.13.Final] at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:321) ~[hibernate-core-6.2.13.Final.jar:6.2.13.Final] at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1383) ~[hibernate-core-6.2.13.Final.jar:6.2.13.Final] at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1454) ~[hibernate-core-6.2.13.Final.jar:6.2.13.Final]

 

⛳해결 : 

@OneToMany(mappedBy = "item",cascade = CascadeType.PERSIST,orphanRemoval = true)
@JoinColumn(name = "item_id")

@OneToMany(mappedBy = "item",cascade = CascadeType.PERSIST,orphanRemoval = true)
joincolumn 삭제

 

 

🚩문제 : references items (item_id)" via JDBC [Failed to add the foreign key constraint. Missing column 'item_id' for constraint 'FK247nnxschdfm8lre0ssvy3k1r' in the referenced table 'items']

alter table orders add constraint FK247nnxschdfm8lre0ssvy3k1r foreign key (item_id) references items (item_id)" via JDBC [Failed to add the foreign key constraint. Missing column 'item_id' for constraint 'FK247nnxschdfm8lre0ssvy3k1r' in the referenced table 'items']

@Table(name = "items")
@NoArgsConstructor
public class Item extends Timestamped {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "item_id")
    private Long id;

⛳해결 : name = item_id도 삭제해봄

그러니까 됨

Q. 왜?

 

🚩문제 : 

localhost:8080/api/orders/add?itemId=1

403 인증문제 아니라고 함

ERROR 31240 --- [nio-8080-exec-6] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.NullPointerException: Cannot invoke "com.raincloud.sunlightmarket.order.service.OrderService.addOrder(com.raincloud.sunlightmarket.order.dto.OrderRequestDto, java.lang.Long, com.raincloud.sunlightmarket.user.entity.User)" because "this.orderService" is null] with root cause

public class OrderController { private OrderService orderService;

이게 회색으로 뜨고 autowired가 안 됨 왜지…

public OrderController(OrderService orderService){
        this.orderService = orderService;
    }

이렇게 넣어주니까 회색이 보라색 됨

ERROR 22552 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.NullPointerException: Cannot invoke "com.raincloud.sunlightmarket.order.service.OrderService.addOrder(com.raincloud.sunlightmarket.order.dto.OrderRequestDto, java.lang.Long, com.raincloud.sunlightmarket.user.entity.User)" because "this.orderService" is null] with root cause

java.lang.NullPointerException: Cannot invoke "com.raincloud.sunlightmarket.order.service.OrderService.addOrder(com.raincloud.sunlightmarket.order.dto.OrderRequestDto, java.lang.Long, com.raincloud.sunlightmarket.user.entity.User)" because "this.orderService" is null

근데 또 안들어가네 뭐지

 

⛳해결 : final 추가했더니 보라색 되고 에러 사라지고 잘 동작함

private OrderService orderService → private final OrderService orderService;

 

Q. 왜죠?

{
    "status": 201,
    "message": "구매 요청 성공했습니다",
    "data": {
        "buyerName": null,
        "address": "주소주소",
        "orderStatus": "Pending"
    }
}

 

🚩문제 : 2023-12-07T17:13:03.025+09:00 WARN 30216 --- [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content-Type 'text/plain;charset=UTF-8' is not supported]

와 근데 희한한게 item 1에는 order가 들어가지고 item 2에는 order이 안 들어가짐

localhost:8080/api/orders/add?itemId=1

{
    "status": 201,
    "message": "구매 요청 성공했습니다",
    "data": {
        "buyerName": "닉",
        "address": "주소주소",
        "orderStatus": "PENDING"
    }
}
localhost:8080/api/orders/add?itemId=2

403forbidden

Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content-Type 'text/plain;charset=UTF-8' is not supported]

이 창에서 1로 보내면 또 안 들어감

아까 되던 창에서 2로 보내면 그거는 또 들어감

⛳해결 :  포스트맨에서 JSON이 아니라 text로 보내고 있었음, JSON 으로 보내니까 잘 됨

 

 

근데 본인이 본인의 글에다가 댓글을 달 수 있으면 안될 거 같음

private Item getNotUserItemById(Long itemId, User user){
        Item item = itemRepository.findById(itemId).orElseThrow(NullPointerException::new);
        Seller seller = item.getSeller();
        User user = getUserBySeller(seller);
    }

 

💡개선 : 바보같이 Join한 Column을 findBy ... 만들어서 가져오던거 그냥 가져오게 수정함

private User getUserBySeller(Seller seller){
        User user = userRepository.findBySellerId(seller.getId()).orElseThrow(NullPointerException::new);
        return user;
    }

이렇게 하고 있다가 깨달음 그냥 가져올 수 있는 거 같은데…?

item.getSeller().getUser();

itemService에서

public ItemResponseDto addItem(ItemRequestDto requestDto, User user) {
        Seller seller = getSellerByUser(user);

...

private Seller getSellerByUser(User user){
        Seller seller = sellerRepository.findByUserId(user.getId()).orElseThrow(NullPointerException::new);
        return seller;
    }

이러고 있었던거 그냥

public ItemResponseDto addItem(ItemRequestDto requestDto, User user) {
        Seller seller = user.getSeller();

이렇게 다 수정함

 

 

💡발견 !! : ApiResponse로 감싸고 에러 날렸더니

{
    "status": 400,
    "message": "작성자는 구매 요청을 할 수 없습니다.",
    "data": null
}

이렇게 리턴값이 옴

→ 위에서 RejectedError에 상태메시지 넣어서 날렸더니

controller단에서 RejectedError를 catch로 받아서 에러메시지가 출력되는듯 !!

어떻게 할지 고민하고 있었는데 좋았다

NullPointerException도 상태메시지 넣어서 Catch해 버리면 될듯

 

🚩문제 : .orElseThrow(NullPointerException::new); 저 안에 상태 메시지를 넣은 NullPointerException을 생성할 줄 모름

⛳해결 : 저 :: 이 부분이 람다식이라는 것을 알고 나서 .orElseThrow(()-> new NullPointerException("해당 id로 아이템을 찾을 수 없습니다."))); 이렇게 함

 

Controller--------
@PostMapping("/add")
    public ApiResponse<OrderResponseDto> addOrder(
            @RequestBody OrderRequestDto requestDto,
            @RequestParam Long itemId,
            @AuthenticationPrincipal UserDetailsImpl userDetails
    ) {
        try {
            OrderResponseDto responseDto = orderService.addOrder(requestDto,itemId, userDetails.getUser());
            return new ApiResponse<OrderResponseDto>(HttpStatus.CREATED.value(),"구매 요청 성공했습니다",responseDto);
        }catch (RejectedExecutionException | IllegalArgumentException ex){
            return new ApiResponse<OrderResponseDto>(HttpStatus.BAD_REQUEST.value(),ex.getMessage());
        }
    }
Service----------
public OrderResponseDto addOrder(OrderRequestDto requestDto, Long itemId , User user)
    {
        Item item  = getNotUserItemById(itemId,user);
        Buyer buyer = user.getBuyer();
        Order order = new Order(requestDto,item,buyer);
        orderRepository.save(order);
        return new OrderResponseDto(order);
    }
private Item getNotUserItemById(Long itemId, User user){
        Item item = itemRepository.findById(itemId).orElseThrow(Item item = itemRepository.findById(itemId).orElseThrow(()-> new NullPointerException("해당 id로 아이템을 찾을 수 없습니다.")););
        User userFound = item.getSeller().getUser();
        if(userFound.getId().equals(user.getId())){
            throw new RejectedExecutionException("작성자는 구매 요청을 할 수 없습니다.");
        }
        return item;
    }
Result-------------
{
    "status": 400,
    "message": "작성자는 구매 요청을 할 수 없습니다.",
    "data": null
}

 

저렇게 하니까 NullPointerException도 받아서 ApiResponse로 상태메시지 출력되어짐!!

 

 

💡개선 : 아이템(판매글)작성자가 댓글(구매요청)을 달지 못하게 하기 위해서

public OrderResponseDto addOrder(OrderRequestDto requestDto, Long itemId , User user)
    {
        Item item  = getNotUserItemById(itemId,user);
        Buyer buyer = getBuyerByUser(user);
        Order order = new Order(requestDto,item,buyer);
        orderRepository.save(order);
        return new OrderResponseDto(order);
    }
private Item getItemById(Long itemId){
         Item item = itemRepository.findById(itemId).orElseThrow(NullPointerException::new);
        return item;
    }

private Item getNotUserItemById(Long itemId, User user){
        Item item = itemRepository.findById(itemId).orElseThrow(NullPointerException::new);
        User userFound = item.getSeller().getUser();
        if(userFound.getId().equals(user.getId())){
            throw new RejectedExecutionException("작성자는 구매 요청을 할 수 없습니다.");
        }
        return item;
    }

이렇게 수정함

 

그러고 나니까 자기 Item 조회할때는 그 Item에 들어온 요청목록을 보이게 하고 싶어졌음

남의 Item을 볼 때나 비로그인시에는 안 보이고

나는 Filter에서 조회하는 부분을 걸러버렸는데 저 부분을 어떻게 구현할지 생각해 보다가

혹시 method주소랑 path가 같아도 parameter가 다르면 오버라이딩 되나 싶어짐

근데 controller로 요청이 들어오기 전에 filter에서 걸러버린다는데 로그인을 안 했는데 Authentication이 되나..?

아니다 남들도 요청을 볼 수 있으면 되나..?

try {
            ItemAllResponseDto responseDto = new ItemAllResponseDto();
            responseDto.setItemResponseDtos(itemService.getAllItems());
            return new ApiResponse<ItemAllResponseDto>(HttpStatus.OK.value(),"아이템 조회에 성공했습니다",responseDto);
        }catch (RejectedExecutionException | IllegalArgumentException | NullPointerException ex){
            return new ApiResponse<ItemAllResponseDto>(HttpStatus.BAD_REQUEST.value(),ex.getMessage());
        }

Controller

@GetMapping("/read")
    public ApiResponse<List<OrderResponseDto>> getOrdersForAll(
            @RequestParam Long itemId
    ) {
        try {
            List<OrderResponseDto> responseDto = orderService.getOrders(itemId);
            return new ApiResponse<List<OrderResponseDto>>(HttpStatus.OK.value(),"구매 요청 성공했습니다",responseDto);
        }catch (RejectedExecutionException | NullPointerException ex){
            return new ApiResponse<List<OrderResponseDto>>(HttpStatus.BAD_REQUEST.value(),ex.getMessage());
        }
    }

Service

public List<OrderResponseDto> getOrders(Long itemId){
        return orderRepository.findAllByItemId(itemId).stream()
                .map(OrderResponseDto::new)
                .collect(Collectors.toList());
    }

 

⛳문제 : 웃긴게 1개만 들어있는 Order는 반환이 되는데

한 Item에 Order이 2개 이상 들어있으면 안 됨

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.dao.IncorrectResultSizeDataAccessException: query did not return a unique result: 2] with root cause

Item은 어케한거야

jakarta.persistence.NonUniqueResultException: query did not return a unique result: 2 at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:128) ~[hibernate-core-6.2.13.Final.jar:6.2.13.Final] at org.hibernate.query.spi.AbstractSelectionQuery.getSingleResult(AbstractSelectionQuery.java:482) ~[hibernate-core-6.2.13.Final.jar:6.2.13.Final]

The error message says it all. findByDescription() is supposed to return 0 or 1 DocumentType, but it returns several ones. So either your Java design, or your data is corrupted. If you're really supposed to have a single document type with a given description, there should be a unique constraint in the database, that would prevent you from breaking that rule.

List<Item> findAllByOrderByModifiedAtDesc();

Item은 이렇게 함

앗 바본가 orderRepository에 이렇게 해놨음

당연히 하나밖에 리턴이 안되겠죠..

Optional <Order> findAllByItemId(Long itemId);

⛳해결 : Optional<Order> -> List<Order>로 수정함

 

💡개선 : List<Order>도 Optional로 감싸서 null일때 에러 throw하고 싶어짐

public List<OrderResponseDto> getOrders(Long itemId){
        return orderRepository.findAllByItemId(itemId)
                .stream()
                .map(OrderResponseDto::new)
                .collect(Collectors.toList());
    }

근데 이것도 못찾거나 null일때 에러 리턴하고 싶은데…

Optional로 감싸봄

Optional<List<Order>> findAllByItemId(Long itemId);

여기는 이렇게 해봄

public List<OrderResponseDto> getOrders(Long itemId){
        return orderRepository.findAllByItemId(itemId).orElseThrow(()-> new NullPointerException("해당 id로 주문요청을 찾을 수 없습니다."))
                .stream()
                .map(OrderResponseDto::new)
                .collect(Collectors.toList());
    }

잘 됨

 

 

🚩문제 : Order update기능 구현하고 수정할 request를 보내니까 백지가 뜸

Error도 안 잡힘 

⛳해결 : 헤더에 Authorization안 넣은 거였어서 저거 넣어줌

 

🚩문제 : 이제 response는 오는데 db가 안 바뀜

"message": "구매 요청 업데이트 성공했습니다",
    "data": {
        "orderId": 5,
        "buyerName": "닉2",
        "address": "수정수정",
        "price": "가격가격",
        "orderStatus": "PENDING"
    }
}

아 뭔가

Transaction안 달아놓은 거 같음

Service단의 Update함수에는 @Transactional

이걸 꼭 달아줘야 함

Q. 저걸 왜 달아줘야 하더라…

해결 : Service의 update method에 @Transaction 달아주니까 잘 됐음

저거 달아주니까 이제 됐다

 

🎪하고싶은 것 : 로그인했을때/ 로그인 안 했을때 path는 같고 method명이랑 variable은 다르게 메서드들 오버로딩 하는 것!

Controller

@GetMapping("/read")
    public ApiResponse<List<OrderResponseDto>> getOrdersForAll(
            @RequestParam Long itemId
    ) {
        try {
            List<OrderResponseDto> responseDto = orderService.getOrders(itemId);
            return new ApiResponse<List<OrderResponseDto>>(HttpStatus.OK.value(),"구매 요청 조회에 성공했습니다",responseDto);
        }catch (RejectedExecutionException | NullPointerException ex){
            return new ApiResponse<List<OrderResponseDto>>(HttpStatus.BAD_REQUEST.value(),ex.getMessage());
        }
    }

    @GetMapping("/read")
    public ApiResponse<List<OrderResponseDto>> getOrdersForItemAuthor(
            @RequestParam Long itemId,
            @AuthenticationPrincipal UserDetailsImpl userDetails
    ) {
        try {
            List<OrderResponseDto> responseDto = orderService.getOrdersForUsers(itemId, userDetails.getUser());
            return new ApiResponse<List<OrderResponseDto>>(HttpStatus.OK.value(),"구매 요청 조회에 성공했습니다",responseDto);
        }catch (RejectedExecutionException | NullPointerException ex){
            return new ApiResponse<List<OrderResponseDto>>(HttpStatus.BAD_REQUEST.value(),ex.getMessage());
        }
    }

Service에서 아이템의 작성자면 order에 id랑 address출력해주고

아니면 저거 빼고 출력하는게 하고싶음

public List<OrderResponseDto> getOrdersForUsers(Long itemId, User user){
        List<Order> orders = orderRepository.findAllByItemId(itemId).orElseThrow(()-> new NullPointerException("해당 id로 구매요청을 찾을 수 없습니다."));
        if(orders.get(0).getItem().getSeller().equals(user.getSeller())){
            return orders.stream()
                    .map(OrderResponseDto::new)
                    .collect(Collectors.toList());
        }else {

        }
    }

 

🚩문제 : 근데 상황에 따라서 리턴 타입이 달라야됨

OrderResponseDto에는 orderid랑 address가 표시되고

저게 약간 바깥에 보여주기 싫은 정보나 개인정보일 수 있으니

PublicOrderResponseDto에는 orderid랑 address를 뺀 price랑 nickname이런것만 출력됨

상황에 따라서 리턴 타입이 다른걸 대체 어떻게 하냐 싶었음

 

⛳해결 : 그래서 데이터타입이 두개 있는 리턴 타입 클래스를 제너릭으로 만들어봄

package com.raincloud.sunlightmarket.global.dto;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class DoubleResponse<T,U> {
    
    private T data1;
    private U data2;

    public DoubleResponse(T data1, U data2){
        this.data1 = data1;
        this.data2 = data2;
    }
}
public DoubleResponse<List<OrderResponseDto>,List<PublicOrderResponseDto>> getOrdersForUsers(Long itemId, User user){
        List<Order> orders = orderRepository.findAllByItemId(itemId).orElseThrow(()-> new NullPointerException("해당 id로 구매요청을 찾을 수 없습니다."));
        List<OrderResponseDto> orderDtos = null;
        List<PublicOrderResponseDto> publicOrderDtos = null;
        if(orders.get(0).getItem().getSeller().equals(user.getSeller())){//Item의 작성자가 볼때는 orderId와 address가 포함된 response리턴
            orderDtos = orders.stream()
                    .map(OrderResponseDto::new)
                    .collect(Collectors.toList());
        }else {//Item의 작성자가 아닌 유저가 볼때는 orderId와 address가 제외된 response리턴
            publicOrderDtos = orders.stream()
                    .map(PublicOrderResponseDto::new)
                    .collect(Collectors.toList());
        }
        return new DoubleResponse(orderDtos,publicOrderDtos);
    }

Controller

@GetMapping("/read")
    public ApiResponse<DoubleResponse<List<OrderResponseDto>,List<PublicOrderResponseDto>>> getOrdersForItemAuthor(
            @RequestParam Long itemId,
            @AuthenticationPrincipal UserDetailsImpl userDetails
    ) {
        try {
            DoubleResponse<List<OrderResponseDto>,List<PublicOrderResponseDto>> responseDto = orderService.getOrdersForUsers(itemId, userDetails.getUser());
            return new ApiResponse<DoubleResponse<List<OrderResponseDto>,List<PublicOrderResponseDto>>>(HttpStatus.OK.value(),"구매 요청 조회에 성공했습니다",responseDto);
        }catch (RejectedExecutionException | NullPointerException ex){
            return new ApiResponse<DoubleResponse<List<OrderResponseDto>,List<PublicOrderResponseDto>>>(HttpStatus.BAD_REQUEST.value(),ex.getMessage());
        }
    }

기적의 3단 제너릭 ㅋㅋㅋㅋㅋ 넘 웃기다

 

🚩문제 : path 오버로딩이 안 됨

com.raincloud.sunlightmarket.order.controller.OrderController#getOrdersForItemAuthor(Long, UserDetailsImpl) to {GET [/api/orders/read]}: There is already 'orderController' bean method com.raincloud.sunlightmarket.order.controller.OrderController#getOrdersForAll(Long) mapped.

orderController에서 오류남 따흑

com.raincloud.sunlightmarket.order.controller.OrderController#getOrdersForAll(Long) to {GET [/api/orders/read]}: There is already 'orderController' bean method com.raincloud.sunlightmarket.order.controller.OrderController#getOrdersForUsers(Long, UserDetailsImpl) mapped.

path 오버로딩이 안되나봄…

method parameter가 Long으로 똑같아서 그런가…

다른 방식 한번 써봄

⛳해결 : 같은 path를 공유하는 다른 메소드의 parameter를 PathVariable로 바꿔봄

@GetMapping("/read")
    public ApiResponse<List<OrderResponseDto>> getOrdersForAll(
            @RequestParam Long itemId
    ) {
        try {
            List<OrderResponseDto> responseDto = orderService.getOrders(itemId);
            return new ApiResponse<List<OrderResponseDto>>(HttpStatus.OK.value(),"구매 요청 조회에 성공했습니다",responseDto);
        }catch (RejectedExecutionException | NullPointerException ex){
            return new ApiResponse<List<OrderResponseDto>>(HttpStatus.BAD_REQUEST.value(),ex.getMessage());
        }
    }

@GetMapping("/read/{itenId}")
    public ApiResponse<List<OrderResponseDto>> getOrdersForAll(
            @PathVariable Long itemId
    ) {
        try {
            List<OrderResponseDto> responseDto = orderService.getOrders(itemId);
            return new ApiResponse<List<OrderResponseDto>>(HttpStatus.OK.value(),"구매 요청 조회에 성공했습니다",responseDto);
        }catch (RejectedExecutionException | NullPointerException ex){
            return new ApiResponse<List<OrderResponseDto>>(HttpStatus.BAD_REQUEST.value(),ex.getMessage());
        }
    }

오… 이렇게는 오버로딩이 되나봄 문제없이 동작됨

Authentication은 parameter로 안 쳐주나봄…

근데 생각해보니 저러면 path가 걍 달라지잖아.. 오버로딩이라고 볼 수 없으니 되는듯

같은 path에다가는 두개의 함수를 달 수 없는걸까?

 

 

🚩문제 : Item글쓴이어도 orderId랑 address가 보이는 response가 리턴되지 않음

아무튼 유저 1로 로그인해서 아이템의 Order들을 읽어봄

"status": 200,
    "message": "구매 요청 조회에 성공했습니다",
    "data": {
        "data1": null,
        "data2": [
            {
                "buyerName": "닉",
                "price": null,
                "orderStatus": "PENDING"
            },
            {
                "buyerName": "닉",
                "price": null,
                "orderStatus": "PENDING"
            }
        ]
    }
}

유저 2로 로그인해서 읽어봄

{
    "status": 200,
    "message": "구매 요청 조회에 성공했습니다",
    "data": {
        "data1": null,
        "data2": [
            {
                "buyerName": "닉",
                "price": null,
                "orderStatus": "PENDING"
            },
            {
                "buyerName": "닉",
                "price": null,
                "orderStatus": "PENDING"
            }
        ]
    }
}

똑같으면 안되는데…

아 read밑에다 놔두면 filter를 거쳐서 @AuthenticationPrincipal UserDetailsImpl userDetails 로 User 정보가 안 들어오기 때문에

그냥 public만 리턴되는 걸수도 있겠다…

 

WebSecurityConfig에서 /orders/read/**는 인증없이 다 지나가게 필터에 처리해뒀으니 path를 /read말고 다른걸로 바꿔봄

유저 1로 로그인해봄

{
    "status": 200,
    "message": "구매 요청 조회에 성공했습니다",
    "data": {
        "data1": null,
        "data2": [
            {
                "buyerName": "닉",
                "price": null,
                "orderStatus": "PENDING"
            },
            {
                "buyerName": "닉",
                "price": null,
                "orderStatus": "PENDING"
            }
        ]
    }
}

유저 2로 로그인해봄 안 됨

{
    "status": 200,
    "message": "구매 요청 조회에 성공했습니다",
    "data": {
        "data1": null,
        "data2": [
            {
                "buyerName": "닉",
                "price": null,
                "orderStatus": "PENDING"
            },
            {
                "buyerName": "닉",
                "price": null,
                "orderStatus": "PENDING"
            }
        ]
    }
}

 

⛳해결 : 해당 유저인지 판별할때 Object끼리 equals하지 않고 String끼리 equals하게 함

if(orders.get(0).getItem().getSeller().equals(user.getSeller()))

if(orders.get(0).getItem().getSeller().getId().equals(user.getSeller().getId()))

지금 보니 id가 아니라 seller로 비교하고 있었음

{
    "status": 200,
    "message": "구매 요청 조회에 성공했습니다",
    "data": {
        "data1": [
            {
                "orderId": 2,
                "buyerName": "닉",
                "address": "주소주소2",
                "price": null,
                "orderStatus": "PENDING"
            },
            {
                "orderId": 3,
                "buyerName": "닉",
                "address": "주소주소2",
                "price": null,
                "orderStatus": "PENDING"
            }
        ],
        "data2": null
    }
}

오 Seller대신 seller_id로 비교하니까 됨

filter로 거르지 않아도 로그인 정보 없어도 메소드 안에서 돌아가게 하는 법은 없는지 내일 알아보기로 함

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

2023-12-11, Today I Learned  (0) 2023.12.11
2023-12-08, Today I Learned  (1) 2023.12.08
2023-12-06, Today I Leanred  (2) 2023.12.06
2023-12-05, Today I Learned  (0) 2023.12.05
2023-12-04, Today I Learned  (0) 2023.12.04