diff --git a/.DS_Store b/.DS_Store index d203a1a..cb328c0 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/src/main/java/umc/TripPiece/domain/Travel.java b/src/main/java/umc/TripPiece/domain/Travel.java index 5d52bcb..bef1db2 100644 --- a/src/main/java/umc/TripPiece/domain/Travel.java +++ b/src/main/java/umc/TripPiece/domain/Travel.java @@ -36,11 +36,12 @@ public class Travel extends BaseEntity { private City city; private String title; + private String description; private LocalDateTime startDate; private LocalDateTime endDate; - private String description; private boolean travelOpen; private Long likeCount; + @Setter private String thumbnail; @@ -60,9 +61,6 @@ public class Travel extends BaseEntity { @Enumerated(EnumType.STRING) private TravelStatus status; -// @OneToMany(mappedBy = "travel") -// private List likes = new ArrayList<>(); - - @OneToMany(mappedBy = "travel") + @OneToMany(mappedBy = "travel", cascade = CascadeType.ALL, orphanRemoval = true) private List tripPieces = new ArrayList<>(); } diff --git a/src/main/java/umc/TripPiece/domain/User.java b/src/main/java/umc/TripPiece/domain/User.java index caba347..5339679 100644 --- a/src/main/java/umc/TripPiece/domain/User.java +++ b/src/main/java/umc/TripPiece/domain/User.java @@ -20,17 +20,21 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor public class User extends BaseEntity { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name="user_id", unique = true, nullable = false) + @Column(name = "user_id", unique = true, nullable = false) private Long id; + @Setter @Column(length = 20) private String name; + @Setter @Column(nullable = false) private String email; + @Setter @Column private String password; @@ -46,22 +50,25 @@ public class User extends BaseEntity { @Setter @Column(nullable = false, length = 20) private String birth; - - @Column + @Setter + @Column private String profileImg; @Setter @Column(nullable = false, length = 30) private String country; - @Column (nullable = false) + @Setter + @Column(nullable = false) private Boolean gpsConsent; + @Setter @Column(nullable = false, length = 10) @Enumerated(EnumType.STRING) private UserMethod method; + @Setter @Column(nullable = false) @ColumnDefault("false") private Boolean isPublic; @@ -74,14 +81,10 @@ public class User extends BaseEntity { @Column(name = "refresh_token") private String refreshToken; - // 일반 가입자와 소셜 로그인 회원 구분을 위한 providerId + @Setter @Column(name = "provider_id", unique = true) private Long providerId; @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) private List tripPieces = new ArrayList<>(); - - public Uuid getUuid() { - return this.uuid; - } -} \ No newline at end of file +} diff --git a/src/main/java/umc/TripPiece/service/UserService.java b/src/main/java/umc/TripPiece/service/UserService.java index 4dddcfb..b3ceff3 100644 --- a/src/main/java/umc/TripPiece/service/UserService.java +++ b/src/main/java/umc/TripPiece/service/UserService.java @@ -7,6 +7,7 @@ import umc.TripPiece.web.dto.response.UserResponseDto; public interface UserService { + /* 회원가입 */ User signUp(UserRequestDto.SignUpDto request, MultipartFile profileImg); @@ -28,12 +29,12 @@ public interface UserService { /* 회원탈퇴 */ void withdrawal(Long userId); + /* 유저 저장 */ User save(User user); - /* 수정하기 */ + /* 유저 수정 */ User update(UserRequestDto.@Valid UpdateDto request, String token, MultipartFile profileImg); /* 프로필 조회 */ UserResponseDto.ProfileDto getProfile(String token); - } diff --git a/src/main/java/umc/TripPiece/web/controller/UserController.java b/src/main/java/umc/TripPiece/web/controller/UserController.java index 8637db2..e02e3c5 100644 --- a/src/main/java/umc/TripPiece/web/controller/UserController.java +++ b/src/main/java/umc/TripPiece/web/controller/UserController.java @@ -5,20 +5,19 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.validation.FieldError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; +import umc.TripPiece.apiPayload.ApiResponse; import umc.TripPiece.apiPayload.code.status.ErrorStatus; import umc.TripPiece.apiPayload.exception.GeneralException; import umc.TripPiece.apiPayload.exception.handler.UserHandler; import umc.TripPiece.converter.UserConverter; import umc.TripPiece.domain.User; import umc.TripPiece.domain.jwt.JWTUtil; -import umc.TripPiece.apiPayload.ApiResponse; import umc.TripPiece.service.UserService; import umc.TripPiece.web.dto.request.UserRequestDto; import umc.TripPiece.web.dto.response.UserResponseDto; @@ -36,9 +35,10 @@ public class UserController { private final JWTUtil jwtUtil; @PostMapping(value = "/signup", consumes = "multipart/form-data") - @Operation(summary = "회원가입 API", - description = "회원가입") - public ApiResponse signUp(@RequestPart("info") @Valid UserRequestDto.SignUpDto request, @RequestPart("profileImg") MultipartFile profileImg) { + @Operation(summary = "회원가입 API", description = "회원가입") + public ApiResponse signUp( + @RequestPart("info") @Valid UserRequestDto.SignUpDto request, + @RequestPart("profileImg") MultipartFile profileImg) { try { User user = userService.signUp(request, profileImg); return ApiResponse.onSuccess(UserConverter.toSignUpResultDto(user)); @@ -48,16 +48,12 @@ public ApiResponse signUp(@RequestPart("info") } @PostMapping("/login") - @Operation(summary = "이메일 로그인 API", - description = "이메일 로그인 (일반)") + @Operation(summary = "이메일 로그인 API", description = "이메일 로그인 (일반)") public ApiResponse login(@RequestBody @Valid UserRequestDto.LoginDto request) { User user = userService.login(request); - if (user != null) { - // 로그인 성공 시 토큰 생성 String accessToken = jwtUtil.createAccessToken(request.getEmail()); String refreshToken = user.getRefreshToken(); - return ApiResponse.onSuccess(UserConverter.toLoginResultDto(user, accessToken, refreshToken)); } else { return ApiResponse.onFailure("400", "로그인에 실패했습니다.", null); @@ -68,28 +64,27 @@ public ApiResponse login(@RequestBody @Valid Use @Operation(summary = "토큰 재발급 API", description = "refresh token을 통한 access token, refresh token 재발급") public ApiResponse refresh( @RequestBody @Valid UserRequestDto.ReissueDto request) { - User user = userService.reissue(request); String newAccessToken = jwtUtil.createAccessToken(user.getEmail()); String newRefreshToken = jwtUtil.createRefreshToken(user.getEmail()); user.setRefreshToken(newRefreshToken); - userService.save(user); return ApiResponse.onSuccess(UserConverter.toReissueResultDto(newAccessToken, newRefreshToken)); } @PostMapping("/logout") @Operation(summary = "로그아웃 API", description = "로그아웃") - public ApiResponse logout(HttpServletRequest request) { - String header = request.getHeader("Authorization"); - if (header == null || !header.startsWith("Bearer ")) { - return ApiResponse.onFailure("400", "토큰이 유효하지 않습니다.", null); + public ApiResponse logout(@RequestHeader("Authorization") String token) { + if (!token.startsWith("Bearer ")) { + return ApiResponse.onFailure("400", "유효하지 않은 토큰 형식입니다.", null); } - String token = header.substring(7); + String tokenWithoutBearer = token.substring(7); try { - Long userId = jwtUtil.getUserIdFromToken(token); - if (userId==null) return ApiResponse.onFailure("400", "존재하지 않거나 만료된 토큰입니다.", null); + Long userId = jwtUtil.getUserIdFromToken(tokenWithoutBearer); + if (userId == null) { + return ApiResponse.onFailure("400", "존재하지 않거나 만료된 토큰입니다.", null); + } userService.logout(userId); return ApiResponse.onSuccess("로그아웃에 성공했습니다."); } catch (Exception e) { @@ -99,17 +94,17 @@ public ApiResponse logout(HttpServletRequest request) { @DeleteMapping("/withdrawal") @Operation(summary = "회원탈퇴 API", description = "회원탈퇴") - public ApiResponse withdrawal(HttpServletRequest request) { - String header = request.getHeader("Authorization"); - if (header == null || !header.startsWith("Bearer ")) { - return ApiResponse.onFailure("400", "토큰이 유효하지 않습니다.", null); + public ApiResponse withdrawal(@RequestHeader("Authorization") String token) { + if (!token.startsWith("Bearer ")) { + return ApiResponse.onFailure("400", "유효하지 않은 토큰 형식입니다.", null); } - String token = header.substring(7); - + String tokenWithoutBearer = token.substring(7); try { - Long userId = jwtUtil.getUserIdFromToken(token); - if (userId==null) return ApiResponse.onFailure("400", "존재하지 않거나 만료된 토큰입니다.", null); + Long userId = jwtUtil.getUserIdFromToken(tokenWithoutBearer); + if (userId == null) { + return ApiResponse.onFailure("400", "존재하지 않거나 만료된 토큰입니다.", null); + } userService.withdrawal(userId); return ApiResponse.onSuccess("회원탈퇴에 성공했습니다."); } catch (Exception e) { @@ -118,9 +113,11 @@ public ApiResponse withdrawal(HttpServletRequest request) { } @PatchMapping(value = "/update", consumes = "multipart/form-data") - @Operation(summary = "프로필 수정하기 API", - description = "프로필 수정하기") - public ApiResponse update(@RequestPart("info") @Valid UserRequestDto.UpdateDto request, @RequestHeader("Authorization") String token, @RequestPart(value = "profileImg", required = false) MultipartFile profileImg) { + @Operation(summary = "프로필 수정하기 API", description = "프로필 수정하기") + public ApiResponse update( + @RequestPart("info") @Valid UserRequestDto.UpdateDto request, + @RequestHeader("Authorization") String token, + @RequestPart(value = "profileImg", required = false) MultipartFile profileImg) { try { String tokenWithoutBearer = token.substring(7); User user = userService.update(request, tokenWithoutBearer, profileImg); @@ -133,8 +130,7 @@ public ApiResponse update(@RequestPart("info") } @GetMapping("/myprofile") - @Operation(summary = "프로필 조회 API", - description = "마이페이지 프로필 조회") + @Operation(summary = "프로필 조회 API", description = "마이페이지 프로필 조회") public ApiResponse getProfile(@RequestHeader("Authorization") String token) { String tokenWithoutBearer = token.substring(7); return ApiResponse.onSuccess(userService.getProfile(tokenWithoutBearer)); @@ -149,9 +145,9 @@ public ResponseEntity>> handleValidationExceptio errors.put(fieldName, errorMessage); }); - String combinedMessage = String.join(" + ", errors.values()); + String combinedMessage = String.join(", ", errors.values()); - return new ResponseEntity<>(ApiResponse.onFailure("400", combinedMessage, null), HttpStatus.BAD_REQUEST); + return new ResponseEntity<>(ApiResponse.onFailure("400", combinedMessage, errors), HttpStatus.BAD_REQUEST); } @ExceptionHandler(IllegalArgumentException.class) diff --git a/src/main/java/umc/TripPiece/web/dto/response/UserResponseDto.java b/src/main/java/umc/TripPiece/web/dto/response/UserResponseDto.java index 7664838..6bb793c 100644 --- a/src/main/java/umc/TripPiece/web/dto/response/UserResponseDto.java +++ b/src/main/java/umc/TripPiece/web/dto/response/UserResponseDto.java @@ -24,7 +24,6 @@ public static class SignUpResultDto { String profileImg; String country; LocalDateTime createdAt; - } /* 로그인 */ @@ -98,6 +97,7 @@ public static class UpdateResultDto { @Getter @AllArgsConstructor public static class ProfileDto { + Long userId; // 유저 식별자 추가 String nickname; String profileImg; Integer travelNum; @@ -106,5 +106,4 @@ public static class ProfileDto { String country; String birth; } - }