Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[4기 윤영운, 김별] Spring Boot JPA 게시판 구현 미션 제출합니다. #258

Open
wants to merge 18 commits into
base: 김별/윤영운
Choose a base branch
from

Conversation

byeolhaha
Copy link
Member

📌 과제 설명

SpringDataJPA 를 설정한다.

  • datasource : h2 or mysql

엔티티를 구성한다

  • 회원(User)
  • id (PK) (auto increment)
  • name
  • age
  • hobby
  • created_at
  • created_by
  • 게시글(Post)
  • id (PK) (auto increment)
  • title
  • content
  • created_at
  • created_by
  • 회원과 게시글에 대한 연관관계를 설정한다.
  • 회원과 게시글은 1:N 관계이다.
  • 게시글 Repository를 구현한다. (PostRepository)

API를 구현한다.

  • 게시글 조회
  • 페이징 조회 (GET "/posts")
  • 단건 조회 (GET "/posts/{id}")
  • 게시글 작성 (POST "/posts")
  • 게시글 수정 (POST "/posts/{id}")

REST-DOCS를 이용해서 문서화한다.

👩‍💻 요구 사항과 구현 내용

  • 게시글 조회
    • 게시글 조회할 때 제목과 내용으로 검색이 가능하도록 필터 기능을 넣었습니다.
    • N+1 문제가 발생되는 것을 개선하여 PostRepository에서 Join문을 이용하였습니다.
    @Query("SELECT p FROM Post p " +
            "JOIN FETCH p.member " +
            "WHERE (p.title LIKE %:title%) " +
            "AND (p.content LIKE %:content%)")
     Slice<Post> findPostAllByFilter(@Param("title") String title,
                                    @Param("content") String content,
                                    Pageable pageable);
  • 페이징 조회 (GET "/posts")
    • Slice를 이용하여 무한스크롤로 구현하였습니다.
  • 게시글 수정 요구 사항의 경우 "POST "로 되어 있었으나 PATCH로 수정하였습니다.
  • 로그인 기능이 구현되지 않아서 AuditorAware 커스텀하여 CreatedBy에 관리자 이름이 들어가도록 하였습니다.
    @EnableJpaAuditing
    @Configuration
    @Component
    public class AuditorAwareConfig implements AuditorAware<String>, DateTimeProvider {
    
     @Override
     public Optional<String> getCurrentAuditor() {
         return Optional.of("별앤영");
      }
    
      @Override
      public Optional<TemporalAccessor> getNow() {
         return Optional.of(LocalDateTime.now());
       }
     }
  • REST-DOCS를 이용해서 문서화를 진행하였습니다.

image

build.gradle Outdated
Comment on lines 40 to 44
tasks.named('asciidoctor') {
inputs.dir snippetsDir
attributes 'snippets': snippetsDir
dependsOn test
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

테스트 코드 수정시 resources/static/docs/index.html이 업그레이드 되나요?

private String name;

@Embedded
private Age age;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

원시값 포장하여 저장하는 방식 좋은 것 같습니다!👍

public FindMemberResponse findById(Long id) {
Member member = memberRepository.findById(id).orElseThrow(() -> new EntityNotFoundException("존재하지 않은 고객입니다."));

return new FindMemberResponse(member);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FindMemberResponse 해당 클래스가 함수명처럼 느껴지는 것 같습니다.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MemberRetrieveResponse 이건 어떰요?


import jakarta.validation.constraints.NotNull;

public record SaveApiRequest(@NotNull(message = "memberId 값이 입력되지 않았습니다.") Long memberId,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

상세 메시지를 작성해놓으면 에러 찾을 때도 좋을 것 같네용👍

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

�제가 원한게 이거였어요.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

근데 NotBlank가 더 맞음 ㅎㅎ

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String에 한정해서는요.

public class PostController {

private final PostService postService;
private final PostApiMapper postApiMapper;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apicontroller를 나타내는 걸까요?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 맞습니다!!

Comment on lines +60 to +63
URI location = ServletUriComponentsBuilder.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(saveResponse.postId())
.toUri();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 이런 방식이 있군요!👍

Comment on lines +34 to +58
void findAllByFilter() throws Exception {
FieldDescriptor[] responseFields = new FieldDescriptor[] {
subsectionWithPath("result").description("Result details"),
fieldWithPath("result.content[]").description("The list of content items"),
subsectionWithPath("result.pageable").description("Pagination information"),
fieldWithPath("result.pageable.sort.empty").description("Indicates if the sort is empty"),
fieldWithPath("result.pageable.sort.sorted").description("Indicates if the sort is sorted"),
fieldWithPath("result.pageable.sort.unsorted").description("Indicates if the sort is unsorted"),
fieldWithPath("result.pageable.offset").description("Offset value for pagination"),
fieldWithPath("result.pageable.pageSize").description("Page size for pagination"),
fieldWithPath("result.pageable.pageNumber").description("Page number"),
fieldWithPath("result.pageable.unpaged").description("Indicates if the page is unpaged"),
fieldWithPath("result.pageable.paged").description("Indicates if the page is paged"),
fieldWithPath("result.size").description("The page size"),
fieldWithPath("result.number").description("The current page number"),
fieldWithPath("result.sort.empty").description("Indicates if the sort is empty"),
fieldWithPath("result.sort.sorted").description("Indicates if the sort is sorted"),
fieldWithPath("result.sort.unsorted").description("Indicates if the sort is unsorted"),
fieldWithPath("result.first").description("Indicates if this is the first page"),
fieldWithPath("result.last").description("Indicates if this is the last page"),
fieldWithPath("result.numberOfElements").description("Number of elements in the current page"),
fieldWithPath("result.empty").description("Indicates if the content is empty"),
fieldWithPath("resultCode").description("The result code of the response"),
fieldWithPath("resultMsg").description("The result message of the response")
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

클라이언트에 이 정보들이 필요한가용?

Copy link
Member Author

@byeolhaha byeolhaha Aug 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

restdocs의 경우 필드 하나하나 맞춰줘야 해서 넣게 되었습니다. ✏️

.orElseThrow(() -> new EntityNotFoundException("해당 post가 존재하지 않습니다."));
Long postOwnerId = findPost.getMember().getId();

if (isNotOwner(request.memberId(), postOwnerId)){
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 이런 로직 좋네용👍

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어순에 맞게 코드를 작성 해주는게 제일 좋긴해요.

thePost.isOwner(memberId) 처럼.

Comment on lines 48 to 49
FindMemberResponse findMember = memberService.findById(request.memberId());
Post post = mapper.to(request, findMember);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Member entity가 생성되는 거 같습니다.
그럼 Post에서 저장하는 Member, Entity로 쓰이는 Member 두가지 의미로 사용되는 거 같은데, 괜찮을까요?

@wonu606
Copy link

wonu606 commented Aug 7, 2023

영운님 별님 코드 잘 보았습니다!
페어프로그래밍이라 서로 의견을 조율해 나가는 과정이 쉽진 않으셨을텐데,
수고하셨습니다!!😁😁😁
저희 프로젝트엔 적용하지 못한 로직들이 많은 것 같아 배우고 가는 시간이었습니다.

Comment on lines 20 to 21
@CreatedDate
@DateTimeFormat(pattern = "yyyy-MM-dd/HH:mm:ss")
Copy link

@onetuks onetuks Aug 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

만약 밀리세컨드를 표시하고 싶지 않다면, @column 어노테이션을 이용해서 타입을 명시해줄 수도 있어요.

Copy link
Member

@JaeyoungAhn JaeyoungAhn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

영운님, 별님 코드 잘 보았습니다!

여러 상황들을 대비하기 위해 코드가 세부적으로 작성되었다는게 느껴집니다!

리뷰를 하면서 오히려 제가 많이 배울 수 있는 시간이었습니다.

페어프로그래밍 하신다고 수고 많으셨습니다!


@Transactional
public PostResponse updatePost(Long id, UpdateRequest request) {
Post findPost = postRepository.findById(id)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

findMember의 find가 동사처럼 보이는데 더 좋은 변수명은 없을까용?

Comment on lines +69 to +73
for (FieldError fieldError : bindingResult.getFieldErrors()) {
stringBuilder.append(fieldError.getField()).append(":");
stringBuilder.append(fieldError.getDefaultMessage());
stringBuilder.append(", ");
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BindException 발생 시 세부적인 내용을 알려주는 코드 좋습니다!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

악의적인 유저가 Filter를 무시하고 모든 데이터들을 불러오는 것은 어려울까요? 만약 가능하다면 이를 예방할 수 있는 방법들이 있을까요?

@onetuks onetuks self-requested a review August 8, 2023 11:45
Copy link

@onetuks onetuks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

영운님, 별님
과제하시느라 고생하셨습니다.

강의 내용을 바탕으로 연관된 걸 많이 공부하신 느낌이 드네요.

전반적으로 코드도 깔끔했던 것 같아요.

고생하셨습니다~~😄

StringBuilder resultStringBuilder = getResultStringBuilder(e);
int statusCode = HttpStatus.BAD_REQUEST.value();

return ResponseEntity.status(statusCode).body(getErrorResponse(statusCode, resultStringBuilder.toString(), request.getRequestURI()));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

메소드 체이닝 마다 라인을 바꿔주면 한눈에 어떤 응답을 하는지 보기 좋을 것 같아요

return ResponseEntity
                  .status(statusCode)
                  .body(getErrorResponse(
                           statusCode, 
                           resultStringBuilder.toString(), 
                           request.getRequestURI()));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

status(BAD_REQUEST) 하면 안되나요?ㅠ statusCode 한번 보러가야 하잖아요 ㅠ

Comment on lines +5 to +9
public class SliceResponse<T> extends ApiResponse {

private Slice<T> data;

public SliceResponse(Slice<T> data, SuccessCode successCode) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

무한 스크롤을 생각하셨다니! 👍👍

@Embeddable
public class Age {

private static final int AGE_MIN = 0;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이런 디테일이 프로그램을 좋게 만드는 것 같아요

return postResponseSliceResponse;
}

@PatchMapping("/{id}")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기본값이 json이긴 하지만, consumes 같은 메소드를 사용해서 명시해주는 것도 좋을 것 같아요.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

me too

private void setupData() {
Member member1 = new Member("김별", new Age(27), "락 부르기");
Member member2 = new Member("윤영운", new Age(27), "저글링 돌리기");
Member member3 = new Member("박세영", new Age(27), "산책");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

과제하시면서 제 생각이 나다니... 감동입니다👍


import java.time.LocalDateTime;

public record ErrorResponse(int statusCode,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

int 타입의 원시 http 상태코드는 버전 6 이후로 deprecated 된다고 해요.
HttpStatus enum 클래스를 써보시면 좋을 것 같습니다.

@@ -0,0 +1,9 @@
package com.example.jpaboard.global.exception;

public class PermissionDeniedEditException extends RuntimeException {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EntityNotFound 처럼 무엇에 대한 것인지 먼저 나오면 좋을 것 같아요.
EditPermissionDeniedException 추천합니다!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋은 네이밍 추천 감사합니다ㅎㅎ

Comment on lines +142 to +143
requestFields(requestFields),
responseFields(responseFields)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

preprocess(prettyPrint()) 로 예쁘게 표현 가능하다고 해요!

Copy link

@KimMinheee KimMinheee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

영운님, 별님 JPA 게시판 과제 구현하시느라 정말 고생 많으셨습니다 :)
코드가 깔끔해서 정말 쉽게 읽을 수 있었던 것 같아요 👍🏼
궁금했던 부분에 대해 겹치는 코멘트는 중복으로 달지 않고 다른분들 코멘트에 이모지👀를 달아두었고 제가 추가로 궁금했던 부분에 코멘트를 달아놨습니다 :)
코드 읽으면서 많이 배웠습니다! 고생하셨습니다 !

Comment on lines +7 to +11
@SpringBootApplication
@EnableJpaAuditing(
auditorAwareRef = "auditorAwareConfig",
dateTimeProviderRef = "auditorAwareConfig"
)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dateTimeProviderRef라는 속성이 있었군요! 하나 배워갑니다~
Jpa와 관련된 속성 혹은 어노테이션들은 별도의 JPA 관련 config 파일들을 두어 관리할 수 있을 것 같습니다! :)

Comment on lines 21 to 22
@NotNull
private String name;
Copy link

@KimMinheee KimMinheee Aug 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

name에 NotBlank가 아닌 NotNull로 validation을 거신 이유가 궁금합니다! :)
"" 나 " "를 허용함을 염두에 두신것이라면 NotNull이 맞을 것 같네요

다만, @NotNull 어노테이션은 db의 ddl에 notnull이 적용되지만, @notblank는 적용되지 않으니 이 부분을 고려하여 DTO에도 적절히 validation을 추가하면 좋을 듯 합니다.
nullable = false와 @NotNull 비교

Comment on lines +22 to +27
@Autowired
MemberRepository memberRepository;

@Autowired
MemberService memberService;
Long id;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

접근제한자가 추가되면 좋을 것 같습니다 😊

@Embedded
private Age age;

private String hobby;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

회원의 hobby에도 필드 검증이 추가되면 좋을 듯 합니다!


public class SliceResponse<T> extends ApiResponse {

private Slice<T> data;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

무한스크롤까지 구현하셨군요!! 최고최고👍🏼

Copy link

@WooSungHwan WooSungHwan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

과제하시느라 수고많으셨습니다 ㅎㅎ 테스트코드도 많이 작성하셨고 코드도 괜찮은데 기본적으로 있어야할 부분이 빠진게 좀 있어서 그 부분 채워졌다 싶을떄 approve 드릴게요! 리뷰내용이 도움이 되었으면 좋겠습니다.

auditorAwareRef = "auditorAwareConfig",
dateTimeProviderRef = "auditorAwareConfig"
)
public class JpaboardApplication {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

클래스명 camel 아닌듯

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@byeolhaha 해당 부분 해결이 안됐네요.


@EnableJpaAuditing
@Configuration
@Component

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

component는 필요없지 않을까요?ㅎㅎ

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

configuration과 component가 합쳐져 있는 것 같은데 분리하셔요.

Comment on lines 36 to 42
@ExceptionHandler({IllegalArgumentException.class, MissingRequestHeaderException.class, HttpMessageNotReadableException.class,
HttpClientErrorException.class, NoHandlerFoundException.class})
public ResponseEntity<ErrorResponse> handleBadRequestException(HttpServletRequest request, Exception e) {
int statusCode = HttpStatus.BAD_REQUEST.value();

return ResponseEntity.status(statusCode).body(getErrorResponse(statusCode, e.getMessage(), request.getRequestURI()));
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

적어도 switch 문이라도 있거나 instanceof라도 있어서 어떤 exception이 인스턴스로 넘어왔는지 log는 찍어줄 수 있을 것 같아요. 이후처리에 대한 대비를 하거나요. 근데 그럴거면 굳이 이렇게 합쳐놓을 필요가 애초에 없겠죠 ㅎㅎㅎ 이렇게 퉁처리는 장점이 될 수 없습니다.

StringBuilder resultStringBuilder = getResultStringBuilder(e);
int statusCode = HttpStatus.BAD_REQUEST.value();

return ResponseEntity.status(statusCode).body(getErrorResponse(statusCode, resultStringBuilder.toString(), request.getRequestURI()));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

status(BAD_REQUEST) 하면 안되나요?ㅠ statusCode 한번 보러가야 하잖아요 ㅠ

Comment on lines 58 to 63
@ExceptionHandler(Exception.class)
public ResponseEntity<Void> handleException(HttpServletRequest request, Exception e) {
logger.error("Sever Exception: ", e.getMessage());

return ResponseEntity.ok().build();
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exception인데 왜 ok죠?


import jakarta.validation.constraints.NotNull;

public record SaveApiRequest(@NotNull(message = "memberId 값이 입력되지 않았습니다.") Long memberId,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

�제가 원한게 이거였어요.


import jakarta.validation.constraints.NotNull;

public record SaveApiRequest(@NotNull(message = "memberId 값이 입력되지 않았습니다.") Long memberId,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

근데 NotBlank가 더 맞음 ㅎㅎ


import jakarta.validation.constraints.NotNull;

public record SaveApiRequest(@NotNull(message = "memberId 값이 입력되지 않았습니다.") Long memberId,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String에 한정해서는요.

Comment on lines 24 to 25
@ManyToOne
private Member member;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

관계 맺을거면 확실하게!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lazy인지 제약조건 뭐있는지 어디 컬럼으로 걸건지 등등

.orElseThrow(() -> new EntityNotFoundException("해당 post가 존재하지 않습니다."));
Long postOwnerId = findPost.getMember().getId();

if (isNotOwner(request.memberId(), postOwnerId)){

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어순에 맞게 코드를 작성 해주는게 제일 좋긴해요.

thePost.isOwner(memberId) 처럼.

Copy link

@WooSungHwan WooSungHwan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고 많으셨습니다 ㅎㅎ 코드가 깔끔합니다!
그런데 facade 같은 경우 service 보다는 별도 패키지로 둬주는게 좋을 것 같아요. 우선 service layer보다는 더 앞단에 있는 layer이기 때문에 service는 아니라고 판단해야 할 것 같습니다.

auditorAwareRef = "auditorAwareConfig",
dateTimeProviderRef = "auditorAwareConfig"
)
public class JpaboardApplication {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@byeolhaha 해당 부분 해결이 안됐네요.

private int resultCode;
private String resultMsg;

public ApiResponse(final T result, SuccessCode successCode) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

왜 result만 final인가요?ㅎㅎ

Comment on lines +30 to +43

public Member(Name name, Age age, String hobby) {
this.name = name;
this.age = age;
this.hobby = hobby;
}

public Member(Long id, Name name, Age age, String hobby) {
this.id = id;
this.name = name;
this.age = age;
this.hobby = hobby;
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VO로 잘 구현했지만, null 방어가 아쉽습니다! 실수를 방지할 수 있으면 방지하는게 좋은것같아요

Comment on lines +12 to +18

public Name(String value) {
validateName(value);
this.value = value;
}

public void changeName(String value) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

풍부하네요.

Comment on lines +7 to +9

private String value;

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

컬럼이 될 존재이고 nonnull이면

@Column(nullable=false) 

는 어떨까요?

Comment on lines +20 to +25

public MemberFindResponse findById(Long id) {
Member member = memberRepository.findById(id).orElseThrow(() -> new EntityNotFoundException("존재하지 않은 고객입니다."));

return new MemberFindResponse(member);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Transactional(readonly=true)

Comment on lines +53 to +56

if (findPost.isNotOwner(request.memberId())){
throw new UnauthorizedEditException("해당 게시글을 수정할 권한이 없습니다.");
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋네요 도메인 로직.

이정도면 다음것도 고민해볼수 있겠어요

findPost.checkUpdate(memberId); // 내부적으로 throw하여 로직 응집

Comment on lines +9 to +22
@RequiredArgsConstructor
public class RpcInput {

private final PostService postService;

public void create(Map<String, String> request) {

var title = request.get("title");

var content = request.get("content");

Post.create(title, content, null);
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이건모에용 ㅎㅎ

Comment on lines +12 to +14
@Test
@DisplayName("나이에 대해서 음수를 입력한 경우 예외를 던진다.")
void member_MinusAge_throwsException() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

생성할수 없다도 좋겠어요

Comment on lines +37 to +59
subsectionWithPath("result").description("Result details"),
fieldWithPath("result.content[]").description("The list of content items"),
subsectionWithPath("result.pageable").description("Pagination information"),
fieldWithPath("result.pageable.sort.empty").description("Indicates if the sort is empty"),
fieldWithPath("result.pageable.sort.sorted").description("Indicates if the sort is sorted"),
fieldWithPath("result.pageable.sort.unsorted").description("Indicates if the sort is unsorted"),
fieldWithPath("result.pageable.offset").description("Offset value for pagination"),
fieldWithPath("result.pageable.pageSize").description("Page size for pagination"),
fieldWithPath("result.pageable.pageNumber").description("Page number"),
fieldWithPath("result.pageable.unpaged").description("Indicates if the page is unpaged"),
fieldWithPath("result.pageable.paged").description("Indicates if the page is paged"),
fieldWithPath("result.size").description("The page size"),
fieldWithPath("result.number").description("The current page number"),
fieldWithPath("result.sort.empty").description("Indicates if the sort is empty"),
fieldWithPath("result.sort.sorted").description("Indicates if the sort is sorted"),
fieldWithPath("result.sort.unsorted").description("Indicates if the sort is unsorted"),
fieldWithPath("result.first").description("Indicates if this is the first page"),
fieldWithPath("result.last").description("Indicates if this is the last page"),
fieldWithPath("result.numberOfElements").description("Number of elements in the current page"),
fieldWithPath("result.empty").description("Indicates if the content is empty"),
fieldWithPath("resultCode").description("The result code of the response"),
fieldWithPath("resultMsg").description("The result message of the response")
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

외국계 회사군요

Comment on lines +38 to +53

@Autowired
PostService postService;
@Autowired
PostRepository postRepository;
@Autowired
MemberRepository memberRepository;


Long setupPostId1;

Long setupPostId2;
Long setupMemberId2;

Long setupMemberId3;

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

테스트코드도 이쁘게 관리하면 좋을것같아요

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants