diff --git a/build.gradle b/build.gradle index ea942bd..7e97bb6 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ plugins { id 'java' - id 'org.springframework.boot' version '3.4.1' - id 'io.spring.dependency-management' version '1.1.7' + id 'org.springframework.boot' version '3.2.0' // 최신 Spring Boot 버전 + id 'io.spring.dependency-management' version '1.1.3' } group = 'com.neighbors' diff --git a/src/main/java/com/neighbors/tohero/application/baseResponse/BaseResponseMessage.java b/src/main/java/com/neighbors/tohero/application/baseResponse/BaseResponseMessage.java index 61a996b..0cd2054 100644 --- a/src/main/java/com/neighbors/tohero/application/baseResponse/BaseResponseMessage.java +++ b/src/main/java/com/neighbors/tohero/application/baseResponse/BaseResponseMessage.java @@ -13,6 +13,9 @@ public enum BaseResponseMessage { //user 이미_존재하는_유저입니다("이미 존재하는 유저입니다"), + 유저_이름_변경이_완료되었습니다("유저 이름 변경이 완료되었습니다"), + 존재하지_않는_유저입니다("존재하지 않는 유저입니다"), + 유저_이름의_길이는_1부터_5까지만_가능합니다("유저 이름의 길이는 1부터 5까지만 가능합니다"), //jwt error message JWT_토큰_오류입니다("JWT 토큰 오류입니다"), diff --git a/src/main/java/com/neighbors/tohero/application/user/dto/UpdateUserName.java b/src/main/java/com/neighbors/tohero/application/user/dto/UpdateUserName.java new file mode 100644 index 0000000..376dbaf --- /dev/null +++ b/src/main/java/com/neighbors/tohero/application/user/dto/UpdateUserName.java @@ -0,0 +1,9 @@ +package com.neighbors.tohero.application.user.dto; + +import org.hibernate.validator.constraints.Length; + +public record UpdateUserName( + @Length(min = 1, max = 5) + String nickname +) { +} diff --git a/src/main/java/com/neighbors/tohero/application/user/service/UserService.java b/src/main/java/com/neighbors/tohero/application/user/service/UserService.java new file mode 100644 index 0000000..982eaba --- /dev/null +++ b/src/main/java/com/neighbors/tohero/application/user/service/UserService.java @@ -0,0 +1,25 @@ +package com.neighbors.tohero.application.user.service; + +import com.neighbors.tohero.application.baseResponse.BaseResponse; +import com.neighbors.tohero.application.baseResponse.BaseResponseMessage; +import com.neighbors.tohero.application.baseResponse.BaseResponseStatus; +import com.neighbors.tohero.domain.user.service.UpdateUser; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class UserService { + + private final UpdateUser updateUser; + + public BaseResponse updateUserName(long userId, String nickname){ + + updateUser.updateUserName(userId, nickname); + + return new BaseResponse( + BaseResponseStatus.OK, + BaseResponseMessage.유저_이름_변경이_완료되었습니다.getMessage() + ); + } +} diff --git a/src/main/java/com/neighbors/tohero/common/ErrorResponseUtil.java b/src/main/java/com/neighbors/tohero/common/ErrorResponseUtil.java index 49f3a1a..f0f8636 100644 --- a/src/main/java/com/neighbors/tohero/common/ErrorResponseUtil.java +++ b/src/main/java/com/neighbors/tohero/common/ErrorResponseUtil.java @@ -13,7 +13,7 @@ public class ErrorResponseUtil { public static void setResponse(HttpServletResponse response, BaseResponseStatus responseStatus) throws IOException { - BaseResponse errorResponse = new BaseResponse(responseStatus, ""); + BaseResponse errorResponse = new BaseResponse(responseStatus, "JWT TOKEN 오류입니다."); response.setStatus(HttpServletResponse.SC_BAD_REQUEST); response.setContentType("application/json"); diff --git a/src/main/java/com/neighbors/tohero/common/config/SecurityConfig.java b/src/main/java/com/neighbors/tohero/common/config/SecurityConfig.java index 99e29f1..23263b4 100644 --- a/src/main/java/com/neighbors/tohero/common/config/SecurityConfig.java +++ b/src/main/java/com/neighbors/tohero/common/config/SecurityConfig.java @@ -3,10 +3,10 @@ import com.neighbors.tohero.common.security.CustomAccessDeniedHandler; import com.neighbors.tohero.common.security.CustomJwtAuthenticationEntryPoint; import com.neighbors.tohero.common.security.JwtAuthenticationFilter; +import jakarta.annotation.Priority; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpMethod; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; @@ -19,6 +19,7 @@ @Configuration @RequiredArgsConstructor @EnableWebSecurity +@Priority(0) public class SecurityConfig { private final JwtAuthenticationFilter jwtAuthenticationFilter; @@ -46,7 +47,7 @@ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { .httpBasic(AbstractHttpConfigurer::disable)//http 기본 인증 비활성화 .cors(Customizer.withDefaults()) .authorizeHttpRequests(auth -> auth - .requestMatchers(HttpMethod.POST, "/user").permitAll() + .requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll() .anyRequest().authenticated()) .sessionManagement(session -> { session.sessionCreationPolicy(SessionCreationPolicy.STATELESS); diff --git a/src/main/java/com/neighbors/tohero/domain/query/UserRepository.java b/src/main/java/com/neighbors/tohero/domain/query/UserRepository.java index 3c5d68e..17ab7da 100644 --- a/src/main/java/com/neighbors/tohero/domain/query/UserRepository.java +++ b/src/main/java/com/neighbors/tohero/domain/query/UserRepository.java @@ -4,4 +4,5 @@ public interface UserRepository { User createUser(User user); + void updateUserName(long userId, String nickname); } diff --git a/src/main/java/com/neighbors/tohero/domain/user/service/UpdateUser.java b/src/main/java/com/neighbors/tohero/domain/user/service/UpdateUser.java new file mode 100644 index 0000000..e1144aa --- /dev/null +++ b/src/main/java/com/neighbors/tohero/domain/user/service/UpdateUser.java @@ -0,0 +1,16 @@ +package com.neighbors.tohero.domain.user.service; + +import com.neighbors.tohero.common.annotaion.DomainService; +import com.neighbors.tohero.domain.query.UserRepository; +import lombok.RequiredArgsConstructor; + +@DomainService +@RequiredArgsConstructor +public class UpdateUser { + + private final UserRepository userRepository; + + public void updateUserName(long userId, String nickname) { + userRepository.updateUserName(userId, nickname); + } +} diff --git a/src/main/java/com/neighbors/tohero/infrastructure/entity/UserEntity.java b/src/main/java/com/neighbors/tohero/infrastructure/entity/UserEntity.java index 9253aab..8b23df4 100644 --- a/src/main/java/com/neighbors/tohero/infrastructure/entity/UserEntity.java +++ b/src/main/java/com/neighbors/tohero/infrastructure/entity/UserEntity.java @@ -32,6 +32,10 @@ public UserEntity(String nickName, String email, Role role){ this.role = role; } + public void changeNickname(final String nickName){ + this.nickName = nickName; + } + public static UserEntity of(String nickName, String email, Role role) { return new UserEntity(nickName, email, role); } diff --git a/src/main/java/com/neighbors/tohero/infrastructure/query/impl/UserRepositoryImpl.java b/src/main/java/com/neighbors/tohero/infrastructure/query/impl/UserRepositoryImpl.java index d3c9039..4863646 100644 --- a/src/main/java/com/neighbors/tohero/infrastructure/query/impl/UserRepositoryImpl.java +++ b/src/main/java/com/neighbors/tohero/infrastructure/query/impl/UserRepositoryImpl.java @@ -1,10 +1,14 @@ package com.neighbors.tohero.infrastructure.query.impl; +import com.neighbors.tohero.application.baseResponse.BaseResponseMessage; +import com.neighbors.tohero.application.baseResponse.BaseResponseStatus; +import com.neighbors.tohero.common.exception.user.UserException; import com.neighbors.tohero.domain.login.model.User; import com.neighbors.tohero.domain.query.UserRepository; import com.neighbors.tohero.infrastructure.entity.UserEntity; import com.neighbors.tohero.infrastructure.mapper.UserMapper; import com.neighbors.tohero.infrastructure.repository.UserEntityRepository; +import jakarta.persistence.EntityNotFoundException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; @@ -26,4 +30,16 @@ public User createUser(User user) { UserEntity createdUserEntity = userEntityRepository.findByEmail(user.getEmail()); return userMapper.toDomain(createdUserEntity); } + + @Override + public void updateUserName(long userId, String nickname) { + UserEntity matchedUserEntity = userEntityRepository.findByUserId(userId) + .orElseThrow(() -> new UserException( + BaseResponseStatus.BAD_REQUEST, + BaseResponseMessage.존재하지_않는_유저입니다.getMessage() + )); + + matchedUserEntity.changeNickname(nickname); + userEntityRepository.save(matchedUserEntity); + } } diff --git a/src/main/java/com/neighbors/tohero/infrastructure/repository/UserEntityRepository.java b/src/main/java/com/neighbors/tohero/infrastructure/repository/UserEntityRepository.java index b5fcf5c..2598d13 100644 --- a/src/main/java/com/neighbors/tohero/infrastructure/repository/UserEntityRepository.java +++ b/src/main/java/com/neighbors/tohero/infrastructure/repository/UserEntityRepository.java @@ -4,8 +4,11 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.Optional; + @Repository public interface UserEntityRepository extends JpaRepository { boolean existsByEmail(String email); UserEntity findByEmail(String email); + Optional findByUserId(long userId); } diff --git a/src/main/java/com/neighbors/tohero/presentation/NoticeController.java b/src/main/java/com/neighbors/tohero/presentation/controller/NoticeController.java similarity index 94% rename from src/main/java/com/neighbors/tohero/presentation/NoticeController.java rename to src/main/java/com/neighbors/tohero/presentation/controller/NoticeController.java index ab12acf..aa191a1 100644 --- a/src/main/java/com/neighbors/tohero/presentation/NoticeController.java +++ b/src/main/java/com/neighbors/tohero/presentation/controller/NoticeController.java @@ -1,4 +1,4 @@ -package com.neighbors.tohero.presentation; +package com.neighbors.tohero.presentation.controller; import com.neighbors.tohero.application.baseResponse.BaseResponse; import com.neighbors.tohero.application.notice.service.NoticeService; diff --git a/src/main/java/com/neighbors/tohero/presentation/OAuthController.java b/src/main/java/com/neighbors/tohero/presentation/controller/OAuthController.java similarity index 93% rename from src/main/java/com/neighbors/tohero/presentation/OAuthController.java rename to src/main/java/com/neighbors/tohero/presentation/controller/OAuthController.java index 02edec8..4682acc 100644 --- a/src/main/java/com/neighbors/tohero/presentation/OAuthController.java +++ b/src/main/java/com/neighbors/tohero/presentation/controller/OAuthController.java @@ -1,4 +1,4 @@ -package com.neighbors.tohero.presentation; +package com.neighbors.tohero.presentation.controller; import com.neighbors.tohero.application.login.service.OAuthService; import com.neighbors.tohero.application.baseResponse.BaseResponse; diff --git a/src/main/java/com/neighbors/tohero/presentation/controller/UserController.java b/src/main/java/com/neighbors/tohero/presentation/controller/UserController.java new file mode 100644 index 0000000..e1a3168 --- /dev/null +++ b/src/main/java/com/neighbors/tohero/presentation/controller/UserController.java @@ -0,0 +1,34 @@ +package com.neighbors.tohero.presentation.controller; + +import com.neighbors.tohero.application.baseResponse.BaseResponse; +import com.neighbors.tohero.application.user.dto.UpdateUserName; +import com.neighbors.tohero.application.user.service.UserService; +import com.neighbors.tohero.common.jwt.JwtUserDetails; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.RequiredArgsConstructor; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("") +public class UserController { + + private final UserService userService; + + @Operation(summary = "유저 API", description = "유저 이름 변경 API입니다.") + @PutMapping("/user/name") + public ResponseEntity updateUserName( + @Parameter(hidden=true) @AuthenticationPrincipal JwtUserDetails jwtUserDetail, + @ParameterObject @Validated UpdateUserName updateUserName + ){ + return ResponseEntity.ok() + .body(userService.updateUserName(jwtUserDetail.getUserId(), updateUserName.nickname())); + } +} diff --git a/src/main/java/com/neighbors/tohero/presentation/exception_handler/UserExceptionControllerAdvice.java b/src/main/java/com/neighbors/tohero/presentation/exception_handler/UserExceptionControllerAdvice.java new file mode 100644 index 0000000..34b577f --- /dev/null +++ b/src/main/java/com/neighbors/tohero/presentation/exception_handler/UserExceptionControllerAdvice.java @@ -0,0 +1,41 @@ +package com.neighbors.tohero.presentation.exception_handler; + +import com.neighbors.tohero.application.baseResponse.BaseResponse; +import com.neighbors.tohero.application.baseResponse.BaseResponseMessage; +import com.neighbors.tohero.application.baseResponse.BaseResponseStatus; +import jakarta.annotation.Priority; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.util.HashMap; +import java.util.Map; + +import static com.neighbors.tohero.application.baseResponse.BaseResponseMessage.유저_이름의_길이는_1부터_5까지만_가능합니다; + +@Priority(0) +@RestControllerAdvice +public class UserExceptionControllerAdvice { + + private final Map fieldErrorMapper; + + public UserExceptionControllerAdvice() { + fieldErrorMapper = new HashMap<>(); + fieldErrorMapper.put("nickname", 유저_이름의_길이는_1부터_5까지만_가능합니다); + } + + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity handle_UserValidationException(MethodArgumentNotValidException e) { + BaseResponse response = new BaseResponse( + BaseResponseStatus.BAD_REQUEST, + fieldErrorMapper.get(e.getBindingResult().getFieldError().getField()).getMessage() + ); + + return ResponseEntity.badRequest() + .body(response); + } +}