Super Kawaii Cute Cat Kaoani [인스타그램 클론 코딩][Spring boot] 9. 스토리(메인) 페이지

[인스타그램 클론 코딩][Spring boot] 9. 스토리(메인) 페이지

2024. 2. 22. 17:10
728x90
SMALL

✅ 필요한 것

  • 게시글을 올린 user 정보 (이름, 프로필사진)
  • 사진에 대한 정보
  • 캡션에 대한 정보
  • 좋아요, 댓글에 대한 정보 (좀 뒤에 구현 예정)

 

📌 ImageDto

package yerong.InstagramCloneCoding.web.dto.image;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.*;
import yerong.InstagramCloneCoding.domain.user.User;

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
public class ImageDto {

    private Long id;
    private String caption;
    private String postImageUrl;
    private Long userId;
    private String username;
    private String profileImageUrl;
}
  • 필요한 정보들을 담을 dto 생성

 

📌 Image 엔티티

package yerong.InstagramCloneCoding.domain.image;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import jakarta.persistence.*;
import lombok.*;
import yerong.InstagramCloneCoding.domain.user.User;

@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Builder
@Entity
public class Image {


    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "image_id")
    private Long id;

    private String caption;
    private String postImageUrl;

    @JsonIgnoreProperties({"images"}) //user에 있는 images는 무시
    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    //좋아요

    //댓글

}

 

  • user에 @JsonIgnoreProperties를 걸어줘서 무한로딩을 방지

 

📌 Image Repository

package yerong.InstagramCloneCoding.repository.image;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import yerong.InstagramCloneCoding.domain.image.Image;

import java.util.List;

@Repository
public interface ImageRepository extends JpaRepository<Image, Long> {
    @Query(value = "SELECT * from image where user_id = :principalId OR user_id In (SELECT to_user_id FROM subscribe WHERE from_user_id = :principalId) ", nativeQuery = true)
    List<Image> mStory(Long principalId);

}
  • 자신이 구독한 사람들의 이미지들과 나의 이미지를 가져오는 코드 구현

 

📌 ImageApiController

package yerong.InstagramCloneCoding.web.api;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import yerong.InstagramCloneCoding.config.auth.PrincipalDetails;
import yerong.InstagramCloneCoding.service.ImageService;
import yerong.InstagramCloneCoding.web.dto.CMRespDto;
import yerong.InstagramCloneCoding.web.dto.image.ImageDto;

import java.util.List;

@RequiredArgsConstructor
@RestController
@Slf4j
public class ImageApiController {

    private final ImageService imageService;
    @GetMapping("/api/image")
    public ResponseEntity<CMRespDto<?>> imageStory(@AuthenticationPrincipal PrincipalDetails principalDetails){
        List<ImageDto> imageDtos = imageService.imageStory(principalDetails.getUser().getId());
      
        return new ResponseEntity<CMRespDto<?>>(new CMRespDto<>(1, "이미지 정보 가져오기 성공", imageDtos), HttpStatus.OK);
    }
}
  • 이미지 정보를 들고오는 controller

 

✔️ 페이징하기

 

📌 ImageApiController

package yerong.InstagramCloneCoding.web.api;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import yerong.InstagramCloneCoding.config.auth.PrincipalDetails;
import yerong.InstagramCloneCoding.service.ImageService;
import yerong.InstagramCloneCoding.web.dto.CMRespDto;
import yerong.InstagramCloneCoding.web.dto.image.ImageDto;

import java.util.List;

@RequiredArgsConstructor
@RestController
public class ImageApiController {

    private final ImageService imageService;
    @GetMapping("/api/image")
    public ResponseEntity<CMRespDto<?>> imageStory(
            @AuthenticationPrincipal PrincipalDetails principalDetails,
            @PageableDefault(size = 3)Pageable pageable
            ){
        Page<ImageDto> imageDtos = imageService.imageStory(principalDetails.getUser().getId(), pageable);

        return new ResponseEntity<CMRespDto<?>>(new CMRespDto<>(1, "이미지 정보 가져오기 성공", imageDtos), HttpStatus.OK);
    }
}
  •  @PageableDefault 추가 
    • size = 3 : 3개씩 뽑아옴

📌 ImageServiceImpl

package yerong.InstagramCloneCoding.service.impl;

import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import yerong.InstagramCloneCoding.domain.image.Image;
import yerong.InstagramCloneCoding.domain.user.User;
import yerong.InstagramCloneCoding.handler.exception.CustomValidationApiException;
import yerong.InstagramCloneCoding.repository.image.ImageRepository;
import yerong.InstagramCloneCoding.repository.user.UserRepository;
import yerong.InstagramCloneCoding.service.ImageService;
import yerong.InstagramCloneCoding.web.dto.image.ImageDto;
import yerong.InstagramCloneCoding.web.dto.image.ImageUploadDto;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Service
@RequiredArgsConstructor
public class ImageServiceImpl implements ImageService {

    private final ImageRepository imageRepository;
    private final UserRepository userRepository;


    @Transactional(readOnly = true)
    @Override
    public Page<ImageDto> imageStory(Long principalId, Pageable pageable){
        Page<Image> images = imageRepository.mStory(principalId, pageable);
        return images.map(image -> ImageDto.builder()
                        .id(image.getId())
                        .caption(image.getCaption())
                        .postImageUrl(image.getPostImageUrl())
                        .userId(image.getUser().getId())
                        .username(image.getUser().getUsername())
                        .profileImageUrl(image.getUser().getProfileImageUrl())
                        .build());
    }
    @Value("${file.path}")
    private String uploadFolder;

    @Override
    @Transactional
    public void imageUpload(Long userId, ImageUploadDto imageUploadDto){


        UUID uuid = UUID.randomUUID();
        String imageFileName = uuid + "_" + imageUploadDto.getFile().getOriginalFilename();
        Path imageFilePath = Paths.get(uploadFolder+imageFileName);
        try{
            Files.write(imageFilePath, imageUploadDto.getFile().getBytes());
        }
        catch (Exception e){
            e.printStackTrace();
        }
        User user = userRepository.findById(userId).orElseThrow(() -> new CustomValidationApiException("찾을 수 없는 Id 입니다."));
        Image image = imageUploadDto.toEntity(imageFileName, user);

        Image savedImage = imageRepository.save(image);
        user.addImage(savedImage);
    }
}
  • List를 Page로 바꾸고 pageable을 받아옴

 

📌 ImageRepository

package yerong.InstagramCloneCoding.repository.image;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import yerong.InstagramCloneCoding.domain.image.Image;

import java.util.List;

@Repository
public interface ImageRepository extends JpaRepository<Image, Long> {
    @Query(value = "SELECT * from image where user_id = :principalId OR user_id In (SELECT to_user_id FROM subscribe WHERE from_user_id = :principalId) ORDER BY image_id DESC ", nativeQuery = true)
    Page<Image> mStory(Long principalId, Pageable pageable);

}
  • 페이징 코드 추가

 

 

 


PREV

 

[인스타그램 클론 코딩][Spring boot] 8. 구독 정보 뷰 렌더링

✅ 구독 정보를 누르면 page User의 구독 정보를 볼 수 있음 ✅ 여기서 구독취소/구독하기 버튼은 로그인한 user를 기준으로 구분되어야 함. 📌 UserProfileDto package yerong.InstagramCloneCoding.web.dto.user; impor

nyeroni.tistory.com

NEXT

 

[인스타그램 클론 코딩][Spring boot] 10. 좋아요 구현

📌 Likes 엔티티 구현 package yerong.InstagramCloneCoding.domain.likes; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import jakarta.persistence.*; import lombok.*; import yerong.InstagramCloneCoding.domain.BaseTimeEntity; import yero

nyeroni.tistory.com

 

728x90
SMALL

 

728x90
LIST

BELATED ARTICLES

more