spring boot 게시판 - 13 <프로필 사진 구현>

2023. 6. 16. 20:00·Java/Spring Boot 게시판

2023.06.01 - [Java/spring 게시판] - spring boot 게시판 - 12 <댓글 기능 구현>

 

spring boot 게시판 - 12 <댓글 기능 구현>

2023.02.23 - [Java/spring 게시판] - spring boot 게시판 - 11 spring boot 게시판 - 11 2023.02.21 - [Java/spring 게시판] - spring boot 게시판 - 10 spring boot 게시판 - 10 2022.11.30 - [Java/spring 게시판] - spring boot 게시판 - 9 sprin

magicmk.tistory.com

지난번 댓글 기능을 구현하고 무엇인가 허전해서... 고민하다가 프로필 사진을 추가하기로 했다!

역시 개인 프로필에 사진이 빠질 수 없지


✅ Table 작성

우선 Image를 저장하기 위한 테이블부터 만들어본다.

⏹️ Image.java

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "image")
public class Image {

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

    @Column(nullable = false)
    private String url;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "MEMBER_ID")
    private Member member;

    public void updateUrl(String url) {
        this.url = url;
    }
}

프로필 사진이라서 회원당 하나의 이미지만을 매칭시키기로 했다.


✅ 비즈니스 로직

 

🟧 Controller

⏹️ ImageController.java

@Controller
@RequiredArgsConstructor
@RequestMapping("/image")
public class ImageController {

    private final ImageService imageService;

    /**
     * 프로필 사진 등록
     * @param imageUploadDTO 사진 정보
     * @param authentication 유저 정보
     * @return 프로필 페이지
     */
    @PostMapping("/upload")
    public String upload(@ModelAttribute ImageUploadDTO imageUploadDTO, Authentication authentication) {
        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
        imageService.upload(imageUploadDTO, userDetails.getUsername());

        return "redirect:/member/info";
    }
}

이미지 컨트롤러에는 사진을 업로드하기 위한 메서드만 추가해 주었다.

 

🟧 Service

⏹️ ImageService.java

public interface ImageService {

    /**
     * 프로필 사진 upload
     * @param imageUploadDTO file
     * @param email 유저 정보
     */
    void upload(ImageUploadDTO imageUploadDTO, String email);

    /**
     * 이미지 url 조회
     * @param email 유저 정보
     * @return 이미지 url
     */
    ImageResponseDTO findImage(String email);
}

 

⏹️ ImageServiceImpl.java

@Service
@RequiredArgsConstructor
public class ImageServiceImpl implements ImageService{

    private static final Logger logger = LoggerFactory.getLogger(ImageServiceImpl.class);

    private final ImageRepository imageRepository;
    private final MemberRepository memberRepository;

    @Value("${file.path}")
    private String uploadFolder;

    @Override
    public void upload(ImageUploadDTO imageUploadDTO, String email) {
        Member member = memberRepository.findByEmail(email).orElseThrow(() -> new UsernameNotFoundException("이메일이 존재하지 않습니다."));
        MultipartFile file = imageUploadDTO.getFile();

        UUID uuid = UUID.randomUUID();
        String imageFileName = uuid + "_" + file.getOriginalFilename();

        File destinationFile = new File(uploadFolder + imageFileName);

        try {
            file.transferTo(destinationFile);

            Image image = imageRepository.findByMember(member);
            if (image != null) {
                // 이미지가 이미 존재하면 url 업데이트
                image.updateUrl("/profileImages/" + imageFileName);
            } else {
                // 이미지가 없으면 객체 생성 후 저장
                image = Image.builder()
                        .member(member)
                        .url("/profileImages/" + imageFileName)
                        .build();
            }
            imageRepository.save(image);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public ImageResponseDTO findImage(String email) {
        Member member = memberRepository.findByEmail(email).orElseThrow(() -> new UsernameNotFoundException("이메일이 존재하지 않습니다."));
        Image image = imageRepository.findByMember(member);

        String defaultImageUrl = "/profileImages/anonymous.png";

        if (image == null) {
            return ImageResponseDTO.builder()
                    .url(defaultImageUrl)
                    .build();
        } else {
            return ImageResponseDTO.builder()
                    .url(image.getUrl())
                    .build();
        }
    }
}

upload 메서드는 기존에 이미지가 있는지 없는지 판단하고 수정하거나 생성하는 로직이 들어있다.

 

================================================================

회원가입 시 프로필 사진을 등록하지 않기 때문에 이렇게 구현했지만

현재는 회원가입 시 anonymous 사진을 반드시 등록하게끔 만들어져 있기 때문에

사실상 이미지가 없을 리가 없다. 이 부분은 뒤에서 설명

================================================================

 

findImage 메서드에서도 유저의 이미지를 찾고 없으면 anonymous 이미지를 보내주도록 되어 있는데

이것 또한 이미지가 없을리가 없기 때문에 의미는 없음 혹시 모르니 남겨두었다.

 

 

🟧 Repository

⏹️ ImageRepository.java

public interface ImageRepository extends JpaRepository<Image, Long> {

    Image findByMember(Member member);
}

유저 별 이미지를 찾아야 하기 때문에 위와 같이 Repo를 구성했다.


✅ View & 기존 로직 수정사항

우선 View를 보기 이전에 프로필 사진을 구현하면서 기존 로직에 수정사항이 존재한다.

 

🟧 회원가입 시 이미지 저장

기존에 회원가입 시 단순히 유저정보만 받아서 회원가입을 했지만 지금은 anonymous 이미지를 기본적으로

생성하게 되도록 변경하였다.

 

⏹️ GlobalServiceImpl.java

@Override
@Transactional
public Long join(MemberSaveRequestDTO memberSaveRequestDTO) {
    memberSaveRequestDTO.setPassword(passwordEncoder.encode(memberSaveRequestDTO.getPassword()));

    Member member = Member.builder()
            .email(memberSaveRequestDTO.getEmail())
            .username(memberSaveRequestDTO.getUsername())
            .password(memberSaveRequestDTO.getPassword())
            .role(Role.ROLE_USER)
            .build();

    Image image = Image.builder()
            .url("/profileImages/anonymous.png")
            .member(member)
            .build();

    Long id = memberRepository.save(member).getId();
    imageRepository.save(image);

    return id;
}

기존에는 member 객체만 저장했지만

현재는 Image 객체를 생성해서 프로필 사진을 변경하기 전까지는 anonymous 사진을 가지고 있도록

변경하였다.

 

memberRepository와 imageRepository 둘 중에 하나라도 실패하면 롤백 처리를 하기 위해서

@Transactional 어노테이션도 추가했다.

 

🟧 유저 정보에 프로필 이미지 정보 추가

⏹️ Member.java

@Entity
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "member")
public class Member extends  BaseEntity{

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

    @Column(nullable = false, unique = true)
    private String email;

    @Column(nullable = false)
    private String username;

    @Column(nullable = false)
    private String password;

    @Column
    @Enumerated(EnumType.STRING)
    private Role role;

    @OneToOne(mappedBy = "member", fetch = FetchType.LAZY)
    private Image image;

    public void updateUsername(String username) {
        this.username = username;
    }

    public void updatePassword(String password) {
        this.password = password;
    }
}

이렇게 member 객체에 Image를 mapping 하여

 

⏹️ CommentResponseDTO.java

@Getter
@NoArgsConstructor
public class CommentResponseDTO {

    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;
    private Long id;
    private String content;
    private String username;
    private String email;
    private String imageUrl;

    @Builder
    public CommentResponseDTO(Comment comment) {
        this.createdAt = comment.getCreatedAt();
        this.updatedAt = comment.getUpdatedAt();
        this.id = comment.getId();
        this.content = comment.getContent();
        this.username = comment.getMember().getUsername();
        this.email = comment.getMember().getEmail();
        this.imageUrl = comment.getMember().getImage().getUrl();
    }
}

여기서 댓글 정보를 가져올 때 이 댓글 작성자의 프로필 사진을 가져올 수 있도록 하였다.

 

🟧 View

회원정보 페이지

위와 같이 프로필 사진이 없으면 anonymous 이미지가 저장되고 따로 원하는 이미지로

변경할 수 있도록 해뒀다.

 

댓글 작성 시

 

그리고 댓글을 작성하면 댓글 옆에 프로필 사진이 나오도록 하였다.


✅ 끝

요즘 다른 취미(?)와 공부 등으로 회사 일을 제외한 개발은 거의 안 하고 있었는데 다른 것을 하다가 돌아와서 그런가

프로필 사진 구현하는데 너무 재미있어서 시간 가는 줄 모르고 작업했던 것 같다.

그래서 그런가 반나절도 안 걸려서 마무리 지었던 것 같다. 항상 미루는 습관이 문제..

게시판을 너무 질질 끌고 있는 것 같아서 다음으로는 게시물에 이미지를 추가해서 올릴 수 있도록

만드는 것을 마지막으로 게시판 만들기는 마무리 지으려고 한다.

 

https://github.com/Kimmingki/board

 

GitHub - Kimmingki/board: 강의만 듣다 때려치우지 말고 조금씩이라도 개발해보자...!!

강의만 듣다 때려치우지 말고 조금씩이라도 개발해보자...!! Contribute to Kimmingki/board development by creating an account on GitHub.

github.com

저작자표시 비영리 (새창열림)

'Java > Spring Boot 게시판' 카테고리의 다른 글

spring boot 게시판 - 14 <게시물 이미지 기능>  (9) 2023.06.19
spring boot 게시판 - 12 <댓글 기능 구현>  (8) 2023.06.01
spring boot 게시판 - 11 <게시물 검색 페이징 처리>  (2) 2023.02.23
spring boot 게시판 - 10 <JPA Pageable, thymeleaf>  (0) 2023.02.21
spring boot 게시판 - 9 <게시물 수정, 삭제>  (2) 2022.11.30
'Java/Spring Boot 게시판' 카테고리의 다른 글
  • spring boot 게시판 - 14 <게시물 이미지 기능>
  • spring boot 게시판 - 12 <댓글 기능 구현>
  • spring boot 게시판 - 11 <게시물 검색 페이징 처리>
  • spring boot 게시판 - 10 <JPA Pageable, thymeleaf>
요술공주밍키
요술공주밍키
조금씩이라도 꾸준히..
  • 요술공주밍키
    삽질의흔적
    요술공주밍키
  • 전체
    오늘
    어제
    • 분류 전체보기 (139)
      • Java (42)
        • Spring Boot (14)
        • Spring Boot 게시판 (14)
        • 공중화장실 찾기 (4)
        • 쇼핑몰 (8)
      • JavaScript (8)
        • NodeJS (2)
      • Python (5)
        • Django (4)
      • Server (10)
        • Docker (4)
        • K8S (0)
        • Jenkins (1)
      • 알고리즘 (24)
        • 프로그래머스 (19)
        • 백준 (5)
      • Etc (21)
        • 개발 팁 (1)
      • 일상 (27)
        • 독서 포스트 (25)
        • 회고록 (2)
  • 인기 글

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
요술공주밍키
spring boot 게시판 - 13 <프로필 사진 구현>
상단으로

티스토리툴바