Skip to content

Commit

Permalink
Merge pull request #6 from YAPP-Github/feature/#5
Browse files Browse the repository at this point in the history
feat: 사용자 조회, 탈퇴 API 구현
  • Loading branch information
CChuYong authored Jun 22, 2024
2 parents 1938a0e + 4ae2404 commit 3970842
Show file tree
Hide file tree
Showing 16 changed files with 228 additions and 8 deletions.
2 changes: 2 additions & 0 deletions user-service/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ dependencies {
testImplementation("io.projectreactor:reactor-test")
testImplementation("org.springframework.security:spring-security-test")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
implementation("org.projectlombok:lombok:1.18.32")
annotationProcessor("org.projectlombok:lombok:1.18.32")
}

tasks.withType<Test> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package kr.mafoo.user.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER, ElementType.TYPE_PARAMETER})
public @interface RequestMemberId {
}
14 changes: 10 additions & 4 deletions user-service/src/main/java/kr/mafoo/user/api/MeApi.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package kr.mafoo.user.api;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import kr.mafoo.user.annotation.RequestMemberId;
import kr.mafoo.user.controller.dto.response.MemberResponse;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import reactor.core.publisher.Mono;

Expand All @@ -13,9 +15,13 @@
public interface MeApi {
@Operation(summary = "내 정보 조회", description = "현재 토큰 주인의 정보를 조회합니다.")
@GetMapping
Mono<MemberResponse> getMemberWhoRequested();
Mono<MemberResponse> getMemberWhoRequested(
@RequestMemberId @Parameter(hidden = true) String memberId
);

@Operation(summary = "탈퇴", description = "현재 토큰 주인이 탈퇴합니다.")
@PostMapping("/quit")
Mono<Void> deleteMemberWhoRequested();
@DeleteMapping
Mono<Void> deleteMemberWhoRequested(
@RequestMemberId @Parameter(hidden = true) String memberId
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package kr.mafoo.user.config;


import kr.mafoo.user.annotation.RequestMemberId;
import org.springframework.core.MethodParameter;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

public class MemberIdParameterResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterAnnotation(RequestMemberId.class) != null;
}

@Override
public Mono<Object> resolveArgument(MethodParameter parameter, BindingContext bindingContext, ServerWebExchange exchange) {
String memberId = exchange.getRequest().getHeaders().getFirst("X-MEMBER-ID");
return Mono.justOrEmpty(memberId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package kr.mafoo.user.config;

import kr.mafoo.user.controller.dto.response.ErrorResponse;
import kr.mafoo.user.exception.DomainException;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class WebExceptionHandler {
@ExceptionHandler(DomainException.class)
public ResponseEntity<ErrorResponse> handleDomainException(DomainException exception) {
return ResponseEntity
.badRequest()
.body(ErrorResponse.fromErrorCode(exception.getErrorCode()));
}
}
15 changes: 15 additions & 0 deletions user-service/src/main/java/kr/mafoo/user/config/WebFluxConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package kr.mafoo.user.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.reactive.config.WebFluxConfigurer;
import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;

@EnableWebFlux
@Configuration
public class WebFluxConfig implements WebFluxConfigurer {
@Override
public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
configurer.addCustomResolver(new MemberIdParameterResolver());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,26 @@

import kr.mafoo.user.api.MeApi;
import kr.mafoo.user.controller.dto.response.MemberResponse;
import kr.mafoo.user.service.MemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

@RequiredArgsConstructor
@RestController
public class MeController implements MeApi {
private final MemberService memberService;

@Override
public Mono<MemberResponse> getMemberWhoRequested() {
return Mono.just(new MemberResponse("test", "송영민"));
public Mono<MemberResponse> getMemberWhoRequested(String memberId) {
return memberService
.getMemberByMemberId(memberId)
.map(MemberResponse::fromEntity);
}

@Override
public Mono<Void> deleteMemberWhoRequested() {
return Mono.empty();
public Mono<Void> deleteMemberWhoRequested(String memberId) {
return memberService
.quitMemberByMemberId(memberId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package kr.mafoo.user.controller.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import kr.mafoo.user.exception.ErrorCode;

@Schema(description = "에러 응답")
public record ErrorResponse(
@Schema(description = "에러 코드", example = "ME0001")
String code,

@Schema(description = "에러 메시지", example = "사용자를 찾을 수 없습니다")
String message
) {
public static ErrorResponse fromErrorCode(ErrorCode errorCode) {
return new ErrorResponse(
errorCode.getCode(),
errorCode.getMessage()
);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package kr.mafoo.user.controller.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import kr.mafoo.user.domain.MemberEntity;

@Schema(description = "사용자 정보 응답")
public record MemberResponse(
Expand All @@ -10,4 +11,10 @@ public record MemberResponse(
@Schema(description = "사용자 이름", example = "송영민")
String name
) {
public static MemberResponse fromEntity(MemberEntity memberEntity) {
return new MemberResponse(
memberEntity.getId(),
memberEntity.getName()
);
}
}
43 changes: 43 additions & 0 deletions user-service/src/main/java/kr/mafoo/user/domain/MemberEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package kr.mafoo.user.domain;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table;

import java.time.LocalDateTime;

@Getter
@Setter
@NoArgsConstructor
@Table("member")
public class MemberEntity {
@Id
@Column("member_id")
private String id;

@Column("name")
private String name;

@CreatedDate
@Column("created_at")
private LocalDateTime createdAt;

@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;

MemberEntity that = (MemberEntity) obj;

return id.equals(that.id);
}

@Override
public int hashCode() {
return id.hashCode();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package kr.mafoo.user.exception;

import lombok.Getter;

@Getter
public class DomainException extends RuntimeException {
private final ErrorCode errorCode;

public DomainException(ErrorCode errorCode) {
super(errorCode.getMessage());
this.errorCode = errorCode;
}
}
12 changes: 12 additions & 0 deletions user-service/src/main/java/kr/mafoo/user/exception/ErrorCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package kr.mafoo.user.exception;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum ErrorCode {
MEMBER_NOT_FOUND("ME0001", "사용자를 찾을 수 없습니다");
private final String code;
private final String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package kr.mafoo.user.exception;

public class MemberNotFoundException extends DomainException {
public MemberNotFoundException() {
super(ErrorCode.MEMBER_NOT_FOUND);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package kr.mafoo.user.repository;

import kr.mafoo.user.domain.MemberEntity;
import org.springframework.data.r2dbc.repository.R2dbcRepository;
import reactor.core.publisher.Mono;

public interface MemberRepository extends R2dbcRepository<MemberEntity, String> {
Mono<Void> deleteMemberById(String memberId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package kr.mafoo.user.service;

import kr.mafoo.user.domain.MemberEntity;
import kr.mafoo.user.exception.MemberNotFoundException;
import kr.mafoo.user.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

@RequiredArgsConstructor
@Service
public class MemberService {
private final MemberRepository memberRepository;

public Mono<Void> quitMemberByMemberId(String memberId) {
return memberRepository.deleteMemberById(memberId);
}

public Mono<MemberEntity> getMemberByMemberId(String memberId) {
return memberRepository
.findById(memberId)
.switchIfEmpty(Mono.error(new MemberNotFoundException()));
}

}
3 changes: 3 additions & 0 deletions user-service/src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ spring:
url: ${MYSQL_URL}
username: ${MYSQL_USERNAME}
password: ${MYSQL_PASSWORD}
logging:
level:
org.springframework.data.r2dbc: DEBUG

0 comments on commit 3970842

Please sign in to comment.