글 등록 , 조회 하기

김창모·2023년 6월 3일
0

SpringBoot

목록 보기
16/19

Intro

이제 우리는 회원가입과 로그인을 할수 있다.
로그인한 유저는 GUEST -> USER 로 등업 신청을 할수 있으니
글 등록 기능을 만들어보자.

.antMatchers("/post/**")
.hasRole("USER")

SpringSecurityConfig 에 위의 설정을 추가하여
글 등록 관련 기능들은 USER 권한이 있는 유저만 사용할수 있도록 하겠다.

Auditing

현재 우리가 사용하는 Entity 는 Member 와 Post 이다.
이 두가지 Entity 에 대해 공통으로 필요한 로직중 하나는 언제 생성된 정보인가
언제 수정되었는가 등의 데이터가 필요하다.
이 공통된 기능들을 BaseTimeEntity 라는 추상 클래스를 만들어 적용해보자.

package com.hello.hello.domain;

import java.time.LocalDateTime;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseTimeEntity {

    @CreatedDate
    private LocalDateTime createDate;
}

@MappedSuperclass

JPA 매핑 정보를 상속할수 있는 클래스 임을 나타내는 어노테이션이다.
이 클래스를 상속받은 엔티티 클래스들은 해당 클래스의 멤버 변수를 상속받게 된다.

@EntityListeners(AuditingEntityListener.class)

해당 클래스에 JPA 엔티티 리스너를 등록한다.
AuditingEntityListener.class 는 생성일자 등의 감사 정보를 처리하기 위한 리스너이다.

@CreatedDate

해당 필드가 생성일자를 관리하는 필드임을 나타내는 어노테이션이다.
Spring Data Jpa 가 해당 필드에 생성일을 자동으로 주입한다.

Member Entity변경

package com.hello.hello.domain.entity;

import com.hello.hello.domain.Authority;
import com.hello.hello.domain.BaseTimeEntity;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Member extends BaseTimeEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String email;
    private String name;
    private String password;

    @Enumerated(EnumType.STRING)
    @ElementCollection(fetch = FetchType.EAGER)
    private Set<Authority> roles = new HashSet<>();

    @OneToMany(mappedBy = "member",fetch = FetchType.LAZY)
    private List<Post> posts = new ArrayList<>();

    public void updateMember(String email,String name,String password) {
        this.email = email;
        this.name = name;
        this.password = password;
    }

    public void addRole(Set<Authority> roles) {
        this.roles = roles;
    }
}

Post Entity 생성

package com.hello.hello.domain.entity;

import com.hello.hello.domain.BaseTimeEntity;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Post extends BaseTimeEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private String content;

    @ManyToOne(fetch = FetchType.LAZY)
    private Member member;
}

두 Entity 모두 BaseTimeEntity 를 상속하게 하였다.

글 등록하기

Controller

package com.hello.hello.controller;

import com.hello.hello.domain.dto.request.NewPostRequest;
import com.hello.hello.service.PostService;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
public class PostController {

    private final PostService postService;

    @PostMapping("/post")
    public Long newPost(@RequestBody @Valid NewPostRequest newPostRequest, HttpServletRequest httpServletRequest) {
        return postService.save(newPostRequest, httpServletRequest);
    }
}

NewPostRequest

package com.hello.hello.domain.dto.request;

import javax.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
@Builder
@AllArgsConstructor
public class NewPostRequest {
    @NotBlank
    private String title;
    private String content;
}

PostService

package com.hello.hello.service;

import com.hello.hello.domain.dto.request.NewPostRequest;
import com.hello.hello.domain.entity.Member;
import com.hello.hello.domain.entity.Post;
import com.hello.hello.repository.MemberJpaRepository;
import com.hello.hello.repository.PostJpaRepository;
import com.hello.hello.utils.JwtProvider;
import javax.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class PostService {
    private final PostJpaRepository postJpaRepository;
    private final MemberJpaRepository memberJpaRepository;
    private final JwtProvider jwtProvider;

    public Long save(NewPostRequest newPostRequest, HttpServletRequest httpServletRequest) {

        String token = httpServletRequest.getHeader("Authorization");
        String getToken = token.replace("Bearer ", "");

        String memberEmail = jwtProvider.getMember(getToken);

        Member member = memberJpaRepository.findByEmail(memberEmail)
                .orElseThrow(() -> new UsernameNotFoundException(memberEmail + " 유저를 찾을수 없습니다."));

        Post post = Post.builder().title(newPostRequest.getTitle()).content(newPostRequest.getContent()).member(member)
                .build();

        postJpaRepository.save(post);

        return post.getId();
    }
}

실행

로그인 후 등급을 GUEST -> USER 로 등업신청을 하고
Authorization 에 로그인시 발급받은 토큰을 넣어주었다.
"/post" URL로 POST 요청을 보냈더니 원하는대로 POST 가 저장되었고
POST 의 ID 를 전달받았다.

글 조회하기

Init

글 조회를 하기 전에 필요한 데이터를 미리 넣어놓았다.

package com.hello.hello.service;

import com.hello.hello.domain.Authority;
import com.hello.hello.domain.entity.Member;
import com.hello.hello.domain.entity.Post;
import com.hello.hello.repository.MemberJpaRepository;
import com.hello.hello.repository.PostJpaRepository;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
@Slf4j
public class InitService {

    private final MemberJpaRepository memberJpaRepository;
    private final PostJpaRepository postJpaRepository;
    private final PasswordEncoder passwordEncoder;

    @PostConstruct
    @Transactional
    public void init() {
        memberInit();
        postInit();
    }

    public void memberInit() {
        for (int i = 0; i < 3; i++) {
            Set<Authority> roles = new HashSet<>();
            roles.add(Authority.ROLE_USER);

            Member member = Member.builder().email("test" + i + "@gmail.com").name("tester" + i).password(
                            passwordEncoder.encode("123123"))
                    .build();

            member.addRole(roles);

            memberJpaRepository.save(member);

        }
    }

    public void postInit() {
        for (int i = 0; i < 3; i++) {
            postJpaRepository.save(Post.builder().title("title").content("content")
                    .member(memberJpaRepository.findByEmail("test"+i+"@gmail.com")
                            .orElseThrow(() -> new UsernameNotFoundException("유저를 찾을수 없습니다.")))
                    .build());
        }
    }
}

전체 조회

Controller

    @GetMapping("/post")
    public List<PostResponse> allPost() {
        return postService.findAll();
    }

Service

    public List<PostResponse> findAll() {

        return postJpaRepository.findAll().stream()
                .map(p -> PostResponse.builder().id(p.getId()).title(p.getTitle()).content(p.getContent()).author(p.getMember().getEmail()).build())
                .collect(
                        Collectors.toList());
    }

실행

test0 , test1 , test2 셋중 하나의 이메일로 로그인 하여 토큰정보를 획득한후
이 토큰을 Authorization 에 추가해준후 "/post" URL 로 Get 요청을 보냈다.

세건의 게시글이 정상적으로 조회되는걸 확인하였다.

단건 조회

단건조회를 하기 위해서는 글의 유니크한 부분이 존재해야 하며
ID를 이용하여 조회해 보겠다.

Controller

    @GetMapping("/post/{id}")
    public PostResponse findOnePost(@PathVariable Long id) {
        return postService.findOne(id);
    }

Service

    public PostResponse findOne(Long id) {

        return new PostResponse(postJpaRepository.findById(id).orElseThrow(RuntimeException::new));
    }

PostResponse Add

    public PostResponse(Post post) {
        this.id = post.getId();
        this.title = post.getTitle();
        this.content = post.getContent();
        this.author = post.getMember().getEmail();
    }

실행

로그인 후 Authorization 입력을 해주고 "/post/2" URL로 GET 요청을 보냈다.
(ID 가 2 인 Post 를 조회해줘)
ID 가 2 인 Post 의 정보가 잘 전송되었다.

0개의 댓글