Rental Application (React & Spring boot Microservice) - 31 : 게시글(4)

yellow_note·2021년 9월 16일
0

#1 게시글 리스트

게시글 리스트 ui를 마무리하도록 하겠습니다. 우선 더미데이터를 활용해서 게시글을 불러왔을 때 게시판이 어떻게 되는지 확인해보도록 하겠습니다.

  • ./src/components/posts/PostListTemplate.js
import React from 'react';
import styled from 'styled-components';
import palette from '../../lib/styles/palettes';
import { withRouter } from 'react-router';
import PostHeader from './PostHeader';
import PostCard from './PostCard';

const PostListTemplateBlock = styled.div`
    background: ${ palette.gray[2] };
    padding-top: 30px;
    display: flex;
    flex-direction: center;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
`;

const PostListTemplate = ({ history }) => {
    const dummyData = [
        { "images": ["https://picsum.photos/id/0/1000/1000.jpg"], "title": "test-01", "nickname": "test-01", createdAt: "2020-01-01" },
        { "images": ["https://picsum.photos/id/1/1000/1000.jpg"], "title": "test-01", "nickname": "test-01", createdAt: "2020-01-01" },
        { "images": ["https://picsum.photos/id/2/1000/1000.jpg"], "title": "test-01", "nickname": "test-01", createdAt: "2020-01-01" },
        { "images": ["https://picsum.photos/id/3/1000/1000.jpg"], "title": "test-01", "nickname": "test-01", createdAt: "2020-01-01" },
        { "images": ["https://picsum.photos/id/4/1000/1000.jpg"], "title": "test-01", "nickname": "test-01", createdAt: "2020-01-01" },
        { "images": ["https://picsum.photos/id/5/1000/1000.jpg"], "title": "test-01", "nickname": "test-01", createdAt: "2020-01-01" },
        { "images": ["https://picsum.photos/id/6/1000/1000.jpg"], "title": "test-01", "nickname": "test-01", createdAt: "2020-01-01" },
        { "images": ["https://picsum.photos/id/7/1000/1000.jpg"], "title": "test-01", "nickname": "test-01", createdAt: "2020-01-01" },
        { "images": ["https://picsum.photos/id/8/1000/1000.jpg"], "title": "test-01", "nickname": "test-01", createdAt: "2020-01-01" },
    ];
    
    return(
        <>
            <PostHeader />
            <PostListTemplateBlock>
                {
                    dummyData.map((item, i) => {
                        return  <PostCard item={ item }
                                          i={ i }
                                />
                    })
                }
            </PostListTemplateBlock>
        </>
    );
};

export default withRouter(PostListTemplate);
  • ./src/components/posts/PostCard.js
import React from 'react';
import styled from 'styled-components';
import { Link } from 'react-router-dom';
import palette from '../../lib/styles/palettes';

const PostCardBlock = styled.div`
    background-color: white;
    width: 400px;
    height: 300px;
    margin: 20px;
    box-shadow: 0px 0px 2px 1px rgba(0, 0, 0, 0.1);
    border-radius: 10px;
`;

const CardTitle = styled.div`
    float: left;
    width: 400px;
    height: 50px;
    overflow: hidden;
    text-align: left;
    padding-top: 10px;
    padding-left: 10px;
`;

const CardImage = styled.img`
    float: left;
    width: 400px;
    height: 200px;
`;

const CardNickname = styled.div`
    float: left;
    width: 300px;
    text-align: left;
    padding-left: 10px;
`;

const CardDate = styled.div`
    float: left;
    width: 90px;
    color: ${ palette.gray[6] }
`;

const PostCard = ({ item, i }) => {
    return(
        <Link to={ `/posts/post/${item.postId}` }>
            <PostCardBlock>
                <CardImage 
                    src={ item.images[0] }
                />
                <CardTitle>
                    { item.title }
                </CardTitle>
                <CardNickname>
                    { item.nickname }
                </CardNickname>
                <CardDate>
                    { item.createdAt }
                </CardDate>
            </PostCardBlock>
        </Link>
    );
};

export default PostCard;


화면의 크기에 따라 가변적으로 열의 갯수가 잘 변하고, 포스트 카드 또한 잘 나오는 모습을 볼 수 있습니다. 그러면 리스트 상단에 분류 탭을 만들어 보도록 하겠습니다.

  • ./src/components/posts/PostHeader.js
import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import Select from 'react-select';
import styled from 'styled-components';
import palette from '../../lib/styles/palettes';

const HeaderBlock = styled.div`
    display: flex;
    padding: 40px;
    align-items: center;
    justify-content: center;
`;

const ButtonBlock = styled.div`
    disflay: flex;
    width: 40%;
    justify-content: flex-start;
`;

const BorderButton = styled.button`
    width: 100px;
    height: 50px;
    border-radius: 30px;
    border: 2px solid ${palette.blue[1]};
    color: ${palette.blue[1]};
    background-color: white;
    font-size: 20px;
    font-weight: bold;
`;

const ClassificationBlock = styled.div`
    display: flex;
    width: 40%;
    justify-content: flex-end;
    align-items: center;
`;

const StyledClassification = styled(Select)`
    width: 200px;
`;

const PostHeader = () => {
    const [option, setOption] = useState('');
    const options = [
        { value: 'ALL', label: '전체' },
        { value: 'REQUEST_RENTAL', label: '요청글' },
        { value: 'READY_RENTAL', label: '대여 가능' }
    ];

    const onSelect = (value) => {
        setOption(value);
    };

    return(
        <HeaderBlock>
            <ButtonBlock>
                <BorderButton>
                    <Link to="/posts/write">
                        글쓰기
                    </Link>
                </BorderButton>
            </ButtonBlock>
            <ClassificationBlock>
                <StyledClassification onChange={ onSelect }
                                      options={ options }
                                      value={ option }
                                      placeholder="분류"
                />
            </ClassificationBlock>
        </HeaderBlock>
    );
};

export default PostHeader;

PostHeader컴포넌트를 위와 같이 수정했습니다. 분류탭의 경우 해당 컴포넌트에서만 사용하면되므로 리덕스 모듈을 만들어 state에 저장하는 방법은 사용하지 않도록 하겠습니다.

post-service와 게시글을 불러오는 부분은 우선 글쓰기에 대한 post-service연결을 진행한 후에 구현하도록 하겠습니다.

#2 post-service, 글쓰기 연동

이전에 post-service를 작성하면서 image와 관련된 코드는 주석처리를 했습니다. 다음과 같이 주석처리를 풀어주고, status 케이스에 대한 코드도 추가하도록 하겠습니다.

  • PostController
...

@RestController
@RequestMapping("/")
@Slf4j
public class PostController {
    ...

    @GetMapping("/health_check")
    public String status() {
        return String.format(
        "It's working in Post Service"
            + ", port(local.server.port) =" + env.getProperty("local.server.port")
            + ", port(server.port) =" + env.getProperty("server.port")
        );
    }

    // Using by RequestCreate class, Write Post
    @PostMapping("/write")
    public ResponseEntity<?> write(@ModelAttribute RequestWrite postVo) throws Exception {
        log.info("Post Service's Controller Layer :: Call write Method!");

        PostDto postDto = null;

        if(postVo.getPostType().equals("빌려줄게요")) {
            postDto = PostDto.builder()
                             .postType(postVo.getPostType())
                             .category(postVo.getCategory())
                             .title(postVo.getTitle())
                             .content(postVo.getContent())
                             .startDate(postVo.getDate().get(0))
                             .endDate(postVo.getDate().get(1))
                             .rentalPrice(postVo.getRentalPrice())
                             .writer(postVo.getWriter())
                             .status("READY_RENTAL")
                             .userId(postVo.getUserId())
                             .multipartFiles(postVo.getImages())
                             .build();
        } else {
            postDto = PostDto.builder()
                             .postType(postVo.getPostType())
                             .title(postVo.getTitle())
                             .content(postVo.getContent())
                             .startDate(null)
                             .endDate(null)
                             .rentalPrice(null)
                             .writer(postVo.getWriter())
                             .status("REQUEST_RENTAL")
                             .userId(postVo.getUserId())
                             .multipartFiles(postVo.getImages())
                             .build();
        }

        PostDto post = postService.write(postDto);
        ResponsePost result = ResponsePost.builder()
                                          .id(post.getId())
                                          .postType(post.getPostType())
                                          .category(post.getCategory())
                                          .title(post.getTitle())
                                          .content(post.getContent())
                                          .rentalPrice(post.getRentalPrice())
                                          .startDate(post.getStartDate())
                                          .endDate(post.getEndDate())
                                          .createdAt(post.getCreatedAt())
                                          .writer(post.getWriter())
                                          .userId(post.getUserId())
                                          .images(post.getImages())
                                          .comments(post.getComments())
                                          .status(post.getStatus())
                                          .build();

        return ResponseEntity.status(HttpStatus.CREATED).body(result);
    }

    // Get All Posts
    @GetMapping("/")
    public ResponseEntity<?> getAllPosts() {
        log.info("Post Service's Controller Layer :: Call getAllPosts Method!");

        Iterable<PostDto> postList = postService.getAllPosts();
        List<ResponsePost> result = new ArrayList<>();

        postList.forEach(post -> {
            result.add(
                ResponsePost.builder()
                            .id(post.getId())
                            .postType(post.getPostType())
                            .category(post.getCategory())
                            .title(post.getTitle())
                            .content(post.getContent())
                            .rentalPrice(post.getRentalPrice())
                            .startDate(post.getStartDate())
                            .endDate(post.getEndDate())
                            .createdAt(post.getCreatedAt())
                            .writer(post.getWriter())
                            .userId(post.getUserId())
                            .status(post.getStatus())
                            .images(post.getImages())
                            .comments(post.getComments())
                            .build());
        });

        return ResponseEntity.status(HttpStatus.OK).body(result);
    }

    @GetMapping("/post/{id}")
    public ResponseEntity<?> readPostById(@PathVariable("id") Long id) {
        log.info("Post Service's Controller Layer :: Call readPostById Method!");

        PostDto post = postService.readPostById(id);

        return ResponseEntity.status(HttpStatus.OK).body(ResponsePost.builder()
                                                                     .id(post.getId())
                                                                     .postType(post.getPostType())
                                                                     .category(post.getCategory())
                                                                     .title(post.getTitle())
                                                                     .content(post.getContent())
                                                                     .rentalPrice(post.getRentalPrice())
                                                                     .startDate(post.getStartDate())
                                                                     .endDate(post.getEndDate())
                                                                     .createdAt(post.getCreatedAt())
                                                                     .writer(post.getWriter())
                                                                     .userId(post.getUserId())
                                                                     .images(post.getImages())
                                                                     .comments(post.getComments())
                                                                     .status(post.getStatus())
                                                                     .build());
    }

    @GetMapping("/posts/{status}")
    public ResponseEntity<?> getAllPostsByStatus(@PathVariable("status") String status) {
        log.info("Post Service's Controller Layer :: Call getAllPostsByStatus Method!");

        Iterable<PostDto> postList = postService.getAllPostsByStatus(status);
        List<ResponsePost> result = new ArrayList<>();

        postList.forEach(post -> {
            result.add(ResponsePost.builder()
                                   .id(post.getId())
                                   .postType(post.getPostType())
                                   .category(post.getCategory())
                                   .title(post.getTitle())
                                   .content(post.getContent())
                                   .rentalPrice(post.getRentalPrice())
                                   .startDate(post.getStartDate())
                                   .endDate(post.getEndDate())
                                   .createdAt(post.getCreatedAt())
                                   .writer(post.getWriter())
                                   .userId(post.getUserId())
                                   .status(post.getStatus())
                                   .images(post.getImages())
                                   .comments(post.getComments())
                                   .build());
        });

        return ResponseEntity.status(HttpStatus.OK).body(result);
    }

    @GetMapping("/{userId}/posts")
    public ResponseEntity<?> getPostsByUserId(@PathVariable("userId") String userId) {
        log.info("Post Service's Controller Layer :: Call getPostsByUserId Method!");

        log.info("Before receive post data");

        Iterable<PostDto> postList = postService.getPostsByUserId(userId);
        List<ResponsePost> result = new ArrayList<>();

        postList.forEach(post -> {
            result.add(ResponsePost.builder()
                                   .id(post.getId())
                                   .postType(post.getPostType())
                                   .category(post.getCategory())
                                   .title(post.getTitle())
                                   .content(post.getContent())
                                   .rentalPrice(post.getRentalPrice())
                                   .startDate(post.getStartDate())
                                   .endDate(post.getEndDate())
                                   .createdAt(post.getCreatedAt())
                                   .writer(post.getWriter())
                                   .userId(post.getUserId())
                                   .status(post.getStatus())
                                   .images(post.getImages())
                                   .comments(post.getComments())
                                   .build());
            }
        );

        log.info("After received post data");

        return ResponseEntity.status(HttpStatus.OK).body(result);
    }

    @GetMapping("/posts/keyword/{keyword}")
    public ResponseEntity<?> getPostsByKeyword(@PathVariable("keyword") String keyword) {
        log.info("Post Service's Controller Layer :: Call getPostsByKeyword Method!");

        Iterable<PostDto> postList = postService.getPostsByKeyword(keyword);
        List<ResponsePost> result = new ArrayList<>();

        postList.forEach(post -> {
                result.add(ResponsePost.builder()
                                       .id(post.getId())
                                       .postType(post.getPostType())
                                       .category(post.getCategory())
                                       .title(post.getTitle())
                                       .content(post.getContent())
                                       .rentalPrice(post.getRentalPrice())
                                       .startDate(post.getStartDate())
                                       .endDate(post.getEndDate())
                                       .createdAt(post.getCreatedAt())
                                       .writer(post.getWriter())
                                       .userId(post.getUserId())
                                       .status(post.getStatus())
                                       .images(post.getImages())
                                       .comments(post.getComments())
                                       .build());
               }
        );

        return ResponseEntity.status(HttpStatus.OK).body(result);
    }

    @GetMapping("/posts/category/{category}")
    public ResponseEntity<?> getPostsByCategory(@PathVariable("category") String category) {
        log.info("Post Service's Controller Layer :: Call getPostsByCategory Method!");

        Iterable<PostDto> postList = postService.getPostsByCategory(category);
        List<ResponsePost> result = new ArrayList<>();

        postList.forEach(post -> {
                result.add(ResponsePost.builder()
                                       .id(post.getId())
                                       .postType(post.getPostType())
                                       .category(post.getCategory())
                                       .title(post.getTitle())
                                       .content(post.getContent())
                                       .rentalPrice(post.getRentalPrice())
                                       .startDate(post.getStartDate())
                                       .endDate(post.getEndDate())
                                       .createdAt(post.getCreatedAt())
                                       .writer(post.getWriter())
                                       .userId(post.getUserId())
                                       .status(post.getStatus())
                                       .images(post.getImages())
                                       .comments(post.getComments())
                                       .build());
            }
        );

        return ResponseEntity.status(HttpStatus.OK).body(result);
    }

    @PostMapping("/rental")
    public ResponseEntity<?> rental(@RequestBody RequestRental postVo) {
        log.info("Post Service's Controller Layer :: Call rental Method!");

        kafkaProducer.send("rental-topic", postVo);

        return ResponseEntity.status(HttpStatus.OK).body(postVo);
    }
    
    @PostMapping("/{id}/delete")
    public ResponseEntity<?> deletePost(@PathVariable("id") Long id) {
        log.info("Post Service's Controller Layer :: Call deletePost Method!");

        return ResponseEntity.status(HttpStatus.OK).body(postService.deletePost(id));
    }

    ...
}

수정한 메서드 위주로 살펴 보겠습니다.

1) write : formData에 데이터를 담아 요청할 경우 RequestBody타입으로 데이터를 받을 수 없으니 ModelAttribute로 변경했습니다. 그리고 게시글 타입에 따라 status의 값을 달리 했습니다. 빌려줄게요의 경우 대여를 위한 글이므로 READY_RENTAL을, 빌려주세요의 경우 대여 요청을 위한 글이므로 REQUEST_RENTAL이란 상태값을 부여했습니다.

  • PostServiceImpl
...

@Service
@Slf4j
public class PostServiceImpl implements PostService {
    ...

    @Transactional
    @Override
    public PostDto write(PostDto postDto) throws Exception {
        log.info("Post Service's Service Layer :: Call write Method!");

        PostEntity postEntity = PostEntity.builder()
                                          .postType(postDto.getPostType())
                                          .category(postDto.getCategory())
                                          .rentalPrice(postDto.getRentalPrice())
                                          .title(postDto.getTitle())
                                          .content(postDto.getContent())
                                          .startDate(postDto.getStartDate())
                                          .endDate(postDto.getEndDate())
                                          .writer(postDto.getWriter())
                                          .userId(postDto.getUserId())
                                          .createdAt(DateUtil.dateNow())
                                          .status(postDto.getStatus())
                                          .build();
        List<ImageEntity> images = FileUploader.parseFileInfo(
            postDto.getMultipartFiles(),
            postEntity
        );

        postRepository.save(postEntity);
        
        if(!images.isEmpty()) {
            for(ImageEntity image: images) {
                postEntity.addImage(imageRepository.save(image));
            }
        }

        return PostDto.builder()
                      .id(postEntity.getId())
                      .userId(postEntity.getUserId())
                      .postType(postEntity.getPostType())
                      .category(postEntity.getCategory())
                      .rentalPrice(postEntity.getRentalPrice())
                      .title(postEntity.getTitle())
                      .content(postEntity.getContent())
                      .startDate(postEntity.getStartDate())
                      .endDate(postEntity.getEndDate())
                      .createdAt(postEntity.getCreatedAt())
                      .writer(postEntity.getWriter())
                      .images(images)
                      .build();
    }

    @Transactional
    @Override
    public PostDto readPostById(Long id) {
        log.info("Post Service's Service Layer :: Call readPostById Method!");

        PostEntity postEntity = postRepository.findPostById(id);
        List<ImageEntity> images = new ArrayList<>();
        List<CommentEntity> comments = new ArrayList<>();

        postEntity.getImages().forEach(i -> {
            images.add(i);
        });

        postEntity.getComments().forEach(i -> {
            comments.add(CommentEntity.builder()
                                      .id(i.getId())
                                      .comment(i.getComment())
                                      .writer(i.getWriter())
                                      .createdAt(i.getCreatedAt())
                                      .build());
        });

        return PostDto.builder()
                      .userId(postEntity.getUserId())
                      .postType(postEntity.getPostType())
                      .category(postEntity.getCategory())
                      .rentalPrice(postEntity.getRentalPrice())
                      .title(postEntity.getTitle())
                      .content(postEntity.getContent())
                      .startDate(postEntity.getStartDate())
                      .endDate(postEntity.getEndDate())
                      .createdAt(postEntity.getCreatedAt())
                      .writer(postEntity.getWriter())
                      .images(images)
                      .comments(comments)
                      .status(postEntity.getStatus())
                      .build();
    }

    @Transactional
    @Override
    public List<PostDto> getAllPosts() {
        log.info("Post Service's Service Layer :: Call getAllPosts Method!");

        List<String> exceptList = new ArrayList<>();

        exceptList.add("COMPLETE_RENTAL");
        exceptList.add("DELETE_POST");

        Iterable<PostEntity> posts = postRepository.findAllByStatusNotIn(exceptList);
        List<PostDto> postList = new ArrayList<>();

        posts.forEach(v -> {
            List<CommentEntity> comments = new ArrayList<>();

            v.getComments().forEach(i -> {
                comments.add(CommentEntity.builder()
                                          .id(i.getId())
                                          .comment(i.getComment())
                                          .writer(i.getWriter())
                                          .createdAt(i.getCreatedAt())
                                          .build());
            });

            postList.add(PostDto.builder()
                                .userId(v.getUserId())
                                .postType(v.getPostType())
                                .category(v.getCategory())
                                .rentalPrice(v.getRentalPrice())
                                .title(v.getTitle())
                                .content(v.getContent())
                                .startDate(v.getStartDate())
                                .endDate(v.getEndDate())
                                .createdAt(v.getCreatedAt())
                                .writer(v.getWriter())
                                .images(v.getImages())
                                .comments(comments)
                                .status(v.getStatus())
                                .build());
        });

        return postList;
    }

    @Transactional
    @Override
    public Iterable<PostDto> getAllPostsByStatus(String status) {
        log.info("Post Service's Service Layer :: Call getAllPostsByStatus Method!");

        Iterable<PostEntity> posts = postRepository.findAllByStatus(status);
        List<PostDto> postList = new ArrayList<>();

        posts.forEach(v -> {
            List<CommentEntity> comments = new ArrayList<>();

            v.getComments().forEach(i -> {
                comments.add(CommentEntity.builder()
                                          .id(i.getId())
                                          .comment(i.getComment())
                                          .writer(i.getWriter())
                                          .createdAt(i.getCreatedAt())
                                          .build());
            });

            postList.add(PostDto.builder()
                                .userId(v.getUserId())
                                .postType(v.getPostType())
                                .category(v.getCategory())
                                .rentalPrice(v.getRentalPrice())
                                .title(v.getTitle())
                                .content(v.getContent())
                                .startDate(v.getStartDate())
                                .endDate(v.getEndDate())
                                .createdAt(v.getCreatedAt())
                                .writer(v.getWriter())
                                .images(v.getImages())
                                .comments(comments)
                                .status(v.getStatus())
                                .build());
        });

        return postList;
    }

    @Transactional
    @Override
    public List<PostDto> getPostsByUserId(String userId) {
        log.info("Post Service's Service Layer :: Call getPostsByUserId Method!");

        Iterable<PostEntity> posts = postRepository.findAllByUserId(userId);
        List<PostDto> postList = new ArrayList<>();

        posts.forEach(v -> {
            List<CommentEntity> comments = new ArrayList<>();

            v.getComments().forEach(i -> {
                comments.add(CommentEntity.builder()
                                          .id(i.getId())
                                          .comment(i.getComment())
                                          .writer(i.getWriter())
                                          .createdAt(i.getCreatedAt())
                                          .build());
            });

            postList.add(PostDto.builder()
                                .userId(v.getUserId())
                                .postType(v.getPostType())
                                .category(v.getCategory())
                                .rentalPrice(v.getRentalPrice())
                                .title(v.getTitle())
                                .content(v.getContent())
                                .startDate(v.getStartDate())
                                .endDate(v.getEndDate())
                                .createdAt(v.getCreatedAt())
                                .writer(v.getWriter())
                                .images(v.getImages())
                                .comments(comments)
                                .status(v.getStatus())
                                .build());
        });

        return postList;
    }

    @Transactional
    @Override
    public PostDto deletePost(Long id) {
        log.info("Post Service's Service Layer :: Call deletePost Method!");

        PostEntity postEntity = postRepository.findPostById(id);

        postEntity.setStatus("DELETE_POST");

        postRepository.save(postEntity);

        return PostDto.builder()
                      .id(postEntity.getId())
                      .status(postEntity.getStatus())
                      .build();
    }

    @Transactional
    @Override
    public Iterable<PostDto> getPostsByKeyword(String keyword) {
        log.info("Post Service's Service Layer :: Call getPostsByKeyword Method!");

        Iterable<PostEntity> posts = postRepository.findByKeywordLike(keyword);
        List<PostDto> postList = new ArrayList<>();

        posts.forEach(v -> {
            List<CommentEntity> comments = new ArrayList<>();

            v.getComments().forEach(i -> {
                comments.add(CommentEntity.builder()
                                          .id(i.getId())
                                          .comment(i.getComment())
                                          .writer(i.getWriter())
                                          .createdAt(i.getCreatedAt())
                                          .build());
            });

            postList.add(PostDto.builder()
                                .userId(v.getUserId())
                                .postType(v.getPostType())
                                .category(v.getCategory())
                                .rentalPrice(v.getRentalPrice())
                                .title(v.getTitle())
                                .content(v.getContent())
                                .startDate(v.getStartDate())
                                .endDate(v.getEndDate())
                                .createdAt(v.getCreatedAt())
                                .writer(v.getWriter())
                                .images(v.getImages())
                                .comments(comments)
                                .status(v.getStatus())
                                .build());
        });

        return postList;
    }

    @Transactional
    @Override
    public Iterable<PostDto> getPostsByCategory(String category) {
        log.info("Post Service's Service Layer :: Call getPostsByCategory Method!");

        Iterable<PostEntity> posts = postRepository.findAllByCategory(category);
        List<PostDto> postList = new ArrayList<>();

        posts.forEach(v -> {
            List<CommentEntity> comments = new ArrayList<>();

            v.getComments().forEach(i -> {
                comments.add(CommentEntity.builder()
                                          .id(i.getId())
                                          .comment(i.getComment())
                                          .writer(i.getWriter())
                                          .createdAt(i.getCreatedAt())
                                          .build());
            });

            postList.add(PostDto.builder()
                                .userId(v.getUserId())
                                .postType(v.getPostType())
                                .category(v.getCategory())
                                .rentalPrice(v.getRentalPrice())
                                .title(v.getTitle())
                                .content(v.getContent())
                                .startDate(v.getStartDate())
                                .endDate(v.getEndDate())
                                .createdAt(v.getCreatedAt())
                                .writer(v.getWriter())
                                .images(v.getImages())
                                .comments(comments)
                                .status(v.getStatus())
                                .build());
        });

        return postList;
    }
}

1) getAllPosts : exceptList라는 ArrayList에 제외시킬 상태값을 담아 이 값들을 제외한 게시글들을 findAllByStatusNotIn으로 불러오게 수정하였습니다.

2) getPostsByKeyword : keyword를 매개로 해당 키워드가 들어가는 글들을 모두 불러오게끔 findByKeywordLike메서드를 사용하였습니다.

3) getPostsByCategory : getAllPosts와 마찬가지로 카테고리를 클릭하면 카테고리에 해당하는 글이면서 예외 리스트에 해당하는 상태값들은 제외한 글들을 불러오도록 수정하였습니다.

  • PostRepository
package com.microservices.postservice.repository;

import com.microservices.postservice.entity.PostEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.ArrayList;
import java.util.List;

public interface PostRepository extends JpaRepository<PostEntity, Long> {
    Iterable<PostEntity> findAllByStatus(String status);

    Iterable<PostEntity> findAllByUserId(String userId);

    PostEntity findPostById(Long id);

    @Query(
        value="SELECT * " +
              "FROM posts " +
              "LIKE '%' + :keyword + '%' ",
        nativeQuery = true
    )
    Iterable<PostEntity> findByKeywordLike(String s);

    @Query(
        value="SELECT * " +
              "FROM posts p " +
              "WHERE p.category = :category " +
              "NOT IN(:exceptList.get(0), :exceptList().get(1))",
        nativeQuery = true
    )
    Iterable<PostEntity> findAllByCategory(
        String category,
        ArrayList<String> exceptList
    );

    Iterable<PostEntity> findAllByStatusNotIn(List<String> exceptList);
}

1) findAllByCategory : 직접 쿼리를 만들어 조건에 맞는 데이터를 불러올 수 있게 하였습니다.

어느 정도 post-service가 마무리 된 것 같으니 post-service데이터베이스를 create옵션으로 초기화시키고, 서버를 구동시켜 연동이 잘 되는지 글쓰기를 진행하도록 하겠습니다.

#3 중간 테스트

  • 테스트 하기전에 post-service의 vo객체인 RequestWrite에 @Setter 어노테이션을 추가해주도록 하겠습니다. 이유는 @Setter어노테이션이 없으면 ModelAttribute에 데이터가 매핑이 되지않는 오류가 생기기 때문입니다.

  • Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) 게시글 등록 중 다음과 같은 에러가 나타났습니다. Infinite recursion 예전에도 접했던 양방향 매핑에 대한 문제입니다. 당시 오류는 응답의 경우 였는데 한쪽에서 데이터 참조를 끊어서 양방향 매핑을 해결했었습니다. 하지만 이번에는 요청을 하는 중 데이터가 양방향으로 매핑이 되는 오류인 것 같습니다.
    다음의 방법으로 양방향 매핑 문제를 해결했습니다.

  • PostEntity
@OneToMany(
    fetch = FetchType.LAZY,
    mappedBy = "post",
    cascade = { CascadeType.PERSIST, CascadeType.REMOVE },
    orphanRemoval = true
)
@JsonManagedReference
private List<ImageEntity> images = new ArrayList<>();

@OneToMany(
    fetch = FetchType.LAZY,
    mappedBy = "post",
    cascade = { CascadeType.PERSIST, CascadeType.REMOVE },
    orphanRemoval = true
)
@JsonManagedReference
private List<CommentEntity> comments = new ArrayList<>();
  • CommentEntity
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name="post_id")
@JsonBackReference
private PostEntity post;
  • ImageEntity
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name="post_id")
@JsonBackReference
private PostEntity post;

@JsonManagedReference : 양방향 관계에서 참조할 변수에 달아주면 변수가 직렬화에 포함됩니다.
@JsonBackReference : 양방햔 관계에서 직렬화에서 제외됩니다.

직렬화란 객체에 저장된 데이터를 I/O 스트림에 쓰기 위해 연속적인 데이터로 변환하는 것입니다. 즉, JsonManagedReference를 이용해 comment, image를 I/O 스트림에 쓸 수 있는 것이고, JsonBackReference를 이용해 직렬화에서 제외되므로 I/O 스트림에 포함되지 않기 때문에 양방향 매핑이 해결되는 것입니다.

그러면 이를 바탕으로 테스트를 마저 진행하겠습니다.

  • post-service
Hibernate: 
    /* insert com.microservices.postservice.entity.PostEntity
        */ insert 
        into
            posts
            (category, content, created_at, end_date, post_type, rental_price, start_date, status, title, user_id, writer) 
        values
            (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: 
    /* insert com.microservices.postservice.entity.ImageEntity
        */ insert 
        into
            images
            (file_name, file_path, file_size, org_filename, post_id) 
        values
            (?, ?, ?, ?, ?)



데이터가 잘 저장되는 모습을 볼 수 있습니다. 글쓰기를 이용해 데이터를 9개 정도 추가시키고 다음 포스트에서는 이 게시글 리스트를 불러오도록 하겠습니다.

참고

0개의 댓글

관련 채용 정보