fix(crud): P4-1 백엔드 CRUD 결함 일괄 수정 (#290+#294+#295)
#294 (리뷰/메모): - MemoService.upsert: 동시성 INSERT 시 DuplicateKeyException 폴백 → UPDATE - ReviewService.toggleFavorite: 동시성 INSERT 시 DuplicateKeyException ignored (토글 ON) - ReviewController: rating(0~5) Bean validation 헬퍼, body.rating null/비숫자 → 400 - ReviewMapper.xml getAvgRating: NVL로 0건 시에도 0.0 보장 #295 (채널): - ChannelController.create: typed DataIntegrityViolationException으로 유니크 충돌 감지 (제약명 문자열 매칭 폐기) - ChannelController.create: channel_id/channel_name null/빈값 → 400 - ChannelService.deactivate: "UC..." 형식 검증으로 명시적 분기 (이전 폴백 방식의 의도 모호함 해결) - ChannelMapper.xml findByChannelId: description/tags/sort_order까지 SELECT #290 (식당 CRUD): - RestaurantController: @PreDestroy로 virtual thread executor shutdown - RestaurantController: 캐시 역직렬화 실패를 silent ignore → log.warn + cache.del 자동 evict - RestaurantController: setTablingUrl/setCatchtableUrl URL 스킴 화이트리스트 검증 - CacheService: 단일 키 del() 메서드 추가 후속 분리: - #333 (#290 DTO 화이트리스트 + DDG 대체) - #334 (#295 cache.flush 세분화 + scan 비동기) - #335 (#294 테스트) Refs: #290 #294 #295
This commit is contained in:
@@ -7,6 +7,7 @@ import com.tasteby.security.AuthUtil;
|
||||
import com.tasteby.service.CacheService;
|
||||
import com.tasteby.service.ChannelService;
|
||||
import com.tasteby.service.YouTubeService;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
@@ -52,15 +53,20 @@ public class ChannelController {
|
||||
String channelId = body.get("channel_id");
|
||||
String channelName = body.get("channel_name");
|
||||
String titleFilter = body.get("title_filter");
|
||||
// #295 — body 필수값 가드 (NOT NULL 컬럼에 빈 값 들어가 500 나는 것 방지)
|
||||
if (channelId == null || channelId.isBlank()) {
|
||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "channel_id는 필수입니다");
|
||||
}
|
||||
if (channelName == null || channelName.isBlank()) {
|
||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "channel_name은 필수입니다");
|
||||
}
|
||||
try {
|
||||
String id = channelService.create(channelId, channelName, titleFilter);
|
||||
cache.flush();
|
||||
return Map.of("id", id, "channel_id", channelId);
|
||||
} catch (Exception e) {
|
||||
if (e.getMessage() != null && e.getMessage().toUpperCase().contains("UQ_CHANNELS_CID")) {
|
||||
throw new ResponseStatusException(HttpStatus.CONFLICT, "Channel already exists");
|
||||
}
|
||||
throw e;
|
||||
} catch (DataIntegrityViolationException e) {
|
||||
// #295 — 유니크 충돌을 메시지 문자열 매칭 대신 typed 예외로 감지 (제약명 변경에도 견고).
|
||||
throw new ResponseStatusException(HttpStatus.CONFLICT, "Channel already exists");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user