Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
75e4cdd
refactor(#33): 스케줄 업데이트 Input 으로 scheduleId 받아오는 것 PathVariable 방식으로 변경
5nam Apr 14, 2025
a16b16b
refactor(#33): 정적 팩토리 메서드 네이밍 적용(createSchedule -> from)
5nam Apr 14, 2025
9e9197f
refactor(#33): Club 내부 함수 네이밍에서 Club 빼기
5nam Apr 14, 2025
a9ddd5c
refactor(#33): ScheduleService 중복 함수 제거
5nam Apr 14, 2025
359accc
refactor(#33): URL 모두 복수형으로 변경. RESTful 명명 규칙
5nam Apr 14, 2025
0e6c904
refactor(#33): ScheduleCategory Enum 추가
5nam Apr 14, 2025
095b3ad
refactor(#33): ScheduleInput Valid 추가
5nam Apr 14, 2025
3ef21c7
refactor(#33): schedule 에 CQS 패턴 적용
5nam Apr 14, 2025
7b8f650
refactor(#33): schedule, vote, comment 분리. schedule 에서 vote 처리하는 것. A…
5nam Apr 14, 2025
52ce3b5
refactor(#33): Match.createScheduleFromMatch 메서드에 ScheduleCategory 적용
5nam Apr 17, 2025
5ecfa37
refactor(#33): 스케줄 댓글 기능 분리
5nam Apr 17, 2025
1a8bcda
refactor(#33): 스케줄 도메인 Controller 들 컨벤션에 맞게 이름 변경.
5nam Apr 17, 2025
f50dfb7
feat(#33): 댓글 저장 기능, 테스트 코드 구현 완료
5nam Apr 18, 2025
de431b5
Merge branch 'develop' into refactor/33-schedule
5nam Apr 18, 2025
effe391
refactor(#33): 일정 삭제 기능 리팩터링 완료
5nam Apr 18, 2025
416e98f
refacotr(#33): 한달 일정 조회 기능 리팩터링 완료
5nam Apr 18, 2025
ad5b836
refactor(#33): 하루 일정 조회 기능 리팩터링 완료
5nam Apr 18, 2025
3f03800
merge(#33): develop 브랜치와 머지
5nam Apr 24, 2025
20f9398
refactor(#33): 일정 세부 정보 조회 기능 리팩터링
5nam Apr 24, 2025
fb98f8e
refactor(#33): schedule, club 부분 알림 리팩터링 반영하여 푸쉬 알림 로직 추가 완료
5nam Apr 24, 2025
5d3e6f5
refactor(#33): 투표 void 로 처리된 컨트롤러 모든 기본 응답 나가도록 변경
5nam Apr 25, 2025
5dedce2
refactor(#33): 투표 기능들 회원, 운영진 권한 확인하는 로직 추가
5nam Apr 25, 2025
7bc893d
refactor(#33): 스케줄에 유저가 투표할 때 알림 가는 로직 삭제
5nam Apr 30, 2025
e81d964
refactor(#33): 일정 세부 조회에 댓글 정보 포함하도록 추가
5nam May 7, 2025
60fe16d
refactor(#33): 일정 타입에 따라 응답 값 다르게 반환하도록 변경
5nam May 9, 2025
0293d89
refactor(#33): JSON 필드 타입 오류, 형식으로 인한 parse 오류 핸들러에서 처리
5nam May 15, 2025
d94c975
fix(#33): join 으로 하면, 댓글이 없는 일정은 조회가 안되는 문제 발생. left join 으로 변경하여 댓글이…
5nam May 15, 2025
a5dfd54
refactor(#33): 일정 투표 API 에서 일정 ID 받아오는 방식 PathVariable 로 변경
5nam May 15, 2025
38f1291
chore(#33): 주석 제거
5nam May 15, 2025
3ffab85
refactor(#33): Enumerated 어노테이션으로 상대 팀 연령 문자열로 저장되도록 변경.
5nam May 15, 2025
ce5a757
refactor(#33): 일정 추가 Input DTO 검증 방식 변경
5nam May 15, 2025
34b5ba7
refactor(#33): 일정 업데이트 시, 상대 팀 정보 반영 로직 이전 팀 정보가 있을때와 없을 때로 분리
5nam May 15, 2025
d2bd242
docs(#33): 스케줄 정식 매치 반환 부분 주석 추가
5nam May 26, 2025
e821b81
merge(#33): develop 브랜치와 충돌 해결
5nam May 28, 2025
4b60690
fix(#33): merge 로 인한 잘못된 함수명 사용과 잘못된 로직으로 인한 오류 해결
5nam May 28, 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
14 changes: 13 additions & 1 deletion deploy/local.init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,16 @@ values (default, '2024-12-10', null, 1, 'title', 'content');
INSERT INTO notice (id, created_date, updated_date, club_id, title, content)
values (default, '2024-12-11', null, 1, 'title2', 'content2');
INSERT INTO notice (id, created_date, updated_date, club_id, title, content)
values (default, '2024-12-12', null, 1, 'title3', 'content4');
values (default, '2024-12-12', null, 1, 'title3', 'content4');

-- 스케줄 생성(3번 동아리)
insert into `schedule` (id, club_id, created_date, updated_date, title, location, start_time, end_time, min_people, category, note, attend, non_attend, is_close, view_count)
values (default, 3, '2024-03-06 14:30:00', null, '운동 매치 스케줄', '서울시 마포구', '2024-03-11 14:30:00', '2024-03-11 17:30:00', 10, 'REGULAR_TRAINING', 'note', 10, 12, 0, 0);
insert into `schedule` (id, club_id, created_date, updated_date, title, location, start_time, end_time, min_people, category, note, attend, non_attend, is_close, view_count)
values (default, 3, '2024-03-06 14:30:00', null, '운동 매치 스케줄2', '서울시 마포구', '2024-03-11 14:30:00', '2024-03-11 17:30:00', 10, 'REGULAR_TRAINING', 'note', 10, 12, 0, 0);
insert into `schedule` (id, club_id, created_date, updated_date, title, location, start_time, end_time, min_people, category, note, attend, non_attend, is_close, view_count)
values (default, 3, '2024-03-05 14:30:00', null, '운동 매치 스케줄3', '서울시 마포구', '2024-03-12 14:30:00', '2024-03-12 17:30:00', 10, 'REGULAR_TRAINING', 'note', 10, 12, 0, 1);
insert into `schedule` (id, club_id, created_date, updated_date, title, location, start_time, end_time, min_people, category, note, attend, non_attend, is_close, view_count, opponent_team_name, opponent_team_age_range)
values (default, 3, '2024-04-01 14:30:00', null, '운동 매치 스케줄4', '서울시 마포구', '2024-04-05 14:30:00', '2024-04-05 17:30:00', 10, 'FRIENDLY_MATCH', 'note', 10, 12, 0, 10, 'opponent_team_name', 'TWENTIES');
insert into `schedule` (id, club_id, created_date, updated_date, title, location, start_time, end_time, min_people, category, note, attend, non_attend, is_close, view_count, opponent_team_name, opponent_team_age_range)
values (default, 3, '2024-02-22 14:30:00', null, '운동 매치 스케줄5', '서울시 마포구', '2024-02-27 14:30:00', '2024-02-27 17:30:00', 10, 'FRIENDLY_MATCH', 'note', 10, 12, 0, 5, 'opponent_team_name', 'THIRTIES');
21 changes: 9 additions & 12 deletions src/main/java/com/example/moim/club/entity/Club.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,17 @@ public class Club extends BaseEntity {
/**
* TODO : university 는 없을 수도 있으므로, null 일 경우를 처리해주기
*/
public static Club createClub(ClubInput clubInput, FileInfo fileInfo) {
public static Club from(ClubInput clubInput, FileInfo fileInfo) {
Club club = new Club();
club.title = clubInput.getTitle();
club.explanation = clubInput.getExplanation();
club.introduction = clubInput.getIntroduction();
club.clubCategory = ClubCategory.fromKoreanName(clubInput.getClubCategory()).get();
club.clubCategory = ClubCategory.fromKoreanName(clubInput.getClubCategory()).orElseThrow(() -> new ClubControllerAdvice(ResponseCode.INVALID_CLUB_CATEGORY));
club.university = clubInput.getUniversity();
club.gender = Gender.fromKoreanName(clubInput.getGender()).get();
club.activityArea = ActivityArea.fromKoreanName(clubInput.getActivityArea()).get();
club.sportsType = SportsType.fromKoreanName(clubInput.getSportsType()).get();
club.ageRange = AgeRange.fromKoreanName(clubInput.getAgeRange()).get();
if (!clubInput.getClubPassword().equals(clubInput.getClubCheckPassword())) {
throw new ClubControllerAdvice(ResponseCode.CLUB_CHECK_PASSWORD_INCORRECT);
}
club.gender = Gender.fromKoreanName(clubInput.getGender()).orElseThrow(() -> new ClubControllerAdvice(ResponseCode.INVALID_GENDER));
club.activityArea = ActivityArea.fromKoreanName(clubInput.getActivityArea()).orElseThrow(() -> new ClubControllerAdvice(ResponseCode.INVALID_ACTIVITY_AREA));
club.sportsType = SportsType.fromKoreanName(clubInput.getSportsType()).orElseThrow(() -> new ClubControllerAdvice(ResponseCode.INVALID_SPORTS_TYPE));
club.ageRange = AgeRange.fromKoreanName(clubInput.getAgeRange()).orElseThrow(() -> new ClubControllerAdvice(ResponseCode.INVALID_AGE_RANGE));
club.clubPassword = clubInput.getClubPassword();
if (fileInfo != null) {
club.imgUrl = fileInfo.getFileUrl();
Expand All @@ -91,7 +88,7 @@ public static Club createClub(ClubInput clubInput, FileInfo fileInfo) {
return club;
}

public Club updateClubSearch(ClubSearch clubSearch) {
public Club updateSearch(ClubSearch clubSearch) {
this.clubSearch = clubSearch;
return this;
}
Expand All @@ -104,7 +101,7 @@ public void plusMemberCount() {
memberCount++;
}

public void updateClub(ClubUpdateInput clubUpdateInput, FileInfo fileInfo) {
public void update(ClubUpdateInput clubUpdateInput, FileInfo fileInfo) {
if (StringUtils.hasText(clubUpdateInput.getTitle())) {
this.title = clubUpdateInput.getTitle();
}
Expand Down Expand Up @@ -139,7 +136,7 @@ public void updateClub(ClubUpdateInput clubUpdateInput, FileInfo fileInfo) {
}
}

public void updateClubPassword(String newPassword) {
public void updatePassword(String newPassword) {
this.clubPassword = newPassword;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public class ClubCommandServiceImpl implements ClubCommandService {

@Transactional
public ClubSaveOutput saveClub(User user, ClubInput clubInput) throws IOException {
Club club = clubRepository.save(Club.createClub(clubInput, fileService.upload(clubInput.getProfileImg(), "/club-profile")));
Club club = clubRepository.save(Club.from(clubInput, fileService.upload(clubInput.getProfileImg(), "/club-profile")));
// 검색을 위한 저장
saveClubSearch(club);

Expand All @@ -67,8 +67,8 @@ public ClubUpdateOutput updateClub(User user, ClubUpdateInput clubUpdateInput, L
if (clubUpdateInput.getProfileImg() != null) {
fileService.remove(club.getStoredImgName());
}
club.update(clubUpdateInput, fileService.upload(clubUpdateInput.getProfileImg(), "/club-profile"));

club.updateClub(clubUpdateInput, fileService.upload(clubUpdateInput.getProfileImg(), "/club-profile"));
// 검색 정보 동기화를 위한 처리
club.getClubSearch().updateFrom(club);
List<UserClubOutput> userList = userClubRepository.findAllByClub(club).stream().map(UserClubOutput::new).toList();
Expand All @@ -87,9 +87,7 @@ public UserClubOutput saveClubUser(User user, ClubUserSaveInput clubUserSaveInpu
}
club.plusMemberCount();
UserClub userClub = userClubRepository.save(UserClub.createUserClub(user, club));
/**
* TODO: 알림 보내는 것 새로운 방식에 맞춰서 다시 구현해야 함
*/

eventPublisher.publishEvent(new ClubJoinEvent(user, club));
return new UserClubOutput(userClub);
}
Expand Down Expand Up @@ -146,7 +144,7 @@ public String clubPasswordUpdate(User user, ClubPswdUpdateInput clubPswdUpdateIn
throw new ClubControllerAdvice(ResponseCode.CLUB_CHECK_PASSWORD_INCORRECT);
}

club.updateClubPassword(clubPswdUpdateInput.getNewPassword());
club.updatePassword(clubPswdUpdateInput.getNewPassword());

return club.getTitle() + "의 비밀번호를 변경하였습니다.";
}
Expand Down Expand Up @@ -178,7 +176,7 @@ private void saveClubSearch(Club club) {
.allFieldsConcat(TextUtils.concatClean("|", club.getTitle(), club.getIntroduction(), club.getExplanation()))
.build();

club.updateClubSearch(clubSearchRepository.save(clubSearch));
club.updateSearch(clubSearchRepository.save(clubSearch));
}

// @Transactional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,25 @@
import com.example.moim.global.enums.ClubRole;
import com.example.moim.global.exception.ResponseCode;
import com.example.moim.user.entity.User;
import com.example.moim.notification.dto.NoticeSaveEvent;
import com.example.moim.user.entity.User;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
@RequiredArgsConstructor
public class NoticeCommandServiceImpl implements NoticeCommandService {
private final NoticeRepository noticeRepository;
private final ClubRepository clubRepository;
private final UserClubRepository userClubRepository;
private final ApplicationEventPublisher eventPublisher;

@Transactional
public NoticeOutput saveNotice(User user, NoticeInput noticeInput, Long clubId) {
log.debug("saveNotice 진입");
Club club = clubRepository.findById(clubId).orElseThrow(() -> new ClubControllerAdvice(ResponseCode.CLUB_NOT_FOUND));
Expand All @@ -36,9 +43,7 @@ public NoticeOutput saveNotice(User user, NoticeInput noticeInput, Long clubId)

Notice notice = noticeRepository.save(Notice.createNotice(club, noticeInput.getTitle(), noticeInput.getContent()));

/**
* TODO: 알림 보내는 부분 구현해야함
*/
eventPublisher.publishEvent(new NoticeSaveEvent(user, club));

return new NoticeOutput(notice);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
* FIXME: 이건 API 수동 테스트할때만 필요한 것
*/
httpSecurity.csrf(csrf -> csrf
.ignoringRequestMatchers("/club/**")
.ignoringRequestMatchers("/clubs/**", "/schedules/**", "/notices/**")
);
httpSecurity.csrf(csrf -> csrf.ignoringRequestMatchers("/notice/**"));

Expand All @@ -78,7 +78,7 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
//http basic 인증 방식 disable
httpSecurity.httpBasic(AbstractHttpConfigurer::disable);
/**
* FIXME: 이건 API 수동 테스트할때만 필요한 것
* FIXME: 이건 API 수동 테스트할때만 필요한 것 : 주석 제거하기
*/
//경로별 인가 작업
// httpSecurity.authorizeHttpRequests((auth) -> auth
Expand All @@ -92,7 +92,7 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
httpSecurity.authorizeHttpRequests((auth) -> auth.anyRequest().permitAll());

/**
* FIXME: 이건 API 수동 테스트할때만 필요한 것
* FIXME: 이건 API 수동 테스트할때만 필요한 것 : 주석 제거해야 함
*/
//JWTFilter 등록
// httpSecurity
Expand Down
82 changes: 41 additions & 41 deletions src/main/java/com/example/moim/external/fcm/FcmConfig.java
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
package com.example.moim.external.fcm;

import com.google.auth.oauth2.GoogleCredentials;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import com.google.firebase.messaging.FirebaseMessaging;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;

@Configuration
public class FcmConfig {

@Bean
FirebaseMessaging firebaseMessaging() throws IOException {
ClassPathResource resource = new ClassPathResource("secret/sample-firebase-test-f3c27-firebase-adminsdk-fbsvc-c15b4b66c6.json");
InputStream refreshToken = resource.getInputStream();

FirebaseApp firebaseApp = null;
List<FirebaseApp> firebaseAppList = FirebaseApp.getApps();

if (firebaseAppList != null && !firebaseAppList.isEmpty()) {
for (FirebaseApp app : firebaseAppList) {
if (app.getName().equals(FirebaseApp.DEFAULT_APP_NAME)) {
firebaseApp = app;
}
}
} else {
FirebaseOptions options = FirebaseOptions.builder()
.setCredentials(GoogleCredentials.fromStream(refreshToken))
.build();

firebaseApp = FirebaseApp.initializeApp(options);
}

return FirebaseMessaging.getInstance(firebaseApp);
}
}
//package com.example.moim.external.fcm;
//
//import com.google.auth.oauth2.GoogleCredentials;
//import com.google.firebase.FirebaseApp;
//import com.google.firebase.FirebaseOptions;
//import com.google.firebase.messaging.FirebaseMessaging;
//import java.io.IOException;
//import java.io.InputStream;
//import java.util.List;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//import org.springframework.core.io.ClassPathResource;
//
//@Configuration
//public class FcmConfig {
//
// @Bean
// FirebaseMessaging firebaseMessaging() throws IOException {
// ClassPathResource resource = new ClassPathResource("secret/sample-firebase-test-f3c27-firebase-adminsdk-fbsvc-c15b4b66c6.json");
// InputStream refreshToken = resource.getInputStream();
//
// FirebaseApp firebaseApp = null;
// List<FirebaseApp> firebaseAppList = FirebaseApp.getApps();
//
// if (firebaseAppList != null && !firebaseAppList.isEmpty()) {
// for (FirebaseApp app : firebaseAppList) {
// if (app.getName().equals(FirebaseApp.DEFAULT_APP_NAME)) {
// firebaseApp = app;
// }
// }
// } else {
// FirebaseOptions options = FirebaseOptions.builder()
// .setCredentials(GoogleCredentials.fromStream(refreshToken))
// .build();
//
// firebaseApp = FirebaseApp.initializeApp(options);
// }
//
// return FirebaseMessaging.getInstance(firebaseApp);
// }
//}
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@
public enum ResponseCode {

// 정상 code
OK(HttpStatus.OK,"2000", "Ok"),
OK(HttpStatus.OK,"2000", "OK"),

// Common Error
_INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "COMMON000", "서버 에러, 관리자에게 문의 바랍니다."),
_BAD_REQUEST(HttpStatus.BAD_REQUEST,"COMMON001","잘못된 요청입니다."),
_UNAUTHORIZED(HttpStatus.UNAUTHORIZED,"COMMON002","권한이 잘못되었습니다"),
_METHOD_NOT_ALLOWED(HttpStatus.METHOD_NOT_ALLOWED, "COMMON003", "지원하지 않는 Http Method 입니다."),
_FORBIDDEN(HttpStatus.FORBIDDEN, "COMMON004", "금지된 요청입니다."),
_INVALID_FORMAT(HttpStatus.BAD_REQUEST, "COMMON005", "날짜 형식이 잘못되었습니다."),
_MISMATCHED_INPUT(HttpStatus.BAD_REQUEST, "COMMON006", "필드 타입이 일치하지 않습니다."),

// Member Error
MEMBER_NOT_FOUND(HttpStatus.BAD_REQUEST, "MEMBER4001", "사용자가 없습니다."),
Expand All @@ -37,6 +39,7 @@ public enum ResponseCode {
MATCH_APPLICATION_NOT_FOUND(HttpStatus.BAD_REQUEST, "MATCH4006", "올바른 매치가 아닙니다."),
MATCH_TIME_OUT(HttpStatus.BAD_REQUEST, "MATCH4007", "매치가 종료된 후 48시간이 지났습니다."),
MATCH_NOT_CONFIRMED(HttpStatus.BAD_REQUEST, "MATCH4008", "확정된 매치가 아닙니다."),
MATCH_SCHEDULE_NOT_FOUND(HttpStatus.BAD_REQUEST, "MATCH4009", "매치 일정이 확정되지 않았거나, 존재하지 않습니다."),

// MatchUser Error
MATCH_USER_NOT_FOUND(HttpStatus.BAD_REQUEST, "MATCH4005", "가입된 모임이 없습니다."),
Expand All @@ -60,6 +63,9 @@ public enum ResponseCode {
CLUB_CHECK_PASSWORD_INCORRECT(HttpStatus.UNAUTHORIZED, "CLUB4005", "모임 확인 비밀번호가 틀렸습니다."),
CLUB_USER_ALREADY_JOINED(HttpStatus.CONFLICT, "CLUB4006", "해당 사용자는 이미 모임에 가입되어 있습니다."),

// Schedule Error
SCHEDULE_NOT_FOUND(HttpStatus.BAD_REQUEST, "SCHEDULE4001", "존재하지 않는 일정입니다."),

// File Error
FILE_MAX_SIZE_OVER(HttpStatus.PAYLOAD_TOO_LARGE, "FILE4001", "100MB 이하 파일만 업로드 할 수 있습니다."),
FILE_CONTENT_TYPE_NOT_IMAGE(HttpStatus.UNSUPPORTED_MEDIA_TYPE, "FILE4002", "이미지 파일만 업로드할 수 있습니다."),
Expand All @@ -73,7 +79,9 @@ public enum ResponseCode {
INVALID_ACTIVITY_AREA(HttpStatus.BAD_REQUEST, "ENUM4005", "유효하지 않은 지역입니다."),
INVALID_MAIN_FOOT(HttpStatus.BAD_REQUEST, "ENUM4006", "유효하지 않은 주발입니다."),
INVALID_SPORTS_TYPE(HttpStatus.BAD_REQUEST, "ENUM4007", "유효하지 않은 종목입니다."),
INVALID_CLUB_ROLE(HttpStatus.BAD_REQUEST, "ENUM4008", "유효하지 않은 모임 역할입니다.");
INVALID_CLUB_ROLE(HttpStatus.BAD_REQUEST, "ENUM4008", "유효하지 않은 모임 역할입니다."),
INVALID_SCHEDULE_CATEGORY(HttpStatus.BAD_REQUEST, "ENUM4009", "유효하지 않은 일정 종류입니다."),
INVALID_ATTENDANCE_TYPE(HttpStatus.BAD_REQUEST, "ENUM4010", "유효하지 않은 투표입니다.(참석/불참)");

private final HttpStatus httpStatus;
private final String code;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
import com.example.moim.global.exception.BaseResponse;
import com.example.moim.global.exception.GeneralException;
import com.example.moim.global.exception.ResponseCode;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
Expand All @@ -16,6 +19,7 @@
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;

import java.time.format.DateTimeParseException;
import java.util.List;
import java.util.stream.Collectors;

Expand All @@ -33,6 +37,18 @@ public ResponseEntity<Object> general(GeneralException e, WebRequest request) {
return handleExceptionInternal(e, e.getErrorCode(), request);
}

@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity<Object> formatException(HttpMessageNotReadableException e, WebRequest request) {
Throwable root = getRootCause(e);
if (root instanceof DateTimeParseException) {
return handleExceptionInternal(e, ResponseCode._INVALID_FORMAT, request);
} else if (root instanceof MismatchedInputException) {
return handleExceptionInternal(e, ResponseCode._MISMATCHED_INPUT, request);

}
return handleExceptionInternal(e, ResponseCode._BAD_REQUEST, request);
}

@ExceptionHandler(Exception.class)
public ResponseEntity<Object> exception(Exception e, WebRequest request) {
e.printStackTrace(); // 클라이언트에게 불필요한 정보를 노출할 수 있으므로 삭제
Expand Down Expand Up @@ -87,4 +103,12 @@ private ResponseEntity<Object> handleExceptionInternalFalse(Exception e, Respons
.body(body);
}

private Throwable getRootCause(Throwable ex) {
Throwable result = ex;
while (result.getCause() != null) {
result = result.getCause();
}
return result;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class FileInfo {
private String fileUrl;

@Builder
public FileInfo(String originalFileName, String storedFileName, String fileUrl, String contentType, long size) {
public FileInfo(String originalFileName, String storedFileName, String fileUrl) {
this.originalFileName = originalFileName;
this.storedFileName = storedFileName;
this.fileUrl = fileUrl;
Expand Down
Loading