From bd51b5c0ce23d319b57a6322f1d2e30c7f1af400 Mon Sep 17 00:00:00 2001 From: yeobi Date: Wed, 15 Apr 2026 20:47:36 +0900 Subject: [PATCH 1/8] =?UTF-8?q?[Refac]=20=EC=97=AC=ED=96=89=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EC=BD=94=EB=93=9C=20=EC=A0=95=EB=A6=AC=20?= =?UTF-8?q?=EB=B0=8F=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trip/controller/TripController.java | 32 ++++--- .../domain/trip/converter/TripConverter.java | 51 +++++------ .../domain/trip/entity/Trip.java | 14 ++- .../trip/repository/TripMemberRepository.java | 1 - .../domain/trip/service/TripService.java | 3 +- .../domain/trip/service/TripServiceImpl.java | 86 +++++++++++-------- 6 files changed, 95 insertions(+), 92 deletions(-) diff --git a/src/main/java/graduation/project/DoDutch_server/domain/trip/controller/TripController.java b/src/main/java/graduation/project/DoDutch_server/domain/trip/controller/TripController.java index 7ee70d0..27d560e 100644 --- a/src/main/java/graduation/project/DoDutch_server/domain/trip/controller/TripController.java +++ b/src/main/java/graduation/project/DoDutch_server/domain/trip/controller/TripController.java @@ -5,20 +5,18 @@ import graduation.project.DoDutch_server.domain.trip.dto.Request.TripSuggestionRequestDto; import graduation.project.DoDutch_server.domain.trip.dto.Response.TripSuggestionResponseDto; import graduation.project.DoDutch_server.domain.trip.dto.Request.TripUpdateRequestDTO; +import graduation.project.DoDutch_server.domain.trip.service.TripService; import io.swagger.v3.oas.annotations.Operation; import graduation.project.DoDutch_server.domain.trip.dto.Request.TripJoinRequestDTO; import graduation.project.DoDutch_server.domain.trip.dto.Request.TripRequestDTO; import graduation.project.DoDutch_server.domain.trip.dto.Response.TripDetailResponseDTO; import graduation.project.DoDutch_server.domain.trip.dto.Response.TripResponseDTO; -import graduation.project.DoDutch_server.domain.trip.service.TripServiceImpl; import graduation.project.DoDutch_server.global.common.apiPayload.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; -import org.springframework.web.client.RestTemplate; -import java.io.IOException; import java.util.List; @RestController @@ -26,9 +24,9 @@ @RequiredArgsConstructor @Tag(name = "Trip", description = "여행 관련 API") public class TripController { - private final TripServiceImpl tripService; + private final TripService tripService; - /* + /** * 여행 생성 */ @PostMapping @@ -36,13 +34,13 @@ public class TripController { @io.swagger.v3.oas.annotations.responses.ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공") }) - public ApiResponse tripRegister(@ModelAttribute TripRequestDTO tripRequestDTO) throws IOException { //아마존 연결 후 RequestBody를 @ModelAttribute 수정 + public ApiResponse tripRegister(@ModelAttribute TripRequestDTO tripRequestDTO) { //아마존 연결 후 RequestBody를 @ModelAttribute 수정 Long tripId = tripService.createTrip(tripRequestDTO); return ApiResponse.onSuccess(tripId); } - /* + /** * 여행 참여 */ @PostMapping("/join") @@ -56,7 +54,7 @@ public ApiResponse tripJoin(@RequestBody TripJoinRequestDTO tripJoinReques return ApiResponse.onSuccess(); } - /* + /** * 여행 공유 시 정보 조회 */ @GetMapping("/share/{tripId}") @@ -69,7 +67,7 @@ public ApiResponse shareTripInfo(@PathVariable("tripId") Long t return ApiResponse.onSuccess(tripResponseDTO); } - /* + /** * 여행 검색 */ @GetMapping("/search") @@ -82,7 +80,7 @@ public ApiResponse> searchTrip(@RequestParam(value = return ApiResponse.onSuccess(responseDTOList); } - /* + /** * 여행별 조회 */ @GetMapping("/{tripId}") @@ -95,7 +93,7 @@ public ApiResponse detailTripInfo(@PathVariable("tripId") return ApiResponse.onSuccess(tripDetailResponseDTO); } - /* + /** * 여행 경비 예측 */ @PostMapping("/predict") @@ -108,7 +106,7 @@ public ApiResponse predictTrip(@RequestBody PredictRequestDt return ApiResponse.onSuccess(responseDto); } - /* + /** * gpt 여행지 추천 */ @PostMapping("/chat") @@ -123,7 +121,7 @@ public ApiResponse tripRecommend( return ApiResponse.onSuccess(responseDto); } - /* + /** * 여행 수정 */ @PatchMapping("/{tripId}") @@ -131,15 +129,15 @@ public ApiResponse tripRecommend( @io.swagger.v3.oas.annotations.responses.ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공") }) - public ApiResponse tripUpdate( + public ApiResponse tripUpdate( @PathVariable("tripId") Long tripId, @ModelAttribute TripUpdateRequestDTO requestDTO - ) throws IOException { + ) { tripService.updateTrip(tripId, requestDTO); return ApiResponse.onSuccess(); } - /* + /** * 여행 삭제 */ @DeleteMapping("/{tripId}") @@ -147,7 +145,7 @@ public ApiResponse tripUpdate( @io.swagger.v3.oas.annotations.responses.ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공") }) - public ApiResponse tripDelete( + public ApiResponse tripDelete( @PathVariable("tripId") Long tripId ){ tripService.deleteTrip(tripId); diff --git a/src/main/java/graduation/project/DoDutch_server/domain/trip/converter/TripConverter.java b/src/main/java/graduation/project/DoDutch_server/domain/trip/converter/TripConverter.java index 35cb3b8..15d3228 100644 --- a/src/main/java/graduation/project/DoDutch_server/domain/trip/converter/TripConverter.java +++ b/src/main/java/graduation/project/DoDutch_server/domain/trip/converter/TripConverter.java @@ -2,8 +2,6 @@ import graduation.project.DoDutch_server.domain.expense.entity.Expense; import graduation.project.DoDutch_server.domain.member.entity.Member; -import graduation.project.DoDutch_server.domain.photo.entity.Photo; -import graduation.project.DoDutch_server.domain.photo.repository.PhotoRepository; import graduation.project.DoDutch_server.domain.trip.dto.Request.TripRequestDTO; import graduation.project.DoDutch_server.domain.trip.dto.Response.TripDetailResponseDTO; import graduation.project.DoDutch_server.domain.trip.dto.Response.TripExpenseDTO; @@ -13,12 +11,14 @@ import graduation.project.DoDutch_server.domain.trip.entity.TripMember; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; public class TripConverter { - /* - Dto를 Entity로 변환 + /** + * Dto를 Entity로 변환 */ public static Trip toEntity(TripRequestDTO tripRequestDTO, String joinCode ,String tripImageUrl) { return Trip.builder() @@ -33,8 +33,8 @@ public static Trip toEntity(TripRequestDTO tripRequestDTO, String joinCode ,Stri .build(); } - /* - Entity를 Dto로 변환 + /** + * Entity를 Dto로 변환 */ public static TripResponseDTO toDto(Trip trip){ return TripResponseDTO.builder() @@ -81,31 +81,24 @@ public static List toMemberList2(List tripMembers){ // .collect(Collectors.toList()); } - public static List toExpenseDtoList(List expenses, PhotoRepository photoRepository){ + public static List toExpenseDtoList(List expenses, Map> photoUrlsMap){ return expenses.stream() - .map(expense -> { - List photoUrls = photoRepository.findByExpense(expense) - .stream() - .map(Photo::getPhotoUrl) - .collect(Collectors.toList()); - - return TripExpenseDTO.builder() - .expenseId(expense.getId()) - .photoUrl(expense.getExpenseImageUrl()) - .expensePhotoUrls(photoUrls) - .expenseDate(expense.getExpenseDate()) - .title(expense.getTitle()) - .amount(expense.getAmount()) - .memo(expense.getMemo()) - .build(); - }) + .map(expense -> TripExpenseDTO.builder() + .expenseId(expense.getId()) + .photoUrl(expense.getExpenseImageUrl()) + .expensePhotoUrls(photoUrlsMap.getOrDefault(expense.getId(), Collections.emptyList())) + .expenseDate(expense.getExpenseDate()) + .title(expense.getTitle()) + .amount(expense.getAmount()) + .memo(expense.getMemo()) + .build()) .collect(Collectors.toList()); } - /* - 여행 정보 조회용 dto 변환 + /** + * 여행 정보 조회용 dto 변환 */ - public static TripDetailResponseDTO toDetailDto(Trip trip, PhotoRepository photoRepository){ + public static TripDetailResponseDTO toDetailDto(Trip trip, Map> photoUrlsMap){ return TripDetailResponseDTO.builder() .tripId(trip.getId()) .tripName(trip.getName()) @@ -118,12 +111,12 @@ public static TripDetailResponseDTO toDetailDto(Trip trip, PhotoRepository photo .joinCode(trip.getJoinCode()) .dutchCompleted(trip.getDutchCompleted()) .members(toMemberList1(trip.getTripMembers())) - .photos(toExpenseDtoList(trip.getExpenses(), photoRepository)) + .photos(toExpenseDtoList(trip.getExpenses(), photoUrlsMap)) .build(); } - /* - 여행목록 조회용 dto 변환 + /** + * 여행목록 조회용 dto 변환 */ public static List toDetailListDto(List trips){ return trips.stream() diff --git a/src/main/java/graduation/project/DoDutch_server/domain/trip/entity/Trip.java b/src/main/java/graduation/project/DoDutch_server/domain/trip/entity/Trip.java index b562085..52823d6 100644 --- a/src/main/java/graduation/project/DoDutch_server/domain/trip/entity/Trip.java +++ b/src/main/java/graduation/project/DoDutch_server/domain/trip/entity/Trip.java @@ -1,6 +1,5 @@ package graduation.project.DoDutch_server.domain.trip.entity; -import graduation.project.DoDutch_server.domain.trip.dto.Request.TripUpdateRequestDTO; import jakarta.persistence.*; import lombok.*; import lombok.experimental.SuperBuilder; @@ -39,12 +38,11 @@ public class Trip extends BaseEntity { @OneToMany(mappedBy = "trip", cascade = CascadeType.REMOVE, orphanRemoval = true) private List expenses = new ArrayList<>(); - public Trip updateInfo(TripUpdateRequestDTO requestDTO){ - this.name = requestDTO.getTripName(); - this.place = requestDTO.getPlace(); - this.startDate = requestDTO.getStartDate(); - this.endDate = requestDTO.getEndDate(); - this.budget = requestDTO.getBudget(); - return this; + public void updateInfo(String name, String place, LocalDate startDate, LocalDate endDate, Integer budget){ + if (name != null) this.name = name; + if (place != null) this.place = place; + if (startDate != null) this.startDate = startDate; + if (endDate != null) this.endDate = endDate; + if (budget != null) this.budget = budget; } } diff --git a/src/main/java/graduation/project/DoDutch_server/domain/trip/repository/TripMemberRepository.java b/src/main/java/graduation/project/DoDutch_server/domain/trip/repository/TripMemberRepository.java index 03a2924..700267c 100644 --- a/src/main/java/graduation/project/DoDutch_server/domain/trip/repository/TripMemberRepository.java +++ b/src/main/java/graduation/project/DoDutch_server/domain/trip/repository/TripMemberRepository.java @@ -11,6 +11,5 @@ public interface TripMemberRepository extends JpaRepository { List findByTripId(Long tripId); Optional findByTripIdAndMemberId(Long tripId, Long memberId); - Long countTripMemberByTripId(Long tripId); List findByMemberId(Long memberId); } diff --git a/src/main/java/graduation/project/DoDutch_server/domain/trip/service/TripService.java b/src/main/java/graduation/project/DoDutch_server/domain/trip/service/TripService.java index 0d7a7a8..7c3d89b 100644 --- a/src/main/java/graduation/project/DoDutch_server/domain/trip/service/TripService.java +++ b/src/main/java/graduation/project/DoDutch_server/domain/trip/service/TripService.java @@ -10,11 +10,10 @@ import graduation.project.DoDutch_server.domain.trip.dto.Response.TripResponseDTO; import graduation.project.DoDutch_server.domain.trip.dto.Response.TripSuggestionResponseDto; -import java.io.IOException; import java.util.List; public interface TripService { - Long createTrip(TripRequestDTO tripRequestDTO) throws IOException; + Long createTrip(TripRequestDTO tripRequestDTO); void joinTrip(TripJoinRequestDTO tripJoinRequestDTO); TripResponseDTO shareTrip(Long tripId); List searchTrip(String keyWord); diff --git a/src/main/java/graduation/project/DoDutch_server/domain/trip/service/TripServiceImpl.java b/src/main/java/graduation/project/DoDutch_server/domain/trip/service/TripServiceImpl.java index 6ba48f1..fd1f47f 100644 --- a/src/main/java/graduation/project/DoDutch_server/domain/trip/service/TripServiceImpl.java +++ b/src/main/java/graduation/project/DoDutch_server/domain/trip/service/TripServiceImpl.java @@ -3,9 +3,6 @@ import graduation.project.DoDutch_server.domain.dutch.entity.Dutch; import graduation.project.DoDutch_server.domain.dutch.repository.DutchRepository; import graduation.project.DoDutch_server.domain.expense.entity.Expense; -import graduation.project.DoDutch_server.domain.expense.entity.ExpenseMember; -import graduation.project.DoDutch_server.domain.expense.repository.ExpenseMemberRepository; -import graduation.project.DoDutch_server.domain.expense.repository.ExpenseRepository; import graduation.project.DoDutch_server.domain.member.entity.Member; import graduation.project.DoDutch_server.domain.member.entity.Role; import graduation.project.DoDutch_server.domain.member.repository.MemberRepository; @@ -41,6 +38,7 @@ import org.springframework.web.multipart.MultipartFile; import java.util.*; +import java.util.stream.Collectors; @RequiredArgsConstructor @Service @@ -63,8 +61,8 @@ public class TripServiceImpl implements TripService{ private final S3PathManager s3PathManager; private final S3Manager s3Manager; - /* - 여행 생성 + /** + * 여행 생성 */ @Transactional @Override @@ -78,7 +76,7 @@ public Long createTrip(TripRequestDTO tripRequestDTO) { //UUID를 통해 랜덤한 참여 코드 12자리를 생성한다. String joinCode = UUID.randomUUID().toString().replace("-", "").substring(0, 12); - String savedPath = !tripRequestDTO.getTripImage().isEmpty() ? saveImageToS3(tripRequestDTO.getTripImage()) : null; + String savedPath = (tripRequestDTO.getTripImage() != null && !tripRequestDTO.getTripImage().isEmpty()) ? saveImageToS3(tripRequestDTO.getTripImage()) : null; //여행을 저장한다. Trip savedTrip = tripRepository.save(TripConverter.toEntity(tripRequestDTO, joinCode, savedPath)); @@ -89,8 +87,8 @@ public Long createTrip(TripRequestDTO tripRequestDTO) { return savedTrip.getId(); } - /* - 이미지 저장 및 경로 반환 + /** + * 이미지 저장 및 경로 반환 */ private String saveImageToS3(MultipartFile file) { String uuid = UUID.randomUUID().toString(); @@ -104,8 +102,8 @@ private String saveImageToS3(MultipartFile file) { return s3Manager.upload(file, keyName); } - /* - 여행 참여 + /** + * 여행 참여 */ @Transactional @Override @@ -128,10 +126,10 @@ public void joinTrip(TripJoinRequestDTO tripJoinRequestDTO) { tripMemberRepository.save(tripMember); } - /* - 여행 공유시 정보 조회 + /** + * 여행 공유시 정보 조회 */ - @Transactional + @Transactional(readOnly = true) @Override public TripResponseDTO shareTrip(Long tripId) { Trip trip = tripRepository.findById(tripId) @@ -139,11 +137,11 @@ public TripResponseDTO shareTrip(Long tripId) { return TripConverter.toDto(trip); } - /* - 여행 목록 전체 조회 + /** + * 여행 목록 전체 조회 */ @Override - @Transactional + @Transactional(readOnly = true) public List searchTrip(String keyWord) { Member currentMember = authUtils.getCurrentMember(); Long memberId = currentMember.getId(); @@ -214,11 +212,11 @@ private Set validateTripByMemberName(String keyword, List trips) { return tripSet; } - /* - 여행 정보 조회 + /** + * 여행 정보 조회 */ @Override - @Transactional + @Transactional(readOnly = true) public TripDetailResponseDTO detailTrip(Long tripId) { Member member = authUtils.getCurrentMember(); tripMemberRepository @@ -227,11 +225,20 @@ public TripDetailResponseDTO detailTrip(Long tripId) { Trip trip = tripRepository.findById(tripId) .orElseThrow(()->new ErrorHandler(ErrorStatus.TRIP_NOT_EXIST)); - return TripConverter.toDetailDto(trip, photoRepository); + + Map> photoUrlsMap = trip.getExpenses().stream() + .collect(Collectors.toMap( + Expense::getId, + expense -> photoRepository.findByExpense(expense).stream() + .map(Photo::getPhotoUrl) + .collect(Collectors.toList()) + )); + + return TripConverter.toDetailDto(trip, photoUrlsMap); } - /* - 여행 수정 + /** + * 여행 수정 */ @Override @Transactional @@ -246,7 +253,13 @@ public void updateTrip( Trip trip = tripRepository.findById(tripId) .orElseThrow(() -> new ErrorHandler(ErrorStatus.TRIP_NOT_EXIST)); - trip.updateInfo(requestDTO); + trip.updateInfo( + requestDTO.getTripName(), + requestDTO.getPlace(), + requestDTO.getStartDate(), + requestDTO.getEndDate(), + requestDTO.getBudget() + ); if (requestDTO.getTripImage() != null && !requestDTO.getTripImage().isEmpty()) { if (trip.getTripImageUrl() != null) { @@ -259,8 +272,8 @@ public void updateTrip( } - /* - 여행 삭제 + /** + * 여행 삭제 */ @Override @Transactional @@ -282,13 +295,13 @@ public void deleteTrip(Long tripId) { dutchRepository.deleteById(dutch.getId()); } - deleteExpense(expenses); + deleteExpenseImages(expenses); tripRepository.deleteById(tripId);// 여행 삭제 } - // 지출 삭제 - private void deleteExpense(List expenses) { + // 지출 관련 S3 이미지 및 Photo 엔티티 삭제 + private void deleteExpenseImages(List expenses) { for (Expense expense : expenses) {// 지출 삭제 루프 List photos = photoRepository.findByExpenseId(expense.getId()); for (Photo photo : photos) {// 지출 사진 삭제 @@ -325,8 +338,8 @@ private void isPremiumMember(Long userId) { throw new ErrorHandler(ErrorStatus._FORBIDDEN); } - /* - 여행 경비 예측 + /** + * 여행 경비 예측 */ @Override @Transactional @@ -342,14 +355,17 @@ public PredictResponseDto predictBudget(PredictRequestDto requestDto) { headers.setContentType(MediaType.APPLICATION_JSON); HttpEntity> entity = new HttpEntity<>(body, headers); - RestTemplate restTemplate = new RestTemplate(); - ResponseEntity response = restTemplate.postForEntity(flaskUrl, entity, Map.class); - Double predict = (Double) response.getBody().get("predicted_total_cost"); + ResponseEntity response = template.postForEntity(flaskUrl, entity, Map.class); + Map responseBody = response.getBody(); + if (responseBody == null || responseBody.get("predicted_total_cost") == null) { + throw new ErrorHandler(ErrorStatus._INTERNAL_SERVER_ERROR); + } + Double predict = (Double) responseBody.get("predicted_total_cost"); return new PredictResponseDto(predict.intValue()+"원"); } - /* - gpt 여행지 추천 + /** + * gpt 여행지 추천 */ @Override @Transactional From 2562767ea583a34cad479e398b8817965bdff671 Mon Sep 17 00:00:00 2001 From: yeobi Date: Wed, 15 Apr 2026 21:41:04 +0900 Subject: [PATCH 2/8] =?UTF-8?q?[Refac]=20=EC=A7=80=EC=B6=9C=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EC=BD=94=EB=93=9C=20=EC=A0=95=EB=A6=AC=20?= =?UTF-8?q?=EB=B0=8F=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../expense/controller/ExpenseController.java | 15 ++++++--------- .../domain/expense/entity/Expense.java | 1 - .../expense/repository/ExpenseRepository.java | 1 - .../domain/expense/service/ExpenseService.java | 16 +++++++--------- 4 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/main/java/graduation/project/DoDutch_server/domain/expense/controller/ExpenseController.java b/src/main/java/graduation/project/DoDutch_server/domain/expense/controller/ExpenseController.java index d0b60a3..3c6382a 100644 --- a/src/main/java/graduation/project/DoDutch_server/domain/expense/controller/ExpenseController.java +++ b/src/main/java/graduation/project/DoDutch_server/domain/expense/controller/ExpenseController.java @@ -1,13 +1,10 @@ package graduation.project.DoDutch_server.domain.expense.controller; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import graduation.project.DoDutch_server.domain.expense.dto.*; import graduation.project.DoDutch_server.domain.expense.service.ExpenseService; import graduation.project.DoDutch_server.global.common.apiPayload.ApiResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; @@ -22,7 +19,7 @@ public class ExpenseController { private final ExpenseService expenseService; - /* + /** * 하나의 여행에 대한 전체 지출 목록 조회 */ @GetMapping("/{tripId}/expense") @@ -37,7 +34,7 @@ public ApiResponse getExpensesByTrip(@PathVariable("tripI } - /* + /** * 하나의 여행에 대한 날짜별 지출 목록 조회 */ @GetMapping("/{tripId}/expense/date") @@ -52,7 +49,7 @@ public ApiResponse> getExpensesByTripAndDate(@ } - /* + /** * 지출 세부 조회 */ @Operation(summary = "지출 세부 조회 API") @@ -72,9 +69,9 @@ public ApiResponse getExpensesById(@PathVariable( @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공") }) @PostMapping(value = "/{tripId}/expense", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public ApiResponse addExpense(@PathVariable("tripId") Long tripId, + public ApiResponse addExpense(@PathVariable("tripId") Long tripId, @RequestPart("expenseRequestDto") ExpenseRequestDto expenseRequestDto, - @RequestPart("expenseImages") List expenseImages + @RequestPart(value = "expenseImages", required = false) List expenseImages ) { expenseService.addExpense(tripId, expenseRequestDto, expenseImages); @@ -87,7 +84,7 @@ public ApiResponse addExpense(@PathVariable("tripId") Long tripId, @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공") }) @PatchMapping(value = "/{tripId}/expense/{expenseId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public ApiResponse updateExpense(@PathVariable("tripId") Long tripId, + public ApiResponse updateExpense(@PathVariable("tripId") Long tripId, @PathVariable("expenseId") Long expenseId, @RequestPart("expenseRequestDto") ExpenseRequestDto expenseRequestDto, @RequestPart(value = "expenseImages", required = false) List expenseImages) { diff --git a/src/main/java/graduation/project/DoDutch_server/domain/expense/entity/Expense.java b/src/main/java/graduation/project/DoDutch_server/domain/expense/entity/Expense.java index fd282de..2b64b8f 100644 --- a/src/main/java/graduation/project/DoDutch_server/domain/expense/entity/Expense.java +++ b/src/main/java/graduation/project/DoDutch_server/domain/expense/entity/Expense.java @@ -43,7 +43,6 @@ public class Expense extends BaseEntity { private List expenseMembers = new ArrayList<>(); /** - * * update 함수 */ public void update(String title, diff --git a/src/main/java/graduation/project/DoDutch_server/domain/expense/repository/ExpenseRepository.java b/src/main/java/graduation/project/DoDutch_server/domain/expense/repository/ExpenseRepository.java index 3a68005..d00a76e 100644 --- a/src/main/java/graduation/project/DoDutch_server/domain/expense/repository/ExpenseRepository.java +++ b/src/main/java/graduation/project/DoDutch_server/domain/expense/repository/ExpenseRepository.java @@ -1,7 +1,6 @@ package graduation.project.DoDutch_server.domain.expense.repository; import graduation.project.DoDutch_server.domain.expense.entity.Expense; -import graduation.project.DoDutch_server.domain.member.entity.Member; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; diff --git a/src/main/java/graduation/project/DoDutch_server/domain/expense/service/ExpenseService.java b/src/main/java/graduation/project/DoDutch_server/domain/expense/service/ExpenseService.java index 4d9e4d0..87fa613 100644 --- a/src/main/java/graduation/project/DoDutch_server/domain/expense/service/ExpenseService.java +++ b/src/main/java/graduation/project/DoDutch_server/domain/expense/service/ExpenseService.java @@ -18,7 +18,7 @@ import graduation.project.DoDutch_server.global.common.exception.handler.ErrorHandler; import graduation.project.DoDutch_server.global.config.aws.S3PathManager; import graduation.project.DoDutch_server.global.config.aws.S3Manager; -import jakarta.transaction.Transactional; +import org.springframework.transaction.annotation.Transactional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; @@ -126,7 +126,7 @@ public void addExpense(Long tripId, ExpenseRequestDto expenseRequestDto, List new ErrorHandler(ErrorStatus.TRIP_MEMBER_EXIST)); + .orElseThrow(() -> new ErrorHandler(ErrorStatus.TRIP_MEMBER_NOT_EXIST)); ExpenseMember expenseMember = ExpenseMember.builder() .shareAmount(memberDto.getCost()) @@ -208,7 +208,7 @@ public void updateExpense(Long expenseId, ExpenseRequestDto dto, List new ErrorHandler(ErrorStatus.TRIP_MEMBER_EXIST)); + .orElseThrow(() -> new ErrorHandler(ErrorStatus.TRIP_MEMBER_NOT_EXIST)); ExpenseMember expenseMember = ExpenseMember.builder() .expense(expense) @@ -277,16 +277,16 @@ public void updateTotalCost(Trip trip, int costDifference) { trip.setTotalCost(0); } trip.setTotalCost(trip.getTotalCost() + costDifference); - tripRepository.save(trip); } + @Transactional(readOnly = true) public AllExpenseResponseDto getExpensesByTripId(Long tripId){ //전체 여행 지출 조회 Trip trip = tripRepository.findById(tripId) .orElseThrow(() -> new ErrorHandler(ErrorStatus.TRIP_NOT_EXIST)); List expenses= expenseRepository.findByTripId(tripId); //지출 기록 - int budget = trip.getBudget(); //전체 예산 + int budget = trip.getBudget() != null ? trip.getBudget() : 0; //전체 예산 int remainingCost = (trip.getBudget() != null ? trip.getBudget() : 0) - (trip.getTotalCost() != null ? trip.getTotalCost() : 0); //잔여금액 @@ -309,6 +309,7 @@ public AllExpenseResponseDto getExpensesByTripId(Long tripId){ //전체 여행 } + @Transactional(readOnly = true) public List getExpensesByTripIdAndDate(Long tripId){ //날짜별 여행 지출 조회 Trip trip = tripRepository.findById(tripId) .orElseThrow(() -> new ErrorHandler(ErrorStatus.TRIP_NOT_EXIST)); @@ -318,6 +319,7 @@ public List getExpensesByTripIdAndDate(Long tripId) return ExpenseConverter.toAllExpenseByDateResponseDto(expenses); } + @Transactional(readOnly = true) public ExpenseByExpenseIdResponseDto getExpenseByExpenseId(Long expenseId){ Expense expense = expenseRepository.findById(expenseId) @@ -339,8 +341,4 @@ public void deleteMember(Long memberId){ expense.setPayer(null); } } - - - - } From 9ff2b4ef4cadc9b39b41e7ca4b8888dacd2f7a01 Mon Sep 17 00:00:00 2001 From: yeobi Date: Wed, 15 Apr 2026 21:41:49 +0900 Subject: [PATCH 3/8] =?UTF-8?q?[Refac]=20Member=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EC=BD=94=EB=93=9C=20=EC=A0=95=EB=A6=AC=20=EB=B0=8F?= =?UTF-8?q?=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/controller/MemberController.java | 11 +++++++++-- .../domain/member/repository/MemberRepository.java | 1 - .../domain/member/service/MemberService.java | 7 ++++--- .../domain/trip/service/TripService.java | 1 + 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/main/java/graduation/project/DoDutch_server/domain/member/controller/MemberController.java b/src/main/java/graduation/project/DoDutch_server/domain/member/controller/MemberController.java index 3b32310..1fa4a9f 100644 --- a/src/main/java/graduation/project/DoDutch_server/domain/member/controller/MemberController.java +++ b/src/main/java/graduation/project/DoDutch_server/domain/member/controller/MemberController.java @@ -17,7 +17,7 @@ public class MemberController { private final MemberService memberService; - /* + /** * 개인정보 조회 */ @GetMapping @@ -30,7 +30,7 @@ public ApiResponse getMember(){ return ApiResponse.onSuccess(responseDto); } - /* + /** * 개인정보 수정 */ @PatchMapping @@ -45,7 +45,14 @@ public ApiResponse updateMember( return ApiResponse.onSuccess(responseDto); } + /** + * 계정 삭제 + */ @DeleteMapping + @Operation(summary = "계정 삭제 API") + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공") + }) public ApiResponse deleteAccount() { memberService.deleteMember(); return ApiResponse.onSuccess(); diff --git a/src/main/java/graduation/project/DoDutch_server/domain/member/repository/MemberRepository.java b/src/main/java/graduation/project/DoDutch_server/domain/member/repository/MemberRepository.java index 6d4fde2..9bac7ba 100644 --- a/src/main/java/graduation/project/DoDutch_server/domain/member/repository/MemberRepository.java +++ b/src/main/java/graduation/project/DoDutch_server/domain/member/repository/MemberRepository.java @@ -6,7 +6,6 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.util.List; import java.util.Optional; @Repository diff --git a/src/main/java/graduation/project/DoDutch_server/domain/member/service/MemberService.java b/src/main/java/graduation/project/DoDutch_server/domain/member/service/MemberService.java index af8ec96..54d803a 100644 --- a/src/main/java/graduation/project/DoDutch_server/domain/member/service/MemberService.java +++ b/src/main/java/graduation/project/DoDutch_server/domain/member/service/MemberService.java @@ -9,11 +9,11 @@ import graduation.project.DoDutch_server.domain.member.dto.response.MemberResponseDto; import graduation.project.DoDutch_server.domain.member.entity.Member; import graduation.project.DoDutch_server.domain.member.repository.MemberRepository; -import graduation.project.DoDutch_server.domain.trip.service.TripServiceImpl; +import graduation.project.DoDutch_server.domain.trip.service.TripService; import graduation.project.DoDutch_server.global.common.apiPayload.code.status.ErrorStatus; import graduation.project.DoDutch_server.global.common.exception.handler.ErrorHandler; import graduation.project.DoDutch_server.global.util.AuthUtils; -import jakarta.transaction.Transactional; +import org.springframework.transaction.annotation.Transactional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -24,10 +24,11 @@ public class MemberService { private final MemberRepository memberRepository; private final AuthService authService; - private final TripServiceImpl tripService; + private final TripService tripService; private final ExpenseService expenseService; private final DutchService dutchService; + @Transactional(readOnly = true) public MemberResponseDto getMember() { Member currentMember = getCurrentMember(); return MemberConverter.toMemberResponseDto(currentMember); diff --git a/src/main/java/graduation/project/DoDutch_server/domain/trip/service/TripService.java b/src/main/java/graduation/project/DoDutch_server/domain/trip/service/TripService.java index 7c3d89b..070b070 100644 --- a/src/main/java/graduation/project/DoDutch_server/domain/trip/service/TripService.java +++ b/src/main/java/graduation/project/DoDutch_server/domain/trip/service/TripService.java @@ -22,4 +22,5 @@ public interface TripService { TripSuggestionResponseDto recommendTrip(TripSuggestionRequestDto requestDto); void updateTrip(Long tripId, TripUpdateRequestDTO requestDTO); void deleteTrip(Long tripId); + void deleteMember(Long memberId); } From a60342ea8fc3a39b8fef59498c4de45e154bb83d Mon Sep 17 00:00:00 2001 From: yeobi Date: Wed, 15 Apr 2026 21:42:10 +0900 Subject: [PATCH 4/8] =?UTF-8?q?[Refac]=20Auth=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EC=BD=94=EB=93=9C=20=EC=A0=95=EB=A6=AC=20=EB=B0=8F?= =?UTF-8?q?=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/controller/AuthController.java | 42 ++++++++++++++++++- .../domain/auth/service/AuthService.java | 32 +++++++------- .../global/config/jwt/JwtTokenProvider.java | 10 ++--- 3 files changed, 62 insertions(+), 22 deletions(-) diff --git a/src/main/java/graduation/project/DoDutch_server/domain/auth/controller/AuthController.java b/src/main/java/graduation/project/DoDutch_server/domain/auth/controller/AuthController.java index 7aeb572..7ea4668 100644 --- a/src/main/java/graduation/project/DoDutch_server/domain/auth/controller/AuthController.java +++ b/src/main/java/graduation/project/DoDutch_server/domain/auth/controller/AuthController.java @@ -23,7 +23,14 @@ public class AuthController { private final AuthService authService; + /** + * 카카오 로그인 (웹) + */ @PostMapping("/kakao/login") + @Operation(summary = "카카오 로그인 API (웹)") + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공") + }) public ApiResponse login(@RequestBody KakaoRequestDTO kakaoRequestDTO, HttpServletResponse response) { KakaoResponseDTO kakaoResponseDTO = authService.loginWithKakao(kakaoRequestDTO.getAccessCode(), response); @@ -35,22 +42,38 @@ public ApiResponse login(@RequestBody KakaoRequestDTO kakaoReq */ @PostMapping("/kakao/login-token") @Operation(summary = "카카오 로그인 (모바일 SDK 액세스 토큰)", description = "모바일 앱에서 카카오 SDK로 획득한 액세스 토큰으로 로그인") + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공") + }) public ApiResponse loginWithToken(@RequestBody KakaoRequestDTO kakaoRequestDTO, HttpServletResponse response) { KakaoResponseDTO kakaoResponseDTO = authService.loginWithKakaoToken(kakaoRequestDTO.getAccessToken(), response); return ApiResponse.onSuccess(kakaoResponseDTO); } + /** + * 회원가입 + */ @PostMapping("/signup") @Operation(summary = "회원가입 API", description = "카카오 로그인 후 닉네임 설정하여 회원가입") - public ApiResponse signup(@RequestBody SignupRequestDTO signupRequestDTO, + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공") + }) + public ApiResponse signup(@RequestBody SignupRequestDTO signupRequestDTO, @RequestHeader("Authorization") String authHeader) { String accessToken = authHeader.replace("Bearer ", ""); authService.signup(signupRequestDTO, accessToken); return ApiResponse.onSuccess(); } + /** + * 토큰 갱신 + */ @PostMapping("/refresh-token") + @Operation(summary = "토큰 갱신 API") + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공") + }) public ApiResponse refreshToken(@RequestBody RefreshRequestDTO refreshRequestDTO, HttpServletResponse response) { RefreshResponseDTO refreshResponseDTO = authService.refreshAccessToken(refreshRequestDTO); @@ -62,13 +85,17 @@ public ApiResponse refreshToken(@RequestBody RefreshRequestD * 카카오 OAuth 과정 없이 kakaoId로 바로 JWT 토큰 발급 */ @PostMapping("/dev-login") + @Operation(summary = "개발 전용 로그인 API") + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공") + }) public ApiResponse devLogin(@RequestParam String kakaoId) { log.info("[DEV] Development login requested for kakaoId: {}", kakaoId); KakaoResponseDTO response = authService.createTokensForDev(kakaoId); return ApiResponse.onSuccess(response); } - /* + /** * 닉네임 중복 확인 */ @PostMapping("/check-nickname") @@ -81,7 +108,14 @@ public ApiResponse checkNickname(@RequestBody NicknameRequestDto requestDt return ApiResponse.onSuccess(); } + /** + * 프리미엄 결제 준비 + */ @PostMapping("/premium") + @Operation(summary = "프리미엄 결제 준비 API") + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공") + }) public ApiResponse premium( @RequestBody PayPremiumReadyRequestDto requestDto ) { @@ -89,7 +123,11 @@ public ApiResponse premium( return ApiResponse.onSuccess(responseDto); } + /** + * 프리미엄 결제 승인 콜백 + */ @GetMapping("/approve-callback") + @Operation(summary = "프리미엄 결제 승인 콜백 API") public void approve( @RequestParam("partner_order_id") String partnerOrderId, @RequestParam("pg_token") String pgToken, diff --git a/src/main/java/graduation/project/DoDutch_server/domain/auth/service/AuthService.java b/src/main/java/graduation/project/DoDutch_server/domain/auth/service/AuthService.java index a35b2ec..b8888e6 100644 --- a/src/main/java/graduation/project/DoDutch_server/domain/auth/service/AuthService.java +++ b/src/main/java/graduation/project/DoDutch_server/domain/auth/service/AuthService.java @@ -40,7 +40,6 @@ import graduation.project.DoDutch_server.global.common.exception.GeneralException; import java.util.Map; -import java.util.Optional; import java.util.UUID; @RequiredArgsConstructor @@ -51,6 +50,7 @@ public class AuthService { private final JwtTokenProvider jwtTokenProvider; private final KakaopayService kakaopayService; private final PaymentOrderRepository paymentOrderRepository; + private final RestTemplate restTemplate = new RestTemplate(); @Value("${kakao.client-id}") private String clientId; @@ -68,8 +68,6 @@ public KakaoResponseDTO loginWithKakao(String accessCode, HttpServletResponse re KakaoMemberAndExistDTO kakaoMemberAndExistDTO = getUserProfileByToken(accessToken); - Optional findMember = memberRepository.findById(kakaoMemberAndExistDTO.getMember().getId()); - return getKakaoTokens(kakaoMemberAndExistDTO.getMember().getKakaoId(), kakaoMemberAndExistDTO.isExistingMember(), response); } @@ -85,8 +83,6 @@ public KakaoResponseDTO loginWithKakaoToken(String accessToken, HttpServletRespo // OAuth 인증 코드 교환 과정을 건너뛰고 직접 액세스 토큰 사용 KakaoMemberAndExistDTO kakaoMemberAndExistDTO = getUserProfileByToken(accessToken); - Optional findMember = memberRepository.findById(kakaoMemberAndExistDTO.getMember().getId()); - KakaoResponseDTO result = getKakaoTokens(kakaoMemberAndExistDTO.getMember().getKakaoId(), kakaoMemberAndExistDTO.isExistingMember(), response); @@ -114,8 +110,7 @@ private String getAccessToken(String accessCode) { // HTTP 요청 보내기 HttpEntity> kakaoTokenRequest = new HttpEntity<>(body, headers); - RestTemplate rt = new RestTemplate(); - ResponseEntity response = rt.exchange( + ResponseEntity response = restTemplate.exchange( "https://kauth.kakao.com/oauth/token", HttpMethod.POST, kakaoTokenRequest, @@ -124,14 +119,23 @@ private String getAccessToken(String accessCode) { // HTTP 응답 (JSON) -> 액세스 토큰 파싱 String responseBody = response.getBody(); + if (responseBody == null) { + throw new GeneralException(ErrorStatus.KAKAO_API_ERROR); + } + ObjectMapper objectMapper = new ObjectMapper(); - JsonNode jsonNode = null; + JsonNode jsonNode; try { jsonNode = objectMapper.readTree(responseBody); } catch (JsonProcessingException e) { - e.printStackTrace(); + throw new GeneralException(ErrorStatus.KAKAO_API_ERROR); } - return jsonNode.get("access_token").asText(); //토큰 전송 + + JsonNode accessTokenNode = jsonNode.get("access_token"); + if (accessTokenNode == null) { + throw new GeneralException(ErrorStatus.KAKAO_API_ERROR); + } + return accessTokenNode.asText(); //토큰 전송 } // 카카오 API 호출해서 AccessToken으로 유저정보 가져오기(id) @@ -175,15 +179,15 @@ public KakaoMemberAndExistDTO getUserProfileByToken(String accessToken){ boolean existMember = false; - if(memberRepository.findByKakaoId(member.getKakaoId()) != null) //DB에 회원정보 있으면 existMember = True + Member findMember = memberRepository.findByKakaoId(member.getKakaoId()); //DB에 회원정보 조회 + if(findMember != null) //DB에 회원정보 있으면 existMember = True { existMember = true; } else { - memberRepository.save(member); //DB에 회원정보 없으면 저장 + findMember = memberRepository.save(member); //DB에 회원정보 없으면 저장 } - Member findMember = memberRepository.findByKakaoId(kakaoInfoDto.getKakaoId()); return KakaoMemberAndExistDTO.builder() .member(findMember) .isExistingMember(existMember) @@ -279,7 +283,7 @@ public KakaoResponseDTO createTokensForDev(String kakaoId) { } // 닉네임 중복 확인 - @Transactional + @Transactional(readOnly = true) public void checkNickname(NicknameRequestDto requestDto) { String nickname = requestDto.nickname(); if (nickname == null || nickname.isEmpty()) { diff --git a/src/main/java/graduation/project/DoDutch_server/global/config/jwt/JwtTokenProvider.java b/src/main/java/graduation/project/DoDutch_server/global/config/jwt/JwtTokenProvider.java index ba49761..858b5c9 100644 --- a/src/main/java/graduation/project/DoDutch_server/global/config/jwt/JwtTokenProvider.java +++ b/src/main/java/graduation/project/DoDutch_server/global/config/jwt/JwtTokenProvider.java @@ -8,7 +8,6 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.InitializingBean; import org.springframework.stereotype.Component; -import org.springframework.stereotype.Service; import graduation.project.DoDutch_server.global.common.apiPayload.code.status.ErrorStatus; import graduation.project.DoDutch_server.global.common.exception.GeneralException; @@ -19,20 +18,19 @@ @Slf4j @Component -@Service public class JwtTokenProvider implements InitializingBean { private static final long ACCESS_TOKEN_EXPIRE_TIME = 1000 * 60 * 60; // 1시간 private static final long REFRESH_TOKEN_EXPIRE_TIME = 1000 * 60 * 60 * 24 * 7; // 7일 private final String secretKey; // Jwt 시크릿 키 - private static Key key; + private Key key; public JwtTokenProvider(@Value("${jwt.secret-key}") String secretKey) { this.secretKey = secretKey; } - /* + /** * 비밀키를 Base64 인코딩하고 다시 키로 변환하여 저장 */ @Override @@ -40,7 +38,7 @@ public void afterPropertiesSet() { this.key = getKeyFromBase64EncodedKey(encodeBase64SecretKey(secretKey)); } - //여기서 payload는 멤버의 socialId + // 여기서 payload는 멤버의 socialId public String createAccessToken(String payload) { return createToken(payload, ACCESS_TOKEN_EXPIRE_TIME); } @@ -64,7 +62,7 @@ public String createToken(String payload, long expireLength) { .compact(); } - /* + /** * 페이로드 추출 */ public String getPayload(String token) { From ccda427603c9d5b23cb354a49b0ce8c8100d7dcf Mon Sep 17 00:00:00 2001 From: yeobi Date: Wed, 15 Apr 2026 21:48:25 +0900 Subject: [PATCH 5/8] =?UTF-8?q?[Refac]=20global=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC=20=EB=B0=8F=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 +- .../global/common/ResponseDTO.java | 13 ------- .../common/apiPayload/ApiResponseStatus.java | 14 ------- .../apiPayload/code/status/ErrorStatus.java | 6 ++- .../exception/CustomRuntimeException.java | 12 ------ .../common/exception/ExceptionAdvice.java | 2 +- .../global/config/aws/S3Manager.java | 6 ++- .../global/config/aws/S3PathManager.java | 5 ++- .../config/security/SecurityConfig.java | 38 ++++++++----------- .../global/config/web/WebConfig.java | 14 ------- 10 files changed, 31 insertions(+), 81 deletions(-) delete mode 100644 src/main/java/graduation/project/DoDutch_server/global/common/ResponseDTO.java delete mode 100644 src/main/java/graduation/project/DoDutch_server/global/common/apiPayload/ApiResponseStatus.java delete mode 100644 src/main/java/graduation/project/DoDutch_server/global/common/exception/CustomRuntimeException.java delete mode 100644 src/main/java/graduation/project/DoDutch_server/global/config/web/WebConfig.java diff --git a/build.gradle b/build.gradle index eb2e76e..d03f2fb 100644 --- a/build.gradle +++ b/build.gradle @@ -35,7 +35,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-webflux' implementation 'com.fasterxml.jackson.core:jackson-databind' - implementation 'me.paulschwarz:spring-dotenv:4.0.0' + implementation 'me.paulschwarz:spring-dotenv:3.0.0' implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE' // Swagger 설정 diff --git a/src/main/java/graduation/project/DoDutch_server/global/common/ResponseDTO.java b/src/main/java/graduation/project/DoDutch_server/global/common/ResponseDTO.java deleted file mode 100644 index d799a9b..0000000 --- a/src/main/java/graduation/project/DoDutch_server/global/common/ResponseDTO.java +++ /dev/null @@ -1,13 +0,0 @@ -package graduation.project.DoDutch_server.global.common; - -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter -public class ResponseDTO { - private boolean success; - private String code; - private String message; - private T data; -} diff --git a/src/main/java/graduation/project/DoDutch_server/global/common/apiPayload/ApiResponseStatus.java b/src/main/java/graduation/project/DoDutch_server/global/common/apiPayload/ApiResponseStatus.java deleted file mode 100644 index 2d2c457..0000000 --- a/src/main/java/graduation/project/DoDutch_server/global/common/apiPayload/ApiResponseStatus.java +++ /dev/null @@ -1,14 +0,0 @@ -package graduation.project.DoDutch_server.global.common.apiPayload; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@Getter -@RequiredArgsConstructor -public enum ApiResponseStatus { - REQUEST_SUCCESS(true, "S200", "요청에 성공했습니다."); - - private final boolean success; - private final String status; - private final String message; -} diff --git a/src/main/java/graduation/project/DoDutch_server/global/common/apiPayload/code/status/ErrorStatus.java b/src/main/java/graduation/project/DoDutch_server/global/common/apiPayload/code/status/ErrorStatus.java index f70b694..398bcad 100644 --- a/src/main/java/graduation/project/DoDutch_server/global/common/apiPayload/code/status/ErrorStatus.java +++ b/src/main/java/graduation/project/DoDutch_server/global/common/apiPayload/code/status/ErrorStatus.java @@ -50,7 +50,11 @@ public enum ErrorStatus implements BaseErrorCode { TRIP_CREATE_FAIL(HttpStatus.BAD_REQUEST, "TRIP4005", "여행 생성 실패"), TRIP_NOT_FOUND(HttpStatus.NOT_FOUND, "TRIP4002", "해당하는 여행 목록이 없습니다."), TRIP_MEMBER_EXIST(HttpStatus.BAD_REQUEST, "TRIP4003", "이미 존재하는 여행 멤버입니다."), - TRIP_MEMBER_NOT_EXIST(HttpStatus.BAD_REQUEST, "TRIP4004", "존재하지 않는 여행 멤버입니다.") + TRIP_MEMBER_NOT_EXIST(HttpStatus.BAD_REQUEST, "TRIP4004", "존재하지 않는 여행 멤버입니다."), + + // S3 관련 응답 + S3_UPLOAD_FAIL(HttpStatus.INTERNAL_SERVER_ERROR, "S3_5001", "파일 업로드에 실패했습니다."), + S3_DELETE_FAIL(HttpStatus.INTERNAL_SERVER_ERROR, "S3_5002", "파일 삭제에 실패했습니다.") ; private final HttpStatus httpStatus; diff --git a/src/main/java/graduation/project/DoDutch_server/global/common/exception/CustomRuntimeException.java b/src/main/java/graduation/project/DoDutch_server/global/common/exception/CustomRuntimeException.java deleted file mode 100644 index 274ae77..0000000 --- a/src/main/java/graduation/project/DoDutch_server/global/common/exception/CustomRuntimeException.java +++ /dev/null @@ -1,12 +0,0 @@ -package graduation.project.DoDutch_server.global.common.exception; - -import org.springframework.http.HttpStatus; - -public class CustomRuntimeException extends RuntimeException { - private final HttpStatus status; - - public CustomRuntimeException(String message, HttpStatus status) { - super(message); - this.status = status; - } -} diff --git a/src/main/java/graduation/project/DoDutch_server/global/common/exception/ExceptionAdvice.java b/src/main/java/graduation/project/DoDutch_server/global/common/exception/ExceptionAdvice.java index a947dc6..d5dc3ac 100644 --- a/src/main/java/graduation/project/DoDutch_server/global/common/exception/ExceptionAdvice.java +++ b/src/main/java/graduation/project/DoDutch_server/global/common/exception/ExceptionAdvice.java @@ -54,7 +54,7 @@ protected ResponseEntity handleMethodArgumentNotValid( @ExceptionHandler public ResponseEntity exception(Exception e, WebRequest request) { - e.printStackTrace(); + log.error("Unhandled exception occurred", e); return handleExceptionInternalFalse(e, ErrorStatus._INTERNAL_SERVER_ERROR, HttpHeaders.EMPTY, ErrorStatus._INTERNAL_SERVER_ERROR.getHttpStatus(),request, e.getMessage()); } diff --git a/src/main/java/graduation/project/DoDutch_server/global/config/aws/S3Manager.java b/src/main/java/graduation/project/DoDutch_server/global/config/aws/S3Manager.java index b52d140..9ef1215 100644 --- a/src/main/java/graduation/project/DoDutch_server/global/config/aws/S3Manager.java +++ b/src/main/java/graduation/project/DoDutch_server/global/config/aws/S3Manager.java @@ -6,6 +6,8 @@ import com.amazonaws.services.s3.model.DeleteObjectRequest; import com.amazonaws.services.s3.model.ObjectMetadata; import com.amazonaws.services.s3.model.PutObjectRequest; +import graduation.project.DoDutch_server.global.common.apiPayload.code.status.ErrorStatus; +import graduation.project.DoDutch_server.global.common.exception.handler.ErrorHandler; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -44,7 +46,7 @@ public String upload(MultipartFile file, String keyName) { } catch (IOException e) { log.error("S3 Upload Error", e); - throw new RuntimeException("S3 Upload Failed", e); + throw new ErrorHandler(ErrorStatus.S3_UPLOAD_FAIL); } } @@ -55,7 +57,7 @@ public void delete(String keyName) { } catch (AmazonServiceException e) { log.error("S3 Delete Error", e); - throw new RuntimeException("S3 Delete Failed", e); + throw new ErrorHandler(ErrorStatus.S3_DELETE_FAIL); } } } diff --git a/src/main/java/graduation/project/DoDutch_server/global/config/aws/S3PathManager.java b/src/main/java/graduation/project/DoDutch_server/global/config/aws/S3PathManager.java index ad1f8b6..c361b71 100644 --- a/src/main/java/graduation/project/DoDutch_server/global/config/aws/S3PathManager.java +++ b/src/main/java/graduation/project/DoDutch_server/global/config/aws/S3PathManager.java @@ -16,7 +16,10 @@ public class S3PathManager { public String generateKeyName(String prefix, MultipartFile file, String uuid) { String original = file.getOriginalFilename(); - String ext = original.substring(original.lastIndexOf('.')); + String ext = ""; + if (original != null && original.lastIndexOf('.') != -1) { + ext = original.substring(original.lastIndexOf('.')); + } return prefix + "/" + uuid + ext; } diff --git a/src/main/java/graduation/project/DoDutch_server/global/config/security/SecurityConfig.java b/src/main/java/graduation/project/DoDutch_server/global/config/security/SecurityConfig.java index c16fcea..592a53e 100644 --- a/src/main/java/graduation/project/DoDutch_server/global/config/security/SecurityConfig.java +++ b/src/main/java/graduation/project/DoDutch_server/global/config/security/SecurityConfig.java @@ -23,6 +23,19 @@ public class SecurityConfig { private final JwtTokenProvider jwtTokenProvider; private final MemberRepository memberRepository; + private static final String[] PUBLIC_PATHS = { + "/swagger", + "/swagger-ui.html", + "/swagger-ui/**", + "/api-docs", + "/api-docs/**", + "/v3/api-docs/**", + "/error", + "/api/kakaopay/**", + "/auth/**", + "/api/auth/**" + }; + @Bean public AuthenticationManager authenticationManager( final AuthenticationConfiguration authenticationConfiguration) throws Exception { @@ -41,18 +54,8 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .httpBasic((auth) -> auth.disable()); http - .authorizeHttpRequests((auth) -> auth.requestMatchers( - "/swagger", - "/swagger-ui.html", - "/swagger-ui/**", - "/api-docs", - "/api-docs/**", - "/v3/api-docs/**", - "/error", - "/api/kakaopay/**", - "/auth/**", - "/api/auth/**" - ).permitAll().anyRequest().authenticated()); + .authorizeHttpRequests((auth) -> auth.requestMatchers(PUBLIC_PATHS) + .permitAll().anyRequest().authenticated()); http .addFilterBefore(new JwtFilter(jwtTokenProvider, memberRepository), UsernamePasswordAuthenticationFilter.class); @@ -65,15 +68,6 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { @Bean public WebSecurityCustomizer webSecurityCustomizer() { - return (web) -> web.ignoring().requestMatchers( - "/swagger", - "/swagger-ui.html", - "/swagger-ui/**", - "/api-docs", - "/api-docs/**", - "/v3/api-docs/**", - "/auth/**", - "/api/auth/**" - ); + return (web) -> web.ignoring().requestMatchers(PUBLIC_PATHS); } } diff --git a/src/main/java/graduation/project/DoDutch_server/global/config/web/WebConfig.java b/src/main/java/graduation/project/DoDutch_server/global/config/web/WebConfig.java deleted file mode 100644 index 367ee4d..0000000 --- a/src/main/java/graduation/project/DoDutch_server/global/config/web/WebConfig.java +++ /dev/null @@ -1,14 +0,0 @@ -package graduation.project.DoDutch_server.global.config.web; - -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -@Configuration -public class WebConfig implements WebMvcConfigurer { - @Override - public void addResourceHandlers(ResourceHandlerRegistry registry) { - registry.addResourceHandler("/uploads/**") - .addResourceLocations("file:///C:/Users/kimhy/Desktop/Backend/uploads/"); - } -} From ebcedb5763f17e94fb3697f4cbb508615a3f163a Mon Sep 17 00:00:00 2001 From: yeobi Date: Thu, 30 Apr 2026 09:31:36 +0900 Subject: [PATCH 6/8] =?UTF-8?q?[Refac]=20=EC=93=B0=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EB=8A=94=20=ED=95=84=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/expense/converter/ExpenseConverter.java | 1 - .../domain/expense/dto/ExpenseByExpenseIdResponseDto.java | 1 - .../project/DoDutch_server/domain/expense/entity/Expense.java | 2 -- .../DoDutch_server/domain/trip/converter/TripConverter.java | 1 - .../DoDutch_server/domain/trip/dto/Response/TripExpenseDTO.java | 1 - 5 files changed, 6 deletions(-) diff --git a/src/main/java/graduation/project/DoDutch_server/domain/expense/converter/ExpenseConverter.java b/src/main/java/graduation/project/DoDutch_server/domain/expense/converter/ExpenseConverter.java index b07e8a0..d36d206 100644 --- a/src/main/java/graduation/project/DoDutch_server/domain/expense/converter/ExpenseConverter.java +++ b/src/main/java/graduation/project/DoDutch_server/domain/expense/converter/ExpenseConverter.java @@ -71,7 +71,6 @@ public static ExpenseByExpenseIdResponseDto toExpenseByExpenseIdResponseDto(Expe .expenseDate(expense.getExpenseDate()) .title(expense.getTitle()) .amount(expense.getAmount()) - .expenseImage(expense.getExpenseImageUrl()) .memo(expense.getMemo()) .build(); } diff --git a/src/main/java/graduation/project/DoDutch_server/domain/expense/dto/ExpenseByExpenseIdResponseDto.java b/src/main/java/graduation/project/DoDutch_server/domain/expense/dto/ExpenseByExpenseIdResponseDto.java index 2bc01ac..4d87ebd 100644 --- a/src/main/java/graduation/project/DoDutch_server/domain/expense/dto/ExpenseByExpenseIdResponseDto.java +++ b/src/main/java/graduation/project/DoDutch_server/domain/expense/dto/ExpenseByExpenseIdResponseDto.java @@ -12,6 +12,5 @@ public class ExpenseByExpenseIdResponseDto { private LocalDate expenseDate; private String title; private int amount; - private String expenseImage; private String memo; } diff --git a/src/main/java/graduation/project/DoDutch_server/domain/expense/entity/Expense.java b/src/main/java/graduation/project/DoDutch_server/domain/expense/entity/Expense.java index 2b64b8f..7eb573c 100644 --- a/src/main/java/graduation/project/DoDutch_server/domain/expense/entity/Expense.java +++ b/src/main/java/graduation/project/DoDutch_server/domain/expense/entity/Expense.java @@ -28,8 +28,6 @@ public class Expense extends BaseEntity { private ExpenseCategory expenseCategory; private LocalDate expenseDate; private String memo; - private String expenseImageUrl; - @ManyToOne @JoinColumn(name = "payer", nullable = true) private Member payer; diff --git a/src/main/java/graduation/project/DoDutch_server/domain/trip/converter/TripConverter.java b/src/main/java/graduation/project/DoDutch_server/domain/trip/converter/TripConverter.java index 15d3228..032d455 100644 --- a/src/main/java/graduation/project/DoDutch_server/domain/trip/converter/TripConverter.java +++ b/src/main/java/graduation/project/DoDutch_server/domain/trip/converter/TripConverter.java @@ -85,7 +85,6 @@ public static List toExpenseDtoList(List expenses, Map< return expenses.stream() .map(expense -> TripExpenseDTO.builder() .expenseId(expense.getId()) - .photoUrl(expense.getExpenseImageUrl()) .expensePhotoUrls(photoUrlsMap.getOrDefault(expense.getId(), Collections.emptyList())) .expenseDate(expense.getExpenseDate()) .title(expense.getTitle()) diff --git a/src/main/java/graduation/project/DoDutch_server/domain/trip/dto/Response/TripExpenseDTO.java b/src/main/java/graduation/project/DoDutch_server/domain/trip/dto/Response/TripExpenseDTO.java index 27abb92..732d95f 100644 --- a/src/main/java/graduation/project/DoDutch_server/domain/trip/dto/Response/TripExpenseDTO.java +++ b/src/main/java/graduation/project/DoDutch_server/domain/trip/dto/Response/TripExpenseDTO.java @@ -14,7 +14,6 @@ @Builder public class TripExpenseDTO { private Long expenseId; // 지출 id - private String photoUrl; // 지출 사진 url private List expensePhotoUrls; // 지출 사진 url 목록 private LocalDate expenseDate; // 지출 날짜 private String title; // 지출 제목 From b95bf8e803782d06ee9c6190241132b9f69708cf Mon Sep 17 00:00:00 2001 From: yeobi Date: Thu, 30 Apr 2026 09:32:04 +0900 Subject: [PATCH 7/8] =?UTF-8?q?[Chore]=20Swagger=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../expense/controller/ExpenseController.java | 22 +++++++++++++++++-- .../trip/controller/TripController.java | 21 ++++++++++++++---- .../global/config/swagger/SwaggerConfig.java | 14 ++++++++++++ 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/main/java/graduation/project/DoDutch_server/domain/expense/controller/ExpenseController.java b/src/main/java/graduation/project/DoDutch_server/domain/expense/controller/ExpenseController.java index 3c6382a..8577772 100644 --- a/src/main/java/graduation/project/DoDutch_server/domain/expense/controller/ExpenseController.java +++ b/src/main/java/graduation/project/DoDutch_server/domain/expense/controller/ExpenseController.java @@ -64,7 +64,16 @@ public ApiResponse getExpensesById(@PathVariable( } - @Operation(summary = "지출 생성 API") + @Operation(summary = "지출 생성 API", + requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody( + content = @io.swagger.v3.oas.annotations.media.Content( + encoding = @io.swagger.v3.oas.annotations.media.Encoding( + name = "expenseRequestDto", + contentType = MediaType.APPLICATION_JSON_VALUE + ) + ) + ) + ) @io.swagger.v3.oas.annotations.responses.ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공") }) @@ -79,7 +88,16 @@ public ApiResponse addExpense(@PathVariable("tripId") Long tripId, } - @Operation(summary = "지출 수정 API") + @Operation(summary = "지출 수정 API", + requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody( + content = @io.swagger.v3.oas.annotations.media.Content( + encoding = @io.swagger.v3.oas.annotations.media.Encoding( + name = "expenseRequestDto", + contentType = MediaType.APPLICATION_JSON_VALUE + ) + ) + ) + ) @io.swagger.v3.oas.annotations.responses.ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공") }) diff --git a/src/main/java/graduation/project/DoDutch_server/domain/trip/controller/TripController.java b/src/main/java/graduation/project/DoDutch_server/domain/trip/controller/TripController.java index 27d560e..3ffd690 100644 --- a/src/main/java/graduation/project/DoDutch_server/domain/trip/controller/TripController.java +++ b/src/main/java/graduation/project/DoDutch_server/domain/trip/controller/TripController.java @@ -15,8 +15,12 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import java.beans.PropertyEditorSupport; import java.util.List; @RestController @@ -26,16 +30,25 @@ public class TripController { private final TripService tripService; + @InitBinder + public void initBinder(WebDataBinder binder) { + binder.registerCustomEditor(MultipartFile.class, new PropertyEditorSupport() { + @Override + public void setAsText(String text) { + setValue(null); + } + }); + } + /** * 여행 생성 */ - @PostMapping + @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @Operation(summary = "여행 생성 API") @io.swagger.v3.oas.annotations.responses.ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공") }) - public ApiResponse tripRegister(@ModelAttribute TripRequestDTO tripRequestDTO) { //아마존 연결 후 RequestBody를 @ModelAttribute 수정 - + public ApiResponse tripRegister(@ModelAttribute TripRequestDTO tripRequestDTO) { Long tripId = tripService.createTrip(tripRequestDTO); return ApiResponse.onSuccess(tripId); } @@ -124,7 +137,7 @@ public ApiResponse tripRecommend( /** * 여행 수정 */ - @PatchMapping("/{tripId}") + @PatchMapping(value = "/{tripId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @Operation(summary = "여행 수정 API") @io.swagger.v3.oas.annotations.responses.ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공") diff --git a/src/main/java/graduation/project/DoDutch_server/global/config/swagger/SwaggerConfig.java b/src/main/java/graduation/project/DoDutch_server/global/config/swagger/SwaggerConfig.java index ffb84df..de2b1de 100644 --- a/src/main/java/graduation/project/DoDutch_server/global/config/swagger/SwaggerConfig.java +++ b/src/main/java/graduation/project/DoDutch_server/global/config/swagger/SwaggerConfig.java @@ -1,8 +1,11 @@ package graduation.project.DoDutch_server.global.config.swagger; +import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -11,11 +14,22 @@ public class SwaggerConfig { @Bean public OpenAPI openAPI() { + String securitySchemeName = "Bearer Authentication"; + return new OpenAPI() .info(new Info() .title("DoDutch API") .description("여행 기록 저장 및 정산 서비스 API 문서입니다.") .version("v1.0.0") + ) + .addSecurityItem(new SecurityRequirement().addList(securitySchemeName)) + .components(new Components() + .addSecuritySchemes(securitySchemeName, new SecurityScheme() + .name(securitySchemeName) + .type(SecurityScheme.Type.HTTP) + .scheme("bearer") + .bearerFormat("JWT") + ) ); } } From b84cc0301678cc7eb89cd66fca8b3230864d8501 Mon Sep 17 00:00:00 2001 From: yeobi Date: Thu, 30 Apr 2026 09:32:22 +0900 Subject: [PATCH 8/8] =?UTF-8?q?[Fix]=20createdAt,=20updatedAt=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EB=90=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../project/DoDutch_server/DoDutchServerApplication.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graduation/project/DoDutch_server/DoDutchServerApplication.java b/src/main/java/graduation/project/DoDutch_server/DoDutchServerApplication.java index 5c3f0d1..75fc8f4 100644 --- a/src/main/java/graduation/project/DoDutch_server/DoDutchServerApplication.java +++ b/src/main/java/graduation/project/DoDutch_server/DoDutchServerApplication.java @@ -2,7 +2,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +@EnableJpaAuditing @SpringBootApplication public class DoDutchServerApplication {