diff --git a/simple_sns/src/main/java/com/example/sns/controller/UserController.java b/simple_sns/src/main/java/com/example/sns/controller/UserController.java index 72b32fc8..db976256 100644 --- a/simple_sns/src/main/java/com/example/sns/controller/UserController.java +++ b/simple_sns/src/main/java/com/example/sns/controller/UserController.java @@ -1,8 +1,13 @@ package com.example.sns.controller; +import com.example.sns.controller.request.UserJoinRequest; +import com.example.sns.controller.response.Response; +import com.example.sns.controller.response.UserJoinResponse; +import com.example.sns.model.User; import com.example.sns.service.UserService; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -14,7 +19,9 @@ public class UserController { private final UserService userService; @PostMapping("/join") - public void join() { - userService.join(username, password); + public Response join(@RequestBody UserJoinRequest request) { + User user = userService.join(request.getUsername(), request.getPassword()); + + return Response.success(UserJoinResponse.fromUser(user)); } } diff --git a/simple_sns/src/main/java/com/example/sns/controller/response/Response.java b/simple_sns/src/main/java/com/example/sns/controller/response/Response.java new file mode 100644 index 00000000..2255496a --- /dev/null +++ b/simple_sns/src/main/java/com/example/sns/controller/response/Response.java @@ -0,0 +1,20 @@ +package com.example.sns.controller.response; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class Response { + + private String resultCode; + private T result; + + public static Response success(T result) { + return new Response<>("SUCCESS", result); + } + + public static Response error(String errorCode) { + return new Response<>(errorCode, null); + } +} diff --git a/simple_sns/src/main/java/com/example/sns/controller/response/UserJoinResponse.java b/simple_sns/src/main/java/com/example/sns/controller/response/UserJoinResponse.java new file mode 100644 index 00000000..a1c57c1e --- /dev/null +++ b/simple_sns/src/main/java/com/example/sns/controller/response/UserJoinResponse.java @@ -0,0 +1,21 @@ +package com.example.sns.controller.response; + +import com.example.sns.model.User; +import com.example.sns.model.UserRole; +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public class UserJoinResponse { + + private Integer id; + private String username; + private UserRole role; + + public static UserJoinResponse fromUser(User user) { + return new UserJoinResponse( + user.getId(), + user.getUsername(), + user.getUserRole() + ); + } +} diff --git a/simple_sns/src/main/java/com/example/sns/exception/ErrorCode.java b/simple_sns/src/main/java/com/example/sns/exception/ErrorCode.java new file mode 100644 index 00000000..ddb28a4d --- /dev/null +++ b/simple_sns/src/main/java/com/example/sns/exception/ErrorCode.java @@ -0,0 +1,17 @@ +package com.example.sns.exception; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum ErrorCode { + + DUPLICATED_USER_NAME(HttpStatus.CONFLICT, "Username is duplicated.") + + ; + + private HttpStatus status; + private String message; +} diff --git a/simple_sns/src/main/java/com/example/sns/exception/GlobalControllerAdvice.java b/simple_sns/src/main/java/com/example/sns/exception/GlobalControllerAdvice.java new file mode 100644 index 00000000..53b18148 --- /dev/null +++ b/simple_sns/src/main/java/com/example/sns/exception/GlobalControllerAdvice.java @@ -0,0 +1,19 @@ +package com.example.sns.exception; + +import com.example.sns.controller.response.Response; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@Slf4j +@RestControllerAdvice +public class GlobalControllerAdvice { + + @ExceptionHandler(SnsApplicationException.class) + public ResponseEntity applicationHandler(SnsApplicationException e) { + log.info("Error occurs {}", e.toString()); + return ResponseEntity.status(e.getErrorCode().getStatus()) + .body(Response.error(e.getErrorCode().name())); + } +} diff --git a/simple_sns/src/main/java/com/example/sns/exception/SnsApplicationException.java b/simple_sns/src/main/java/com/example/sns/exception/SnsApplicationException.java index 1b625d22..50a28d2c 100644 --- a/simple_sns/src/main/java/com/example/sns/exception/SnsApplicationException.java +++ b/simple_sns/src/main/java/com/example/sns/exception/SnsApplicationException.java @@ -1,4 +1,23 @@ package com.example.sns.exception; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +@AllArgsConstructor public class SnsApplicationException extends RuntimeException { + + private ErrorCode errorCode; + private String message; + + @Override + public String getMessage() { + if (message==null) { + return errorCode.getMessage(); + } + + return String.format("$s, $s", errorCode.getMessage(), message); + } } diff --git a/simple_sns/src/main/java/com/example/sns/model/User.java b/simple_sns/src/main/java/com/example/sns/model/User.java index d148e703..384b5bf5 100644 --- a/simple_sns/src/main/java/com/example/sns/model/User.java +++ b/simple_sns/src/main/java/com/example/sns/model/User.java @@ -1,7 +1,32 @@ package com.example.sns.model; +import com.example.sns.model.entity.UserEntity; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.sql.Timestamp; + +@Getter +@AllArgsConstructor public class User { + private Integer id; private String username; private String password; + private UserRole userRole; + private Timestamp registeredAt; + private Timestamp updatedAt; + private Timestamp deletedAt; + + public static User fromEntity(UserEntity entity) { + return new User( + entity.getId(), + entity.getUsername(), + entity.getPassword(), + entity.getRole(), + entity.getRegisteredAt(), + entity.getUpdatedAt(), + entity.getDeletedAt() + ); + } } diff --git a/simple_sns/src/main/java/com/example/sns/model/UserRole.java b/simple_sns/src/main/java/com/example/sns/model/UserRole.java new file mode 100644 index 00000000..b7c27122 --- /dev/null +++ b/simple_sns/src/main/java/com/example/sns/model/UserRole.java @@ -0,0 +1,5 @@ +package com.example.sns.model; + +public enum UserRole { + ADMIN, USER +} diff --git a/simple_sns/src/main/java/com/example/sns/model/entity/UserEntity.java b/simple_sns/src/main/java/com/example/sns/model/entity/UserEntity.java index 29a07e6e..a1235d7f 100644 --- a/simple_sns/src/main/java/com/example/sns/model/entity/UserEntity.java +++ b/simple_sns/src/main/java/com/example/sns/model/entity/UserEntity.java @@ -1,13 +1,20 @@ package com.example.sns.model.entity; +import com.example.sns.model.UserRole; import lombok.Getter; import lombok.Setter; +import org.hibernate.annotations.SQLDelete; +import org.hibernate.annotations.Where; import javax.persistence.*; +import java.sql.Timestamp; +import java.time.Instant; @Entity -@Table +@Table(name = "\"user\"") @Getter @Setter +@SQLDelete(sql = "UPDATE \"user\" SET deleted_at = NOW() where id=?") +@Where(clause = "deleted_at IS NULL") public class UserEntity { @Id @@ -16,4 +23,28 @@ public class UserEntity { private String username; private String password; + + @Enumerated(EnumType.STRING) + private UserRole role; + + private Timestamp registeredAt; + private Timestamp updatedAt; + private Timestamp deletedAt; + + @PrePersist + void registeredAt() { + this.registeredAt = Timestamp.from(Instant.now()); + } + + @PreUpdate + void updatedAt() { + this.updatedAt = Timestamp.from(Instant.now()); + } + + public static UserEntity of(String username, String password) { + UserEntity userEntity = new UserEntity(); + userEntity.setUsername(username); + userEntity.setPassword(password); + return userEntity; + } } diff --git a/simple_sns/src/main/java/com/example/sns/service/UserService.java b/simple_sns/src/main/java/com/example/sns/service/UserService.java index 60e41ee0..41aea845 100644 --- a/simple_sns/src/main/java/com/example/sns/service/UserService.java +++ b/simple_sns/src/main/java/com/example/sns/service/UserService.java @@ -1,5 +1,6 @@ package com.example.sns.service; +import com.example.sns.exception.ErrorCode; import com.example.sns.exception.SnsApplicationException; import com.example.sns.model.User; import com.example.sns.model.entity.UserEntity; @@ -18,12 +19,14 @@ public class UserService { public User join(String username, String password){ // username 확인 - Optional userEntity = userEntityRepository.findByUsername(username); + userEntityRepository.findByUsername(username).ifPresent(it -> { + throw new SnsApplicationException(ErrorCode.DUPLICATED_USER_NAME, String.format("$s is duplicated", username)); + }); // 회원가입 진행 - userEntityRepository.save(new UserEntity()); + UserEntity userEntity = userEntityRepository.save(UserEntity.of(username, password)); - return new User(); + return User.fromEntity(userEntity); } public String login(String username, String password) { diff --git a/simple_sns/src/test/java/com/example/sns/controller/UserControllerTest.java b/simple_sns/src/test/java/com/example/sns/controller/UserControllerTest.java index 8994ead7..30fe8d00 100644 --- a/simple_sns/src/test/java/com/example/sns/controller/UserControllerTest.java +++ b/simple_sns/src/test/java/com/example/sns/controller/UserControllerTest.java @@ -2,6 +2,7 @@ package com.example.sns.controller; import com.example.sns.controller.request.UserJoinRequest; import com.example.sns.controller.request.UserLoginRequest; +import com.example.sns.exception.ErrorCode; import com.example.sns.exception.SnsApplicationException; import com.example.sns.model.User; import com.example.sns.service.UserService; @@ -52,7 +53,7 @@ public class UserControllerTest { String username = "username"; String password = "password"; - when(userService.join(username, password)).thenThrow(new SnsApplicationException()); + when(userService.join(username, password)).thenThrow(new SnsApplicationException(ErrorCode.DUPLICATED_USER_NAME, "")); mockMvc.perform(post("/api/v1/users/join") .contentType(MediaType.APPLICATION_JSON)