Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
0fa5042
[feat] BaseEntity 적용
KiSeungMin Jul 4, 2025
e726586
[feat] JPA, MySQL 의존성 추가
KiSeungMin Jul 4, 2025
7be9e31
[feat] 주소 정보를 담는 Address 구현 완료
KiSeungMin Jul 4, 2025
e4e8de0
[feat] 유저 엔티티 정의 완료
KiSeungMin Jul 4, 2025
321598c
[feat] 유저 관련 repository, service, controller 생성 완료
KiSeungMin Jul 4, 2025
f849e88
[feat] 유저 관련 예외 구조체 정의
KiSeungMin Jul 4, 2025
47f3ff5
[chore] 디렉터리 구조 수정
KiSeungMin Jul 4, 2025
5f9d400
[feat] 유저 관련 예외 발생 로직을 Service로 옮기기
KiSeungMin Jul 5, 2025
556defb
[feat] 웨이블존 예외 객체 생성 완료
KiSeungMin Jul 5, 2025
59b6cf1
[chore] 디렉토리명을 domain -> entity로 수정
KiSeungMin Jul 5, 2025
95f60cf
[feat] User 관련 Dto 생성 완료
KiSeungMin Jul 5, 2025
49f9701
[feat] 웨이블존 관련 Dto 생성 완료
KiSeungMin Jul 5, 2025
03945be
[feat] 웨이블존 관련 repository, service, controller 생성 완료
KiSeungMin Jul 5, 2025
c5df0ba
[feat] 웨이블존 엔티티 구현 완료
KiSeungMin Jul 5, 2025
63215be
[feat] 리뷰 관련 controller, service, repository 구현 완료
KiSeungMin Jul 5, 2025
3a8af36
[feat] 리뷰 관련 dto 구현 완료
KiSeungMin Jul 5, 2025
5f05e6b
[feat] Review 엔티티 구현 완료
KiSeungMin Jul 5, 2025
0ce6768
[feat] 길찾기 관련 controller, service, exception 구현 완료
KiSeungMin Jul 5, 2025
28847ec
[feat] 지도 검색 관련 controller, service, exception 구현 완료
KiSeungMin Jul 5, 2025
c61723c
[fix] 위도, 경도 필드 소숫점 설정 오류 해결
KiSeungMin Jul 5, 2025
6d7d78e
[fix] CodeRabbit이 알려준 개선사항 반영
KiSeungMin Jul 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ repositories {
}

dependencies {
//implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-aop'

runtimeOnly 'com.mysql:mysql-connector-j'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/wayble/server/ServerApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@SpringBootApplication
@EnableJpaAuditing
public class ServerApplication {

public static void main(String[] args) {
Expand Down
37 changes: 37 additions & 0 deletions src/main/java/com/wayble/server/common/entity/Address.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.wayble.server.common.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import lombok.Getter;

@Getter
@Embeddable
public class Address {
/** 시·도 */
@Column(name = "state", length = 100, nullable = false)
private String state;

/** 시·군·구 */
@Column(name = "city", length = 100, nullable = false)
private String city;

/** 동·읍·면 */
@Column(name = "district", length = 100)
private String district;

/** 도로명 주소 */
@Column(name = "street_address", length = 200)
private String streetAddress;

/** 상세 주소 */
@Column(name = "detail_address", length = 200)
private String detailAddress;

/** 위도 */
@Column(name = "latitude", columnDefinition = "DECIMAL(10,7)", nullable = false)
private Double latitude;

/** 경도 */
@Column(name = "longitude", columnDefinition = "DECIMAL(10,7)", nullable = false)
private Double longitude;
}
Comment on lines +7 to +37

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

생성자와 유효성 검증 추가 고려

Address 클래스에 생성자와 유효성 검증을 추가하는 것을 고려해보세요.

@Getter
@Embeddable
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PUBLIC)
public class Address {
    // ... 기존 필드들 ...
    
    // 필수 필드 생성자
    public Address(String state, String city, Double latitude, Double longitude) {
        this.state = validateNotBlank(state, "시·도는 필수입니다");
        this.city = validateNotBlank(city, "시·군·구는 필수입니다");
        this.latitude = validateLatitude(latitude);
        this.longitude = validateLongitude(longitude);
    }
    
    private String validateNotBlank(String value, String message) {
        if (value == null || value.trim().isEmpty()) {
            throw new IllegalArgumentException(message);
        }
        return value;
    }
    
    private Double validateLatitude(Double latitude) {
        if (latitude == null || latitude < -90 || latitude > 90) {
            throw new IllegalArgumentException("위도는 -90~90 범위여야 합니다");
        }
        return latitude;
    }
    
    private Double validateLongitude(Double longitude) {
        if (longitude == null || longitude < -180 || longitude > 180) {
            throw new IllegalArgumentException("경도는 -180~180 범위여야 합니다");
        }
        return longitude;
    }
}
🤖 Prompt for AI Agents
In src/main/java/com/wayble/server/common/entity/Address.java lines 7 to 37, add
constructors and validation methods to ensure required fields are set and valid.
Implement a protected no-args constructor and a public all-args constructor
using Lombok annotations. Add a custom constructor for mandatory fields (state,
city, latitude, longitude) that validates non-blank strings for state and city,
and checks latitude is between -90 and 90 and longitude between -180 and 180,
throwing IllegalArgumentException if validations fail.

26 changes: 26 additions & 0 deletions src/main/java/com/wayble/server/common/entity/BaseEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.wayble.server.common.entity;

import jakarta.persistence.Column;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;

import java.time.LocalDateTime;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

@MappedSuperclass
@Getter
@EntityListeners(AuditingEntityListener.class)
public class BaseEntity {

@CreatedDate
private LocalDateTime createdAt;

@LastModifiedDate
private LocalDateTime updatedAt;

@Column(name = "deleted_at")
private LocalDateTime deletedAt;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.wayble.server.direction.controller;

import com.wayble.server.common.response.CommonResponse;
import com.wayble.server.direction.service.DirectionService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/directions")
public class DirectionController {

private final DirectionService directionService;

// 참고용 컨트롤러(지우셔도 돼요)
@GetMapping("/hello")
public CommonResponse<String> hello() {
return CommonResponse.success("hello");
}

// 예외 사용 참고용 컨트롤러(지우셔도 돼요)
@GetMapping("/ex")
public CommonResponse<String> exception() {
directionService.makeException();
return CommonResponse.success("예외 발생!");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.wayble.server.direction.exception;

import com.wayble.server.common.exception.ErrorCase;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum DirectionErrorCase implements ErrorCase {

PATH_NOT_FOUND(400, 4001, "해당하는 경로를 찾을 수 없습니다.");

private final Integer httpStatusCode;
private final Integer errorCode;
private final String message;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.wayble.server.direction.service;

import com.wayble.server.common.exception.ApplicationException;
import com.wayble.server.direction.exception.DirectionErrorCase;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class DirectionService {

public void makeException() {
throw new ApplicationException(DirectionErrorCase.PATH_NOT_FOUND);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.wayble.server.review.controller;

import com.wayble.server.common.response.CommonResponse;
import com.wayble.server.review.service.ReviewService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/reviews")
public class ReviewController {

private final ReviewService reviewService;

// 참고용 컨트롤러(지우셔도 돼요)
@GetMapping("/hello")
public CommonResponse<String> hello() {
return CommonResponse.success("hello");
}

// 예외 사용 참고용 컨트롤러(지우셔도 돼요)
@GetMapping("/ex")
public CommonResponse<String> exception() {
reviewService.makeException();
return CommonResponse.success("예외 발생!");
}
Comment on lines +23 to +28

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

예외 처리 로직이 잘못되었습니다.

makeException() 메서드를 호출한 후 성공 응답을 반환하는 것은 논리적으로 맞지 않습니다. 예외가 발생했다면 해당 지점에서 예외가 던져져야 하고, 이후 코드는 실행되지 않아야 합니다.

현재 구현에서는 예외가 실제로 발생하지 않거나, 발생해도 적절히 처리되지 않는 상황을 암시합니다.

다음과 같이 수정하는 것을 고려해보세요:

// 예외 사용 참고용 컨트롤러(지우셔도 돼요)
@GetMapping("/ex")
public CommonResponse<String> exception() {
-    reviewService.makeException();
-    return CommonResponse.success("예외 발생!");
+    // 이 메서드는 예외를 발생시키므로 성공 응답은 반환되지 않습니다
+    reviewService.makeException();
+    // 이 줄은 실행되지 않습니다
+    return CommonResponse.success("이 메시지는 보이지 않습니다");
}

또는 예외 처리를 명시적으로 보여주려면:

@GetMapping("/ex")
public CommonResponse<String> exception() {
+    try {
+        reviewService.makeException();
+        return CommonResponse.success("예외가 발생하지 않았습니다");
+    } catch (Exception e) {
+        // 실제로는 GlobalExceptionHandler에서 처리됩니다
+        throw e;
+    }
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// 예외 사용 참고용 컨트롤러(지우셔도 돼요)
@GetMapping("/ex")
public CommonResponse<String> exception() {
reviewService.makeException();
return CommonResponse.success("예외 발생!");
}
// 예외 사용 참고용 컨트롤러(지우셔도 돼요)
@GetMapping("/ex")
public CommonResponse<String> exception() {
// 이 메서드는 예외를 발생시키므로 성공 응답은 반환되지 않습니다
reviewService.makeException();
// 이 줄은 실행되지 않습니다
return CommonResponse.success("이 메시지는 보이지 않습니다");
}
🤖 Prompt for AI Agents
In src/main/java/com/wayble/server/review/controller/ReviewController.java
around lines 23 to 28, the method calls reviewService.makeException() but then
returns a success response, which is logically incorrect if an exception is
expected. To fix this, remove the success return statement after calling
makeException() so that if an exception occurs, it propagates properly and the
method does not continue execution. Alternatively, explicitly catch the
exception within the method and handle it appropriately to demonstrate exception
handling.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.wayble.server.review.dto;

public record ReviewRegisterDto() {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.wayble.server.review.dto;

public record ReviewResponseDto() {
}
52 changes: 52 additions & 0 deletions src/main/java/com/wayble/server/review/entity/Review.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.wayble.server.review.entity;

import com.wayble.server.common.entity.BaseEntity;
import com.wayble.server.user.entity.User;
import com.wayble.server.wayblezone.entity.WaybleZone;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.SQLRestriction;

import java.util.ArrayList;
import java.util.List;

@Entity
@Getter
@Builder(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@SQLDelete(sql = "UPDATE review SET deleted_at = now() WHERE id = ?")
@SQLRestriction("deleted_at IS NULL")
@Table(name = "review")
public class Review extends BaseEntity {

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

@Lob
@Column(columnDefinition = "TEXT")
private String content;

@Column(nullable = false)
private double rating = 0.0;

@Column(nullable = false)
private Integer likeCount = 0;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "wayble_zone_id", nullable = false)
private WaybleZone waybleZone;

@OneToMany(mappedBy = "review", cascade = CascadeType.ALL, orphanRemoval = true)
private List<ReviewImage> reviewImageList = new ArrayList<>();

/**
* TODO: 접근성 정보 관련 구현 필요
*/
}
29 changes: 29 additions & 0 deletions src/main/java/com/wayble/server/review/entity/ReviewImage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.wayble.server.review.entity;

import com.wayble.server.common.entity.BaseEntity;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.SQLRestriction;

@Entity
@Getter
@Builder(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "review_image")
@SQLDelete(sql = "UPDATE review_image SET deleted_at = now() WHERE id = ?")
@SQLRestriction("deleted_at IS NULL")
public class ReviewImage extends BaseEntity {

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

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "review_id", nullable = false)
private Review review;

@Column(name = "image_url", nullable = false)
private String imageUrl;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.wayble.server.review.exception;

import com.wayble.server.common.exception.ErrorCase;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum ReviewErrorCase implements ErrorCase {

REVIEW_NOT_FOUND(400, 3001, "리뷰를 찾을 수 없습니다.");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

도메인 간 에러 케이스 사용 검증 필요

DirectionService에서 이 ReviewErrorCase를 잘못 사용하고 있는 것이 확인되었습니다. 각 도메인은 자신만의 에러 케이스를 사용해야 합니다.

다음 스크립트를 실행하여 ReviewErrorCase가 다른 도메인에서 잘못 사용되고 있는지 확인해주세요:


🏁 Script executed:

#!/bin/bash
# ReviewErrorCase가 review 도메인 외부에서 사용되는지 확인
rg -A 3 "ReviewErrorCase" --type java | grep -v "review/"

Length of output: 799


DirectionService에서 ReviewErrorCase 사용 금지 및 도메인 전용 에러 케이스 도입

DirectionService에서 리뷰 도메인 전용 에러 케이스(ReviewErrorCase)를 참조하고 있습니다. 각 도메인은 고유한 에러 케이스를 사용해야 하므로, direction 도메인용 에러 케이스를 새로 정의하고 해당 부분을 교체해주세요.

  • 수정 대상
    • src/main/java/com/wayble/server/direction/service/DirectionService.java

  • 조치 사항

    1. direction 도메인용 에러 케이스(enum) 생성
      • 예: src/main/java/com/wayble/server/direction/exception/DirectionErrorCase.java
    2. import 및 예외 발생부 변경
      - import com.wayble.server.review.exception.ReviewErrorCase;
      + import com.wayble.server.direction.exception.DirectionErrorCase;
      
      - throw new ApplicationException(ReviewErrorCase.REVIEW_NOT_FOUND);
      + throw new ApplicationException(DirectionErrorCase.REVIEW_NOT_FOUND);

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/main/java/com/wayble/server/review/exception/ReviewErrorCase.java at line
11, the ReviewErrorCase enum is being used in the DirectionService, which
violates domain separation. To fix this, create a new enum DirectionErrorCase in
src/main/java/com/wayble/server/direction/exception/DirectionErrorCase.java with
appropriate error codes for the direction domain. Then, update
src/main/java/com/wayble/server/direction/service/DirectionService.java to
import and use DirectionErrorCase instead of ReviewErrorCase for error handling.


private final Integer httpStatusCode;
private final Integer errorCode;
private final String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.wayble.server.review.repository;

import com.wayble.server.review.entity.ReviewImage;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ReviewImageRepository extends JpaRepository<ReviewImage, Long> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.wayble.server.review.repository;

import com.wayble.server.review.entity.Review;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ReviewRepository extends JpaRepository<Review, Long> {
}
17 changes: 17 additions & 0 deletions src/main/java/com/wayble/server/review/service/ReviewService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.wayble.server.review.service;

import com.wayble.server.common.exception.ApplicationException;
import com.wayble.server.review.exception.ReviewErrorCase;
import com.wayble.server.review.repository.ReviewRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class ReviewService {
private final ReviewRepository reviewRepository;

public void makeException() {
throw new ApplicationException(ReviewErrorCase.REVIEW_NOT_FOUND);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.wayble.server.search.controller;

import com.wayble.server.common.response.CommonResponse;
import com.wayble.server.search.service.SearchService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/search")
public class SearchController {

private final SearchService searchService;

// 참고용 컨트롤러(지우셔도 돼요)
@GetMapping("/hello")
public CommonResponse<String> hello() {
return CommonResponse.success("hello");
}

// 예외 사용 참고용 컨트롤러(지우셔도 돼요)
@GetMapping("/ex")
public CommonResponse<String> exception() {
searchService.makeException();
return CommonResponse.success("예외 발생!");
}
Comment on lines +24 to +28

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

예외 처리 로직 오류

/ex 엔드포인트에서 searchService.makeException()을 호출하면 예외가 발생하여 다음 줄의 return 문은 실행되지 않습니다. 이는 도달할 수 없는 코드(unreachable code)입니다.

예외 처리 데모가 목적이라면 try-catch 블록을 사용하거나, 아니면 success 응답 반환 부분을 제거해야 합니다:

     @GetMapping("/ex")
     public CommonResponse<String> exception() {
-        searchService.makeException();
-        return CommonResponse.success("예외 발생!");
+        try {
+            searchService.makeException();
+            return CommonResponse.success("예외 발생하지 않음");
+        } catch (ApplicationException e) {
+            throw e; // 글로벌 예외 핸들러에서 처리
+        }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@GetMapping("/ex")
public CommonResponse<String> exception() {
searchService.makeException();
return CommonResponse.success("예외 발생!");
}
@GetMapping("/ex")
public CommonResponse<String> exception() {
try {
searchService.makeException();
return CommonResponse.success("예외 발생하지 않음");
} catch (ApplicationException e) {
throw e; // 글로벌 예외 핸들러에서 처리
}
}
🤖 Prompt for AI Agents
In src/main/java/com/wayble/server/search/controller/SearchController.java
around lines 24 to 28, the method calls searchService.makeException() which
throws an exception, making the subsequent return statement unreachable. To fix
this, wrap the call to makeException() in a try-catch block to handle the
exception and then return the success response, or remove the return statement
if the exception is meant to propagate without a success response.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.wayble.server.search.exception;

import com.wayble.server.common.exception.ErrorCase;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum SearchErrorCase implements ErrorCase {

SEARCH_EXCEPTION(400, 5001, "검색 과정에서 오류가 발생했습니다.");

private final Integer httpStatusCode;
private final Integer errorCode;
private final String message;
}
15 changes: 15 additions & 0 deletions src/main/java/com/wayble/server/search/service/SearchService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.wayble.server.search.service;

import com.wayble.server.common.exception.ApplicationException;
import com.wayble.server.search.exception.SearchErrorCase;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class SearchService {

public void makeException() {
throw new ApplicationException(SearchErrorCase.SEARCH_EXCEPTION);
}
}
Loading