2023.06.16 - [Java/spring 게시판] - spring boot 게시판 - 13 <프로필 사진 구현>
게시판 만들기 마지막 코스 게시물에 이미지 추가하는 기능을 만들었다.
기본적인 게시판 만들기는 3일 이내로 만드는 게 좋다는데 게으르고 멍청해서 반년이 걸렸다..
그래도 마무리한게 다행인가...
✅ Table 작성
지난번 프로필 사진을 구현했을 때처럼 간단하게 Entity를 만들어준다.
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "boardImage")
public class BoardImage {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String url;
@ManyToOne
@JoinColumn(name = "BOARD_ID")
private Board board;
}
위와 같이 Entity를 만들었으면 기존 Board Entity에서도 지금 만든 것을 확인할 수 있도록 연관관계를
설정해 준다.
@Entity
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "board")
public class Board extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String title;
@Column(nullable = false)
private String content;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "MEMBER_ID")
private Member member;
@OneToMany(mappedBy = "board", cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
@OrderBy("id asc")
private List<Comment> comments;
// 이부분이 추가
@OneToMany(mappedBy = "board", cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
@OrderBy("id asc")
private List<BoardImage> boardImages;
public void update(String title, String content) {
this.title = title;
this.content = content;
}
}
보이는 것처럼 기존 코드에서 주석처리 한 곳을 추가하였다.
✅ 비즈니스 로직
그리고 게시물에 들어가는 이미지는 다중 이미지로 전달할 것이기 때문에
다중 이미지를 전달받을 DTO를 먼저 만들었다.
🟧 DTO
⏹️ BoardImageUploadDTO.java
@Data
public class BoardImageUploadDTO {
private List<MultipartFile> files;
}
그저 MultipartFile을 List로 받는 간단한 DTO이다.
그리고 이후에 나올 테지만 board detail 페이지에서 board의 이미지 url을 넘겨줘야 하기 때문에
기존 BoardResponseDTO의 코드를 수정하였다.
@Getter
@NoArgsConstructor
public class BoardResponseDTO {
private Long id;
private String title;
private String content;
private LocalDateTime createdAt;
private String username;
private String email;
// 이부분 추가
private List<String> imageUrls;
@Builder
public BoardResponseDTO(Board board) {
this.id = board.getId();
this.title = board.getTitle();
this.content = board.getContent();
this.createdAt = board.getCreatedAt();
this.username = board.getMember().getUsername();
this.email = board.getMember().getEmail();
// 이부분 추가
this.imageUrls = board.getBoardImages().stream()
.map(BoardImage::getUrl)
.collect(Collectors.toList());
}
}
위와 같이 뷰에서 url을 통해 이미지를 보여줄 수 있게끔 이미지 url을 추가해 줬다.
이제 DTO도 만들었다면 기존에 게시물을 작성하는 컨트롤러를 변경해 준다.
🟧 Controller
⏹️ BoardController.java
@PostMapping("/write")
public String write(BoardWriteRequestDTO boardWriteRequestDTO,
@ModelAttribute BoardImageUploadDTO boardImageUploadDTO,
Authentication authentication) {
logger.info("boardImageDTO is {}", boardImageUploadDTO);
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
boardService.saveBoard(boardWriteRequestDTO, boardImageUploadDTO, userDetails.getUsername());
return "redirect:/";
}
기존의 컨트롤러에서 새로 만든 BoardImageUploadDTO를 추가한 뒤 service로 같이 넘겨준다.
🟧 Service
⏹️ ImageServiceImpl.java
@Override
@Transactional
public Long saveBoard(BoardWriteRequestDTO boardWriteRequestDTO,
BoardImageUploadDTO boardImageUploadDTO,
String email) {
Member member = memberRepository.findByEmail(email).orElseThrow(() -> new UsernameNotFoundException("이메일이 존재하지 않습니다."));
Board result = Board.builder()
.title(boardWriteRequestDTO.getTitle())
.content(boardWriteRequestDTO.getContent())
.member(member)
.build();
boardRepository.save(result);
// 이 부분 추가
if (boardImageUploadDTO.getFiles() != null && !boardImageUploadDTO.getFiles().isEmpty()) {
for (MultipartFile file : boardImageUploadDTO.getFiles()) {
UUID uuid = UUID.randomUUID();
String imageFileName = uuid + "_" + file.getOriginalFilename();
File destinationFile = new File(uploadFolder + imageFileName);
try {
file.transferTo(destinationFile);
} catch (IOException e) {
throw new RuntimeException(e);
}
BoardImage image = BoardImage.builder()
.url("/boardImages/" + imageFileName)
.board(result)
.build();
boardImageRepository.save(image);
}
}
return result.getId();
}
기존 board를 업로드하던 Service에 파일을 전달받아 저장하고 DB에 저장하는 로직을 추가한 뒤
실패 시 롤백을 위해 @Transactional 어노테이션을 추가하였다.
🟧 Repository
⏹️ boardImageRepository.java
public interface BoardImageRepository extends JpaRepository<BoardImage, Long> {
}
레포지토리는 별거 없이 extends만 해줬다.
✅ View
위와 같이 이미지를 등록하고 게시물 상세페이지로 들어가면 등록했던 이미지가 나오도록
구현하였다.
✅ 끝
길고 길었던 게시판의 여정이 끝이 났다. 사실 실제로 개발했던 시간만 생각하면 얼마 안 되지만 뭐가 그리
귀찮고 하기 싫었는지 뒹굴뒹굴 거리다가 이제야 마무리를 지었다.
낭비했던 시간만 잘 활용했으면 프로젝트 2개쯤은 더 나왔을 텐데 하는 아쉬움도 있다.
항상 시간 낭비하지 말고 유튜브나 만화에 시간 쏟지 말고 활동적인 것을 하자고 다짐하지만
유혹 앞에 나는 연약하고 늘 무너지는 것 같다. 그래도 이렇게 꾸준히 해서 완성하는 게 어디인가 싶다 ^^
https://github.com/Kimmingki/board
'Java > Spring Boot 게시판' 카테고리의 다른 글
spring boot 게시판 - 13 <프로필 사진 구현> (8) | 2023.06.16 |
---|---|
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 |