Skip to content

Commit

Permalink
Merge pull request #10 from YAPP-Github/feature/#9
Browse files Browse the repository at this point in the history
feat: 사진 서비스 중 앨범 기능 구현
  • Loading branch information
CChuYong authored Jun 30, 2024
2 parents e0a2357 + 964de84 commit 7c94857
Show file tree
Hide file tree
Showing 20 changed files with 362 additions and 32 deletions.
8 changes: 6 additions & 2 deletions photo-service/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,16 @@ dependencies {
implementation("org.flywaydb:flyway-mysql")
implementation("org.springframework:spring-jdbc")
implementation("org.springdoc:springdoc-openapi-starter-webflux-ui:2.5.0")
runtimeOnly("org.mariadb:r2dbc-mariadb:1.1.3")
runtimeOnly("org.mariadb.jdbc:mariadb-java-client")
implementation("com.mysql:mysql-connector-j:8.4.0")
implementation("io.asyncer:r2dbc-mysql:1.1.0")
testImplementation("org.springframework.boot:spring-boot-starter-test")
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")
implementation("com.github.f4b6a3:ulid-creator:5.2.3")

}

tasks.withType<Test> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package kr.mafoo.photo.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: 13 additions & 1 deletion photo-service/src/main/java/kr/mafoo/photo/api/AlbumApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
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.photo.annotation.RequestMemberId;
import kr.mafoo.photo.controller.dto.request.AlbumCreateRequest;
import kr.mafoo.photo.controller.dto.request.AlbumUpdateRequest;
import kr.mafoo.photo.controller.dto.response.AlbumResponse;
Expand All @@ -16,18 +17,26 @@ public interface AlbumApi {
@Operation(summary = "앨범 조회", description = "앨범 목록을 조회합니다.")
@GetMapping
Flux<AlbumResponse> getAlbums(
@RequestMemberId
String memberId
);

@Operation(summary = "앨범 생성", description = "앨범을 생성합니다.")
@PostMapping
Mono<AlbumResponse> createAlbum(
@RequestMemberId
String memberId,

@RequestBody
AlbumCreateRequest request
);

@Operation(summary = "앨범 수정", description = "앨범의 이름 및 종류를 수정합니다.")
@Operation(summary = "앨범 변경", description = "앨범의 속성을 변경합니다.")
@PutMapping("/{albumId}")
Mono<AlbumResponse> updateAlbum(
@RequestMemberId
String memberId,

@Parameter(description = "앨범 ID", example = "test_album_id")
@PathVariable
String albumId,
Expand All @@ -39,6 +48,9 @@ Mono<AlbumResponse> updateAlbum(
@Operation(summary = "앨범 삭제", description = "앨범을 삭제합니다.")
@DeleteMapping("/{albumId}")
Mono<Void> deleteAlbum(
@RequestMemberId
String memberId,

@Parameter(description = "앨범 ID", example = "test_album_id")
@PathVariable
String albumId
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package kr.mafoo.photo.config;

import kr.mafoo.photo.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.photo.config;

import kr.mafoo.photo.controller.dto.response.ErrorResponse;
import kr.mafoo.photo.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()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package kr.mafoo.photo.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 @@ -4,52 +4,54 @@
import kr.mafoo.photo.controller.dto.request.AlbumCreateRequest;
import kr.mafoo.photo.controller.dto.request.AlbumUpdateRequest;
import kr.mafoo.photo.controller.dto.response.AlbumResponse;
import org.springframework.web.bind.annotation.*;
import kr.mafoo.photo.domain.AlbumType;
import kr.mafoo.photo.service.AlbumService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import static kr.mafoo.photo.domain.AlbumType.*;

@RequiredArgsConstructor
@RestController
public class AlbumController implements AlbumApi {
private final AlbumService albumService;

@Override
public Flux<AlbumResponse> getAlbums(
String memberId
) {
return Flux.just(
new AlbumResponse("test_album_id_a", "단짝이랑", TYPE_A, "1"),
new AlbumResponse("test_album_id_b", "야뿌들", TYPE_B, "5"),
new AlbumResponse("test_album_id_c", "농구팟", TYPE_C, "2"),
new AlbumResponse("test_album_id_d", "화사사람들", TYPE_D, "12"),
new AlbumResponse("test_album_id_e", "기념일", TYPE_E, "4"),
new AlbumResponse("test_album_id_f", "친구들이랑", TYPE_F, "9")
);
return albumService
.findAllByOwnerMemberId(memberId)
.map(AlbumResponse::fromEntity);
}

@Override
public Mono<AlbumResponse> createAlbum(
String memberId,
AlbumCreateRequest request
){
return Mono.just(
new AlbumResponse("test_album_id", "시금치파슷하", TYPE_A, "0")
);
AlbumType type = AlbumType.valueOf(request.type());
return albumService
.createNewAlbum(memberId, request.name(), type)
.map(AlbumResponse::fromEntity);
}

@Override
public Mono<AlbumResponse> updateAlbum(
String albumId,
AlbumUpdateRequest request
){
return Mono.just(
new AlbumResponse("test_album_id", "시금치파슷하", TYPE_A, "0")
);
public Mono<AlbumResponse> updateAlbum(String memberId, String albumId, AlbumUpdateRequest request) {
return albumService
.updateAlbumName(albumId, request.name(), memberId)
.then(albumService.updateAlbumType(albumId, request.type(), memberId))
.map(AlbumResponse::fromEntity);
}


@Override
public Mono<Void> deleteAlbum(
String memberId,
String albumId
){
return Mono.empty();
return albumService
.deleteAlbumById(albumId, memberId);
}

}
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package kr.mafoo.photo.controller.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;
import kr.mafoo.photo.domain.AlbumType;

@Schema(description = "앨범 수정 요청")
public record AlbumUpdateRequest(
@Schema(description = "앨범 이름", example = "시금치파슷하")
String name,

@Schema(description = "앨범 타입", example = "TYPE_A")
String type
AlbumType type
) {
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package kr.mafoo.photo.controller.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import kr.mafoo.photo.domain.AlbumEntity;
import kr.mafoo.photo.domain.AlbumType;

@Schema(description = "앨범 응답")
Expand All @@ -17,4 +18,12 @@ public record AlbumResponse(
@Schema(description = "앨범 내 사진 수", example = "6")
String photoCount
) {
public static AlbumResponse fromEntity(AlbumEntity entity) {
return new AlbumResponse(
entity.getAlbumId(),
entity.getName(),
entity.getType(),
"0"
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package kr.mafoo.photo.controller.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import kr.mafoo.photo.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()
);
}
}
83 changes: 83 additions & 0 deletions photo-service/src/main/java/kr/mafoo/photo/domain/AlbumEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package kr.mafoo.photo.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.annotation.LastModifiedDate;
import org.springframework.data.annotation.Transient;
import org.springframework.data.domain.Persistable;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table;

import java.time.LocalDateTime;

@Getter
@Setter
@NoArgsConstructor
@Table("album")
public class AlbumEntity implements Persistable<String> {
@Id
@Column("id")
private String albumId;

@Column("name")
private String name;

@Column("type")
private AlbumType type;

@Column("owner_member_id")
private String ownerMemberId;

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

@LastModifiedDate
@Column("updated_at")
private LocalDateTime updatedAt;

@Transient
private boolean isNew = false;

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

AlbumEntity that = (AlbumEntity) obj;
return albumId.equals(that.albumId);
}

@Override
public int hashCode() {
return albumId.hashCode();
}

@Override
public String getId() {
return albumId;
}

public AlbumEntity updateName(String newName) {
this.name = newName;
return this;
}

public AlbumEntity updateType(AlbumType newType) {
this.type = newType;
return this;
}

public static AlbumEntity newAlbum(String albumId, String albumName, AlbumType albumType, String ownerMemberId) {
AlbumEntity album = new AlbumEntity();
album.albumId = albumId;
album.name = albumName;
album.type = albumType;
album.ownerMemberId = ownerMemberId;
album.isNew = true;
return album;
}
}
12 changes: 6 additions & 6 deletions photo-service/src/main/java/kr/mafoo/photo/domain/AlbumType.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package kr.mafoo.photo.domain;

public enum AlbumType {
TYPE_A,
TYPE_B,
TYPE_C,
TYPE_D,
TYPE_E,
TYPE_F,
HEART,
FIRE,
BASKETBALL,
BUILDING,
STARFALL,
SMILE_FACE
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package kr.mafoo.photo.exception;

public class AlbumNotFoundException extends DomainException {
public AlbumNotFoundException() {
super(ErrorCode.ALBUM_NOT_FOUND);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package kr.mafoo.photo.exception;

import lombok.Getter;

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

public DomainException(ErrorCode errorCode) {
super(errorCode.getMessage());
this.errorCode = errorCode;
}
}
Loading

0 comments on commit 7c94857

Please sign in to comment.