Skip to content

Commit

Permalink
Merge pull request #41 from seoshinehyo/feature/#40
Browse files Browse the repository at this point in the history
[Feat] 받은 편지함 조회, 보낸 편지함 조회, 내게 쓴 편지함 조회, 저장한 편지함 조회 구현
  • Loading branch information
seoshinehyo authored Dec 20, 2024
2 parents 5daf35b + e798ed4 commit 116225d
Show file tree
Hide file tree
Showing 11 changed files with 321 additions and 4 deletions.
4 changes: 2 additions & 2 deletions src/main/java/com/dearnote/apipayload/ApiResponse.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.dearnote.apipayload;

import com.dearnote.apipayload.code.BaseCode;
import com.dearnote.apipayload.code.status.SuccessStatus;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.dearnote.apipayload.code.BaseCode;
import com.dearnote.apipayload.code.status.SuccessStatus;
import lombok.AllArgsConstructor;
import lombok.Getter;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public enum ErrorStatus implements BaseErrorCode {
_BAD_REQUEST(HttpStatus.BAD_REQUEST,"COMMON400","잘못된 요청입니다."),
_UNAUTHORIZED(HttpStatus.UNAUTHORIZED,"COMMON401","인증이 필요합니다."),
_FORBIDDEN(HttpStatus.FORBIDDEN, "COMMON403", "금지된 요청입니다."),
PAGE_NUMBER_INVALID(HttpStatus.BAD_REQUEST, "PAGE4001", "페이지 번호는 1 이상이어야 합니다."),


// 편지 관려 에러
Expand Down
36 changes: 36 additions & 0 deletions src/main/java/com/dearnote/converter/MemberConverter.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,40 @@
package com.dearnote.converter;

import com.dearnote.domain.Letter;
import com.dearnote.web.dto.MemberResponseDTO;
import org.springframework.data.domain.Page;

import java.util.List;
import java.util.stream.Collectors;

public class MemberConverter {
public static MemberResponseDTO.LetterPreviewDTO letterPreviewDTO(Letter letter){
return MemberResponseDTO.LetterPreviewDTO.builder()
.letterId(letter.getId())
.senderId(letter.getSender().getId())
.receiverId(letter.getReceiver().getId())
.name(letter.getReceiver().getName())
.type(letter.getType())
.mark(letter.getMark())
.isPublic(letter.getIsPublic())
.keyword(letter.getKeyword().getKeyword())
.sentAt(letter.getCreatedAt())
.build();
}


public static MemberResponseDTO.LetterPreviewListDTO letterPreviewListDTO(Page<Letter> letterList){

List<MemberResponseDTO.LetterPreviewDTO> letterPreViewDTOList = letterList.stream()
.map(MemberConverter::letterPreviewDTO).collect(Collectors.toList());

return MemberResponseDTO.LetterPreviewListDTO.builder()
.isLast(letterList.isLast())
.isFirst(letterList.isFirst())
.totalPage(letterList.getTotalPages())
.totalElements(letterList.getTotalElements())
.listSize(letterPreViewDTOList.size())
.letterList(letterPreViewDTOList)
.build();
}
}
2 changes: 1 addition & 1 deletion src/main/java/com/dearnote/domain/enums/LetterType.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package com.dearnote.domain.enums;

public enum LetterType {
RECEIVED, SENT
RECEIVED, SENT, SELF
}
13 changes: 13 additions & 0 deletions src/main/java/com/dearnote/repository/LetterRepository.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
package com.dearnote.repository;

import com.dearnote.domain.Letter;
import com.dearnote.domain.Member;
import com.dearnote.domain.enums.LetterType;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface LetterRepository extends JpaRepository<Letter, Long> {
Page<Letter> findAllBySender(Member member, Pageable pageable);
Page<Letter> findAllByReceiver(Member member, Pageable pageable);

Page<Letter> findAllBySenderAndType(Member member, LetterType type, Pageable pageable);

Page<Letter> findAllBySenderAndMarkTrue(Member member, Pageable pageable);

}
17 changes: 17 additions & 0 deletions src/main/java/com/dearnote/service/member/MemberQueryService.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,25 @@
package com.dearnote.service.member;

import com.dearnote.domain.Letter;
import com.dearnote.domain.Member;
import org.springframework.data.domain.Page;

public interface MemberQueryService {

Member getMember(Long memberId);

// 전체 편지함 조회
Page<Letter> getAllLetterList(Long memberId, Integer page);

// 받은 편지함 조회
Page<Letter> getReceivedLetterList(Long memberId, Integer page);

// 보낸 편지함 조회
Page<Letter> getSentLetterList(Long memberId, Integer page);

// 내게 쓴 편지함 조회
Page<Letter> getSelfLetterList(Long memberId, Integer page);

// 저장한 편지함 조회
Page<Letter> getMarkedLetterList(Long memberId, Integer page);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@

import com.dearnote.apipayload.code.status.ErrorStatus;
import com.dearnote.apipayload.exception.handler.MemberHandler;
import com.dearnote.domain.Letter;
import com.dearnote.domain.Member;
import com.dearnote.domain.enums.LetterType;
import com.dearnote.repository.LetterRepository;
import com.dearnote.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

@Service
Expand All @@ -13,9 +18,51 @@ public class MemberQueryServiceImpl implements MemberQueryService {

private final MemberRepository memberRepository;

private final LetterRepository letterRepository;

@Override
public Member getMember(Long memberId) {
return memberRepository.findById(memberId)
.orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND));
}

@Override
public Page<Letter> getAllLetterList(Long memberId, Integer page){

Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND));
return letterRepository.findAllBySender(member, PageRequest.of(page, 10));
}

@Override
public Page<Letter> getReceivedLetterList(Long memberId, Integer page){

Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND));
return letterRepository.findAllBySenderAndType(member, LetterType.RECEIVED, PageRequest.of(page, 10));
}

@Override
public Page<Letter> getSentLetterList(Long memberId, Integer page){

Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND));
return letterRepository.findAllBySenderAndType(member, LetterType.SENT, PageRequest.of(page, 10));
}

@Override
public Page<Letter> getSelfLetterList(Long memberId, Integer page){

Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND));
return letterRepository.findAllBySenderAndType(member, LetterType.SELF, PageRequest.of(page, 10));
}

@Override
public Page<Letter> getMarkedLetterList(Long memberId, Integer page){
Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND));
return letterRepository.findAllBySenderAndMarkTrue(member, PageRequest.of(page, 10));
}

}
21 changes: 21 additions & 0 deletions src/main/java/com/dearnote/validation/annotation/CheckPage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.dearnote.validation.annotation;

import com.dearnote.validation.validator.CheckPageValidator;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;

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

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = CheckPageValidator.class)
public @interface CheckPage {
String message() default "페이지 번호는 1 이상이어야 합니다.";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.dearnote.validation.validator;

import com.dearnote.apipayload.code.status.ErrorStatus;
import com.dearnote.validation.annotation.CheckPage;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class CheckPageValidator implements ConstraintValidator<CheckPage, Integer>{
@Override
public void initialize(CheckPage constraintAnnotation) {
ConstraintValidator.super.initialize(constraintAnnotation);
}

@Override
public boolean isValid(Integer page, ConstraintValidatorContext context) {
// 페이지가 0 이하이거나 널인 경우 유효성 검증을 실패로 처리
if (page == null || page < 1) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(ErrorStatus.PAGE_NUMBER_INVALID.toString()).addConstraintViolation();
return false;
}


return true;
}
}
117 changes: 116 additions & 1 deletion src/main/java/com/dearnote/web/controller/MemberRestController.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,124 @@
package com.dearnote.web.controller;

import com.dearnote.converter.MemberConverter;
import com.dearnote.domain.Letter;
import com.dearnote.service.member.MemberQueryService;
import com.dearnote.validation.annotation.CheckPage;
import com.dearnote.validation.annotation.ExistMember;
import com.dearnote.web.dto.MemberResponseDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.data.domain.Page;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import com.dearnote.apipayload.*;


@RestController
@RequiredArgsConstructor
@Validated
@RequestMapping("/dearnote/letters")
public class MemberRestController {
private final MemberQueryService memberQueryService;

@GetMapping("/{memberId}/all")
@Operation(summary = "특정 회원의 전체 편지함 조회 API", description = "특정 회원의 전체 편지함을 조회하는 API이며, 페이징을 포함합니다. query String 으로 page 번호를 주세요.")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200",description = "OK, 성공"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!",content = @Content(schema = @Schema(implementation = ApiResponse.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH004", description = "acess 토큰 만료",content = @Content(schema = @Schema(implementation = ApiResponse.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH006", description = "acess 토큰 모양이 이상함",content = @Content(schema = @Schema(implementation = ApiResponse.class))),
})
@Parameters({
@Parameter(name = "memberId", description = "회원의 아이디, path variable 입니다!")
})
public ApiResponse<MemberResponseDTO.LetterPreviewListDTO> getAllLetterList(
@ExistMember @PathVariable(name = "memberId") Long memberId,
@CheckPage @RequestParam(name = "page") Integer page
){
Page<Letter> letterList = memberQueryService.getAllLetterList(memberId,page - 1);
return ApiResponse.onSuccess(MemberConverter.letterPreviewListDTO(letterList));
}

@GetMapping("/{memberId}/received")
@Operation(summary = "특정 회원의 받은 편지함 조회 API", description = "특정 회원의 받은 편지함을 조회하는 API이며, 페이징을 포함합니다. query String 으로 page 번호를 주세요.")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200",description = "OK, 성공"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!",content = @Content(schema = @Schema(implementation = ApiResponse.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH004", description = "acess 토큰 만료",content = @Content(schema = @Schema(implementation = ApiResponse.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH006", description = "acess 토큰 모양이 이상함",content = @Content(schema = @Schema(implementation = ApiResponse.class))),
})
@Parameters({
@Parameter(name = "memberId", description = "회원의 아이디, path variable 입니다!")
})
public ApiResponse<MemberResponseDTO.LetterPreviewListDTO> getReceivedLetterList(
@ExistMember @PathVariable(name = "memberId") Long memberId,
@CheckPage @RequestParam(name = "page") Integer page
){
Page<Letter> letterList = memberQueryService.getReceivedLetterList(memberId,page - 1);
return ApiResponse.onSuccess(MemberConverter.letterPreviewListDTO(letterList));
}

@GetMapping("/{memberId}/sent")
@Operation(summary = "특정 회원의 보낸 편지함 조회 API", description = "특정 회원의 보낸 편지함을 조회하는 API이며, 페이징을 포함합니다. query String 으로 page 번호를 주세요.")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200",description = "OK, 성공"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!",content = @Content(schema = @Schema(implementation = ApiResponse.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH004", description = "acess 토큰 만료",content = @Content(schema = @Schema(implementation = ApiResponse.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH006", description = "acess 토큰 모양이 이상함",content = @Content(schema = @Schema(implementation = ApiResponse.class))),
})
@Parameters({
@Parameter(name = "memberId", description = "회원의 아이디, path variable 입니다!")
})
public ApiResponse<MemberResponseDTO.LetterPreviewListDTO> getSentLetterList(
@ExistMember @PathVariable(name = "memberId") Long memberId,
@CheckPage @RequestParam(name = "page") Integer page
){
Page<Letter> letterList = memberQueryService.getSentLetterList(memberId,page - 1);
return ApiResponse.onSuccess(MemberConverter.letterPreviewListDTO(letterList));
}

@GetMapping("/{memberId}/self")
@Operation(summary = "특정 회원의 내게 쓴 편지함 조회 API", description = "특정 회원의 내게 쓴 편지함을 조회하는 API이며, 페이징을 포함합니다. query String 으로 page 번호를 주세요.")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200",description = "OK, 성공"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!",content = @Content(schema = @Schema(implementation = ApiResponse.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH004", description = "acess 토큰 만료",content = @Content(schema = @Schema(implementation = ApiResponse.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH006", description = "acess 토큰 모양이 이상함",content = @Content(schema = @Schema(implementation = ApiResponse.class))),
})
@Parameters({
@Parameter(name = "memberId", description = "회원의 아이디, path variable 입니다!")
})
public ApiResponse<MemberResponseDTO.LetterPreviewListDTO> getSelfLetterList(
@ExistMember @PathVariable(name = "memberId") Long memberId,
@CheckPage @RequestParam(name = "page") Integer page
){
Page<Letter> letterList = memberQueryService.getSelfLetterList(memberId,page - 1);
return ApiResponse.onSuccess(MemberConverter.letterPreviewListDTO(letterList));
}


@GetMapping("/{memberId}/mark")
@Operation(summary = "특정 회원의 저장한 편지함 조회 API", description = "특정 회원의 저장한 편지함을 조회하는 API이며, 페이징을 포함합니다. query String 으로 page 번호를 주세요.")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200",description = "OK, 성공"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!",content = @Content(schema = @Schema(implementation = ApiResponse.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH004", description = "acess 토큰 만료",content = @Content(schema = @Schema(implementation = ApiResponse.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH006", description = "acess 토큰 모양이 이상함",content = @Content(schema = @Schema(implementation = ApiResponse.class))),
})
@Parameters({
@Parameter(name = "memberId", description = "회원의 아이디, path variable 입니다!")
})
public ApiResponse<MemberResponseDTO.LetterPreviewListDTO> getMarkedLetterList(
@ExistMember @PathVariable(name = "memberId") Long memberId,
@CheckPage @RequestParam(name = "page") Integer page
){
Page<Letter> letterList = memberQueryService.getMarkedLetterList(memberId,page - 1);
return ApiResponse.onSuccess(MemberConverter.letterPreviewListDTO(letterList));
}
}
Loading

0 comments on commit 116225d

Please sign in to comment.