[Spring Boot] 게시판 CRUD 구현 - REST API (access token 이용)

sy·2022년 11월 22일
0

Spring Boot

목록 보기
2/3

Spring Boot 2.7.5
Java 17
MySQL 8.0

프로젝트 구조

-- controller
  ⌞ PostController.java
-- domain
  ⌞ Post.java
-- dto
  - request
   ⌞ PostRequestDto.java
  - response
   ⌞ PostResponseDto.java
-- repository
  ⌞ PostRepository.java
-- service
  ⌞ PostService.java

1. Setting

- Post.java

post 테이블의 컬럼을 추가합니다.
dto에서 builder를 사용하기 위해 builder 추가하였습니다.
builder 추가 시 @NoArgsConstructor @AllArgsConstructor 필요

@Getter
@Setter
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Post extends BaseTimeEntity {
    @Id
    @GeneratedValue
    @Column(name = "post_id")
    private Integer id;

    @ManyToOne
    @JoinColumn(name="member_id", nullable = false, updatable = false)
    private Member member;
    
    @Column(columnDefinition = "TEXT")
    private String content;

    
}

- PostRepository.java

public interface PostRepository extends JpaRepository<Post, Integer> {
}

2. Create (게시글 작성)

게시글 쓰기를 위해 PostRequestDto.java를 작성합니다.

- PostRequestDto.java

@NoArgsConstructor
@Getter
@Setter
@ToString
public class PostRequestDto {

    private String content;
    private Member member;

    @Builder
    public PostRequestDto(String content, Member member) {
        this.content = content;
        this.member = member;
    }

    public Post toEntity() {
        return Post.builder()
                .content(content)
                .member(member)
                .build();
    }
    
}

프론트에서 요청이 왔을 때 처리할 기능을 controller에 작성합니다.
저번 시간에 만든 SecurityUser를 이용하여 게시글을 작성한 Member를 저장합니다.

- PostController.java

@RequiredArgsConstructor
@RestController
@RequestMapping("/api/post")
public class PostController {

	private final PostService postService;
    
    @PostMapping(value = "/create")
    public String create(@RequestBody PostRequestDto requestDto, @AuthenticationPrincipal SecurityUser principal) {
    	// 프론트에서 받은 토큰으로 Member 구분함
    	requestDto.setMember(principal.getMember());
        Post post = postService.save(requestDto);
        
        return "success";
    }

}

- PostService.java

@RequiredArgsConstructor
@Service
public class PostService {
	private final PostRepository postRepository;
    
    // create
    @Transactional
    public Post save(PostRequestDto requestDto) {
        return postRepository.save(requestDto.toEntity());
    }

}

Headers에 access token 을 넣어주고

Body에 데이터를 작성해주면 게시글 쓰기가 완료됩니다.

3. READ (게시글 읽기)

  • 게시글 리스트 보기와 상세 보기
  • 게시글을 보여주기 위해 PostResponseDto 작성

List (게시글 리스트)

- PostResponseDto.java

@Getter
@ToString
public class PostResponseDto {
    private Integer id;
    private String content;
    private String nickname;
    private String profilePath;
    private String createdAt;
    
    public PostResponseDto(Post entity) {
        this.id = entity.getId();
        this.nickname = entity.getMember().getNickname();
        this.profilePath = entity.getMember().getProfilePath();
        this.content = entity.getContent();
        this.createdAt = entity.getCreated_at().format(DateTimeFormatter.ofPattern("yyyy.MM.dd"));
    }
}

글을 작성한 유저의 모든 정보가 필요하지는 않기 때문에 닉네임만 보여주기 위해서 entity.getMember().getNickname(); 작성하였습니다.

작성일을 yyyy.MM.dd 로 표현하기 위해 format(DateTimeFormatter.ofPattern("yyyy.MM.dd")); 작성하였습니다.

- PostService.java

public List<PostResponseDto> list(Member member, String nickname) {
        List<Post> posts = postRepository.findAll();
        List<PostResponseDto> postList = new ArrayList<>();

        for (Post post : posts) {
            PostResponseDto postResponseDto = new PostResponseDto(post);
            postList.add(postResponseDto);
        }
        
        return postList;
}

프론트에 보여줄 내용만 PostResponseDto 에 정리했으므로 PostService 에서 ArrayList를 만들어 담아줍니다. 다음에 postList에 댓글 수, 좋아요 수를 담을 예정입니다.

- PostController.java

public class PostController {

    private final PostService postService;
    
	@GetMapping()
    public List<PostResponseDto> list(@AuthenticationPrincipal SecurityUser principal ,@RequestParam(value = "nickname", required=false) String nickname) {
        return postService.list(principal.getMember(), nickname);
    }
}

PostController 에서 PostService로 보내줍니다.

Get (게시글 상세 조회)

게시글 리스트와 게시글 상세 조회를 했을 때 보여지는 데이터가 같다면 위에서 사용했던 PostResponseDto를 사용하고 다르다면 새로 만들어줍니다.
현재는 동일한 데이터를 보여줄 것이므로 PostResponseDto를 사용하겠습니다.
(다음에 댓글 목록을 추가하여 보여줄 때는 분리할 예정)

- PostService.java

@RequiredArgsConstructor
@Service
public class PostService {
	public PostDetailResponseDto find(Member member, Integer id) {
        Post post = postRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("해당 게시글이 없습니다."));
        PostDetailResponseDto postDetailResponseDto = new PostDetailResponseDto(post);
	}
}

- PostController.java

@RequiredArgsConstructor
@RestController
@RequestMapping("/api/post")
public class PostController {
@GetMapping("/{id}")
    public PostDetailResponseDto get(@AuthenticationPrincipal SecurityUser principal, @PathVariable Integer id) {
        return postService.find(principal.getMember(), id);
    }
}

4. Update (게시글 수정)

게시글을 수정하기 위해 domain/Post.java에 아래의 코드를 추가합니다.

- Post.java

public class Post extends BaseTimeEntity {
	
    ... (생략)
    
	public void update(String content) {
        this.content = content;
    }
}

수정할 때 content만 수정 가능하도록 할 것이기 때문에 content만 추가하였습니다.

- PostService.java

public class PostService {
	@Transactional
    public String update(Integer id, PostRequestDto requestDto) {
        String message = "fail";
        Post post = postRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("해당 게시글이 없습니다."));

        // 작성자만 수정 가능 
        if (postRepository.findById(id).get().getMember().getId().equals(requestDto.getMember().getId())) {
            post.update(requestDto.getContent());
            message = "success";
        } 

        return message;

    }
}

- PostController.java

public class PostController {
	@PutMapping("{id}/update")
    public String update(@PathVariable Integer id, @RequestBody PostRequestDto requestDto, @AuthenticationPrincipal SecurityUser principal) {
        requestDto.setMember(principal.getMember());
        return postService.update(id, requestDto);
    }
}

5. Delete (게시글 삭제)

- PostService.java

public class PostService {
	@Transactional
    public String delete(Integer id, Member member) {
        String message = "fail";
        Post post = postRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("해당 게시글이 없습니다."));
        
        if (post.getMember().getId().equals(member.getId())) { // 작성자만 삭제 가능
            postRepository.delete(post);
            message = "success";
        }

        return message;
        
    }
}

- PostController.java

public class PostController {

    public String delete(@PathVariable Integer id, @AuthenticationPrincipal SecurityUser principal) {
        return postService.delete(id, principal.getMember());
    }
}

0개의 댓글