스프링

뉴스피드 프로젝트

148june 2025. 4. 11. 16:04

와이어프레임

erd

컨트롤러

package org.example.snsprojcet.domain.friend.controller;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import org.example.snsprojcet.domain.friend.dto.FriendRequestDto;
import org.example.snsprojcet.domain.friend.dto.FriendResponseDto;
import org.example.snsprojcet.domain.friend.entity.Friend;
import org.example.snsprojcet.domain.friend.service.FriendService;
import org.example.snsprojcet.domain.user.entity.User;
import org.example.snsprojcet.domain.user.service.UserService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

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

@RestController
@RequestMapping("/api/friends")
@RequiredArgsConstructor
public class FriendController {

    private final FriendService friendService;
    private final UserService userService;

    // 친구 요청 보내기
    @PostMapping("/request")
    public ResponseEntity<String> sendFriendRequest(@RequestBody FriendRequestDto dto, User user) {
        User request = userService.findByNickname(dto.getRequestNickname());// 송신자 사용자 받아오기
        User receiver = userService.findByNickname(dto.getReceiverNickname()); // 수신자 유저 받아오기
        //
        //
        Friend friend = friendService.sendFriendRequest(request, receiver);
        return ResponseEntity.ok("친구 요청이 성공적으로 전송되었습니다.");
    }

    // 친구 수락
    @PostMapping("/{friendId}/accept")
    public ResponseEntity<String> accept(@PathVariable Long friendId) {
        friendService.acceptFriendRequest(friendId);
        return ResponseEntity.ok("친구 요청을 수락했습니다.");
    }

    // 친구 거절
    @PostMapping("/{friendId}/reject")
    public ResponseEntity<String> reject(@PathVariable Long friendId) {
        friendService.rejectFriendRequest(friendId);
        return ResponseEntity.ok("친구 요청을 거절했습니다.");
    }

    // 보낸 요청 목록
    @GetMapping("/requestList")
    public ResponseEntity<List<FriendResponseDto>> sentRequests(@RequestParam String nickname) {
        User loginUser = userService.findByNickname(nickname);
        List<FriendResponseDto> list =
                friendService
                        .getSentRequests(loginUser)
                        .stream()
                        .map(FriendResponseDto::new)
                        .collect(Collectors.toList()
                );
        return ResponseEntity.ok(list);
    }

    // 받은 요청 목록
    @GetMapping("/receivedList")
    public ResponseEntity<List<FriendResponseDto>> receivedRequests(String nickname) {
        User loginUser = userService.findByNickname(nickname);
        List<FriendResponseDto> list = friendService.getReceivedRequests(loginUser)
                .stream().map(FriendResponseDto::new).collect(Collectors.toList());
        return ResponseEntity.ok(list);
    }

    //친구목록
    @GetMapping("/friendList")
    public ResponseEntity<List<String>> FriendList(@RequestParam String nickname) {
        // 친구 목록 조회
        List<String> friendList = friendService.findAllFriendList(nickname);
        return new ResponseEntity<>(friendList, HttpStatus.OK);
    }

    // 친구 삭제
    @DeleteMapping("/delete")
    public ResponseEntity<String> deleteFriend(HttpServletRequest request, @RequestParam String nickname) {
        // 세션에서 로그인한 사용자 정보 가져오기
        HttpSession session = request.getSession();
        Long loginUserId = (Long) session.getAttribute("userId");

        // 로그인한 사용자와 친구 정보를 가져오기
        User loginUser = userService.findById(loginUserId);
        User friend = userService.findByNickname(nickname);

        // 친구 관계 삭제
        boolean success = friendService.deleteFriend(loginUser, friend);

        if (success) {
            return ResponseEntity.ok("친구가 삭제되었습니다.");
        } else {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("친구 삭제에 실패했습니다.");
        }
    }

}

엔티티

package org.example.snsprojcet.domain.friend.entity;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.example.snsprojcet.domain.friend.enums.FriendStatus;
import org.example.snsprojcet.domain.user.entity.User;

@NoArgsConstructor
@Getter
@Entity
@Table(name = "friend")
public class Friend {

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

    //친구 요청 보내는 사람
    @ManyToOne
    @JoinColumn(name = "userrequest_id",nullable = false)
    private User userrequest;

    //받는사람
    @ManyToOne
    @JoinColumn(name = "userreceiver_id",nullable = false)
    private User userreceiver;

    public Friend(User userrequest, User userreceiver, FriendStatus status) {
        this.userrequest = userrequest;
        this.userreceiver = userreceiver;
        this.status = status;
    }

    @Enumerated(EnumType.STRING)
    private FriendStatus status;

    //친구수락
    public void accept() {
        this.status = FriendStatus.ACCEPTED;
    }

    //친구 거절
    public void reject() {
        this.status = FriendStatus.REJECTED;
    }

}

 

레포지토리

package org.example.snsprojcet.domain.friend.repository;

import org.example.snsprojcet.domain.friend.entity.Friend;
import org.example.snsprojcet.domain.friend.enums.FriendStatus;
import org.example.snsprojcet.domain.user.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;
import java.util.Optional;

public interface FriendRepository extends JpaRepository<Friend,Long> {

    //요청 보내는 리스트
    List<Friend> findByUserrequest(User userrequest);

    //요청 받는 리스트
    List<Friend> findByUserreceiver(User userreciever);

    //친구 조회
    @Query("SELECT f FROM Friend f WHERE (f.userrequest = :user OR f.userreceiver = :user) AND f.status = :status")
    List<Friend> findAcceptedFriends(FriendStatus friendStatus, User user);

    // userrequest는 친구 요청을 보내는 사람이고, userreceiver는 친구 요청을 받는 사람
    Friend findByUserrequestAndUserreceiver(User userrequest, User userreceiver);

    // 반대편 관계도 찾기 위해 userreceiver와 userrequest를 반대로 사용
    Friend findByUserreceiverAndUserrequest(User userreceiver, User userrequest);
}

서비스

package org.example.snsprojcet.domain.friend.service;

import lombok.RequiredArgsConstructor;
import org.example.snsprojcet.domain.friend.dto.FriendResponseDto;
import org.example.snsprojcet.domain.friend.entity.Friend;
import org.example.snsprojcet.domain.friend.enums.FriendStatus;
import org.example.snsprojcet.domain.friend.repository.FriendRepository;
import org.example.snsprojcet.domain.user.entity.User;
import org.example.snsprojcet.domain.user.repository.UserRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

import static org.example.snsprojcet.domain.friend.enums.FriendStatus.ACCEPTED;

@Service
@RequiredArgsConstructor
public class FriendService {

    private final FriendRepository friendRepository;
    private final UserRepository userRepository;

    // 친구 요청 보내기
    public Friend sendFriendRequest(User requester, User receiver) {
        return friendRepository.save(new Friend(requester, receiver, FriendStatus.PENDING));
    }

    // 친구 수락
    @Transactional
    public void acceptFriendRequest(Long friendId) {
        Friend friend = friendRepository.findById(friendId)
                .orElseThrow(() -> new IllegalArgumentException("친구 요청이 존재하지 않습니다."));
        friend.accept();
    }

    // 친구 거절
    @Transactional
    public void rejectFriendRequest(Long friendId) {
        Friend friend = friendRepository.findById(friendId)
                .orElseThrow(() -> new IllegalArgumentException("친구 요청이 존재하지 않습니다."));
        friend.reject();
    }

    // 내가 요청한 친구 목록
    public List<Friend> getSentRequests(User user) {
        return friendRepository.findByUserrequest(user);
    }

    // 내가 받은 친구 요청 목록
    public List<Friend> getReceivedRequests(User user) {

        return friendRepository.findByUserreceiver(user);
    }

    // 친구 목록 조회
    public List<String> findAllFriendList (String nickname) {
        // 유저 조회
        User userByNicknameOrElseThrow = userRepository.findUserByNicknameOrElseThrow(nickname);
        // 친구 요청 리스트 불러오기(친구 요청 목록에서 nickname 뽑아오기위해)
        // 수락 한 친구 상태만 보여주기
        List<FriendResponseDto> list =
                friendRepository.findByUserrequest(userByNicknameOrElseThrow)
                        .stream()
                        .filter(friend -> friend.getStatus().equals(ACCEPTED)) // 친구 요청을 수락했는지 확인
                        .map(friend -> new FriendResponseDto(friend))
                        .toList();
        // nickname 뽑아와 새로운 리스트 생성
        List<String> nicknames = list.stream()
                .map(friendResponseDto -> friendResponseDto.getReceiverNickname()) // FriendResponseDto에서 nickname 가져오기
                .toList();
        return nicknames;
    }

    //친구삭제 및 확인
    public boolean deleteFriend(User loginUser, User friend) {
        // 로그인한 사용자와 친구 간의 관계를 찾음
        Friend relation = friendRepository.findByUserrequestAndUserreceiver(loginUser, friend);

        // 만약 첫 번째 관계가 없으면, 반대 관계를 찾음 (친구가 로그인한 사용자에게 보낸 요청을 찾기)
        if (relation == null) {
            relation = friendRepository.findByUserreceiverAndUserrequest(loginUser, friend);
        }

        // 친구 관계가 존재하면 삭제
        if (relation != null) {
            friendRepository.delete(relation);

            // 반대편 관계도 삭제 (친구가 로그인한 사용자를 팔로우한 경우)
            Friend reverseRelation = friendRepository.findByUserrequestAndUserreceiver(friend, loginUser);
            if (reverseRelation == null) {
                reverseRelation = friendRepository.findByUserreceiverAndUserrequest(friend, loginUser);
            }
            if (reverseRelation != null) {
                friendRepository.delete(reverseRelation);
            }

            return true;  // 삭제 성공
        }

        return false;  // 친구 관계가 존재하지 않으면 삭제할 수 없음
    }
}