반응형
댓글 관련 코드
CommentRepository
@Repository
public interface CommentRepository extends JpaRepository<Comment, Long> {
List<Comment> findAllByBoardId(Long boardId);
List<Comment> findAllByUserLoginId(String loginId);
}
CommentService
- 댓글에 관련된 CRUD
@Service
@RequiredArgsConstructor
public class CommentService {
private final CommentRepository commentRepository;
private final BoardRepository boardRepository;
private final UserRepository userRepository;
public void writeComment(Long boardId, CommentCreateRequest req, String loginId) {
Board board = boardRepository.findById(boardId).get();
User user = userRepository.findByLoginId(loginId).get();
board.commentChange(board.getCommentCnt() + 1);
commentRepository.save(req.toEntity(board, user));
}
public List<Comment> findAll(Long boardId) {
return commentRepository.findAllByBoardId(boardId);
}
@Transactional
public Long editComment(Long commentId, String newBody, String loginId) {
Optional<Comment> optComment = commentRepository.findById(commentId);
Optional<User> optUser = userRepository.findByLoginId(loginId);
if (optComment.isEmpty() || optUser.isEmpty() || !optComment.get().getUser().equals(optUser.get())) {
return null;
}
Comment comment = optComment.get();
comment.update(newBody);
return comment.getBoard().getId();
}
public Long deleteComment(Long commentId, String loginId) {
Optional<Comment> optComment = commentRepository.findById(commentId);
Optional<User> optUser = userRepository.findByLoginId(loginId);
if (optComment.isEmpty() || optUser.isEmpty() ||
(!optComment.get().getUser().equals(optUser.get()) && !optUser.get().getUserRole().equals(UserRole.ADMIN))) {
return null;
}
Board board = optComment.get().getBoard();
board.commentChange(board.getCommentCnt() + 1);
commentRepository.delete(optComment.get());
return board.getId();
}
}
CommentController
- 댓글 추가, 수정, 삭제 시 완료 메세지 출력 후 해당 댓글이 포함된 게시글 페이지로 이동
@Controller
@RequestMapping("/comments")
@RequiredArgsConstructor
public class CommentController {
private final CommentService commentService;
private final BoardService boardService;
@PostMapping("/{boardId}")
public String addComments(@PathVariable Long boardId, @ModelAttribute CommentCreateRequest req,
Authentication auth, Model model) {
commentService.writeComment(boardId, req, auth.getName());
model.addAttribute("message", "댓글이 추가되었습니다.");
model.addAttribute("nextUrl", "/boards/" + boardService.getCategory(boardId) + "/" + boardId);
return "printMessage";
}
@PostMapping("/{commentId}/edit")
public String editComment(@PathVariable Long commentId, @ModelAttribute CommentCreateRequest req,
Authentication auth, Model model) {
Long boardId = commentService.editComment(commentId, req.getBody(), auth.getName());
model.addAttribute("message", boardId == null? "잘못된 요청입니다." : "댓글이 수정 되었습니다.");
model.addAttribute("nextUrl", "/boards/" + boardService.getCategory(boardId) + "/" + boardId);
return "printMessage";
}
@GetMapping("/{commentId}/delete")
public String deleteComment(@PathVariable Long commentId, Authentication auth, Model model) {
Long boardId = commentService.deleteComment(commentId, auth.getName());
model.addAttribute("message", boardId == null? "작성자만 삭제 가능합니다." : "댓글이 삭제 되었습니다.");
model.addAttribute("nextUrl", "/boards/" + boardService.getCategory(boardId) + "/" + boardId);
return "printMessage";
}
}
CommentCreateRequest
- 댓글을 입력받아 DB에 저장할 때 사용하는 DTO
@Data
public class CommentCreateRequest {
private String body;
public Comment toEntity(Board board, User user) {
return Comment.builder()
.user(user)
.board(board)
.body(body)
.build();
}
}
좋아요 관련 코드
LikeRepository
@Repository
public interface LikeRepository extends JpaRepository<Like, Long> {
void deleteByUserLoginIdAndBoardId(String loginId, Long boardId);
Boolean existsByUserLoginIdAndBoardId(String loginId, Long boardId);
List<Like> findAllByUserLoginId(String loginId);
}
LikeService
- 좋아요 추가, 삭제 및 로그인 한 유저가 특정 게시글에 좋아요를 눌렀는지 여부 확인
@Service
@RequiredArgsConstructor
public class LikeService {
private final LikeRepository likeRepository;
private final UserRepository userRepository;
private final BoardRepository boardRepository;
@Transactional
public void addLike(String loginId, Long boardId) {
Board board = boardRepository.findById(boardId).get();
User loginUser = userRepository.findByLoginId(loginId).get();
User boardUser = board.getUser();
// 자신이 누른 좋아요가 아니라면
if (!boardUser.equals(loginUser)) {
boardUser.likeChange(boardUser.getReceivedLikeCnt() + 1);
}
board.likeChange(board.getLikeCnt() + 1);
likeRepository.save(Like.builder()
.user(loginUser)
.board(board)
.build());
}
@Transactional
public void deleteLike(String loginId, Long boardId) {
Board board = boardRepository.findById(boardId).get();
User loginUser = userRepository.findByLoginId(loginId).get();
User boardUser = board.getUser();
// 자신이 누른 좋아요가 아니라면
if (!boardUser.equals(loginUser)) {
boardUser.likeChange(boardUser.getReceivedLikeCnt() - 1);
}
board.likeChange(board.getLikeCnt() - 1);
likeRepository.deleteByUserLoginIdAndBoardId(loginId, boardId);
}
public Boolean checkLike(String loginId, Long boardId) {
return likeRepository.existsByUserLoginIdAndBoardId(loginId, boardId);
}
}
LikeController
- 댓글과는 달리 메세지를 출력하지 않기 때문에 redirect를 통해 바로 이동
@Controller
@RequestMapping("/likes")
@RequiredArgsConstructor
public class LikeController {
private final LikeService likeService;
private final BoardService boardService;
@GetMapping("/add/{boardId}")
public String addLike(@PathVariable Long boardId, Authentication auth) {
likeService.addLike(auth.getName(), boardId);
return "redirect:/boards/" + boardService.getCategory(boardId) + "/" + boardId;
}
@GetMapping("/delete/{boardId}")
public String deleteLike(@PathVariable Long boardId, Authentication auth) {
likeService.deleteLike(auth.getName(), boardId);
return "redirect:/boards/" + boardService.getCategory(boardId) + "/" + boardId;
}
}
파일 업로드 관련 코드
UploadImageRepository
@Repository
public interface UploadImageRepository extends JpaRepository<UploadImage, Long> {
}
UploadImageService
- saveImage() 메소드에서 입력된 파일의 이름을 "UUID + 원본 파일의 확장자"로 바꿔서 저장
- downloadImage() 메소드에서는 다시 원본 파일명으로 수정 후 파일 return
- 이 프로젝트에서 파일 업로드 기능은 로컬 프로젝트에 "/src/main/resources/static/upload-images" 폴더를 추가하고 해당 폴더에 이미지를 업로드하는 방식
- 따라서 해당 경로에 폴더가 없으면 에러가 발생할 수 있기 때문에 직접 폴더를 추가해줘야 함
- 만약 이 프로젝트를 EC2 서버로 배포하고 싶다면 EC2 인스턴스 프로젝트 내부에서 파일을 관리해도 되지만, AWS S3를 사용하는 것도 좋은 방법이라 생각함
- [Spring Boot] AWS S3를 이용한 파일 업로드 참고
@Service
@RequiredArgsConstructor
public class UploadImageService {
private final UploadImageRepository uploadImageRepository;
private final BoardRepository boardRepository;
private final String rootPath = System.getProperty("user.dir");
private final String fileDir = rootPath + "/src/main/resources/static/upload-images/";
public String getFullPath(String filename) {
return fileDir + filename;
}
public UploadImage saveImage(MultipartFile multipartFile, Board board) throws IOException {
if (multipartFile.isEmpty()) {
return null;
}
String originalFilename = multipartFile.getOriginalFilename();
// 원본 파일명 -> 서버에 저장된 파일명 (중복 X)
// 파일명이 중복되지 않도록 UUID로 설정 + 확장자 유지
String savedFilename = UUID.randomUUID() + "." + extractExt(originalFilename);
// 파일 저장
multipartFile.transferTo(new File(getFullPath(savedFilename)));
return uploadImageRepository.save(UploadImage.builder()
.originalFilename(originalFilename)
.savedFilename(savedFilename)
.board(board)
.build());
}
@Transactional
public void deleteImage(UploadImage uploadImage) throws IOException {
uploadImageRepository.delete(uploadImage);
Files.deleteIfExists(Paths.get(getFullPath(uploadImage.getSavedFilename())));
}
// 확장자 추출
private String extractExt(String originalFilename) {
int pos = originalFilename.lastIndexOf(".");
return originalFilename.substring(pos + 1);
}
public ResponseEntity<UrlResource> downloadImage(Long boardId) throws MalformedURLException {
// boardId에 해당하는 게시글이 없으면 null return
Board board = boardRepository.findById(boardId).get();
if (board == null || board.getUploadImage() == null) {
return null;
}
UrlResource urlResource = new UrlResource("file:" + getFullPath(board.getUploadImage().getSavedFilename()));
// 업로드 한 파일명이 한글인 경우 아래 작업을 안해주면 한글이 깨질 수 있음
String encodedUploadFileName = UriUtils.encode(board.getUploadImage().getOriginalFilename(), StandardCharsets.UTF_8);
String contentDisposition = "attachment; filename=\"" + encodedUploadFileName + "\"";
// header에 CONTENT_DISPOSITION 설정을 통해 클릭 시 다운로드 진행
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition)
.body(urlResource);
}
}
반응형
'Spring Boot > 프로젝트' 카테고리의 다른 글
[Spring Boot] 게시판 만들기 6 - 화면 제작 (0) | 2023.04.17 |
---|---|
[Spring Boot] 게시판 만들기 4 - 게시판 기능 (0) | 2023.04.17 |
[Spring Boot] 게시판 만들기 3 - 유저 기능 (0) | 2023.04.17 |
[Spring Boot] 게시판 만들기 2 - 라이브러리 설치, ERD, Entity 생성 (1) | 2023.04.17 |
[Spring Boot] 게시판 만들기 1 - 설계 & 결과 (2) | 2023.04.16 |