[241118 TIL] AI 검증 비즈니스 프로젝트

    Soft Delete 적용 - IsDeletedFalse 활용

    Soft Delete 수정

    ✔️ BaseEntity & IsDeletedFalse 활용

    • 수정 전 예시
    @SQLDelete(sql = "UPDATE p_reviews SET is_deleted = true WHERE id = ?")
    @Where(clause = "is_deleted = false")
    reviewRepository.deleteById(reviewId);
    
    • 수정 후
    public void delete(Long userId) {
        this.deletedAt = LocalDateTime.now();
        this.deletedBy = userId;
        this.isDeleted = true;
    }
    review.delete(user.getId());
    
    Optional<Review> findByIdAndIsDeletedFalse(UUID id);
    
    List<Review> findAllByUserIdAndIsDeletedFalse(Long userId);
    
    Page<Review> findAllByStoreIdAndIsDeletedFalse(UUID storeId, Pageable pageable);

     

    • @SQLDelete ➡️ BaseEntity 활용
      • deleteById ➡️ delete 함수 생성 후 Soft Delete 적용
    • @Where ➡️ IsDeletedFalse 활용

    Soft Delete 구현

    1) 어려웠던 점

    • 논리적 삭제 처리: 데이터를 물리적으로 삭제하지 않고 isDeleted 컬럼을 활용해 논리적으로 삭제 상태를 관리하고자 했습니다. 이는 삭제된 데이터 복구와 조회를 가능하게 하지만, 모든 조회 쿼리에 삭제 상태를 고려해야 한다는 어려움이 있었습니다.
    • 테이블 간 연관 관계: 테이블 간 연관 관계가 설정된 상태에서, 삭제된 데이터를 제외하고 연관 데이터를 조회하거나 처리하는 데에 복잡함이 있었습니다.

    2) 해결 방안

    • isDeleted 컬럼 추가
      • 각 테이블에 isDeleted컬럼을 추가하여 논리적 삭제 여부를 관리했습니다.
      • 삭제 시 데이터를 물리적으로 제거하지 않고, 해당 컬럼 값을 true로 설정하여 삭제 상태를 표시하도록 구현했습니다.
    • JPA 메서드 조건 활용
      • JPA의 Spring Data 메서드 쿼리를 활용하여, isDeleted가 false인 데이터만 조회되도록 구현하였습니다.
      • 예: findByIdAndIsDeletedFalse
    • 연관 데이터 처리
      • 연관된 테이블 간 Soft Delete를 고려하여 데이터 무결성을 유지하였습니다.
      • 예: 리뷰 평점 계산 시 삭제 상태인 리뷰 데이터를 제외하고 평점을 계산하도록 구현

    3) 더 효율적으로 하려면

    • 공통 처리 메서드화: Soft delete를 처리하는 로직을 각 엔티티의 서비스에서 반복적으로 작성하기보다, 공통적인 로직을 **AOP(Aspect-Oriented Programming)**나 BaseRepository를 사용 중복을 최소화할 수 있을 것 입니다.

    [241115 TIL] AI 검증 비즈니스 프로젝트

    EC2 + Docker + Github Action 이용해서 자동 배포

     

    계속 dockerfile 을 찾을 수 없다는 에러만 나와서,,, 

    경로 설정 백만번씩 다시하고 푸시하는데 결국 해결 못했고

    알고보니 우리 리포지토리에 dockerfile 이 있어야한대요

    찾아봤을 때 나왔는데 너무 귀찮아서 무시하고 그냥 aws 서버 안에 만들어놨는데...

    ㅎr...

     

    오늘은 진짜 너무 시간이 없어서 백만번실패하는 걸로 마무리...


    [241114 TIL] AI 검증 비즈니스 프로젝트

    카테고리, 가게, 리뷰 CRUD API 구현

    • 코드리뷰 수정사항 반영
    • Soft Delete 수정
    • 리뷰 CRUD 추가 기능 구현

    코드리뷰 수정사항 반영

     

    ✔️ 카테고리 아이디 null 체크 부분 ➡️ 공백값도 같이 체크 가능하게 변경

     

    • 수정 전
    if (categoryId == null) 

     

    • 수정 후
    if (!StringUtils.hasText(String.valueOf(categoryId)))

     

    StringUtils.hasText 이용

     

    내부 로직

    public static boolean hasText(@Nullable String str) {
        return str != null && !str.isEmpty() && containsText(str);
    }
    
    private static boolean containsText(CharSequence str) {
        int strLen = str.length();
        
        for(int i = 0; i < strLen; ++i) {
          if (!Character.isWhitespace(str.charAt(i))) {
            return true;
          }
        }
        
        return false;
    }

     

    • str 이 null 인가
    • str이 빈 문자열 ("")인가
    • str이 공백으로만(whitespace) 이루어져 있는가 

    [241113 TIL] AI 검증 비즈니스 프로젝트

    카테고리, 가게, 리뷰 CRUD API 구현

     

    • API 동작 확인
    • 리뷰 평점 스케줄러 적용
    • Soft Delete 적용

    API 동작 확인

    ⚠️ 트러블슈팅 ⚠️

     

    1. 문제 정의

    • 가게 생성 API 동작 확인 중 에러 발생 (POST)
    org.springframework.dao.DataIntegrityViolationException: could not execute statement [Duplicate entry 'b\xDD\x98\xF0\xBD\x8E\x11\xED\x93\xAB2P\x96\xB3\x9FG' for key 'p_stores.UK260ia2wautdp3fq67hyklg3cu'] [/* insert for com.sparta.gourmate.domain.store.entity.Store */insert into p_stores (average_rating,category_id,created_at,created_by,deleted_at,deleted_by,is_deleted,location,name,updated_at,updated_by,user_id,id) values (?,?,?,?,?,?,?,?,?,?,?,?,?)]; SQL [/* insert for com.sparta.gourmate.domain.store.entity.Store */insert into p_stores (average_rating,category_id,created_at,created_by,deleted_at,deleted_by,is_deleted,location,name,updated_at,updated_by,user_id,id) values (?,?,?,?,?,?,?,?,?,?,?,?,?)]; constraint [p_stores.UK260ia2wautdp3fq67hyklg3cu]

     

     

    • org.springframework.dao.DataIntegrityViolationException
      • 데이터베이스에서 중복된 값이 삽입되려고 했을 때 발생하는 오류

    2. 원인 추론

     

    1) 가게 엔티티에 중복된 값을 허용하지 않는 컬럼 확인

    • id - UUID 로 자동 생성되므로 고려 대상 아님
    • user_id - 같은 유저로 여러 개의 가게 생성이 가능됨을 확인
    • category_id - 같은 카테고리의 가게를 생성하려고 할 때 위의 에러 발생

    2) 카테고리 엔티티와 가게 엔티티의 연관관계 확인

    • 현재 카테고리와 가게의 연관관계 - @OneToOne
    • 한 가게 당 하나의 카테고리를 갖기에 위 연관관계 설정

    3) 연관관계 고려

    • @OneToOne
      • 한 가게가 하나의 카테고리만 가질 수 있다는 것 의미
      • 예를 들어, "피자 가게" 하나가 "피자 카테고리"를 가진다면 적합
      • 여러 가게가 동일한 카테고리를 공유할 수 있다면, @OneToOne 설정은 적합하지 않음

     

     

    3. 해결 방안 및 결과

    • 연관관계 변경
      • 여러 개의 가게가 하나의 카테고리를 공유 ➡️ @ManyToOne 이 적합
      • 가게 엔티티에서 @ManyToOne 사용하고, 카테고리 엔티티에서 @OneToMany 사용
    @Entity
    public class Store {
    	// 중략
        @ManyToOne
        @JoinColumn(name = "category_id")
        private Category category;
       
    }
    
    
    
    @Entity
    public class Category {
    	// 중략
        @OneToMany(mappedBy = "category")
        private List<Store> storeList;
        
    }
    • 연관관계 변경 후 같은 카테고리를 가진 가게 생성 성공!



    [241112 TIL] AI 검증 비즈니스 프로젝트

    CRUD 구현


    Spring Data Jpa

    Containing

    • 컬럼에 특정 문자열이 포함된 엔티티 검색
    • SQL Qurey 의 LIKE 와 같음
    // SELECT * FROM Store WHERE category_id = categoryID AND name LIKE %query%;
    Page<Store> storeList = storeRepository.findByCategoryIdAndNameContaining(categoryId, query, pageable);

     


     

    POSTMAN 

    ⚠️ 트러블슈팅 ⚠️

     

    1. 문제 정의

    • API 테스트 진행을 위해 POSTMAN 을 사용하여 회원가입 진행 중 에러 발생
    {
        "code": null,
        "message": "Required request body is missing: public com.sparta.gourmate.domain.user.dto.UserResponseDto com.sparta.gourmate.domain.user.controller.UserController.createUser(com.sparta.gourmate.domain.user.dto.SignupRequestDto)"
    }

     

     

    2. 원인 추론

    • POSTMAN POST 상황

     

    1) 입력 조건을 만족하지 못했나?

    @NotBlank
    @Size(min = 4, max = 10)
    @Pattern(regexp = "^[a-z0-9]+$")
    private String username;
    
    @NotBlank
    @Size(min = 8, max = 15)
    @Pattern(regexp = "^(?=.*[a-zA-Z])(?=.*\\d)(?=.*[!@#$%^&*)(+=._-])[a-zA-Z\\d!@#$%^&*)(+=._-]+$")
    private String password;
    
    @Email
    @NotBlank
    private String email;

     

    • 모든 조건 만족

     

    2) NOTNULL 값만 작성하고 나머지는 작성하지 않아서 그런가?

    • 회원가입(SignupRequestDto)에 필요한 모든 값을 작성해도 같은 에러 발생

     

    3) @RequestBody 가 제대로 작동되고 있는지?

    • 모든 값을 Query Params 으로 넘기고 있음을 확인

     

    3. 해결 방안 및 결과

    • Boby - JSON raw 로 값 넘겨주기
    {
        "username" : "customer",
        "password" : "customer1!",
        "email" : "customer@naver.com",
        "isAdmin" : false,
        "isOwner" : false
    
    }

     

    • 성공적으로 POST
    {
        "id": 3,
        "username": "customer",
        "email": "customer@naver.com",
        "role": "CUSTOMER"
    }

     

     

     

    사실 너무 어이없는 실수라 트러블슈팅으로 적어도 되나~ 싶지만~

    그래도 나는 바보라서 똑같은 실수를 하게 될 수도 있으니 일단 적어놓자...

     


    POSTMAN 

    로그인 후 토큰 처리

     

    Login - POST username, password Authorization

    Response Header >  Authorization 값 복사

     

    Request Header 에 Authorization 입력


    [241111 TIL] AI 검증 비즈니스 프로젝트

    [Github] IntelliJ 에서 Git Branch 생성하고 Merge 하기


    branch 생성

    1. develop 에서 Update Project
    2. develop 에서 New Branch from 'origin/devlop' 클릭 후 branch 생성
    3. 생성한 branch 로 Checkout

    branch 작업 후 Merge

    1. develop 에서 Update Project
    2. 작업하던 branch 로 Checkout
    3. Git > Merge 클릭

     




     

    + Recent posts