2023.06.01 - [Java/spring 게시판] - spring boot 게시판 - 12 <댓글 기능 구현>
지난번 댓글 기능을 구현하고 무엇인가 허전해서... 고민하다가 프로필 사진을 추가하기로 했다!
역시 개인 프로필에 사진이 빠질 수 없지
✅ 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 이미지가 저장되고 따로 원하는 이미지로
변경할 수 있도록 해뒀다.
그리고 댓글을 작성하면 댓글 옆에 프로필 사진이 나오도록 하였다.
✅ 끝
요즘 다른 취미(?)와 공부 등으로 회사 일을 제외한 개발은 거의 안 하고 있었는데 다른 것을 하다가 돌아와서 그런가
프로필 사진 구현하는데 너무 재미있어서 시간 가는 줄 모르고 작업했던 것 같다.
그래서 그런가 반나절도 안 걸려서 마무리 지었던 것 같다. 항상 미루는 습관이 문제..
게시판을 너무 질질 끌고 있는 것 같아서 다음으로는 게시물에 이미지를 추가해서 올릴 수 있도록
만드는 것을 마지막으로 게시판 만들기는 마무리 지으려고 한다.
'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 |