Skip to content

Commit

Permalink
feat: 게시글 좋아요 기능 - #64
Browse files Browse the repository at this point in the history
  • Loading branch information
juryheed authored Aug 18, 2024
2 parents a4b211c + acf0921 commit 298c6c4
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class BoardController {
//게시글 전체 조회
@GetMapping
public ResponseEntity<ResponseDto<BoardListData>> getBoardList(@AuthenticatedUser User user, @RequestParam(value = "dormitory") String dormitory) {
BoardListData boardListData = boardService.getBoardList(dormitory);
BoardListData boardListData = boardService.getBoardList(user, dormitory);
return new ResponseEntity<>(ResponseDto.res(HttpStatus.OK, "게시글 목록 조회 완료", boardListData), HttpStatus.OK);
}

Expand Down Expand Up @@ -64,5 +64,26 @@ public ResponseEntity<ResponseDto<Void>> deleteBoard(@RequestParam(value = "dorm
boardService.deleteBoard(dormitory, boardId, user);
return new ResponseEntity<>(ResponseDto.res(HttpStatus.OK, "게시글 삭제 완료"), HttpStatus.OK);
}

// 게시글 좋아요 등록
@PostMapping("/{boardId}/like")
public ResponseEntity<ResponseDto<Void>> likeBoard(@AuthenticatedUser User user, @PathVariable UUID boardId) {
boardService.likeBoard(user, boardId);
return new ResponseEntity<>(ResponseDto.res(HttpStatus.OK, "게시글 좋아요 등록 완료"), HttpStatus.OK);
}

// 게시글 좋아요 삭제
@DeleteMapping("/{boardId}/like")
public ResponseEntity<ResponseDto<Void>> unlikeBoard(@AuthenticatedUser User user, @PathVariable UUID boardId) {
boardService.unlikeBoard(user, boardId);
return new ResponseEntity<>(ResponseDto.res(HttpStatus.OK, "게시글 좋아요 삭제 완료"), HttpStatus.OK);
}

// 사용자가 좋아요를 누른 게시글 목록 조회
@GetMapping("/likes")
public ResponseEntity<ResponseDto<BoardListData>> getLikedBoards(@AuthenticatedUser User user) {
BoardListData interestListData = boardService.getLikedBoards(user);
return new ResponseEntity<>(ResponseDto.res(HttpStatus.OK, "좋아요한 게시글 목록 조회 완료", interestListData), HttpStatus.OK);
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ public class BoardDetailResponseDto {
private int current;
private int total;
private GenderType gender;
private boolean like;
private String createdAt;

public static BoardDetailResponseDto from(Board board){
public static BoardDetailResponseDto of(Boolean isLike, Board board){
return BoardDetailResponseDto.builder()
.id(board.getId())
.title(board.getTitle())
Expand All @@ -33,6 +34,7 @@ public static BoardDetailResponseDto from(Board board){
.current(board.getChattingRoom().getMemberCount())
.total(board.getTotal())
.gender(board.getUser().getGender())
.like(isLike)
.createdAt(board.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")))
.build();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.example.swcompetitionproject.dto.response.board;

import com.example.swcompetitionproject.entity.Board;
import com.example.swcompetitionproject.entity.User;
import com.example.swcompetitionproject.repository.InterestRepository;
import lombok.Builder;
import lombok.Getter;

Expand All @@ -12,11 +14,23 @@
public class BoardListData {
private List<BoardDetailResponseDto> boardDtoList;

public static BoardListData of(List<Board> boards, User user, InterestRepository interestRepository) {
return BoardListData.builder()
.boardDtoList(
boards.stream()
.map(board -> {
boolean isLiked = interestRepository.existsByUserAndBoard(user, board);
return BoardDetailResponseDto.of(isLiked, board);
})
.collect(Collectors.toList()))
.build();
}

public static BoardListData from(List<Board> boards) {
return BoardListData.builder()
.boardDtoList(
boards.stream()
.map(BoardDetailResponseDto::from)
.map(board -> BoardDetailResponseDto.of(true, board))
.collect(Collectors.toList()))
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ public class Board extends BaseEntity {
@Setter
private List<BoardCategory> boardCategories;

@OneToMany(mappedBy = "board", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Interest> interests;

public Board setContent(String content){
this.content = content;
return this;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.example.swcompetitionproject.entity;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Table(name = "interests")
public class Interest extends BaseEntity{
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "board_id")
private Board board;
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ public class User extends BaseEntity {
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<UserRoom> userRooms;

@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Interest> interests;

public User setName(String name){
this.name = name;
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public enum ErrorCode {
INVALID_DORMITORY("4012", "유효하지 않은 기숙사입니다."),
INVALID_GENDER("4013", "유효하지 않은 성별입니다."),
ROOM_FULL("4014", "채팅방 인원이 가득찼습니다."),
ALREADY_LIKED("4015","이미 좋아요를 눌렀습니다."),

//ForbiddenException
NO_ACCESS("4030", "접근 권한이 없습니다."),
Expand All @@ -25,6 +26,7 @@ public enum ErrorCode {
ROOM_NOT_FOUND("4042", "방을 찾을 수 없습니다."),
BOARD_NOT_FOUND("4043", "게시글을 찾을 수 없습니다."),
CATEGORY_NOT_FOUND("4044", "카테고리를 찾을 수 없습니다"),
LIKE_NOT_FOUND("4045","좋아요를 찾을 수 없습니다."),

//ConflictException

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.example.swcompetitionproject.repository;

import com.example.swcompetitionproject.entity.Board;
import com.example.swcompetitionproject.entity.Interest;
import com.example.swcompetitionproject.entity.User;
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;
import java.util.Optional;
import java.util.UUID;

public interface InterestRepository extends JpaRepository<Interest, UUID> {
boolean existsByUserAndBoard(User user, Board board);
Optional<Interest> findByUserAndBoard(User user, Board board);
@Query("SELECT i.board FROM Interest i WHERE i.user = :user")
List<Board> findBoardsByUser(@Param("user") User user);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@
import com.example.swcompetitionproject.dto.request.board.UpdateBoardDto;
import com.example.swcompetitionproject.dto.response.board.BoardData;
import com.example.swcompetitionproject.dto.response.board.BoardListData;
import com.example.swcompetitionproject.entity.Board;
import com.example.swcompetitionproject.entity.BoardCategory;
import com.example.swcompetitionproject.entity.DormitoryType;
import com.example.swcompetitionproject.entity.User;
import com.example.swcompetitionproject.entity.*;
import com.example.swcompetitionproject.exception.ErrorCode;
import com.example.swcompetitionproject.exception.ForbiddenException;
import com.example.swcompetitionproject.exception.NotFoundException;
import com.example.swcompetitionproject.exception.UnauthorizedException;
import com.example.swcompetitionproject.repository.BoardRepository;
import com.example.swcompetitionproject.repository.InterestRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -26,15 +24,16 @@
public class BoardService {
private final BoardRepository boardRepository;
private final ChattingService chattingService;
private final InterestRepository interestRepository;

/**
* 게시글 전체 조회
**/
@Transactional
public BoardListData getBoardList(String dormitory) {
public BoardListData getBoardList(User user, String dormitory) {
DormitoryType dormitoryType = dormitoryNameValidate(dormitory);
List<Board> boards = boardRepository.findAllByDormitoryOrderByCreatedAtDesc(dormitoryType);
return BoardListData.from(boards);
return BoardListData.of(boards, user, interestRepository);
}

/**
Expand Down Expand Up @@ -114,6 +113,47 @@ public void deleteBoard(String dormitory, UUID boardId, User user) {
chattingService.deleteRoom(board);
}

/**
* 게시글 좋아요 등록
**/
@Transactional
public void likeBoard(User user, UUID boardId) {
Board board = boardRepository.findById(boardId)
.orElseThrow(() -> new NotFoundException(ErrorCode.BOARD_NOT_FOUND));
//이미 좋아요를 누른 게시물
if (interestRepository.existsByUserAndBoard(user, board)) {
throw new UnauthorizedException(ErrorCode.ALREADY_LIKED);
}

Interest like = Interest.builder()
.user(user)
.board(board)
.build();
interestRepository.save(like);
}

/**
* 게시글 좋아요 삭제
**/
@Transactional
public void unlikeBoard(User user, UUID boardId) {
Board board = boardRepository.findById(boardId)
.orElseThrow(() -> new NotFoundException(ErrorCode.BOARD_NOT_FOUND));
Interest like = interestRepository.findByUserAndBoard(user, board)
.orElseThrow(() -> new NotFoundException(ErrorCode.LIKE_NOT_FOUND));

interestRepository.delete(like);
}

/**
* 관심 게시글 조회
**/
@Transactional
public BoardListData getLikedBoards(User user) {
List<Board> likedBoards = interestRepository.findBoardsByUser(user);
return BoardListData.from(likedBoards);
}

/**
* 접근 유저의 게시글 권한 확인
**/
Expand Down

0 comments on commit 298c6c4

Please sign in to comment.