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

[7회차] 1:N 관계 #14

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions src/main/java/com/jscode/board/controller/BoardController.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.jscode.board.controller;

import com.jscode.board.dto.board.BoardAndCommentsDto;
import com.jscode.board.dto.board.BoardRequest;
import com.jscode.board.dto.board.BoardResponse;
import com.jscode.board.exception.response.ExceptionResponse;
Expand Down Expand Up @@ -33,7 +34,7 @@ public class BoardController {
@ApiResponse(code = 400, message = "유효하지 않은 입력입니다.", response = ExceptionResponse.class)
})
public ResponseEntity<BoardResponse> boardAdd(@ApiParam(value = "요청 dto")
@Valid @RequestBody BoardRequest boardRequest){
@Valid @RequestBody BoardRequest boardRequest){
BoardResponse response = boardService.saveBoard(boardRequest);
return ResponseEntity.status(HttpStatus.CREATED).body(response);
}
Expand Down Expand Up @@ -64,9 +65,9 @@ public ResponseEntity<List<BoardResponse>> boardListByKeyword(@ApiParam(value =
@ApiResponse(code = 200, message = "조회 성공", response = BoardResponse.class),
@ApiResponse(code = 404, message = "게시글이 존재하지 않습니다.", response = FieldExceptionResponse.class)
})
public ResponseEntity<BoardResponse> boardDetails(@ApiParam(value = "게시글 id 명", example = "13")
@PathVariable(value = "boardId") Long id){
BoardResponse response = boardService.findBoardById(id);
public ResponseEntity<BoardAndCommentsDto> boardDetails(@ApiParam(value = "게시글 id 명", example = "13")
@PathVariable Long id){
BoardAndCommentsDto response = boardService.findBoardById(id);
return ResponseEntity.ok(response);
}

Expand All @@ -77,7 +78,7 @@ public ResponseEntity<BoardResponse> boardDetails(@ApiParam(value = "게시글 i
@ApiResponse(code = 400, message = "유효하지 않은 입력입니다.", response = FieldExceptionResponse.class)
})
public ResponseEntity<BoardResponse> boardModify(@ApiParam(value = "게시글 id 명", example = "13")
@PathVariable(value = "boardId") Long id,
@PathVariable Long id,
@Valid @RequestBody BoardRequest boardRequest){
BoardResponse response = boardService.updateBoard(id, boardRequest);
return ResponseEntity.ok(response);
Expand All @@ -90,7 +91,7 @@ public ResponseEntity<BoardResponse> boardModify(@ApiParam(value = "게시글 id
@ApiResponse(code = 404, message = "게시글이 존재하지 않습니다.", response = FieldExceptionResponse.class)
})
public ResponseEntity<Long> boardRemove(@ApiParam(value = "게시글 id 명", example = "13")
@PathVariable(value = "boardId") Long id){
@PathVariable Long id){
Long deletedId = boardService.deleteBoard(id);
return ResponseEntity.ok(deletedId);
}
Expand Down
22 changes: 22 additions & 0 deletions src/main/java/com/jscode/board/controller/CommentController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.jscode.board.controller;

import com.jscode.board.dto.comment.CommentDto;
import com.jscode.board.service.CommentService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequiredArgsConstructor
@RequestMapping("/boards/{boardId}/comments")
public class CommentController {

private final CommentService commentService;

@PostMapping
public ResponseEntity<Long> commentAdd(@PathVariable Long boardId, @RequestBody CommentDto commentDto) {
Long id = commentService.saveComment(boardId, commentDto);
return ResponseEntity.status(HttpStatus.CREATED).body(id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ public class MemberController {
private final MemberService memberService;

@GetMapping("/info")
public ResponseEntity<MemberResponse> Info(@RequestHeader("Authorization") String token) {
MemberResponse response = memberService.findMemberInfo(token.substring(7));
public ResponseEntity<MemberResponse> Info() {
MemberResponse response = memberService.findMemberInfo();
return ResponseEntity.ok(response);
}
}
3 changes: 2 additions & 1 deletion src/main/java/com/jscode/board/domain/Board.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ public class Board extends BaseEntity {
private Member member;

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

public void updateTitle(String title){
Expand Down
17 changes: 16 additions & 1 deletion src/main/java/com/jscode/board/domain/Comment.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
package com.jscode.board.domain;

import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Entity
public class Comment {
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class Comment extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Lob
private String content;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "board_id")
private Board board;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
private Member member;

Copy link

Choose a reason for hiding this comment

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

작성하신 Comment 기능 관련 코드들 잘 작성하셨습니다!! 특히 사용자 인증의 경우 제 방법보다 더 깔끔하게 작성하셔서 배워갑니다!!

@Builder
public Comment(String content, Board board, Member member) {
this.content = content;
this.board = board;
this.member = member;
}
}
41 changes: 41 additions & 0 deletions src/main/java/com/jscode/board/dto/board/BoardAndCommentsDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.jscode.board.dto.board;

import com.jscode.board.domain.Board;
import com.jscode.board.domain.Comment;
import com.jscode.board.dto.comment.CommentDto;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

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

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class BoardAndCommentsDto {

private Long id;
private String title;
private String content;
private LocalDateTime createdDate;
private List<CommentDto> comments;

@Builder
public static BoardAndCommentsDto from(Board board, List<Comment> comments){
BoardAndCommentsDto boardAndCommentsDto = new BoardAndCommentsDto();
boardAndCommentsDto.id = board.getId();
boardAndCommentsDto.title = board.getTitle();
boardAndCommentsDto.content = board.getContent();
boardAndCommentsDto.createdDate = board.getCreatedDate();

List<CommentDto> commentDtos = comments.stream().map(CommentDto::from)
.collect(Collectors.toList());

boardAndCommentsDto.comments = commentDtos;
return boardAndCommentsDto;
}


}
43 changes: 43 additions & 0 deletions src/main/java/com/jscode/board/dto/comment/CommentDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.jscode.board.dto.comment;

import com.jscode.board.domain.Board;
import com.jscode.board.domain.Comment;
import com.jscode.board.domain.Member;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class CommentDto {

private String email;
private String content;
private LocalDateTime createdDate;

@Builder
public CommentDto(String email, String content, LocalDateTime createdDate) {
this.email = email;
this.content = content;
this.createdDate = createdDate;
}

public static CommentDto from(Comment comment){
return CommentDto.builder()
.email(comment.getMember().getEmail())
.content(comment.getContent())
.createdDate(comment.getCreatedDate())
.build();
}

public static Comment toEntity(CommentDto commentDto, Board board, Member member){
return Comment.builder()
.content(commentDto.getContent())
.board(board)
.member(member)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.jscode.board.exception.board;

import com.jscode.board.exception.code.ErrorCode;
import com.jscode.board.exception.common.BusinessException;

public class NoAuthorityMemberException extends BusinessException {
public NoAuthorityMemberException() {
super(ErrorCode.NO_AUTHORITY_MEMBER_EXCEPTION);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public enum ErrorCode {

//member
NOT_FOUND_MEMBER_EXCEPTION(404, "사용자가 존재하지 않습니다.", NOT_FOUND),
NO_AUTHORITY_MEMBER_EXCEPTION(403,"해당 서비스의 권한이 없는 유저입니다.", FORBIDDEN),

//jwt
NO_AUTHORITY_INFO_EXCEPTION(403, "권한 정보가 없는 토큰입니다.", FORBIDDEN),
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/com/jscode/board/repository/CommentRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.jscode.board.repository;

import com.jscode.board.domain.Board;
import com.jscode.board.domain.Comment;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

public interface CommentRepository extends JpaRepository<Comment, Long> {

@Query("SELECT c FROM Comment c JOIN FETCH c.member m JOIN FETCH c.board b WHERE b = :board")
List<Comment> findAllByBoardAndMember(@Param("board") Board board);
}
28 changes: 24 additions & 4 deletions src/main/java/com/jscode/board/service/BoardService.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
package com.jscode.board.service;

import com.jscode.board.domain.Board;
import com.jscode.board.domain.Comment;
import com.jscode.board.domain.Member;
import com.jscode.board.dto.board.BoardAndCommentsDto;
import com.jscode.board.dto.board.BoardRequest;
import com.jscode.board.dto.board.BoardResponse;
import com.jscode.board.exception.board.NoAuthorityMemberException;
import com.jscode.board.exception.board.NotFoundBoardException;
import com.jscode.board.repository.BoardRepository;
import com.jscode.board.repository.CommentRepository;
import com.jscode.board.repository.MemberRepository;
import com.jscode.board.util.SecurityUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -18,13 +25,16 @@
public class BoardService {

private final BoardRepository boardRepository;
private final CommentRepository commentRepository;
private final MemberRepository memberRepository;

/**
* 게시글 생성
*/
public BoardResponse saveBoard(BoardRequest request) {
Board savedBoard = boardRepository.save(BoardRequest.toEntity(request));
return BoardResponse.from(savedBoard);
Member member = memberRepository.getOne(SecurityUtil.getCurrentMemberId());
Board newBoard = new Board(request.getTitle(), request.getContent(), member);
return BoardResponse.from(boardRepository.save(newBoard));
}

/**
Expand All @@ -41,9 +51,11 @@ public List<BoardResponse> findBoards() {
/**
* id로 게시글 조회
*/
public BoardResponse findBoardById(Long id) {
public BoardAndCommentsDto findBoardById(Long id) {
Board board = boardRepository.findById(id).orElseThrow(NotFoundBoardException::new);
return BoardResponse.from(board);
List<Comment> comments = commentRepository.findAllByBoardAndMember(board);
BoardAndCommentsDto boardAndCommentsDto = BoardAndCommentsDto.from(board, comments);
return boardAndCommentsDto;
}

/**
Expand All @@ -61,7 +73,11 @@ public List<BoardResponse> findBoardByKeyword(String keyword) {
* 게시글 내용 변경
*/
public BoardResponse updateBoard(Long id, BoardRequest request) {
Long currentMemberId = SecurityUtil.getCurrentMemberId();
Board board = boardRepository.findById(id).orElseThrow(NotFoundBoardException::new);
if(currentMemberId != board.getMember().getId()){
throw new NoAuthorityMemberException();
}
board.updateTitle(request.getTitle());
board.updateContent(request.getContent());
return BoardResponse.from(board);
Expand All @@ -71,7 +87,11 @@ public BoardResponse updateBoard(Long id, BoardRequest request) {
* 게시글 삭제
*/
public Long deleteBoard(Long id){
Long currentMemberId = SecurityUtil.getCurrentMemberId();
Copy link

Choose a reason for hiding this comment

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

jwt 인증 깔끔하게 잘 하신 것 같습니다!

Board board = boardRepository.findById(id).orElseThrow(NotFoundBoardException::new);
if(currentMemberId != board.getMember().getId()){
throw new NoAuthorityMemberException();
}
boardRepository.delete(board);
return board.getId();
}
Expand Down
31 changes: 31 additions & 0 deletions src/main/java/com/jscode/board/service/CommentService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.jscode.board.service;

import com.jscode.board.domain.Board;
import com.jscode.board.domain.Comment;
import com.jscode.board.domain.Member;
import com.jscode.board.dto.comment.CommentDto;
import com.jscode.board.exception.board.NotFoundBoardException;
import com.jscode.board.repository.BoardRepository;
import com.jscode.board.repository.CommentRepository;
import com.jscode.board.repository.MemberRepository;
import com.jscode.board.util.SecurityUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
@RequiredArgsConstructor
public class CommentService {

private final BoardRepository boardRepository;
private final CommentRepository commentRepository;
private final MemberRepository memberRepository;

public Long saveComment(Long boardId, CommentDto commentDto) {
Member member = memberRepository.getOne(SecurityUtil.getCurrentMemberId());
Board board = boardRepository.findById(boardId).orElseThrow(NotFoundBoardException::new);
Comment comment = commentRepository.save(CommentDto.toEntity(commentDto, board, member));
return comment.getId();
}
}
8 changes: 4 additions & 4 deletions src/main/java/com/jscode/board/service/MemberService.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.jscode.board.exception.member.NotFoundMemberException;
import com.jscode.board.jwt.TokenProvider;
import com.jscode.board.repository.MemberRepository;
import com.jscode.board.util.SecurityUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
Expand All @@ -18,10 +19,9 @@ public class MemberService {
private final MemberRepository memberRepository;
private final TokenProvider tokenProvider;

public MemberResponse findMemberInfo(String token){
Authentication authentication = tokenProvider.getAuthentication(token);
Long id = Long.valueOf(authentication.getName());
Member member = memberRepository.findById(id).orElseThrow(NotFoundMemberException::new);
public MemberResponse findMemberInfo(){
Long currentMemberId = SecurityUtil.getCurrentMemberId();
Member member = memberRepository.findById(currentMemberId).orElseThrow(NotFoundMemberException::new);
return MemberResponse.from(member);
}
}