[refactor/#131-refactor-safety-calculator] 안전 점수 계산 최적화#132
Conversation
📝 Walkthrough개요세 가지 주요 구성 요소를 최적화합니다: Kakao WebClient에서 baseUrl 매개변수를 제거하고, SafetyExplanationService에서 AI 설명 생성 흐름을 삭제하며, HomeSafetyRepository의 공간 쿼리를 WITH 부쿼리와 사전 계산된 지오메트리 필드를 사용하도록 재작성합니다. 변경 사항
예상 코드 리뷰 시간🎯 3 (보통) | ⏱️ ~25분 시
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
src/main/java/com/example/Dingle/global/config/KaKaoWebClientConfig.java (1)
13-17: P3: 주석 처리된 설정 코드는 정리하는 것을 권장합니다.Line 13, Line 17의 주석 코드는 현재 동작과 분리되어 있어 설정 의도를 흐립니다. 유지할 이유가 없다면 제거해 주세요.
정리 예시(diff)
-// `@Value`("${kakao.base-url}") String baseUrl `@Bean` public WebClient kaKaoWebClient(`@Value`("${kakao.api-key}") String apiKey) { return WebClient.builder() -// .baseUrl(baseUrl) .defaultHeader(HttpHeaders.AUTHORIZATION, "KakaoAK " + apiKey) .build(); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/example/Dingle/global/config/KaKaoWebClientConfig.java` around lines 13 - 17, Remove the stale commented configuration lines in KaKaoWebClientConfig to avoid confusion: delete the commented `@Value`("${kakao.base-url}") declaration and the commented .baseUrl(baseUrl) call inside the kaKaoWebClient method, keeping only the active `@Value`("${kakao.api-key}") injection and the WebClient.builder() configuration; ensure no leftover commented code remains in the kaKaoWebClient method so the intent is clear.src/main/java/com/example/Dingle/safety/repository/HomeSafetyRepository.java (1)
75-86: P3: CCTV/보안등 카운트 쿼리는 공통 메서드로 묶는 리팩터링을 권장합니다.Line 75-112는
infra_type만 달라 중복 유지비가 큽니다. 단일 내부 메서드로 합치면 수정 포인트를 줄일 수 있습니다.리팩터링 예시
+ private int countInfraWithin50m(String infraType, double lat, double lon) { + String sql = """ + WITH target AS ( + SELECT ST_Transform(ST_SetSRID(ST_MakePoint(?2, ?3), 4326), 5179) AS g + ) + SELECT COUNT(*) + FROM safety s, target + WHERE s.infra_type = ?1 + AND s.geom_5179 IS NOT NULL + AND ST_DWithin(s.geom_5179, target.g, 50) + """; + + return ((Number) em.createNativeQuery(sql) + .setParameter(1, infraType) + .setParameter(2, lon) + .setParameter(3, lat) + .getSingleResult()).intValue(); + } + public int countCctvWithin50m(double lat, double lon) { - String sql = """ - SELECT COUNT(*) - FROM safety s - WHERE s.infra_type = 'CCTV' - AND s.geom_5179 IS NOT NULL - AND ST_DWithin( - s.geom_5179, - ST_Transform(ST_SetSRID(ST_MakePoint(?1, ?2), 4326), 5179), - 50 - ) - """; - - return ((Number) em.createNativeQuery(sql) - .setParameter(1, lon) - .setParameter(2, lat) - .getSingleResult()).intValue(); + return countInfraWithin50m("CCTV", lat, lon); } public int countSafetyLightWithin50m(double lat, double lon) { - String sql = """ - SELECT COUNT(*) - FROM safety s - WHERE s.infra_type = 'SAFETY_LIGHT' - AND s.geom_5179 IS NOT NULL - AND ST_DWithin( - s.geom_5179, - ST_Transform(ST_SetSRID(ST_MakePoint(?1, ?2), 4326), 5179), - 50 - ) - """; - - return ((Number) em.createNativeQuery(sql) - .setParameter(1, lon) - .setParameter(2, lat) - .getSingleResult()).intValue(); + return countInfraWithin50m("SAFETY_LIGHT", lat, lon); }Also applies to: 95-106
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/example/Dingle/safety/repository/HomeSafetyRepository.java` around lines 75 - 86, Extract the duplicated SQL/count logic into a single private helper (e.g., countInfraWithinDistance) that accepts infraType, lat, lon and distance, move the shared SQL string and JDBC/query parameter binding there, and update public methods like countCctvWithin50m and the analogous lamp/streetlight method to call this helper with infraType = "CCTV" (or the other infra value) and distance = 50; ensure the helper preserves the ST_Transform/ST_SetSRID/ST_MakePoint parameter ordering and returns the int count so callers remain unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/main/java/com/example/Dingle/global/config/KaKaoWebClientConfig.java`:
- Around line 15-19: The kaKaoWebClient factory removed the baseUrl causing
relative-path requests in KaKaoGeocodingService.getGeoPoint() to fail at
runtime; restore a baseUrl parameter on the kaKaoWebClient method (e.g., add a
String baseUrl `@Value`("${kakao.base-url}") parameter) and re-enable
.baseUrl(baseUrl) on the WebClient.builder(), and ensure application config
contains kakao.base-url (https://dapi.kakao.com) along with kakao.api-key
entries in application.properties or application.yml so the injected values
resolve.
In
`@src/main/java/com/example/Dingle/safety/repository/HomeSafetyRepository.java`:
- Around line 56-67: The query can return zero rows (empty police_office or all
geom_5179 NULL), causing getSingleResult() in HomeSafetyRepository to throw
NoResultException; change the SQL so the COALESCE wraps the entire subquery
result (e.g. SELECT COALESCE((SELECT ... FROM police_office p, target WHERE
p.geom_5179 IS NOT NULL ORDER BY p.geom_5179 <-> target.g LIMIT 1), 999999) AS
distance) so the call in the repository method (the code that calls
getSingleResult() for the nearest police distance) always returns a numeric
default when no row exists; alternatively adjust the repository method to use
getResultList() and return 999999 when the list is empty.
---
Nitpick comments:
In `@src/main/java/com/example/Dingle/global/config/KaKaoWebClientConfig.java`:
- Around line 13-17: Remove the stale commented configuration lines in
KaKaoWebClientConfig to avoid confusion: delete the commented
`@Value`("${kakao.base-url}") declaration and the commented .baseUrl(baseUrl) call
inside the kaKaoWebClient method, keeping only the active
`@Value`("${kakao.api-key}") injection and the WebClient.builder() configuration;
ensure no leftover commented code remains in the kaKaoWebClient method so the
intent is clear.
In
`@src/main/java/com/example/Dingle/safety/repository/HomeSafetyRepository.java`:
- Around line 75-86: Extract the duplicated SQL/count logic into a single
private helper (e.g., countInfraWithinDistance) that accepts infraType, lat, lon
and distance, move the shared SQL string and JDBC/query parameter binding there,
and update public methods like countCctvWithin50m and the analogous
lamp/streetlight method to call this helper with infraType = "CCTV" (or the
other infra value) and distance = 50; ensure the helper preserves the
ST_Transform/ST_SetSRID/ST_MakePoint parameter ordering and returns the int
count so callers remain unchanged.
ℹ️ Review info
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/main/java/com/example/Dingle/global/config/KaKaoWebClientConfig.javasrc/main/java/com/example/Dingle/property/service/openAI/SafetyExplanationService.javasrc/main/java/com/example/Dingle/safety/repository/HomeSafetyRepository.java
💤 Files with no reviewable changes (1)
- src/main/java/com/example/Dingle/property/service/openAI/SafetyExplanationService.java
| public WebClient kaKaoWebClient(@Value("${kakao.api-key}") String apiKey) { | ||
| return WebClient.builder() | ||
| .baseUrl(baseUrl) | ||
| // .baseUrl(baseUrl) | ||
| .defaultHeader(HttpHeaders.AUTHORIZATION, "KakaoAK " + apiKey) | ||
| .build(); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# 1) WebClient 사용 지점 및 주입 지점 확인
echo "=== kaKaoWebClient 사용 지점 ==="
rg -nP --type=java -C3 'kaKaoWebClient'
echo ""
echo "=== 상대 경로 URI 사용 지점 ==="
rg -nP --type=java -C2 '\.uri\s*\(\s*"/[^"]*"'
echo ""
echo "=== 절대 URL URI 사용 지점 ==="
rg -nP --type=java -C2 '\.uri\s*\(\s*"https?://[^"]*"'Repository: D-ingle/backend
Length of output: 1684
🏁 Script executed:
#!/bin/bash
# KaKaoGeocodingService 파일 전체 내용 확인
cat src/main/java/com/example/Dingle/user/service/KaKaoGeocodingService.javaRepository: D-ingle/backend
Length of output: 1621
🏁 Script executed:
#!/bin/bash
# KaKaoWebClientConfig 전체 파일 확인
echo "=== KaKaoWebClientConfig.java ==="
cat src/main/java/com/example/Dingle/global/config/KaKaoWebClientConfig.java
echo ""
echo "=== application properties 파일에서 kakao 설정 확인 ==="
fd --type f -e properties -e yml -e yaml | xargs rg -l 'kakao' 2>/dev/null || echo "No kakao config found"
echo ""
echo "=== kakao 관련 설정값 ==="
fd --type f -e properties -e yml -e yaml -x cat {} \; | rg -C2 'kakao' || echo "No kakao properties found"Repository: D-ingle/backend
Length of output: 915
baseUrl 제거로 인한 런타임 오류 발생 - 반드시 복구 필요
상대 경로 /v2/local/search/address.json를 사용하는 KaKaoGeocodingService.getGeoPoint()가 이 WebClient를 주입받아 사용하고 있습니다. baseUrl이 없으면 상대 경로를 절대 URL로 변환할 수 없어 런타임에 실패합니다.
baseUrl 파라미터와 .baseUrl(baseUrl) 설정을 복구하고, 해당 설정값을 application.properties 또는 application.yml에 추가해야 합니다:
kakao.base-url=https://dapi.kakao.com
kakao.api-key=your-api-key또는 yml 형식:
kakao:
base-url: https://dapi.kakao.com
api-key: your-api-key🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/main/java/com/example/Dingle/global/config/KaKaoWebClientConfig.java`
around lines 15 - 19, The kaKaoWebClient factory removed the baseUrl causing
relative-path requests in KaKaoGeocodingService.getGeoPoint() to fail at
runtime; restore a baseUrl parameter on the kaKaoWebClient method (e.g., add a
String baseUrl `@Value`("${kakao.base-url}") parameter) and re-enable
.baseUrl(baseUrl) on the WebClient.builder(), and ensure application config
contains kakao.base-url (https://dapi.kakao.com) along with kakao.api-key
entries in application.properties or application.yml so the injected values
resolve.
| WITH target AS ( | ||
| SELECT ST_Transform(ST_SetSRID(ST_MakePoint(?1, ?2), 4326), 5179) AS g | ||
| ) | ||
| SELECT COALESCE( | ||
| ST_Distance(p.geom_5179, target.g), | ||
| 999999 | ||
| ) | ||
| FROM police_office p, target | ||
| WHERE p.geom_5179 IS NOT NULL | ||
| ORDER BY p.geom_5179 <-> target.g | ||
| LIMIT 1 | ||
| """; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name "HomeSafetyRepository.java" -type f 2>/dev/null | head -20Repository: D-ingle/backend
Length of output: 137
🏁 Script executed:
cat -n ./src/main/java/com/example/Dingle/safety/repository/HomeSafetyRepository.java | sed -n '50,80p'Repository: D-ingle/backend
Length of output: 1147
🏁 Script executed:
cat -n ./src/main/java/com/example/Dingle/safety/repository/HomeSafetyRepository.java | head -20Repository: D-ingle/backend
Length of output: 806
🏁 Script executed:
rg "findNearestPoliceDistanceMeter" --type java -A 5 -B 5Repository: D-ingle/backend
Length of output: 2691
🏁 Script executed:
cat -n ./src/main/java/com/example/Dingle/property/service/openAI/SafetyExplanationService.java | grep -A 30 "findNearestPoliceDistanceMeter" | head -40Repository: D-ingle/backend
Length of output: 1712
🏁 Script executed:
cat -n ./src/main/java/com/example/Dingle/property/service/openAI/SafetyExplanationService.java | sed -n '1,80p'Repository: D-ingle/backend
Length of output: 4196
경찰서 최근접 거리 쿼리에서 빈 결과 처리 누락으로 인한 NoResultException 발생 위험
현재 쿼리 구조에서 police_office 테이블이 비어있거나 모든 행의 geom_5179가 NULL인 경우, WHERE 절과 LIMIT 1로 인해 0건의 행이 반환되고, 72번 줄의 getSingleResult()에서 NoResultException이 발생합니다. 현재의 COALESCE는 ST_Distance의 NULL 값만 처리하며, 결과 행 자체가 없는 경우는 처리하지 못합니다.
제안된 수정처럼 COALESCE를 서브쿼리 전체를 감싸도록 변경하여, 0건 결과인 경우도 기본값(999999)으로 반환되도록 해야 합니다:
수정 예시
String sql = """
WITH target AS (
SELECT ST_Transform(ST_SetSRID(ST_MakePoint(?1, ?2), 4326), 5179) AS g
)
- SELECT COALESCE(
- ST_Distance(p.geom_5179, target.g),
- 999999
- )
- FROM police_office p, target
- WHERE p.geom_5179 IS NOT NULL
- ORDER BY p.geom_5179 <-> target.g
- LIMIT 1
+ SELECT COALESCE((
+ SELECT ST_Distance(p.geom_5179, target.g)
+ FROM police_office p, target
+ WHERE p.geom_5179 IS NOT NULL
+ ORDER BY p.geom_5179 <-> target.g
+ LIMIT 1
+ ), 999999)
""";빈 police_office 테이블 또는 geom_5179가 전부 NULL인 경우에 대한 테스트 케이스 추가를 권장합니다.
📝 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.
| WITH target AS ( | |
| SELECT ST_Transform(ST_SetSRID(ST_MakePoint(?1, ?2), 4326), 5179) AS g | |
| ) | |
| SELECT COALESCE( | |
| ST_Distance(p.geom_5179, target.g), | |
| 999999 | |
| ) | |
| FROM police_office p, target | |
| WHERE p.geom_5179 IS NOT NULL | |
| ORDER BY p.geom_5179 <-> target.g | |
| LIMIT 1 | |
| """; | |
| WITH target AS ( | |
| SELECT ST_Transform(ST_SetSRID(ST_MakePoint(?1, ?2), 4326), 5179) AS g | |
| ) | |
| SELECT COALESCE(( | |
| SELECT ST_Distance(p.geom_5179, target.g) | |
| FROM police_office p, target | |
| WHERE p.geom_5179 IS NOT NULL | |
| ORDER BY p.geom_5179 <-> target.g | |
| LIMIT 1 | |
| ), 999999) | |
| """; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/main/java/com/example/Dingle/safety/repository/HomeSafetyRepository.java`
around lines 56 - 67, The query can return zero rows (empty police_office or all
geom_5179 NULL), causing getSingleResult() in HomeSafetyRepository to throw
NoResultException; change the SQL so the COALESCE wraps the entire subquery
result (e.g. SELECT COALESCE((SELECT ... FROM police_office p, target WHERE
p.geom_5179 IS NOT NULL ORDER BY p.geom_5179 <-> target.g LIMIT 1), 999999) AS
distance) so the call in the repository method (the code that calls
getSingleResult() for the nearest police distance) always returns a numeric
default when no row exists; alternatively adjust the repository method to use
getResultList() and return 999999 when the list is empty.
🔍️ 이 PR을 통해 해결하려는 문제가 무엇인가요?
✨ 이 PR에서 핵심적으로 변경된 사항은 무엇일까요?
🙏 Reviewer 분들이 이런 부분을 신경써서 봐 주시면 좋겠어요
🩺 이 PR에서 테스트 혹은 검증이 필요한 부분이 있을까요?
📌 PR 진행 시 이러한 점들을 참고해 주세요
Summary by CodeRabbit
릴리스 노트
기능 변경
성능 개선