From 4a508138fc3b976d4cc2d2565c779f5d85845bc6 Mon Sep 17 00:00:00 2001 From: Hyunuk Date: Mon, 9 Oct 2023 08:34:06 +0900 Subject: [PATCH 01/22] =?UTF-8?q?[tomato-market/plan#8]=20=EB=B8=8C?= =?UTF-8?q?=EB=9E=9C=EC=B9=98=20=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=EA=B8=B0?= =?UTF-8?q?=EC=B4=88=20=EA=B5=AC=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../market/controller/BoardController.java | 114 +++++++++++++----- .../java/com/tomato/market/dao/BoardDao.java | 15 +++ .../tomato/market/dao/impl/BoardDaoImpl.java | 64 ++++++++++ .../com/tomato/market/data/dto/ImageDto.java | 13 ++ .../com/tomato/market/data/dto/PostDto.java | 33 +++++ .../market/data/dto/ResponsePostDto.java | 15 +++ .../market/data/dto/ResponsePostListDto.java | 16 +++ .../market/data/entity/ImageEntity.java | 9 ++ .../tomato/market/data/entity/PostEntity.java | 33 +++++ .../tomato/market/data/entity/UserEntity.java | 1 - .../data/repository/PostRepository.java | 16 +++ .../handler/exception/BoardException.java | 7 ++ .../tomato/market/service/BoardService.java | 11 ++ .../market/service/impl/BoardServiceImpl.java | 66 ++++++++++ 14 files changed, 383 insertions(+), 30 deletions(-) create mode 100644 src/main/java/com/tomato/market/dao/BoardDao.java create mode 100644 src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java create mode 100644 src/main/java/com/tomato/market/data/dto/ImageDto.java create mode 100644 src/main/java/com/tomato/market/data/dto/PostDto.java create mode 100644 src/main/java/com/tomato/market/data/dto/ResponsePostDto.java create mode 100644 src/main/java/com/tomato/market/data/dto/ResponsePostListDto.java create mode 100644 src/main/java/com/tomato/market/data/entity/ImageEntity.java create mode 100644 src/main/java/com/tomato/market/data/entity/PostEntity.java create mode 100644 src/main/java/com/tomato/market/data/repository/PostRepository.java create mode 100644 src/main/java/com/tomato/market/handler/exception/BoardException.java diff --git a/src/main/java/com/tomato/market/controller/BoardController.java b/src/main/java/com/tomato/market/controller/BoardController.java index d99de5d..ac9a469 100644 --- a/src/main/java/com/tomato/market/controller/BoardController.java +++ b/src/main/java/com/tomato/market/controller/BoardController.java @@ -1,20 +1,29 @@ package com.tomato.market.controller; +import java.util.ArrayList; +import java.util.List; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import com.tomato.market.data.dto.ImageDto; +import com.tomato.market.data.dto.PostDto; +import com.tomato.market.data.dto.ResponsePostDto; +import com.tomato.market.data.dto.ResponsePostListDto; import com.tomato.market.service.BoardService; -import jakarta.servlet.http.HttpSession; - @RestController @RequestMapping("/api") public class BoardController { private final Logger logger = LoggerFactory.getLogger(BoardController.class); + private final BoardService boardService; @Autowired @@ -22,32 +31,79 @@ public BoardController(BoardService boardService) { this.boardService = boardService; } - @GetMapping("/board/getList") - public void getList(HttpSession session) { // 리턴 타입 변경해야할 가능성 있음 -// logger.info("BoardController.getList() is called"); -// // 세션을 확인 -// logger.info("BoardController.getList() : 세션 아이디-" + session.getId()); -// logger.info("BoardController.getList() : 세션 값-" + session.getAttribute("userId")); -// -// if (session.getAttribute("userId") != null) { // 세션이 있는 경우 -// logger.info("BoardController.getList() : 세션에 userId가 있음"); -// // 있으면 List?? 반환 -// -// // (임시) 세션이 잘 들어왔는지 확인 -// return UserResponseDto.builder() -// .status(HttpStatus.OK) -// .message(session.getAttribute("userId")) -// .build(); -// } else { // 세션이 없는 경우 -// // 없으면 유효하지 않은 세션입니다. -// logger.warn("BoardController.getList() : 세션에 userId가 없음"); -// // throw new // 예외를 던지기 -// // React에서 로그인 페이지로 Redirect -// } -// // 수정 예정 -// return UserResponseDto.builder() -// .status(HttpStatus.BAD_REQUEST) -// .message("세션이 존재하지 않음") -// .build(); + + // 계획을 수정 + // 기본 등록 메소드 부터 만든 후 + // 조회 메소드를 만들기로 함 + @PostMapping("/board/registerPost") + public ResponsePostDto registerPost(@RequestBody PostDto postDto) { // 추후 @Valid // 이미지도 받아와야 함 + // MultiPartFile?? + logger.info("BoardController.registerPost() is called"); + boardService.registerPost(postDto); + + return ResponsePostDto.builder().build(); + } + + + @GetMapping("/board/getPostList") + public ResponsePostListDto getPostList() { // 리턴 타입을 리스트로? + // 모든 게시글 조회 -> 페이징 처리 예정, int page 받기 + logger.info("BoardController.getPostList() is called"); + +// List postList = boardService.getAllPostList(); + List postList = boardService.getPostList(); + if (postList == null) { // 잘못됨 + logger.warn("BoardController.getPostList() : 게시글 리스트를 찾을 수 없음"); + // throw new Error // Service에서 처리? + } + // 게시글 리스트를 받음 + logger.info("BoardController.getPostList() : 게시글 리스트를 찾음"); + + // 찾은 postList에서 각 Post의 ID로 Image를 찾음 + List imageList = new ArrayList<>(); + for (int i = 0; i < postList.size(); i++) { + imageList.add( +// 썸네일로 사용할 Image 1개만 필요 + boardService.getPostImage(postList.get(i).getPostId()) +// 이미지가 없는 경우는 Service 단에서 Default 이미지 전송 + ); + } + + + // Return + // 게시글 List 첨부 + // 이미지 List 첨부 + // 하나의 응답 DTO로 변환하여 반환 + return ResponsePostListDto.builder() + .status(HttpStatus.OK) + .message("게시글 리스트 불러오기 성공") + .content(postList) + .build(); } + + @PostMapping("/board/registerPost") + public void registerPost() { + + } + + @PostMapping("/board/registerImage") + public void uploadImage() { // 이미지 등록 메소드를 별도 처리? + // 게시글 이미지 저장 관련 코드 + // 이미지는 다른 controller 메소드 사용 + // multiPartFile로 받음 .getOriginalFilename(), + // 이미지는 각각 uuid를 가짐 + // File 객체 생성, uuid+주소 + // .transferTo()로 서버에 저장 + + // 경로를 기준, base64? + + + // 게시글 이미지 조회 관련 코드 + // List list = findPostImageListById(postId) + // for() { list.add + // if(image == null) { .add(default Image) + + } + + } diff --git a/src/main/java/com/tomato/market/dao/BoardDao.java b/src/main/java/com/tomato/market/dao/BoardDao.java new file mode 100644 index 0000000..bd796c4 --- /dev/null +++ b/src/main/java/com/tomato/market/dao/BoardDao.java @@ -0,0 +1,15 @@ +package com.tomato.market.dao; + +import java.util.List; + +import com.tomato.market.data.entity.ImageEntity; +import com.tomato.market.data.entity.PostEntity; + +public interface BoardDao { + PostEntity save(PostEntity postEntity); + + List findPostList(); + + ImageEntity findImageByPostId(String postId); + +} diff --git a/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java b/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java new file mode 100644 index 0000000..d58acba --- /dev/null +++ b/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java @@ -0,0 +1,64 @@ +package com.tomato.market.dao.impl; + +import java.util.List; +import java.util.Optional; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.tomato.market.dao.BoardDao; +import com.tomato.market.data.entity.ImageEntity; +import com.tomato.market.data.entity.PostEntity; +import com.tomato.market.data.repository.PostRepository; +import com.tomato.market.handler.exception.BoardException; + +@Service +public class BoardDaoImpl implements BoardDao { + private final Logger logger = LoggerFactory.getLogger(BoardDaoImpl.class); + + private final PostRepository postRepository; + + @Autowired + public BoardDaoImpl(PostRepository postRepository) { + this.postRepository = postRepository; + } + + @Override + public PostEntity save(PostEntity postEntity) { + logger.info("BoardDaoImpl.save() is called"); + // Entity로 Post 등록 + PostEntity savedResult = postRepository.save(postEntity); + if (savedResult != null) { // 변경 있음 + logger.info("BoardDaoImpl.save() : 데이터 저장 성공"); + return savedResult; + } else { + logger.warn("BoardDaoImpl.save() : 데이터 저장 실패"); + return null; + } + } + + @Override + public List findPostList() { + + Optional> postEntities = postRepository.find(); + if (postEntities.isPresent()) { + return postEntities.get(); + } else { + throw new BoardException("데이터를 불러오지 못했습니다."); + } + } + + @Override + public ImageEntity findImageByPostId(String postId) { + Optional imageEntity = postRepository.findImageByPostId(postId); + if (imageEntity.isPresent()) { // PostId로 이미지를 찾음 + return imageEntity.get(); + } else { // 이미지를 찾지 못함 or 애초에 없음? + // throw new ImageException(); + // or return null? + return null; + } + } +} diff --git a/src/main/java/com/tomato/market/data/dto/ImageDto.java b/src/main/java/com/tomato/market/data/dto/ImageDto.java new file mode 100644 index 0000000..b562ee7 --- /dev/null +++ b/src/main/java/com/tomato/market/data/dto/ImageDto.java @@ -0,0 +1,13 @@ +package com.tomato.market.data.dto; + +import com.tomato.market.data.entity.ImageEntity; + +import lombok.Builder; + +@Builder +public class ImageDto { + + public static ImageDto toImageDto(ImageEntity imageEntity) { + return ImageDto.builder().build(); + } +} diff --git a/src/main/java/com/tomato/market/data/dto/PostDto.java b/src/main/java/com/tomato/market/data/dto/PostDto.java new file mode 100644 index 0000000..b0770a6 --- /dev/null +++ b/src/main/java/com/tomato/market/data/dto/PostDto.java @@ -0,0 +1,33 @@ +package com.tomato.market.data.dto; + +import com.tomato.market.data.entity.PostEntity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Builder +@Setter +@Getter +@NoArgsConstructor +@AllArgsConstructor +//@AllArgsConstructor +public class PostDto { + // PostDto 하나로 처리가 맞는지? + // PostDetailDto가 따로 필요? + String postId; + + + // 내부에 Image가 포함? + + + public static PostEntity toPostEntity(PostDto postDto) { + return PostEntity.builder().build(); + } + + public static PostDto toPostDto(PostEntity postEntity) { + return PostDto.builder().build(); + } +} diff --git a/src/main/java/com/tomato/market/data/dto/ResponsePostDto.java b/src/main/java/com/tomato/market/data/dto/ResponsePostDto.java new file mode 100644 index 0000000..5b0c8a2 --- /dev/null +++ b/src/main/java/com/tomato/market/data/dto/ResponsePostDto.java @@ -0,0 +1,15 @@ +package com.tomato.market.data.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Builder +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class ResponsePostDto { +} diff --git a/src/main/java/com/tomato/market/data/dto/ResponsePostListDto.java b/src/main/java/com/tomato/market/data/dto/ResponsePostListDto.java new file mode 100644 index 0000000..dc7db88 --- /dev/null +++ b/src/main/java/com/tomato/market/data/dto/ResponsePostListDto.java @@ -0,0 +1,16 @@ +package com.tomato.market.data.dto; + +import org.springframework.http.HttpStatus; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.NoArgsConstructor; + +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ResponsePostListDto { + HttpStatus status; + Object message; + Object content; +} diff --git a/src/main/java/com/tomato/market/data/entity/ImageEntity.java b/src/main/java/com/tomato/market/data/entity/ImageEntity.java new file mode 100644 index 0000000..8fff03e --- /dev/null +++ b/src/main/java/com/tomato/market/data/entity/ImageEntity.java @@ -0,0 +1,9 @@ +package com.tomato.market.data.entity; + +import jakarta.persistence.Entity; +import lombok.Builder; + +@Entity +@Builder +public class ImageEntity { +} diff --git a/src/main/java/com/tomato/market/data/entity/PostEntity.java b/src/main/java/com/tomato/market/data/entity/PostEntity.java new file mode 100644 index 0000000..646169c --- /dev/null +++ b/src/main/java/com/tomato/market/data/entity/PostEntity.java @@ -0,0 +1,33 @@ +package com.tomato.market.data.entity; + +import java.util.Date; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.NoArgsConstructor; + +@Entity +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "post") +public class PostEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + Integer postNum; + Integer userNum; // 관계를 가지는 키 값을 어떻게 구축? + String location; + String title; + String category; + String content; + Integer price; + String detailLocation; + Integer status; + Date createdAt; // 애노테이션? + String boughtUser; +} diff --git a/src/main/java/com/tomato/market/data/entity/UserEntity.java b/src/main/java/com/tomato/market/data/entity/UserEntity.java index 58b39c9..090fc09 100644 --- a/src/main/java/com/tomato/market/data/entity/UserEntity.java +++ b/src/main/java/com/tomato/market/data/entity/UserEntity.java @@ -38,5 +38,4 @@ public class UserEntity { String lastLogin; Integer status; String resignReason; - } diff --git a/src/main/java/com/tomato/market/data/repository/PostRepository.java b/src/main/java/com/tomato/market/data/repository/PostRepository.java new file mode 100644 index 0000000..15d4a9f --- /dev/null +++ b/src/main/java/com/tomato/market/data/repository/PostRepository.java @@ -0,0 +1,16 @@ +package com.tomato.market.data.repository; + +import java.util.List; +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.tomato.market.data.entity.ImageEntity; +import com.tomato.market.data.entity.PostEntity; + +public interface PostRepository extends JpaRepository { + // findAll()? // int page + Optional> find(); + + Optional findImageByPostId(String postId); +} diff --git a/src/main/java/com/tomato/market/handler/exception/BoardException.java b/src/main/java/com/tomato/market/handler/exception/BoardException.java new file mode 100644 index 0000000..6386523 --- /dev/null +++ b/src/main/java/com/tomato/market/handler/exception/BoardException.java @@ -0,0 +1,7 @@ +package com.tomato.market.handler.exception; + +public class BoardException extends RuntimeException { + public BoardException(String message) { + super(message); + } +} diff --git a/src/main/java/com/tomato/market/service/BoardService.java b/src/main/java/com/tomato/market/service/BoardService.java index 896927c..df1ce43 100644 --- a/src/main/java/com/tomato/market/service/BoardService.java +++ b/src/main/java/com/tomato/market/service/BoardService.java @@ -1,4 +1,15 @@ package com.tomato.market.service; +import java.util.List; + +import com.tomato.market.data.dto.ImageDto; +import com.tomato.market.data.dto.PostDto; + public interface BoardService { + PostDto registerPost(PostDto postDto); + + List getPostList(); + + ImageDto getPostImage(String postId); + } diff --git a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java index 52b5f30..be17961 100644 --- a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java +++ b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java @@ -1,9 +1,75 @@ package com.tomato.market.service.impl; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import com.tomato.market.dao.BoardDao; +import com.tomato.market.data.dto.ImageDto; +import com.tomato.market.data.dto.PostDto; +import com.tomato.market.data.entity.ImageEntity; +import com.tomato.market.data.entity.PostEntity; import com.tomato.market.service.BoardService; @Service public class BoardServiceImpl implements BoardService { + private final Logger logger = LoggerFactory.getLogger(BoardServiceImpl.class); + + private final BoardDao boardDao; + + @Autowired + public BoardServiceImpl(BoardDao boardDao) { + this.boardDao = boardDao; + } + + @Override + public PostDto registerPost(PostDto postDto) { + logger.info("BoardServiceImpl.registerPost() is called"); + // DTO -> Entity 전환 + PostEntity postEntity = PostDto.toPostEntity(postDto); + + // 검증 코드가 필요한가? + + PostEntity saveResult = boardDao.save(postEntity); + if (saveResult == null) { // 등록 실패 + // throw new Exception(); + } + + + // 반환 + return PostDto.toPostDto(saveResult); + } + + @Override + public List getPostList() { + // getPostList의 범위 + // 한번에 모든 데이터를 불러오는 것은 무리가 있음 + // 한 페이지 당으로 제약해서 get? + + List postEntities = boardDao.findPostList(); + if (postEntities != null) { + // 예외처리 + } + + // get한 정보를 어떻게 리스트로? + // Entity -> DTO 전환 + return null; + } + + @Override + public ImageDto getPostImage(String postId) { + // 게시글의 id로 image를 찾아 반환 + ImageEntity imageEntity = boardDao.findImageByPostId(postId); + if (imageEntity == null) { + // 이미지 없는 게시물 + // Default Image 반환 + imageEntity = ImageEntity.builder().build(); + } + + // Entity -> DTO 전환하여 반환 + return ImageDto.toImageDto(imageEntity); + } } From defa73b645bfccaea386dd2d442ea9865e602554 Mon Sep 17 00:00:00 2001 From: Hyunuk Date: Tue, 10 Oct 2023 11:12:28 +0900 Subject: [PATCH 02/22] =?UTF-8?q?[tomato-market/plan#8]=20=EA=B2=8C?= =?UTF-8?q?=EC=8B=9C=EA=B8=80=20=EB=93=B1=EB=A1=9D=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Service에서 Post와 Image를 분리해서 등록 --- .../com/tomato/market/MarketApplication.java | 2 + .../tomato/market/config/SwaggerConfig.java | 34 +++++++ .../market/controller/BoardController.java | 88 +++++++++++-------- .../java/com/tomato/market/dao/BoardDao.java | 4 +- .../tomato/market/dao/impl/BoardDaoImpl.java | 55 ++++++++---- .../com/tomato/market/data/dto/PostDto.java | 42 +++++++-- ...tListDto.java => PostListResponseDto.java} | 2 +- ...ponsePostDto.java => PostResponseDto.java} | 6 +- .../market/data/entity/ImageEntity.java | 12 +++ .../tomato/market/data/entity/PostEntity.java | 10 ++- .../data/repository/ImageRepository.java | 8 ++ .../data/repository/PostRepository.java | 8 +- .../tomato/market/service/BoardService.java | 9 +- .../market/service/impl/BoardServiceImpl.java | 54 ++++++++++-- .../resources/application-local.properties | 2 +- 15 files changed, 255 insertions(+), 81 deletions(-) rename src/main/java/com/tomato/market/data/dto/{ResponsePostListDto.java => PostListResponseDto.java} (88%) rename src/main/java/com/tomato/market/data/dto/{ResponsePostDto.java => PostResponseDto.java} (67%) create mode 100644 src/main/java/com/tomato/market/data/repository/ImageRepository.java diff --git a/src/main/java/com/tomato/market/MarketApplication.java b/src/main/java/com/tomato/market/MarketApplication.java index ee03269..ce03dae 100644 --- a/src/main/java/com/tomato/market/MarketApplication.java +++ b/src/main/java/com/tomato/market/MarketApplication.java @@ -2,8 +2,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; @SpringBootApplication +@EnableJpaAuditing public class MarketApplication { public static void main(String[] args) { diff --git a/src/main/java/com/tomato/market/config/SwaggerConfig.java b/src/main/java/com/tomato/market/config/SwaggerConfig.java index cea189e..f057975 100644 --- a/src/main/java/com/tomato/market/config/SwaggerConfig.java +++ b/src/main/java/com/tomato/market/config/SwaggerConfig.java @@ -1,7 +1,14 @@ package com.tomato.market.config; +import java.lang.reflect.Type; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Info; @@ -17,4 +24,31 @@ public OpenAPI openApi() { return new OpenAPI().info(info); } + // swagger에 multipart/form-data 형식을 인지시키기 위한 설정 + @Component + public class MultipartJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter { + + /** + * "Content-Type: multipart/form-data" 헤더를 지원하는 HTTP 요청 변환기 + */ + public MultipartJackson2HttpMessageConverter(ObjectMapper objectMapper) { + super(objectMapper, MediaType.APPLICATION_OCTET_STREAM); + } + + @Override + public boolean canWrite(Class clazz, MediaType mediaType) { + return false; + } + + @Override + public boolean canWrite(Type type, Class clazz, MediaType mediaType) { + return false; + } + + @Override + protected boolean canWrite(MediaType mediaType) { + return false; + } + } + } diff --git a/src/main/java/com/tomato/market/controller/BoardController.java b/src/main/java/com/tomato/market/controller/BoardController.java index ac9a469..d74cad7 100644 --- a/src/main/java/com/tomato/market/controller/BoardController.java +++ b/src/main/java/com/tomato/market/controller/BoardController.java @@ -1,5 +1,6 @@ package com.tomato.market.controller; +import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -7,16 +8,18 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; import com.tomato.market.data.dto.ImageDto; import com.tomato.market.data.dto.PostDto; -import com.tomato.market.data.dto.ResponsePostDto; -import com.tomato.market.data.dto.ResponsePostListDto; +import com.tomato.market.data.dto.PostListResponseDto; +import com.tomato.market.data.dto.PostResponseDto; import com.tomato.market.service.BoardService; @RestController @@ -35,18 +38,31 @@ public BoardController(BoardService boardService) { // 계획을 수정 // 기본 등록 메소드 부터 만든 후 // 조회 메소드를 만들기로 함 - @PostMapping("/board/registerPost") - public ResponsePostDto registerPost(@RequestBody PostDto postDto) { // 추후 @Valid // 이미지도 받아와야 함 - // MultiPartFile?? + @PostMapping(value = "/board/writePost", consumes = {MediaType.APPLICATION_JSON_VALUE, + MediaType.MULTIPART_FORM_DATA_VALUE}) + public PostResponseDto writePost( + @RequestPart("postDto") PostDto postDto, @RequestPart("files") MultipartFile[] files) + throws IOException { // 추후 @Valid // 이미지도 받아와야 함 logger.info("BoardController.registerPost() is called"); - boardService.registerPost(postDto); - return ResponsePostDto.builder().build(); + // 게시글 등록 + boardService.writePost(postDto); + logger.info("BoardController.registerPost() : 게시글 저장 성공"); + + // postID와 연관하여 이미지 등록 // Image API를 따로 분리? : DB간 관계가 성립되지 않는 문제 있음 + boardService.uploadImages(files); + logger.info("BoardController.registerPost() : 이미지 저장 성공"); + + // 결과 리턴 + return PostResponseDto.builder() + .status(HttpStatus.OK) + .message("게시글 등록에 성공했습니다.") + .build(); } @GetMapping("/board/getPostList") - public ResponsePostListDto getPostList() { // 리턴 타입을 리스트로? + public PostListResponseDto getPostList() { // 리턴 타입을 리스트로? // 모든 게시글 조회 -> 페이징 처리 예정, int page 받기 logger.info("BoardController.getPostList() is called"); @@ -62,11 +78,11 @@ public ResponsePostListDto getPostList() { // 리턴 타입을 리스트로? // 찾은 postList에서 각 Post의 ID로 Image를 찾음 List imageList = new ArrayList<>(); for (int i = 0; i < postList.size(); i++) { - imageList.add( +// imageList.add( // 썸네일로 사용할 Image 1개만 필요 - boardService.getPostImage(postList.get(i).getPostId()) +// boardService.getPostImage(postList.get(i).getPostNum()) // 이미지가 없는 경우는 Service 단에서 Default 이미지 전송 - ); +// ); } @@ -74,36 +90,36 @@ public ResponsePostListDto getPostList() { // 리턴 타입을 리스트로? // 게시글 List 첨부 // 이미지 List 첨부 // 하나의 응답 DTO로 변환하여 반환 - return ResponsePostListDto.builder() + return PostListResponseDto.builder() .status(HttpStatus.OK) .message("게시글 리스트 불러오기 성공") .content(postList) .build(); } - @PostMapping("/board/registerPost") - public void registerPost() { - - } - - @PostMapping("/board/registerImage") - public void uploadImage() { // 이미지 등록 메소드를 별도 처리? - // 게시글 이미지 저장 관련 코드 - // 이미지는 다른 controller 메소드 사용 - // multiPartFile로 받음 .getOriginalFilename(), - // 이미지는 각각 uuid를 가짐 - // File 객체 생성, uuid+주소 - // .transferTo()로 서버에 저장 - - // 경로를 기준, base64? - - - // 게시글 이미지 조회 관련 코드 - // List list = findPostImageListById(postId) - // for() { list.add - // if(image == null) { .add(default Image) - - } +// @PostMapping("/board/registerPost") +// public void registerPost() { +// +// } + +// @PostMapping("/board/registerImage") +// public void uploadImage() { // 이미지 등록 메소드를 별도 처리? +// // 게시글 이미지 저장 관련 코드 +// // 이미지는 다른 controller 메소드 사용 +// // multiPartFile로 받음 .getOriginalFilename(), +// // 이미지는 각각 uuid를 가짐 +// // File 객체 생성, uuid+주소 +// // .transferTo()로 서버에 저장 +// +// // 경로를 기준, base64? +// +// +// // 게시글 이미지 조회 관련 코드 +// // List list = findPostImageListById(postId) +// // for() { list.add +// // if(image == null) { .add(default Image) +// +// } } diff --git a/src/main/java/com/tomato/market/dao/BoardDao.java b/src/main/java/com/tomato/market/dao/BoardDao.java index bd796c4..09e5cca 100644 --- a/src/main/java/com/tomato/market/dao/BoardDao.java +++ b/src/main/java/com/tomato/market/dao/BoardDao.java @@ -8,8 +8,10 @@ public interface BoardDao { PostEntity save(PostEntity postEntity); + ImageEntity saveImage(ImageEntity imageEntity); + List findPostList(); - ImageEntity findImageByPostId(String postId); + ImageEntity findImageByPostNum(Integer postNum); } diff --git a/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java b/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java index d58acba..95a1213 100644 --- a/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java +++ b/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java @@ -1,36 +1,40 @@ package com.tomato.market.dao.impl; import java.util.List; -import java.util.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import com.tomato.market.dao.BoardDao; import com.tomato.market.data.entity.ImageEntity; import com.tomato.market.data.entity.PostEntity; +import com.tomato.market.data.repository.ImageRepository; import com.tomato.market.data.repository.PostRepository; -import com.tomato.market.handler.exception.BoardException; @Service +@Transactional public class BoardDaoImpl implements BoardDao { private final Logger logger = LoggerFactory.getLogger(BoardDaoImpl.class); private final PostRepository postRepository; + private final ImageRepository imageRepository; @Autowired - public BoardDaoImpl(PostRepository postRepository) { + public BoardDaoImpl(PostRepository postRepository, ImageRepository imageRepository) { this.postRepository = postRepository; + this.imageRepository = imageRepository; } + @Override public PostEntity save(PostEntity postEntity) { logger.info("BoardDaoImpl.save() is called"); // Entity로 Post 등록 PostEntity savedResult = postRepository.save(postEntity); - if (savedResult != null) { // 변경 있음 + if (savedResult.getPostNum() != null) { logger.info("BoardDaoImpl.save() : 데이터 저장 성공"); return savedResult; } else { @@ -40,25 +44,40 @@ public PostEntity save(PostEntity postEntity) { } @Override - public List findPostList() { + public ImageEntity saveImage(ImageEntity imageEntity) { + logger.info("BoardDaoImpl.saveImage() is called"); - Optional> postEntities = postRepository.find(); - if (postEntities.isPresent()) { - return postEntities.get(); + ImageEntity savedResult = imageRepository.save(imageEntity); + if (savedResult.getImageNum() != null) { + logger.info("BoardDaoImpl.saveImage() : 이미지 정보 저장 성공"); + return savedResult; } else { - throw new BoardException("데이터를 불러오지 못했습니다."); + logger.warn("BoardDaoImpl.saveImage() : 이미지 정보 저장 실패"); + return null; } } @Override - public ImageEntity findImageByPostId(String postId) { - Optional imageEntity = postRepository.findImageByPostId(postId); - if (imageEntity.isPresent()) { // PostId로 이미지를 찾음 - return imageEntity.get(); - } else { // 이미지를 찾지 못함 or 애초에 없음? - // throw new ImageException(); - // or return null? - return null; - } + public List findPostList() { +// +// Optional> postEntities = postRepository.find(); +// if (postEntities.isPresent()) { +// return postEntities.get(); +// } else { +// throw new BoardException("데이터를 불러오지 못했습니다."); +// } + return null; + } + + @Override + public ImageEntity findImageByPostNum(Integer postNum) { +// Optional imageEntity = postRepository.findImageByPostNum(postNum); +// if (imageEntity.isPresent()) { // PostId로 이미지를 찾음 +// return imageEntity.get(); +// } else { // 이미지를 찾지 못함 or 애초에 없음? +// // throw new ImageException(); +// // or return null? + return null; +// } } } diff --git a/src/main/java/com/tomato/market/data/dto/PostDto.java b/src/main/java/com/tomato/market/data/dto/PostDto.java index b0770a6..5e88b82 100644 --- a/src/main/java/com/tomato/market/data/dto/PostDto.java +++ b/src/main/java/com/tomato/market/data/dto/PostDto.java @@ -13,21 +13,47 @@ @Getter @NoArgsConstructor @AllArgsConstructor -//@AllArgsConstructor public class PostDto { - // PostDto 하나로 처리가 맞는지? - // PostDetailDto가 따로 필요? - String postId; - - // 내부에 Image가 포함? + Integer userNum; // 관계를 가지는 키 값을 어떻게 구축? + String location; + String title; + String category; // Enum 클래스로 제한? + String content; + Integer price; + String detailLocation; + Integer status; // 판매 상태 : 이것도 Enum? + // Date createdAt; // DTO에서는 필요 없을지도 + Integer boughtUser; public static PostEntity toPostEntity(PostDto postDto) { - return PostEntity.builder().build(); + + return PostEntity.builder() + .userNum(postDto.getUserNum()) + .location(postDto.getLocation()) + .title(postDto.getTitle()) + .category(postDto.getCategory()) + .content(postDto.getContent()) + .price(postDto.getPrice()) + .detailLocation(postDto.getDetailLocation()) + .status(postDto.getStatus()) + .boughtUser(postDto.getBoughtUser()) + .build(); } public static PostDto toPostDto(PostEntity postEntity) { - return PostDto.builder().build(); + + return PostDto.builder() + .userNum(postEntity.getUserNum()) + .location(postEntity.getLocation()) + .title(postEntity.getTitle()) + .category(postEntity.getCategory()) + .content(postEntity.getContent()) + .price(postEntity.getPrice()) + .detailLocation(postEntity.getDetailLocation()) + .status(postEntity.getStatus()) + .boughtUser(postEntity.getBoughtUser()) + .build(); } } diff --git a/src/main/java/com/tomato/market/data/dto/ResponsePostListDto.java b/src/main/java/com/tomato/market/data/dto/PostListResponseDto.java similarity index 88% rename from src/main/java/com/tomato/market/data/dto/ResponsePostListDto.java rename to src/main/java/com/tomato/market/data/dto/PostListResponseDto.java index dc7db88..5061e48 100644 --- a/src/main/java/com/tomato/market/data/dto/ResponsePostListDto.java +++ b/src/main/java/com/tomato/market/data/dto/PostListResponseDto.java @@ -9,7 +9,7 @@ @Builder @AllArgsConstructor @NoArgsConstructor -public class ResponsePostListDto { +public class PostListResponseDto { HttpStatus status; Object message; Object content; diff --git a/src/main/java/com/tomato/market/data/dto/ResponsePostDto.java b/src/main/java/com/tomato/market/data/dto/PostResponseDto.java similarity index 67% rename from src/main/java/com/tomato/market/data/dto/ResponsePostDto.java rename to src/main/java/com/tomato/market/data/dto/PostResponseDto.java index 5b0c8a2..472a2fa 100644 --- a/src/main/java/com/tomato/market/data/dto/ResponsePostDto.java +++ b/src/main/java/com/tomato/market/data/dto/PostResponseDto.java @@ -1,5 +1,7 @@ package com.tomato.market.data.dto; +import org.springframework.http.HttpStatus; + import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -11,5 +13,7 @@ @Setter @NoArgsConstructor @AllArgsConstructor -public class ResponsePostDto { +public class PostResponseDto { + HttpStatus status; + String message; } diff --git a/src/main/java/com/tomato/market/data/entity/ImageEntity.java b/src/main/java/com/tomato/market/data/entity/ImageEntity.java index 8fff03e..8f5d8de 100644 --- a/src/main/java/com/tomato/market/data/entity/ImageEntity.java +++ b/src/main/java/com/tomato/market/data/entity/ImageEntity.java @@ -1,9 +1,21 @@ package com.tomato.market.data.entity; import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; import lombok.Builder; +import lombok.Getter; @Entity @Builder +@Getter public class ImageEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + Integer imageNum; + Integer postNum; + String imageName; + String uuid; + } diff --git a/src/main/java/com/tomato/market/data/entity/PostEntity.java b/src/main/java/com/tomato/market/data/entity/PostEntity.java index 646169c..6cdd7b5 100644 --- a/src/main/java/com/tomato/market/data/entity/PostEntity.java +++ b/src/main/java/com/tomato/market/data/entity/PostEntity.java @@ -2,19 +2,26 @@ import java.util.Date; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; import lombok.AllArgsConstructor; import lombok.Builder; +import lombok.Getter; import lombok.NoArgsConstructor; @Entity @Builder +@Getter @NoArgsConstructor @AllArgsConstructor +@EntityListeners(AuditingEntityListener.class) @Table(name = "post") public class PostEntity { @Id @@ -28,6 +35,7 @@ public class PostEntity { Integer price; String detailLocation; Integer status; + @CreatedDate Date createdAt; // 애노테이션? - String boughtUser; + Integer boughtUser; } diff --git a/src/main/java/com/tomato/market/data/repository/ImageRepository.java b/src/main/java/com/tomato/market/data/repository/ImageRepository.java new file mode 100644 index 0000000..c2c427e --- /dev/null +++ b/src/main/java/com/tomato/market/data/repository/ImageRepository.java @@ -0,0 +1,8 @@ +package com.tomato.market.data.repository; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.tomato.market.data.entity.ImageEntity; + +public interface ImageRepository extends JpaRepository { +} diff --git a/src/main/java/com/tomato/market/data/repository/PostRepository.java b/src/main/java/com/tomato/market/data/repository/PostRepository.java index 15d4a9f..f4a122d 100644 --- a/src/main/java/com/tomato/market/data/repository/PostRepository.java +++ b/src/main/java/com/tomato/market/data/repository/PostRepository.java @@ -1,16 +1,12 @@ package com.tomato.market.data.repository; -import java.util.List; -import java.util.Optional; - import org.springframework.data.jpa.repository.JpaRepository; -import com.tomato.market.data.entity.ImageEntity; import com.tomato.market.data.entity.PostEntity; public interface PostRepository extends JpaRepository { // findAll()? // int page - Optional> find(); +// Optional> find(); - Optional findImageByPostId(String postId); +// Optional findImageByPostNum(Integer postNum); } diff --git a/src/main/java/com/tomato/market/service/BoardService.java b/src/main/java/com/tomato/market/service/BoardService.java index df1ce43..a9ddb40 100644 --- a/src/main/java/com/tomato/market/service/BoardService.java +++ b/src/main/java/com/tomato/market/service/BoardService.java @@ -1,15 +1,20 @@ package com.tomato.market.service; +import java.io.IOException; import java.util.List; +import org.springframework.web.multipart.MultipartFile; + import com.tomato.market.data.dto.ImageDto; import com.tomato.market.data.dto.PostDto; public interface BoardService { - PostDto registerPost(PostDto postDto); + PostDto writePost(PostDto postDto); + + void uploadImages(MultipartFile[] files) throws IOException; List getPostList(); - ImageDto getPostImage(String postId); + ImageDto getPostImage(Integer postNum); } diff --git a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java index be17961..9c5910a 100644 --- a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java +++ b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java @@ -1,20 +1,26 @@ package com.tomato.market.service.impl; +import java.io.File; import java.util.List; +import java.util.UUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; import com.tomato.market.dao.BoardDao; import com.tomato.market.data.dto.ImageDto; import com.tomato.market.data.dto.PostDto; import com.tomato.market.data.entity.ImageEntity; import com.tomato.market.data.entity.PostEntity; +import com.tomato.market.handler.exception.BoardException; import com.tomato.market.service.BoardService; @Service +@Transactional public class BoardServiceImpl implements BoardService { private final Logger logger = LoggerFactory.getLogger(BoardServiceImpl.class); @@ -26,23 +32,59 @@ public BoardServiceImpl(BoardDao boardDao) { } @Override - public PostDto registerPost(PostDto postDto) { + public PostDto writePost(PostDto postDto) { logger.info("BoardServiceImpl.registerPost() is called"); // DTO -> Entity 전환 PostEntity postEntity = PostDto.toPostEntity(postDto); - // 검증 코드가 필요한가? - + logger.info("BoardServiceImpl.registerPost() : 게시글 등록 시도"); PostEntity saveResult = boardDao.save(postEntity); if (saveResult == null) { // 등록 실패 - // throw new Exception(); + logger.warn("BoardServiceImpl.registerPost() : 게시글 등록 실패"); + throw new BoardException("게시글 등록에 실패했습니다."); } // 반환 + logger.info("BoardServiceImpl.registerPost() : 게시글 등록 성공"); return PostDto.toPostDto(saveResult); } + @Override + public void uploadImages(MultipartFile[] files) { // 이미지 업로드 + logger.info("BoardServiceImpl.uploadImages() is called"); + //유 + String projectPath = "C:/Users/dksgu/Desktop/캡스톤디자인/images/"; // 프로젝트 경로 얻기 : 변동 여지 있음 profile? + for (int i = 0; i < files.length; i++) { + logger.info("BoardServiceImpl.uploadImages() : 이미지" + (i + 1) + " 저장 시도"); + MultipartFile file = files[i]; + UUID uuid = UUID.randomUUID(); // UUID 생성 + String fileName = uuid + "_" + file.getOriginalFilename(); // 저장될 unique한 이름 생성 : originalName 형식 어떻게 되는지? + logger.info("BoardServiceImpl.uploadImages() : fileName-" + fileName); // 이건 삭제할 로그, 파일 이름 형식 체크 + File savedFile = new File(projectPath, fileName); // + + try { + file.transferTo(savedFile); + } catch (Exception e) { + logger.warn("BoardServiceImpl.uploadImages() : 파일 저장 실패"); + throw new BoardException((i + 1) + "번째 파일 저장에 실패했습니다."); + } + +// DB에 파일 정보 저장 + ImageEntity imageEntity = + ImageEntity.builder().imageName(file.getOriginalFilename()).uuid(fileName).build(); + ImageEntity saveResult = boardDao.saveImage(imageEntity); // 어떤 식으로 저장되는지 repository 분리? + if (imageEntity == null) { + logger.warn("BoardServiceImpl.uploadImages() : DB에 정보 저장 실패"); + throw new BoardException((i + 1) + "번째 이미지 정보 저장에 실패했습니다."); + } // 예외 처리 + logger.info("BoardServiceImpl.uploadImages() : DB에 정보 저장 성공"); + } + + logger.info("BoardServiceImpl.uploadImages() : 모든 이미지 저장 성공"); +// return null; + } + @Override public List getPostList() { // getPostList의 범위 @@ -60,9 +102,9 @@ public List getPostList() { } @Override - public ImageDto getPostImage(String postId) { + public ImageDto getPostImage(Integer postNum) { // 게시글의 id로 image를 찾아 반환 - ImageEntity imageEntity = boardDao.findImageByPostId(postId); + ImageEntity imageEntity = boardDao.findImageByPostNum(postNum); if (imageEntity == null) { // 이미지 없는 게시물 // Default Image 반환 diff --git a/src/main/resources/application-local.properties b/src/main/resources/application-local.properties index 3096c1e..68b74db 100644 --- a/src/main/resources/application-local.properties +++ b/src/main/resources/application-local.properties @@ -4,7 +4,7 @@ spring.datasource.url=jdbc:mariadb://localhost:3306/tomatolocal spring.datasource.username=root spring.datasource.password=1111 # JPA -spring.jpa.hibernate.ddl-auto=none +spring.jpa.hibernate.ddl-auto=create spring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=true spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MariaDBDialect From f504446000f5c0bf7f2c5160d1c1d0e0682e36d7 Mon Sep 17 00:00:00 2001 From: Hyunuk Date: Tue, 10 Oct 2023 15:21:21 +0900 Subject: [PATCH 03/22] =?UTF-8?q?[tomato-market/plan#8]=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=20=EA=B2=BD=EB=A1=9C=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/tomato/market/service/impl/BoardServiceImpl.java | 6 +++++- src/main/resources/application-dev.properties | 3 +++ src/main/resources/application-local.properties | 2 ++ src/main/resources/application.properties | 3 ++- 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java index 9c5910a..ca7688e 100644 --- a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java +++ b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java @@ -7,6 +7,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; @@ -26,6 +27,9 @@ public class BoardServiceImpl implements BoardService { private final BoardDao boardDao; + @Value("${image.path}") + private String projectPath; // 이미지 경로 얻기 : profile + @Autowired public BoardServiceImpl(BoardDao boardDao) { this.boardDao = boardDao; @@ -54,7 +58,6 @@ public PostDto writePost(PostDto postDto) { public void uploadImages(MultipartFile[] files) { // 이미지 업로드 logger.info("BoardServiceImpl.uploadImages() is called"); //유 - String projectPath = "C:/Users/dksgu/Desktop/캡스톤디자인/images/"; // 프로젝트 경로 얻기 : 변동 여지 있음 profile? for (int i = 0; i < files.length; i++) { logger.info("BoardServiceImpl.uploadImages() : 이미지" + (i + 1) + " 저장 시도"); MultipartFile file = files[i]; @@ -67,6 +70,7 @@ public void uploadImages(MultipartFile[] files) { // 이미지 업로드 file.transferTo(savedFile); } catch (Exception e) { logger.warn("BoardServiceImpl.uploadImages() : 파일 저장 실패"); + e.printStackTrace(); throw new BoardException((i + 1) + "번째 파일 저장에 실패했습니다."); } diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties index 3096c1e..f002d20 100644 --- a/src/main/resources/application-dev.properties +++ b/src/main/resources/application-dev.properties @@ -11,3 +11,6 @@ spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MariaDBDialect # Redis spring.redis.host=localhost spring.redis.port=6379 +# image +image.path=/home/ec2-user/app/tomato/images + diff --git a/src/main/resources/application-local.properties b/src/main/resources/application-local.properties index 68b74db..90dbd91 100644 --- a/src/main/resources/application-local.properties +++ b/src/main/resources/application-local.properties @@ -11,3 +11,5 @@ spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MariaDBDialect # Redis spring.redis.host=localhost spring.redis.port=6379 +# image +image.path=C:/Users/dksgu/Desktop/Capstone/images diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 6c2722d..c591df0 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -2,6 +2,7 @@ spring.profiles.active=dev # Logback spring.output.ansi.enabled=always -logging.config=src/main/resources/logback-spring.xml +logging.config=classpath:logback-spring.xml + From 16e95426bdfbbd3cb0ac9f91493501922b1642f9 Mon Sep 17 00:00:00 2001 From: Hyunuk Date: Tue, 10 Oct 2023 15:58:08 +0900 Subject: [PATCH 04/22] =?UTF-8?q?[tomato-market/plan#8]=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../market/controller/BoardController.java | 18 +++++-- .../com/tomato/market/data/dto/PostDto.java | 22 ++++++--- .../market/data/dto/PostResponseDto.java | 2 +- .../tomato/market/data/entity/PostEntity.java | 4 +- .../market/handler/BoardExceptionHandler.java | 49 +++++++++++++++++++ .../market/handler/UserExceptionHandler.java | 3 +- 6 files changed, 83 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/tomato/market/handler/BoardExceptionHandler.java diff --git a/src/main/java/com/tomato/market/controller/BoardController.java b/src/main/java/com/tomato/market/controller/BoardController.java index d74cad7..a07cc0c 100644 --- a/src/main/java/com/tomato/market/controller/BoardController.java +++ b/src/main/java/com/tomato/market/controller/BoardController.java @@ -22,6 +22,8 @@ import com.tomato.market.data.dto.PostResponseDto; import com.tomato.market.service.BoardService; +import jakarta.validation.Valid; + @RestController @RequestMapping("/api") public class BoardController { @@ -41,17 +43,22 @@ public BoardController(BoardService boardService) { @PostMapping(value = "/board/writePost", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE}) public PostResponseDto writePost( - @RequestPart("postDto") PostDto postDto, @RequestPart("files") MultipartFile[] files) + @RequestPart("postDto") @Valid PostDto postDto, + @RequestPart(value = "files", required = false) MultipartFile[] files) throws IOException { // 추후 @Valid // 이미지도 받아와야 함 logger.info("BoardController.registerPost() is called"); + logger.info("BoardController.registerPost() : Validation 검증 성공"); // 게시글 등록 boardService.writePost(postDto); logger.info("BoardController.registerPost() : 게시글 저장 성공"); - // postID와 연관하여 이미지 등록 // Image API를 따로 분리? : DB간 관계가 성립되지 않는 문제 있음 - boardService.uploadImages(files); - logger.info("BoardController.registerPost() : 이미지 저장 성공"); + if (files != null) { + logger.info("BoardController.registerPost() : 이미지가 존재하는 Post"); + // postID와 연관하여 이미지 등록 // Image API를 따로 분리? : DB간 관계가 성립되지 않는 문제 있음 + boardService.uploadImages(files); + logger.info("BoardController.registerPost() : 이미지 저장 성공"); + } // 결과 리턴 return PostResponseDto.builder() @@ -60,6 +67,9 @@ public PostResponseDto writePost( .build(); } +// PutMapping? +// updatePost() {} + @GetMapping("/board/getPostList") public PostListResponseDto getPostList() { // 리턴 타입을 리스트로? diff --git a/src/main/java/com/tomato/market/data/dto/PostDto.java b/src/main/java/com/tomato/market/data/dto/PostDto.java index 5e88b82..ef84bf1 100644 --- a/src/main/java/com/tomato/market/data/dto/PostDto.java +++ b/src/main/java/com/tomato/market/data/dto/PostDto.java @@ -2,6 +2,9 @@ import com.tomato.market.data.entity.PostEntity; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Positive; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -15,22 +18,27 @@ @AllArgsConstructor public class PostDto { - Integer userNum; // 관계를 가지는 키 값을 어떻게 구축? + @Pattern(message = "잘못된 아이디 형식입니다.", regexp = "^[a-z0-9_-]{6,20}") + String userId; // userId는 세션에서 들고옴 + @NotBlank(message = "지역을 입력하세요.") String location; + @NotBlank(message = "제목을 입력하세요.") String title; String category; // Enum 클래스로 제한? + @NotBlank(message = "내용을 입력하세요.") String content; + @Positive(message = "숫자만 입력 가능합니다.") Integer price; + @NotBlank(message = "거래희망 장소를 입력하세요. ") String detailLocation; Integer status; // 판매 상태 : 이것도 Enum? - // Date createdAt; // DTO에서는 필요 없을지도 - Integer boughtUser; + Integer boughtUserId; public static PostEntity toPostEntity(PostDto postDto) { return PostEntity.builder() - .userNum(postDto.getUserNum()) + .userId(postDto.getUserId()) .location(postDto.getLocation()) .title(postDto.getTitle()) .category(postDto.getCategory()) @@ -38,14 +46,14 @@ public static PostEntity toPostEntity(PostDto postDto) { .price(postDto.getPrice()) .detailLocation(postDto.getDetailLocation()) .status(postDto.getStatus()) - .boughtUser(postDto.getBoughtUser()) + .boughtUserId(postDto.getBoughtUserId()) .build(); } public static PostDto toPostDto(PostEntity postEntity) { return PostDto.builder() - .userNum(postEntity.getUserNum()) + .userId(postEntity.getUserId()) .location(postEntity.getLocation()) .title(postEntity.getTitle()) .category(postEntity.getCategory()) @@ -53,7 +61,7 @@ public static PostDto toPostDto(PostEntity postEntity) { .price(postEntity.getPrice()) .detailLocation(postEntity.getDetailLocation()) .status(postEntity.getStatus()) - .boughtUser(postEntity.getBoughtUser()) + .boughtUserId(postEntity.getBoughtUserId()) .build(); } } diff --git a/src/main/java/com/tomato/market/data/dto/PostResponseDto.java b/src/main/java/com/tomato/market/data/dto/PostResponseDto.java index 472a2fa..d42f06d 100644 --- a/src/main/java/com/tomato/market/data/dto/PostResponseDto.java +++ b/src/main/java/com/tomato/market/data/dto/PostResponseDto.java @@ -15,5 +15,5 @@ @AllArgsConstructor public class PostResponseDto { HttpStatus status; - String message; + Object message; } diff --git a/src/main/java/com/tomato/market/data/entity/PostEntity.java b/src/main/java/com/tomato/market/data/entity/PostEntity.java index 6cdd7b5..8b663dd 100644 --- a/src/main/java/com/tomato/market/data/entity/PostEntity.java +++ b/src/main/java/com/tomato/market/data/entity/PostEntity.java @@ -27,7 +27,7 @@ public class PostEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) Integer postNum; - Integer userNum; // 관계를 가지는 키 값을 어떻게 구축? + String userId; // 관계를 가지는 키 값을 어떻게 구축? String location; String title; String category; @@ -37,5 +37,5 @@ public class PostEntity { Integer status; @CreatedDate Date createdAt; // 애노테이션? - Integer boughtUser; + Integer boughtUserId; } diff --git a/src/main/java/com/tomato/market/handler/BoardExceptionHandler.java b/src/main/java/com/tomato/market/handler/BoardExceptionHandler.java new file mode 100644 index 0000000..8db2088 --- /dev/null +++ b/src/main/java/com/tomato/market/handler/BoardExceptionHandler.java @@ -0,0 +1,49 @@ +package com.tomato.market.handler; + +import java.util.HashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import com.tomato.market.controller.BoardController; +import com.tomato.market.data.dto.PostResponseDto; +import com.tomato.market.handler.exception.BoardException; + +@RestControllerAdvice(basePackageClasses = BoardController.class) +public class BoardExceptionHandler { + private final Logger logger = LoggerFactory.getLogger(BoardExceptionHandler.class); + + @ExceptionHandler(BoardException.class) + public PostResponseDto handlePostException(BoardException exception) { + logger.warn("BoardExceptionHandler.handlerPostException() is called"); + + return PostResponseDto.builder() + .status(HttpStatus.OK) + .message(exception.getMessage()) + .build(); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + public PostResponseDto handlePostValidation(MethodArgumentNotValidException exception) { + logger.warn("BoardExceptionHandler.handlePostValidation() is called"); + + // Validation 에러 맵 + HashMap validationErrorMap = new HashMap<>(); + exception.getBindingResult().getFieldErrors().forEach(error -> { + validationErrorMap.put(error.getField(), error.getDefaultMessage()); + }); + + PostResponseDto postResponseDto = PostResponseDto.builder() + .status(HttpStatus.OK) + .message(validationErrorMap) + .build(); + + return postResponseDto; + } + + +} diff --git a/src/main/java/com/tomato/market/handler/UserExceptionHandler.java b/src/main/java/com/tomato/market/handler/UserExceptionHandler.java index 0ba54ed..41ace7a 100644 --- a/src/main/java/com/tomato/market/handler/UserExceptionHandler.java +++ b/src/main/java/com/tomato/market/handler/UserExceptionHandler.java @@ -9,10 +9,11 @@ import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import com.tomato.market.controller.UserController; import com.tomato.market.data.dto.UserResponseDto; import com.tomato.market.handler.exception.UserException; -@RestControllerAdvice +@RestControllerAdvice(basePackageClasses = UserController.class) public class UserExceptionHandler { private final Logger logger = LoggerFactory.getLogger(UserExceptionHandler.class); From 81fbe47e518d206eee3aab1cc2a8fdf9c10759c1 Mon Sep 17 00:00:00 2001 From: Hyunuk Date: Thu, 12 Oct 2023 06:01:27 +0900 Subject: [PATCH 05/22] =?UTF-8?q?[tomato-market/plan#8]=20API=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EB=B0=8F=20Controller=20Test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/tomato/market/MarketApplication.java | 2 - .../market/config/JpaAuditingConfig.java | 9 + .../market/controller/BoardController.java | 23 +- .../com/tomato/market/data/dto/PostDto.java | 6 +- .../market/data/entity/ImageEntity.java | 2 + .../tomato/market/data/entity/PostEntity.java | 2 +- .../market/handler/BoardExceptionHandler.java | 3 +- .../market/handler/UserExceptionHandler.java | 1 + .../tomato/market/service/BoardService.java | 2 +- .../market/service/impl/BoardServiceImpl.java | 24 +- .../controller/BoardControllerTest.java | 219 ++++++++++++++++++ 11 files changed, 265 insertions(+), 28 deletions(-) create mode 100644 src/main/java/com/tomato/market/config/JpaAuditingConfig.java create mode 100644 src/test/java/com/tomato/market/controller/BoardControllerTest.java diff --git a/src/main/java/com/tomato/market/MarketApplication.java b/src/main/java/com/tomato/market/MarketApplication.java index ce03dae..ee03269 100644 --- a/src/main/java/com/tomato/market/MarketApplication.java +++ b/src/main/java/com/tomato/market/MarketApplication.java @@ -2,10 +2,8 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.data.jpa.repository.config.EnableJpaAuditing; @SpringBootApplication -@EnableJpaAuditing public class MarketApplication { public static void main(String[] args) { diff --git a/src/main/java/com/tomato/market/config/JpaAuditingConfig.java b/src/main/java/com/tomato/market/config/JpaAuditingConfig.java new file mode 100644 index 0000000..6eb86bc --- /dev/null +++ b/src/main/java/com/tomato/market/config/JpaAuditingConfig.java @@ -0,0 +1,9 @@ +package com.tomato.market.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; + +@Configuration +@EnableJpaAuditing +public class JpaAuditingConfig { +} diff --git a/src/main/java/com/tomato/market/controller/BoardController.java b/src/main/java/com/tomato/market/controller/BoardController.java index a07cc0c..7b039d3 100644 --- a/src/main/java/com/tomato/market/controller/BoardController.java +++ b/src/main/java/com/tomato/market/controller/BoardController.java @@ -43,30 +43,33 @@ public BoardController(BoardService boardService) { @PostMapping(value = "/board/writePost", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE}) public PostResponseDto writePost( - @RequestPart("postDto") @Valid PostDto postDto, - @RequestPart(value = "files", required = false) MultipartFile[] files) + @RequestPart(value = "postDto") @Valid PostDto postDto, + @RequestPart(value = "images", required = false) List files) throws IOException { // 추후 @Valid // 이미지도 받아와야 함 - logger.info("BoardController.registerPost() is called"); - logger.info("BoardController.registerPost() : Validation 검증 성공"); + logger.info("BoardController.writePost() is called"); + logger.info("BoardController.writerPost() : Validation 검증 성공"); // 게시글 등록 - boardService.writePost(postDto); - logger.info("BoardController.registerPost() : 게시글 저장 성공"); + PostDto savedPost = boardService.writePost(postDto); + logger.info("BoardController.writePost() : 게시글 저장 성공"); + + Integer postNum = savedPost.getPostNum(); // if (files != null) { - logger.info("BoardController.registerPost() : 이미지가 존재하는 Post"); + logger.info("BoardController.writePost() : 이미지 개수-" + files.size()); // postID와 연관하여 이미지 등록 // Image API를 따로 분리? : DB간 관계가 성립되지 않는 문제 있음 - boardService.uploadImages(files); - logger.info("BoardController.registerPost() : 이미지 저장 성공"); + boardService.uploadImages(postNum, files); + logger.info("BoardController.writePost() : 이미지 저장 성공"); } // 결과 리턴 return PostResponseDto.builder() .status(HttpStatus.OK) - .message("게시글 등록에 성공했습니다.") + .message("게시글 등록 성공") .build(); } + // 조회 삭제 수정 : 각각 별도 이슈로 분리? // PutMapping? // updatePost() {} diff --git a/src/main/java/com/tomato/market/data/dto/PostDto.java b/src/main/java/com/tomato/market/data/dto/PostDto.java index ef84bf1..377a6a2 100644 --- a/src/main/java/com/tomato/market/data/dto/PostDto.java +++ b/src/main/java/com/tomato/market/data/dto/PostDto.java @@ -10,14 +10,17 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import lombok.ToString; @Builder @Setter @Getter @NoArgsConstructor @AllArgsConstructor +@ToString public class PostDto { + Integer postNum; @Pattern(message = "잘못된 아이디 형식입니다.", regexp = "^[a-z0-9_-]{6,20}") String userId; // userId는 세션에서 들고옴 @NotBlank(message = "지역을 입력하세요.") @@ -32,7 +35,7 @@ public class PostDto { @NotBlank(message = "거래희망 장소를 입력하세요. ") String detailLocation; Integer status; // 판매 상태 : 이것도 Enum? - Integer boughtUserId; + String boughtUserId; public static PostEntity toPostEntity(PostDto postDto) { @@ -53,6 +56,7 @@ public static PostEntity toPostEntity(PostDto postDto) { public static PostDto toPostDto(PostEntity postEntity) { return PostDto.builder() + .postNum(postEntity.getPostNum()) .userId(postEntity.getUserId()) .location(postEntity.getLocation()) .title(postEntity.getTitle()) diff --git a/src/main/java/com/tomato/market/data/entity/ImageEntity.java b/src/main/java/com/tomato/market/data/entity/ImageEntity.java index 8f5d8de..5680ff3 100644 --- a/src/main/java/com/tomato/market/data/entity/ImageEntity.java +++ b/src/main/java/com/tomato/market/data/entity/ImageEntity.java @@ -4,12 +4,14 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.Table; import lombok.Builder; import lombok.Getter; @Entity @Builder @Getter +@Table(name = "image") public class ImageEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/src/main/java/com/tomato/market/data/entity/PostEntity.java b/src/main/java/com/tomato/market/data/entity/PostEntity.java index 8b663dd..6da9342 100644 --- a/src/main/java/com/tomato/market/data/entity/PostEntity.java +++ b/src/main/java/com/tomato/market/data/entity/PostEntity.java @@ -37,5 +37,5 @@ public class PostEntity { Integer status; @CreatedDate Date createdAt; // 애노테이션? - Integer boughtUserId; + String boughtUserId; } diff --git a/src/main/java/com/tomato/market/handler/BoardExceptionHandler.java b/src/main/java/com/tomato/market/handler/BoardExceptionHandler.java index 8db2088..9ab5df9 100644 --- a/src/main/java/com/tomato/market/handler/BoardExceptionHandler.java +++ b/src/main/java/com/tomato/market/handler/BoardExceptionHandler.java @@ -29,7 +29,8 @@ public PostResponseDto handlePostException(BoardException exception) { @ExceptionHandler(MethodArgumentNotValidException.class) public PostResponseDto handlePostValidation(MethodArgumentNotValidException exception) { - logger.warn("BoardExceptionHandler.handlePostValidation() is called"); + logger.info("BoardExceptionHandler.handlePostValidation() is called"); + logger.warn("BoardExceptionHandler.handlePostValidation() : Validation 오류, 데이터 형식이 올바르지 않음"); // Validation 에러 맵 HashMap validationErrorMap = new HashMap<>(); diff --git a/src/main/java/com/tomato/market/handler/UserExceptionHandler.java b/src/main/java/com/tomato/market/handler/UserExceptionHandler.java index 41ace7a..ddea6c4 100644 --- a/src/main/java/com/tomato/market/handler/UserExceptionHandler.java +++ b/src/main/java/com/tomato/market/handler/UserExceptionHandler.java @@ -36,6 +36,7 @@ public UserResponseDto handleUserException(UserException exception) { @ExceptionHandler(MethodArgumentNotValidException.class) public UserResponseDto handleUserValidation(MethodArgumentNotValidException exception) { + logger.info("UserExceptionHandler.handleUserValidation() is called"); logger.warn("UserExceptionHandler.handleUserValidation() : Validation 오류, 데이터 형식이 올바르지 않음"); // Validation 에러 맵 diff --git a/src/main/java/com/tomato/market/service/BoardService.java b/src/main/java/com/tomato/market/service/BoardService.java index a9ddb40..94147b8 100644 --- a/src/main/java/com/tomato/market/service/BoardService.java +++ b/src/main/java/com/tomato/market/service/BoardService.java @@ -11,7 +11,7 @@ public interface BoardService { PostDto writePost(PostDto postDto); - void uploadImages(MultipartFile[] files) throws IOException; + void uploadImages(Integer postNum, List files) throws IOException; List getPostList(); diff --git a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java index ca7688e..ec16ff2 100644 --- a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java +++ b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java @@ -37,33 +37,33 @@ public BoardServiceImpl(BoardDao boardDao) { @Override public PostDto writePost(PostDto postDto) { - logger.info("BoardServiceImpl.registerPost() is called"); + logger.info("BoardServiceImpl.writePost() is called"); // DTO -> Entity 전환 PostEntity postEntity = PostDto.toPostEntity(postDto); - logger.info("BoardServiceImpl.registerPost() : 게시글 등록 시도"); + logger.info("BoardServiceImpl.writePost() : 게시글 등록 시도"); PostEntity saveResult = boardDao.save(postEntity); if (saveResult == null) { // 등록 실패 - logger.warn("BoardServiceImpl.registerPost() : 게시글 등록 실패"); + logger.warn("BoardServiceImpl.writePost() : 게시글 등록 실패"); throw new BoardException("게시글 등록에 실패했습니다."); } // 반환 - logger.info("BoardServiceImpl.registerPost() : 게시글 등록 성공"); + logger.info("BoardServiceImpl.writePost() : 게시글 등록 성공"); return PostDto.toPostDto(saveResult); } @Override - public void uploadImages(MultipartFile[] files) { // 이미지 업로드 + public void uploadImages(Integer postNum, List files) { // 이미지 업로드 logger.info("BoardServiceImpl.uploadImages() is called"); //유 - for (int i = 0; i < files.length; i++) { - logger.info("BoardServiceImpl.uploadImages() : 이미지" + (i + 1) + " 저장 시도"); - MultipartFile file = files[i]; + int count = 0; + for (MultipartFile file : files) { + logger.info("BoardServiceImpl.uploadImages() : 이미지" + (count + 1) + " 저장 시도"); UUID uuid = UUID.randomUUID(); // UUID 생성 String fileName = uuid + "_" + file.getOriginalFilename(); // 저장될 unique한 이름 생성 : originalName 형식 어떻게 되는지? - logger.info("BoardServiceImpl.uploadImages() : fileName-" + fileName); // 이건 삭제할 로그, 파일 이름 형식 체크 + logger.info("BoardServiceImpl.uploadImages() : fileName-" + fileName); // 파일 이름 형식 체크 File savedFile = new File(projectPath, fileName); // try { @@ -71,16 +71,16 @@ public void uploadImages(MultipartFile[] files) { // 이미지 업로드 } catch (Exception e) { logger.warn("BoardServiceImpl.uploadImages() : 파일 저장 실패"); e.printStackTrace(); - throw new BoardException((i + 1) + "번째 파일 저장에 실패했습니다."); + throw new BoardException((count + 1) + "번째 이미지 저장에 실패했습니다."); } // DB에 파일 정보 저장 ImageEntity imageEntity = - ImageEntity.builder().imageName(file.getOriginalFilename()).uuid(fileName).build(); + ImageEntity.builder().postNum(postNum).imageName(file.getOriginalFilename()).uuid(fileName).build(); ImageEntity saveResult = boardDao.saveImage(imageEntity); // 어떤 식으로 저장되는지 repository 분리? if (imageEntity == null) { logger.warn("BoardServiceImpl.uploadImages() : DB에 정보 저장 실패"); - throw new BoardException((i + 1) + "번째 이미지 정보 저장에 실패했습니다."); + throw new BoardException((count + 1) + "번째 이미지 정보 저장에 실패했습니다."); } // 예외 처리 logger.info("BoardServiceImpl.uploadImages() : DB에 정보 저장 성공"); } diff --git a/src/test/java/com/tomato/market/controller/BoardControllerTest.java b/src/test/java/com/tomato/market/controller/BoardControllerTest.java new file mode 100644 index 0000000..218893d --- /dev/null +++ b/src/test/java/com/tomato/market/controller/BoardControllerTest.java @@ -0,0 +1,219 @@ +package com.tomato.market.controller; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.filter.CharacterEncodingFilter; +import org.springframework.web.multipart.MultipartFile; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.tomato.market.data.dto.PostDto; +import com.tomato.market.handler.exception.BoardException; +import com.tomato.market.service.impl.BoardServiceImpl; + +@WebMvcTest(BoardController.class) +public class BoardControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private BoardServiceImpl boardService; + + // Post 입력값 + private Integer postNum = 1; + private String userId = "spring"; + private String location = "노원구"; + private String title = "제목입니다."; + private String category = "1"; + private String content = "본문입니다."; + private Integer price = 10000; + private String detailLocation = "상계동"; + private Integer status = 0; + private String boughtUserId = ""; + + private PostDto postDto; + private MockMultipartFile postFile; + + // Image 입력값 + private String fileName = "images"; + private List files = new ArrayList<>(); // 어떻게 입력값을 생성? + private MockMultipartFile file1; + private MockMultipartFile file2; + + private String postDtoJson = ""; // API 요청 body + + @Autowired + private WebApplicationContext ctx; + + @BeforeEach + void setUp() { + mockMvc = + MockMvcBuilders.webAppContextSetup(ctx) + .addFilters(new CharacterEncodingFilter("UTF-8", true)).build(); + + // 게시글 객체 + postDto = PostDto.builder() + .postNum(postNum) + .userId(userId) + .location(location) + .title(title) + .category(category) + .content(content) + .price(price).detailLocation(detailLocation).status(status).boughtUserId(boughtUserId).build(); + + // 이미지 객체 + file1 = new MockMultipartFile(fileName, "test1.png", MediaType.IMAGE_PNG_VALUE, "test1".getBytes()); + file2 = new MockMultipartFile(fileName, "test2.png", MediaType.IMAGE_PNG_VALUE, "test2".getBytes()); + + files.add(file1); + files.add(file2); + + } + + @Test + @DisplayName("게시글_등록_성공") + void writePostSuccess() throws Exception { + given(boardService.writePost(any(PostDto.class))).willReturn(postDto); + doNothing().when(boardService).uploadImages(postDto.getPostNum(), files); // void 반환 메소드에 대한 코드 + + // Body 생성 + // PostDto와 MultiPartFile[]이 전달됨 + postDtoJson = new ObjectMapper().writeValueAsString(postDto); // postDto와, Image가 어떻게 전송되는지? + postFile = new MockMultipartFile( + "postDto", "", "application/json", postDtoJson.getBytes()); + mockMvc.perform(multipart("/api/board/writePost") + .file(file1) + .file(file2) + .file(postFile) + .contentType(MediaType.MULTIPART_FORM_DATA) + .accept(MediaType.APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(content().string("{\"status\":\"OK\",\"message\":\"게시글 등록 성공\"}")) + .andDo(print()); + + // + verify(boardService).writePost(any(PostDto.class)); + verify(boardService).uploadImages(postDto.getPostNum(), files); + } + + @Test + @DisplayName("게시글_형식_불일치") + void validationTest() throws Exception { + // 제목이 입력되지 않은 상태 가정 + title = ""; + postDto.setTitle(title); + + postDtoJson = new ObjectMapper().writeValueAsString(postDto); // postDto와, Image가 어떻게 전송되는지? + postFile = new MockMultipartFile( + "postDto", "", "application/json", postDtoJson.getBytes()); + mockMvc.perform(multipart("/api/board/writePost") + .file(file1) + .file(file2) + .file(postFile) + .contentType(MediaType.MULTIPART_FORM_DATA) + .accept(MediaType.APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message.title").exists()) // message: title 존재 + .andDo(print()); + } + + @Test + @DisplayName("게시글_DTO_저장_실패") + void writePostFailed() throws Exception { + given(boardService.writePost(any(PostDto.class))).willThrow(new BoardException("게시글 등록에 실패했습니다.")); + + postDtoJson = new ObjectMapper().writeValueAsString(postDto); // postDto와, Image가 어떻게 전송되는지? + postFile = new MockMultipartFile( + "postDto", "", "application/json", postDtoJson.getBytes()); + mockMvc.perform(multipart("/api/board/writePost") + .file(file1) + .file(file2) + .file(postFile) + .contentType(MediaType.MULTIPART_FORM_DATA) + .accept(MediaType.APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(content().string("{\"status\":\"OK\",\"message\":\"게시글 등록에 실패했습니다.\"}")) + .andDo(print()); + + // + verify(boardService).writePost(any(PostDto.class)); + } + + @Test + @DisplayName("게시글_이미지_저장_실패") + void uploadImageFailed() throws Exception { + given(boardService.writePost(any(PostDto.class))).willReturn(postDto); + doThrow(new BoardException("1번째 이미지 저장에 실패했습니다.")) + .when(boardService).uploadImages(postDto.getPostNum(), files); + + postDtoJson = new ObjectMapper().writeValueAsString(postDto); // postDto와, Image가 어떻게 전송되는지? + postFile = new MockMultipartFile( + "postDto", "", "application/json", postDtoJson.getBytes()); + mockMvc.perform(multipart("/api/board/writePost") + .file(file1) + .file(file2) + .file(postFile) + .contentType(MediaType.MULTIPART_FORM_DATA) + .accept(MediaType.APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(content().string("{\"status\":\"OK\",\"message\":\"1번째 이미지 저장에 실패했습니다.\"}")) + .andDo(print()); + + // + verify(boardService).writePost(any(PostDto.class)); + verify(boardService).uploadImages(postDto.getPostNum(), files); + } + + @Test + @DisplayName("게시글_이미지_정보_저장_실패") + void saveImageInfoFailed() throws Exception { + given(boardService.writePost(any(PostDto.class))).willReturn(postDto); + doThrow(new BoardException("1번째 이미지 정보 저장에 실패했습니다.")) + .when(boardService).uploadImages(postDto.getPostNum(), files); + + postDtoJson = new ObjectMapper().writeValueAsString(postDto); // postDto와, Image가 어떻게 전송되는지? + postFile = new MockMultipartFile( + "postDto", "", "application/json", postDtoJson.getBytes()); + mockMvc.perform(multipart("/api/board/writePost") + .file(file1) + .file(file2) + .file(postFile) + .contentType(MediaType.MULTIPART_FORM_DATA) + .accept(MediaType.APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(content().string("{\"status\":\"OK\",\"message\":\"1번째 이미지 정보 저장에 실패했습니다.\"}")) + .andDo(print()); + + // + verify(boardService).writePost(any(PostDto.class)); + verify(boardService).uploadImages(postDto.getPostNum(), files); + } +} From 44240d0dfea1c6966146a5fb7d1a36b6e6bccb2b Mon Sep 17 00:00:00 2001 From: Hyunuk Date: Thu, 12 Oct 2023 09:22:54 +0900 Subject: [PATCH 06/22] [tomato-market/plan#8] Service Test --- .../market/controller/BoardController.java | 3 + .../tomato/market/data/entity/PostEntity.java | 2 + .../market/service/impl/BoardServiceImpl.java | 11 +- .../controller/BoardControllerTest.java | 39 +++-- .../market/service/BoardServiceTest.java | 151 ++++++++++++++++++ 5 files changed, 186 insertions(+), 20 deletions(-) create mode 100644 src/test/java/com/tomato/market/service/BoardServiceTest.java diff --git a/src/main/java/com/tomato/market/controller/BoardController.java b/src/main/java/com/tomato/market/controller/BoardController.java index 7b039d3..4a4be0e 100644 --- a/src/main/java/com/tomato/market/controller/BoardController.java +++ b/src/main/java/com/tomato/market/controller/BoardController.java @@ -49,6 +49,9 @@ public PostResponseDto writePost( logger.info("BoardController.writePost() is called"); logger.info("BoardController.writerPost() : Validation 검증 성공"); + logger.warn(postDto.toString()); + logger.warn(files.toString()); + // 게시글 등록 PostDto savedPost = boardService.writePost(postDto); logger.info("BoardController.writePost() : 게시글 저장 성공"); diff --git a/src/main/java/com/tomato/market/data/entity/PostEntity.java b/src/main/java/com/tomato/market/data/entity/PostEntity.java index 6da9342..1ff5255 100644 --- a/src/main/java/com/tomato/market/data/entity/PostEntity.java +++ b/src/main/java/com/tomato/market/data/entity/PostEntity.java @@ -15,12 +15,14 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.ToString; @Entity @Builder @Getter @NoArgsConstructor @AllArgsConstructor +@ToString @EntityListeners(AuditingEntityListener.class) @Table(name = "post") public class PostEntity { diff --git a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java index ec16ff2..2055e8b 100644 --- a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java +++ b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java @@ -58,9 +58,9 @@ public PostDto writePost(PostDto postDto) { public void uploadImages(Integer postNum, List files) { // 이미지 업로드 logger.info("BoardServiceImpl.uploadImages() is called"); //유 - int count = 0; + int count = 1; for (MultipartFile file : files) { - logger.info("BoardServiceImpl.uploadImages() : 이미지" + (count + 1) + " 저장 시도"); + logger.info("BoardServiceImpl.uploadImages() : 이미지" + (count++) + " 저장 시도"); UUID uuid = UUID.randomUUID(); // UUID 생성 String fileName = uuid + "_" + file.getOriginalFilename(); // 저장될 unique한 이름 생성 : originalName 형식 어떻게 되는지? logger.info("BoardServiceImpl.uploadImages() : fileName-" + fileName); // 파일 이름 형식 체크 @@ -71,16 +71,17 @@ public void uploadImages(Integer postNum, List files) { // 이미 } catch (Exception e) { logger.warn("BoardServiceImpl.uploadImages() : 파일 저장 실패"); e.printStackTrace(); - throw new BoardException((count + 1) + "번째 이미지 저장에 실패했습니다."); + throw new BoardException("이미지 파일 저장에 실패했습니다."); } + logger.info("BoardServiceImpl.uploadImages() : 이미지 파일 저장 성공"); // DB에 파일 정보 저장 ImageEntity imageEntity = ImageEntity.builder().postNum(postNum).imageName(file.getOriginalFilename()).uuid(fileName).build(); ImageEntity saveResult = boardDao.saveImage(imageEntity); // 어떤 식으로 저장되는지 repository 분리? - if (imageEntity == null) { + if (saveResult == null) { logger.warn("BoardServiceImpl.uploadImages() : DB에 정보 저장 실패"); - throw new BoardException((count + 1) + "번째 이미지 정보 저장에 실패했습니다."); + throw new BoardException("이미지 정보 저장에 실패했습니다."); } // 예외 처리 logger.info("BoardServiceImpl.uploadImages() : DB에 정보 저장 성공"); } diff --git a/src/test/java/com/tomato/market/controller/BoardControllerTest.java b/src/test/java/com/tomato/market/controller/BoardControllerTest.java index 218893d..12e6722 100644 --- a/src/test/java/com/tomato/market/controller/BoardControllerTest.java +++ b/src/test/java/com/tomato/market/controller/BoardControllerTest.java @@ -59,7 +59,7 @@ public class BoardControllerTest { // Image 입력값 private String fileName = "images"; - private List files = new ArrayList<>(); // 어떻게 입력값을 생성? + private List files = new ArrayList<>(); // private MockMultipartFile file1; private MockMultipartFile file2; @@ -82,7 +82,11 @@ void setUp() { .title(title) .category(category) .content(content) - .price(price).detailLocation(detailLocation).status(status).boughtUserId(boughtUserId).build(); + .price(price) + .detailLocation(detailLocation) + .status(status) + .boughtUserId(boughtUserId) + .build(); // 이미지 객체 file1 = new MockMultipartFile(fileName, "test1.png", MediaType.IMAGE_PNG_VALUE, "test1".getBytes()); @@ -104,16 +108,21 @@ void writePostSuccess() throws Exception { postDtoJson = new ObjectMapper().writeValueAsString(postDto); // postDto와, Image가 어떻게 전송되는지? postFile = new MockMultipartFile( "postDto", "", "application/json", postDtoJson.getBytes()); - mockMvc.perform(multipart("/api/board/writePost") - .file(file1) - .file(file2) - .file(postFile) - .contentType(MediaType.MULTIPART_FORM_DATA) - .accept(MediaType.APPLICATION_JSON) - ) - .andExpect(status().isOk()) - .andExpect(content().string("{\"status\":\"OK\",\"message\":\"게시글 등록 성공\"}")) - .andDo(print()); + try { + mockMvc.perform(multipart("/api/board/writePost") + .file(file1) + .file(file2) + .file(postFile) + .contentType(MediaType.MULTIPART_FORM_DATA) + .accept(MediaType.APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(content().string("{\"status\":\"OK\",\"message\":\"게시글 등록 성공\"}")) + .andDo(print()); + + } catch (Exception exception) { + exception.printStackTrace(); + } // verify(boardService).writePost(any(PostDto.class)); @@ -144,7 +153,7 @@ void validationTest() throws Exception { @Test @DisplayName("게시글_DTO_저장_실패") - void writePostFailed() throws Exception { + void writePostFailure() throws Exception { given(boardService.writePost(any(PostDto.class))).willThrow(new BoardException("게시글 등록에 실패했습니다.")); postDtoJson = new ObjectMapper().writeValueAsString(postDto); // postDto와, Image가 어떻게 전송되는지? @@ -167,7 +176,7 @@ void writePostFailed() throws Exception { @Test @DisplayName("게시글_이미지_저장_실패") - void uploadImageFailed() throws Exception { + void uploadImageFailure() throws Exception { given(boardService.writePost(any(PostDto.class))).willReturn(postDto); doThrow(new BoardException("1번째 이미지 저장에 실패했습니다.")) .when(boardService).uploadImages(postDto.getPostNum(), files); @@ -193,7 +202,7 @@ void uploadImageFailed() throws Exception { @Test @DisplayName("게시글_이미지_정보_저장_실패") - void saveImageInfoFailed() throws Exception { + void saveImageInfoFailure() throws Exception { given(boardService.writePost(any(PostDto.class))).willReturn(postDto); doThrow(new BoardException("1번째 이미지 정보 저장에 실패했습니다.")) .when(boardService).uploadImages(postDto.getPostNum(), files); diff --git a/src/test/java/com/tomato/market/service/BoardServiceTest.java b/src/test/java/com/tomato/market/service/BoardServiceTest.java new file mode 100644 index 0000000..914859d --- /dev/null +++ b/src/test/java/com/tomato/market/service/BoardServiceTest.java @@ -0,0 +1,151 @@ +package com.tomato.market.service; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.web.multipart.MultipartFile; + +import com.tomato.market.dao.impl.BoardDaoImpl; +import com.tomato.market.data.dto.PostDto; +import com.tomato.market.data.entity.ImageEntity; +import com.tomato.market.data.entity.PostEntity; +import com.tomato.market.handler.exception.BoardException; +import com.tomato.market.service.impl.BoardServiceImpl; + +@ExtendWith(MockitoExtension.class) +public class BoardServiceTest { + + @Mock + private BoardDaoImpl boardDao; + + // Post 입력값 + private Integer postNum = 1; + private String userId = "spring"; + private String location = "노원구"; + private String title = "제목입니다."; + private String category = "물건"; + private String content = "본문입니다."; + private Integer price = 10000; + private String detailLocation = "상계동"; + private Integer status = 0; + private String boughtUserId = ""; + + private PostDto postDto; + private PostEntity postEntity; + + private ImageEntity imageEntity; + + + private List files = new ArrayList<>(); +// private MultipartFile file1; + // new MockMultipartFile("file1", "testImage", MediaType.IMAGE_PNG_VALUE, "Test file content".getBytes()); +// private MultipartFile file2; +// new MockMultipartFile("file2", "testImage", MediaType.IMAGE_PNG_VALUE, "Test file content".getBytes()); + + + @BeforeEach + void setUp() { + postDto = PostDto.builder().userId(userId).location(location).title(title).category(category).content(content) + .price(price).detailLocation(detailLocation).status(status).boughtUserId(boughtUserId).build(); + + postEntity = PostDto.toPostEntity(postDto); + + imageEntity = ImageEntity.builder().build(); + } + + @Test + @DisplayName("게시글_등록_성공") + void writePostSuccess() { + given(boardDao.save(any(PostEntity.class))).willReturn(postEntity); + + BoardServiceImpl boardService = new BoardServiceImpl(boardDao); + PostDto test1 = PostDto.toPostDto(postEntity); + PostDto test2 = boardService.writePost(postDto); + Assertions.assertEquals(test1.toString(), test2.toString()); + + verify(boardDao).save(any(PostEntity.class)); + } + + @Test + @DisplayName("게시글_데이터_저장_실패") + void writePostFail() { + given(boardDao.save(any(PostEntity.class))).willReturn(null); + + BoardServiceImpl boardService = new BoardServiceImpl(boardDao); + assertThrows(BoardException.class, () -> { + boardService.writePost(postDto); + }); + + verify(boardDao).save(any(PostEntity.class)); + } + + @Test + @DisplayName("이미지_등록_성공") + void uploadImageSuccess() throws IOException { + MultipartFile mockFile1 = Mockito.mock(MultipartFile.class); + MultipartFile mockFile2 = Mockito.mock(MultipartFile.class); + doNothing().when(mockFile1).transferTo(any(File.class)); + doNothing().when(mockFile2).transferTo(any(File.class)); + given(boardDao.saveImage(any(ImageEntity.class))).willReturn(imageEntity); + + BoardServiceImpl boardService = new BoardServiceImpl(boardDao); + boardService.uploadImages(postNum, List.of(mockFile1, mockFile2)); + + verify(mockFile1).transferTo(any(File.class)); + verify(mockFile2).transferTo(any(File.class)); + verify(boardDao, times(2)).saveImage(any(ImageEntity.class)); + } + + @Test + @DisplayName("이미지_파일_저장_실패") + void saveImageFileFailure() throws IOException { + MultipartFile mockFile = Mockito.mock(MultipartFile.class); + // MultipartFile의 transferTo 메소드가 IOException을 던질 때를 시뮬레이트 + doThrow(BoardException.class).when(mockFile).transferTo(any(File.class)); + + BoardServiceImpl boardService = new BoardServiceImpl(boardDao); + BoardException exception = assertThrows(BoardException.class, () -> { + boardService.uploadImages(postNum, List.of(mockFile)); + }); + Assertions.assertEquals(exception.getMessage(), "이미지 파일 저장에 실패했습니다."); + + // transferTo 메소드가 호출되었는지 확인 + verify(mockFile).transferTo(any(File.class)); + } + + @Test + @DisplayName("이미지_정보_저장_실패") + void saveImageInfoFailure() throws IOException { + MultipartFile mockFile = Mockito.mock(MultipartFile.class); + doNothing().when(mockFile).transferTo(any(File.class)); + given(boardDao.saveImage(any(ImageEntity.class))).willReturn(null); + + BoardServiceImpl boardService = new BoardServiceImpl(boardDao); + BoardException exception = assertThrows(BoardException.class, () -> { + boardService.uploadImages(postNum, List.of(mockFile)); + }); + + Assertions.assertEquals(exception.getMessage(), "이미지 정보 저장에 실패했습니다."); + + verify(mockFile).transferTo(any(File.class)); + verify(boardDao).saveImage(any(ImageEntity.class)); + } +} From 6f3b6e2e5a5087669ebab822f95b0a5ce2bee7ab Mon Sep 17 00:00:00 2001 From: Hyunuk Date: Sun, 15 Oct 2023 16:38:42 +0900 Subject: [PATCH 07/22] =?UTF-8?q?[tomato-market/plan#7]=20=EB=B8=8C?= =?UTF-8?q?=EB=9E=9C=EC=B9=98=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/tomato/market/controller/BoardController.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/com/tomato/market/controller/BoardController.java b/src/main/java/com/tomato/market/controller/BoardController.java index 4a4be0e..7b039d3 100644 --- a/src/main/java/com/tomato/market/controller/BoardController.java +++ b/src/main/java/com/tomato/market/controller/BoardController.java @@ -49,9 +49,6 @@ public PostResponseDto writePost( logger.info("BoardController.writePost() is called"); logger.info("BoardController.writerPost() : Validation 검증 성공"); - logger.warn(postDto.toString()); - logger.warn(files.toString()); - // 게시글 등록 PostDto savedPost = boardService.writePost(postDto); logger.info("BoardController.writePost() : 게시글 저장 성공"); From 3d2594393c3b5be92d2ee592415dc8f41ad237df Mon Sep 17 00:00:00 2001 From: Hyunuk Date: Tue, 17 Oct 2023 08:39:45 +0900 Subject: [PATCH 08/22] =?UTF-8?q?[tomato-market/plan#7]=20=EA=B2=8C?= =?UTF-8?q?=EC=8B=9C=EA=B8=80=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20API=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../market/controller/BoardController.java | 32 ++++++------ .../tomato/market/dao/impl/BoardDaoImpl.java | 14 +++--- .../com/tomato/market/data/dto/ImageDto.java | 16 +++++- .../market/data/dto/PostListResponseDto.java | 3 +- .../data/repository/ImageRepository.java | 1 + .../data/repository/PostRepository.java | 3 ++ .../tomato/market/service/BoardService.java | 3 ++ .../market/service/impl/BoardServiceImpl.java | 50 ++++++++++++++----- 8 files changed, 86 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/tomato/market/controller/BoardController.java b/src/main/java/com/tomato/market/controller/BoardController.java index 7b039d3..b226726 100644 --- a/src/main/java/com/tomato/market/controller/BoardController.java +++ b/src/main/java/com/tomato/market/controller/BoardController.java @@ -1,12 +1,14 @@ package com.tomato.market.controller; import java.io.IOException; +import java.net.MalformedURLException; import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.UrlResource; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; @@ -75,38 +77,40 @@ public PostResponseDto writePost( @GetMapping("/board/getPostList") - public PostListResponseDto getPostList() { // 리턴 타입을 리스트로? + public PostListResponseDto getPostList() throws MalformedURLException { // 리턴 타입을 리스트로? // 모든 게시글 조회 -> 페이징 처리 예정, int page 받기 logger.info("BoardController.getPostList() is called"); -// List postList = boardService.getAllPostList(); - List postList = boardService.getPostList(); - if (postList == null) { // 잘못됨 - logger.warn("BoardController.getPostList() : 게시글 리스트를 찾을 수 없음"); - // throw new Error // Service에서 처리? - } // 게시글 리스트를 받음 + List postList = boardService.getPostList(); logger.info("BoardController.getPostList() : 게시글 리스트를 찾음"); // 찾은 postList에서 각 Post의 ID로 Image를 찾음 List imageList = new ArrayList<>(); - for (int i = 0; i < postList.size(); i++) { -// imageList.add( -// 썸네일로 사용할 Image 1개만 필요 -// boardService.getPostImage(postList.get(i).getPostNum()) -// 이미지가 없는 경우는 Service 단에서 Default 이미지 전송 -// ); + for (PostDto postDto : postList) { + // 썸네일로 사용할 Image 1개만 필요 + imageList.add(boardService.getPostImage(postDto.getPostNum())); + } + logger.info("BoardController.getPostList() : 게시글의 이미지 정보를 찾음"); + + // URL을 파일로 변환 + List imageFileList = new ArrayList<>(); + for (ImageDto imageDto : imageList) { + imageFileList.add(boardService.getImageFile(imageDto)); } + logger.info("BoardController.getPostList() : 게시글의 이미지 파일을 찾음"); // Return // 게시글 List 첨부 // 이미지 List 첨부 // 하나의 응답 DTO로 변환하여 반환 + // multiPartFile 반환? return PostListResponseDto.builder() .status(HttpStatus.OK) .message("게시글 리스트 불러오기 성공") - .content(postList) + .postList(postList) + .imageFileList(imageFileList) .build(); } diff --git a/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java b/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java index 95a1213..c939412 100644 --- a/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java +++ b/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java @@ -13,6 +13,7 @@ import com.tomato.market.data.entity.PostEntity; import com.tomato.market.data.repository.ImageRepository; import com.tomato.market.data.repository.PostRepository; +import com.tomato.market.handler.exception.BoardException; @Service @Transactional @@ -60,13 +61,12 @@ public ImageEntity saveImage(ImageEntity imageEntity) { @Override public List findPostList() { // -// Optional> postEntities = postRepository.find(); -// if (postEntities.isPresent()) { -// return postEntities.get(); -// } else { -// throw new BoardException("데이터를 불러오지 못했습니다."); -// } - return null; + List postEntities = postRepository.findAll(); // 페이징 여부에 따라 수정될 여지 있음 // findPostAll + if (postEntities != null) { + return postEntities; + } else { + throw new BoardException("데이터 목록을 불러오지 못했습니다."); + } } @Override diff --git a/src/main/java/com/tomato/market/data/dto/ImageDto.java b/src/main/java/com/tomato/market/data/dto/ImageDto.java index b562ee7..39c1ab9 100644 --- a/src/main/java/com/tomato/market/data/dto/ImageDto.java +++ b/src/main/java/com/tomato/market/data/dto/ImageDto.java @@ -3,11 +3,25 @@ import com.tomato.market.data.entity.ImageEntity; import lombok.Builder; +import lombok.Getter; +import lombok.Setter; @Builder +@Getter +@Setter public class ImageDto { + Integer imageNum; + Integer postNum; + String imageName; + String uuid; public static ImageDto toImageDto(ImageEntity imageEntity) { - return ImageDto.builder().build(); + + return ImageDto.builder() + .imageNum(imageEntity.getImageNum()) + .postNum(imageEntity.getPostNum()) + .imageName(imageEntity.getImageName()) + .uuid(imageEntity.getUuid()) + .build(); } } diff --git a/src/main/java/com/tomato/market/data/dto/PostListResponseDto.java b/src/main/java/com/tomato/market/data/dto/PostListResponseDto.java index 5061e48..81969b7 100644 --- a/src/main/java/com/tomato/market/data/dto/PostListResponseDto.java +++ b/src/main/java/com/tomato/market/data/dto/PostListResponseDto.java @@ -12,5 +12,6 @@ public class PostListResponseDto { HttpStatus status; Object message; - Object content; + Object postList; + Object imageFileList; } diff --git a/src/main/java/com/tomato/market/data/repository/ImageRepository.java b/src/main/java/com/tomato/market/data/repository/ImageRepository.java index c2c427e..470d770 100644 --- a/src/main/java/com/tomato/market/data/repository/ImageRepository.java +++ b/src/main/java/com/tomato/market/data/repository/ImageRepository.java @@ -5,4 +5,5 @@ import com.tomato.market.data.entity.ImageEntity; public interface ImageRepository extends JpaRepository { + ImageEntity findImageByPostNum(Integer postNum); } diff --git a/src/main/java/com/tomato/market/data/repository/PostRepository.java b/src/main/java/com/tomato/market/data/repository/PostRepository.java index f4a122d..abae6bf 100644 --- a/src/main/java/com/tomato/market/data/repository/PostRepository.java +++ b/src/main/java/com/tomato/market/data/repository/PostRepository.java @@ -1,10 +1,13 @@ package com.tomato.market.data.repository; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; import com.tomato.market.data.entity.PostEntity; public interface PostRepository extends JpaRepository { + List findAll(); // findAll()? // int page // Optional> find(); diff --git a/src/main/java/com/tomato/market/service/BoardService.java b/src/main/java/com/tomato/market/service/BoardService.java index 94147b8..b79ff49 100644 --- a/src/main/java/com/tomato/market/service/BoardService.java +++ b/src/main/java/com/tomato/market/service/BoardService.java @@ -1,8 +1,10 @@ package com.tomato.market.service; import java.io.IOException; +import java.net.MalformedURLException; import java.util.List; +import org.springframework.core.io.UrlResource; import org.springframework.web.multipart.MultipartFile; import com.tomato.market.data.dto.ImageDto; @@ -17,4 +19,5 @@ public interface BoardService { ImageDto getPostImage(Integer postNum); + UrlResource getImageFile(ImageDto imageDto) throws MalformedURLException; } diff --git a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java index 2055e8b..dbea05d 100644 --- a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java +++ b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java @@ -1,6 +1,8 @@ package com.tomato.market.service.impl; import java.io.File; +import java.net.MalformedURLException; +import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -8,6 +10,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.UrlResource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; @@ -57,7 +60,7 @@ public PostDto writePost(PostDto postDto) { @Override public void uploadImages(Integer postNum, List files) { // 이미지 업로드 logger.info("BoardServiceImpl.uploadImages() is called"); - //유 + int count = 1; for (MultipartFile file : files) { logger.info("BoardServiceImpl.uploadImages() : 이미지" + (count++) + " 저장 시도"); @@ -91,32 +94,53 @@ public void uploadImages(Integer postNum, List files) { // 이미 } @Override - public List getPostList() { - // getPostList의 범위 - // 한번에 모든 데이터를 불러오는 것은 무리가 있음 - // 한 페이지 당으로 제약해서 get? + public List getPostList() { // 페이징 예정 + logger.info("BoardServiceImpl.getPostList() is called"); List postEntities = boardDao.findPostList(); - if (postEntities != null) { + if (postEntities == null) { // 예외처리 + logger.warn("BoardServiceImpl.getPostList() : 포스트 목록 조회 실패"); + throw new BoardException("목록을 불러오지 못했습니다."); + } + logger.info("BoardServiceImpl.getPostList() : 포스트 목록 조회 성공"); + + // Entity -> DTO 전환 후 List에 추가 + List postList = new ArrayList<>(); + for (PostEntity postEntity : postEntities) { + postList.add(PostDto.toPostDto(postEntity)); } - // get한 정보를 어떻게 리스트로? - // Entity -> DTO 전환 - return null; + return postList; } @Override public ImageDto getPostImage(Integer postNum) { + logger.info("BoardServiceImpl.getPostImage() is called"); // 게시글의 id로 image를 찾아 반환 - ImageEntity imageEntity = boardDao.findImageByPostNum(postNum); - if (imageEntity == null) { - // 이미지 없는 게시물 + ImageEntity imageEntity = boardDao.findImageByPostNum(postNum); // 1개만 받는 메소드 + + // 이미지가 없는 경우, Default 이미지 전송 + if (imageEntity == null) { // 이미지 없는 게시물 + logger.info("BoardServiceImpl.getPostImage() : 이미지가 없는 포스트"); // Default Image 반환 - imageEntity = ImageEntity.builder().build(); + imageEntity = ImageEntity.builder() + .imageNum(0) + .postNum(postNum) + .imageName("default") + .uuid("default.png") + .build(); + } else { + logger.info("BoardServiceImpl.getPostImage() : 이미지가 있는 포스트"); } // Entity -> DTO 전환하여 반환 return ImageDto.toImageDto(imageEntity); } + + @Override + public UrlResource getImageFile(ImageDto imageDto) throws MalformedURLException { + logger.info("BoardServiceImpl.getImageFile() is called"); + return new UrlResource("file:" + projectPath + "/" + imageDto.getUuid()); // + } } From 5c6953deddb0aba871572d9c056f4a3c0327aba6 Mon Sep 17 00:00:00 2001 From: Hyunuk Date: Wed, 18 Oct 2023 01:30:54 +0900 Subject: [PATCH 09/22] =?UTF-8?q?[tomato-market/plan#7]=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=20=EC=A0=91=EA=B7=BC=20=EB=B0=A9=EC=8B=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nginx가 /image로 오는 접근을 이미지 폴더로 전환 --- .../java/com/tomato/market/config/WebConfig.java | 1 - .../tomato/market/controller/BoardController.java | 14 ++------------ .../java/com/tomato/market/data/dto/ImageDto.java | 2 ++ .../market/data/dto/PostListResponseDto.java | 6 +++++- .../com/tomato/market/service/BoardService.java | 3 --- .../market/service/impl/BoardServiceImpl.java | 7 ------- src/main/resources/application-local.properties | 2 +- 7 files changed, 10 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/tomato/market/config/WebConfig.java b/src/main/java/com/tomato/market/config/WebConfig.java index 8564879..b7998a4 100644 --- a/src/main/java/com/tomato/market/config/WebConfig.java +++ b/src/main/java/com/tomato/market/config/WebConfig.java @@ -8,7 +8,6 @@ public class WebConfig implements WebMvcConfigurer { // CORS 처리 - @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") // CORS를 적용할 URL 패턴 diff --git a/src/main/java/com/tomato/market/controller/BoardController.java b/src/main/java/com/tomato/market/controller/BoardController.java index b226726..545a53a 100644 --- a/src/main/java/com/tomato/market/controller/BoardController.java +++ b/src/main/java/com/tomato/market/controller/BoardController.java @@ -8,7 +8,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.io.UrlResource; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; @@ -76,7 +75,7 @@ public PostResponseDto writePost( // updatePost() {} - @GetMapping("/board/getPostList") + @GetMapping(value = "/board/getPostList") public PostListResponseDto getPostList() throws MalformedURLException { // 리턴 타입을 리스트로? // 모든 게시글 조회 -> 페이징 처리 예정, int page 받기 logger.info("BoardController.getPostList() is called"); @@ -93,24 +92,15 @@ public PostListResponseDto getPostList() throws MalformedURLException { // 리 } logger.info("BoardController.getPostList() : 게시글의 이미지 정보를 찾음"); - // URL을 파일로 변환 - List imageFileList = new ArrayList<>(); - for (ImageDto imageDto : imageList) { - imageFileList.add(boardService.getImageFile(imageDto)); - } - logger.info("BoardController.getPostList() : 게시글의 이미지 파일을 찾음"); - - // Return // 게시글 List 첨부 // 이미지 List 첨부 // 하나의 응답 DTO로 변환하여 반환 - // multiPartFile 반환? return PostListResponseDto.builder() .status(HttpStatus.OK) .message("게시글 리스트 불러오기 성공") .postList(postList) - .imageFileList(imageFileList) + .imageList(imageList) .build(); } diff --git a/src/main/java/com/tomato/market/data/dto/ImageDto.java b/src/main/java/com/tomato/market/data/dto/ImageDto.java index 39c1ab9..c58b3d7 100644 --- a/src/main/java/com/tomato/market/data/dto/ImageDto.java +++ b/src/main/java/com/tomato/market/data/dto/ImageDto.java @@ -5,10 +5,12 @@ import lombok.Builder; import lombok.Getter; import lombok.Setter; +import lombok.ToString; @Builder @Getter @Setter +@ToString public class ImageDto { Integer imageNum; Integer postNum; diff --git a/src/main/java/com/tomato/market/data/dto/PostListResponseDto.java b/src/main/java/com/tomato/market/data/dto/PostListResponseDto.java index 81969b7..be81979 100644 --- a/src/main/java/com/tomato/market/data/dto/PostListResponseDto.java +++ b/src/main/java/com/tomato/market/data/dto/PostListResponseDto.java @@ -4,14 +4,18 @@ import lombok.AllArgsConstructor; import lombok.Builder; +import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; @Builder @AllArgsConstructor @NoArgsConstructor +@Getter +@Setter public class PostListResponseDto { HttpStatus status; Object message; Object postList; - Object imageFileList; + Object imageList; } diff --git a/src/main/java/com/tomato/market/service/BoardService.java b/src/main/java/com/tomato/market/service/BoardService.java index b79ff49..94147b8 100644 --- a/src/main/java/com/tomato/market/service/BoardService.java +++ b/src/main/java/com/tomato/market/service/BoardService.java @@ -1,10 +1,8 @@ package com.tomato.market.service; import java.io.IOException; -import java.net.MalformedURLException; import java.util.List; -import org.springframework.core.io.UrlResource; import org.springframework.web.multipart.MultipartFile; import com.tomato.market.data.dto.ImageDto; @@ -19,5 +17,4 @@ public interface BoardService { ImageDto getPostImage(Integer postNum); - UrlResource getImageFile(ImageDto imageDto) throws MalformedURLException; } diff --git a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java index dbea05d..09439d7 100644 --- a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java +++ b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java @@ -1,7 +1,6 @@ package com.tomato.market.service.impl; import java.io.File; -import java.net.MalformedURLException; import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -10,7 +9,6 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.io.UrlResource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; @@ -138,9 +136,4 @@ public ImageDto getPostImage(Integer postNum) { return ImageDto.toImageDto(imageEntity); } - @Override - public UrlResource getImageFile(ImageDto imageDto) throws MalformedURLException { - logger.info("BoardServiceImpl.getImageFile() is called"); - return new UrlResource("file:" + projectPath + "/" + imageDto.getUuid()); // - } } diff --git a/src/main/resources/application-local.properties b/src/main/resources/application-local.properties index 6232692..5ff4739 100644 --- a/src/main/resources/application-local.properties +++ b/src/main/resources/application-local.properties @@ -4,7 +4,7 @@ spring.datasource.url=jdbc:mariadb://localhost:3306/tomatolocal spring.datasource.username=root spring.datasource.password=1111 # JPA -spring.jpa.hibernate.ddl-auto=create +spring.jpa.hibernate.ddl-auto=none spring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=true spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MariaDBDialect From 9e8ff6be9f9a56b5aa8d9c3b55e38ea8b26605f4 Mon Sep 17 00:00:00 2001 From: Hyunuk Date: Wed, 18 Oct 2023 11:45:30 +0900 Subject: [PATCH 10/22] =?UTF-8?q?[tomato-market/plan#7]=20findImage=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/tomato/market/dao/impl/BoardDaoImpl.java | 16 ++++++++-------- .../tomato/market/data/entity/ImageEntity.java | 4 ++++ .../tomato/market/data/entity/PostEntity.java | 2 ++ .../market/data/repository/ImageRepository.java | 4 +++- .../market/service/impl/BoardServiceImpl.java | 1 - 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java b/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java index c939412..d41727c 100644 --- a/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java +++ b/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java @@ -1,6 +1,7 @@ package com.tomato.market.dao.impl; import java.util.List; +import java.util.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -71,13 +72,12 @@ public List findPostList() { @Override public ImageEntity findImageByPostNum(Integer postNum) { -// Optional imageEntity = postRepository.findImageByPostNum(postNum); -// if (imageEntity.isPresent()) { // PostId로 이미지를 찾음 -// return imageEntity.get(); -// } else { // 이미지를 찾지 못함 or 애초에 없음? -// // throw new ImageException(); -// // or return null? - return null; -// } + Optional imageEntity = imageRepository.findImageByPostNum(postNum); + if (imageEntity.isPresent()) { // PostId로 이미지를 찾음 + return imageEntity.get(); + } else { // 이미지를 찾지 못함 or 애초에 없음? + throw new BoardException("이미지를 찾지 못했습니다."); + // or return null? + } } } diff --git a/src/main/java/com/tomato/market/data/entity/ImageEntity.java b/src/main/java/com/tomato/market/data/entity/ImageEntity.java index 5680ff3..c042f77 100644 --- a/src/main/java/com/tomato/market/data/entity/ImageEntity.java +++ b/src/main/java/com/tomato/market/data/entity/ImageEntity.java @@ -5,13 +5,17 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; +import lombok.NoArgsConstructor; @Entity @Builder @Getter @Table(name = "image") +@NoArgsConstructor +@AllArgsConstructor public class ImageEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/src/main/java/com/tomato/market/data/entity/PostEntity.java b/src/main/java/com/tomato/market/data/entity/PostEntity.java index 1ff5255..d31d0b3 100644 --- a/src/main/java/com/tomato/market/data/entity/PostEntity.java +++ b/src/main/java/com/tomato/market/data/entity/PostEntity.java @@ -2,6 +2,7 @@ import java.util.Date; +import org.hibernate.annotations.ColumnDefault; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; @@ -36,6 +37,7 @@ public class PostEntity { String content; Integer price; String detailLocation; + @ColumnDefault("0") Integer status; @CreatedDate Date createdAt; // 애노테이션? diff --git a/src/main/java/com/tomato/market/data/repository/ImageRepository.java b/src/main/java/com/tomato/market/data/repository/ImageRepository.java index 470d770..766b95d 100644 --- a/src/main/java/com/tomato/market/data/repository/ImageRepository.java +++ b/src/main/java/com/tomato/market/data/repository/ImageRepository.java @@ -1,9 +1,11 @@ package com.tomato.market.data.repository; +import java.util.Optional; + import org.springframework.data.jpa.repository.JpaRepository; import com.tomato.market.data.entity.ImageEntity; public interface ImageRepository extends JpaRepository { - ImageEntity findImageByPostNum(Integer postNum); + Optional findImageByPostNum(Integer postNum); } diff --git a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java index 09439d7..8f41f52 100644 --- a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java +++ b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java @@ -49,7 +49,6 @@ public PostDto writePost(PostDto postDto) { throw new BoardException("게시글 등록에 실패했습니다."); } - // 반환 logger.info("BoardServiceImpl.writePost() : 게시글 등록 성공"); return PostDto.toPostDto(saveResult); From 28da49397fe93f11265139d7de6c18a5fed6beaa Mon Sep 17 00:00:00 2001 From: Hyunuk Date: Thu, 19 Oct 2023 08:04:21 +0900 Subject: [PATCH 11/22] [tomato-market/plan#7] Controller Test --- .../tomato/market/dao/impl/BoardDaoImpl.java | 5 +- .../controller/BoardControllerTest.java | 59 +++++++++++++++++++ .../market/service/BoardServiceTest.java | 8 ++- 3 files changed, 68 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java b/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java index d41727c..20cd872 100644 --- a/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java +++ b/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java @@ -75,9 +75,8 @@ public ImageEntity findImageByPostNum(Integer postNum) { Optional imageEntity = imageRepository.findImageByPostNum(postNum); if (imageEntity.isPresent()) { // PostId로 이미지를 찾음 return imageEntity.get(); - } else { // 이미지를 찾지 못함 or 애초에 없음? - throw new BoardException("이미지를 찾지 못했습니다."); - // or return null? + } else { // 이미지를 찾지 못함 or 애초에 없음 + return null; } } } diff --git a/src/test/java/com/tomato/market/controller/BoardControllerTest.java b/src/test/java/com/tomato/market/controller/BoardControllerTest.java index 12e6722..de76d1f 100644 --- a/src/test/java/com/tomato/market/controller/BoardControllerTest.java +++ b/src/test/java/com/tomato/market/controller/BoardControllerTest.java @@ -1,10 +1,13 @@ package com.tomato.market.controller; +import static org.hamcrest.Matchers.is; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; @@ -29,6 +32,7 @@ import org.springframework.web.multipart.MultipartFile; import com.fasterxml.jackson.databind.ObjectMapper; +import com.tomato.market.data.dto.ImageDto; import com.tomato.market.data.dto.PostDto; import com.tomato.market.handler.exception.BoardException; import com.tomato.market.service.impl.BoardServiceImpl; @@ -65,6 +69,15 @@ public class BoardControllerTest { private String postDtoJson = ""; // API 요청 body + // PostList 반환값 + private List postList; + private List imageList; + + private ImageDto imageDto; + private String imageName = "original.png"; + private String uuid = "uuidoriginal.png"; + + @Autowired private WebApplicationContext ctx; @@ -95,6 +108,22 @@ void setUp() { files.add(file1); files.add(file2); + // 게시글 리스트 + postList = new ArrayList<>(); + postList.add(postDto); + postList.add(postDto); + + // 이미지 DB 정보 + imageDto = ImageDto.builder() + .postNum(postNum) + .imageName(imageName) + .uuid(uuid) + .build(); + + // 이미지 리스트 + imageList = new ArrayList<>(); + imageList.add(imageDto); + imageList.add(imageDto); } @Test @@ -225,4 +254,34 @@ void saveImageInfoFailure() throws Exception { verify(boardService).writePost(any(PostDto.class)); verify(boardService).uploadImages(postDto.getPostNum(), files); } + + @Test + @DisplayName("게시글_리스트_불러오기_성공") + void getPostListSuccess() throws Exception { + given(boardService.getPostList()).willReturn(postList); + given(boardService.getPostImage(postNum)).willReturn(imageDto); + + mockMvc.perform(get("/api/board/getPostList")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message", is("게시글 리스트 불러오기 성공"))) + .andExpect(jsonPath("$.postList").exists()) + .andExpect(jsonPath("$.imageList").exists()) + .andDo(print()); + + verify(boardService).getPostList(); + verify(boardService, times(2)).getPostImage(postNum); + } + + @Test + @DisplayName("게시글_리스트_게시글_불러오기_실패") + void getPostListFail() throws Exception { + given(boardService.getPostList()).willThrow(new BoardException("목록을 불러오지 못했습니다.")); + + mockMvc.perform(get("/api/board/getPostList")) + .andExpect(status().isOk()) + .andExpect(content().string("{\"status\":\"OK\",\"message\":\"목록을 불러오지 못했습니다.\"}")) + .andDo(print()); + + verify(boardService).getPostList(); + } } diff --git a/src/test/java/com/tomato/market/service/BoardServiceTest.java b/src/test/java/com/tomato/market/service/BoardServiceTest.java index 914859d..9ca88c5 100644 --- a/src/test/java/com/tomato/market/service/BoardServiceTest.java +++ b/src/test/java/com/tomato/market/service/BoardServiceTest.java @@ -52,6 +52,8 @@ public class BoardServiceTest { private PostEntity postEntity; private ImageEntity imageEntity; + private String imageName = "original.png"; + private String uuid = "uuidoriginal.png"; private List files = new ArrayList<>(); @@ -68,7 +70,11 @@ void setUp() { postEntity = PostDto.toPostEntity(postDto); - imageEntity = ImageEntity.builder().build(); + imageEntity = ImageEntity.builder() + .postNum(postNum) + .imageName(imageName) + .uuid(uuid) + .build(); } @Test From c5d764b600108f03fc5c82f0c445a698eae86d1b Mon Sep 17 00:00:00 2001 From: Hyunuk Date: Thu, 19 Oct 2023 08:27:56 +0900 Subject: [PATCH 12/22] [tomato-market/plan#7] Service Test --- .../market/service/impl/BoardServiceImpl.java | 3 +- .../controller/BoardControllerTest.java | 2 +- .../market/service/BoardServiceTest.java | 75 ++++++++++++++++++- 3 files changed, 73 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java index 8f41f52..a00deb4 100644 --- a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java +++ b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java @@ -122,9 +122,8 @@ public ImageDto getPostImage(Integer postNum) { logger.info("BoardServiceImpl.getPostImage() : 이미지가 없는 포스트"); // Default Image 반환 imageEntity = ImageEntity.builder() - .imageNum(0) .postNum(postNum) - .imageName("default") + .imageName("default.png") .uuid("default.png") .build(); } else { diff --git a/src/test/java/com/tomato/market/controller/BoardControllerTest.java b/src/test/java/com/tomato/market/controller/BoardControllerTest.java index de76d1f..1703426 100644 --- a/src/test/java/com/tomato/market/controller/BoardControllerTest.java +++ b/src/test/java/com/tomato/market/controller/BoardControllerTest.java @@ -274,7 +274,7 @@ void getPostListSuccess() throws Exception { @Test @DisplayName("게시글_리스트_게시글_불러오기_실패") - void getPostListFail() throws Exception { + void getPostListFailure() throws Exception { given(boardService.getPostList()).willThrow(new BoardException("목록을 불러오지 못했습니다.")); mockMvc.perform(get("/api/board/getPostList")) diff --git a/src/test/java/com/tomato/market/service/BoardServiceTest.java b/src/test/java/com/tomato/market/service/BoardServiceTest.java index 9ca88c5..9278e09 100644 --- a/src/test/java/com/tomato/market/service/BoardServiceTest.java +++ b/src/test/java/com/tomato/market/service/BoardServiceTest.java @@ -24,6 +24,7 @@ import org.springframework.web.multipart.MultipartFile; import com.tomato.market.dao.impl.BoardDaoImpl; +import com.tomato.market.data.dto.ImageDto; import com.tomato.market.data.dto.PostDto; import com.tomato.market.data.entity.ImageEntity; import com.tomato.market.data.entity.PostEntity; @@ -57,11 +58,9 @@ public class BoardServiceTest { private List files = new ArrayList<>(); -// private MultipartFile file1; - // new MockMultipartFile("file1", "testImage", MediaType.IMAGE_PNG_VALUE, "Test file content".getBytes()); -// private MultipartFile file2; -// new MockMultipartFile("file2", "testImage", MediaType.IMAGE_PNG_VALUE, "Test file content".getBytes()); + private List postEntities; + private List imageEntities; @BeforeEach void setUp() { @@ -75,6 +74,15 @@ void setUp() { .imageName(imageName) .uuid(uuid) .build(); + + postEntities = new ArrayList<>(); + postEntities.add(postEntity); + postEntities.add(postEntity); + + imageEntities = new ArrayList<>(); + imageEntities.add(imageEntity); + imageEntities.add(imageEntity); + } @Test @@ -154,4 +162,63 @@ void saveImageInfoFailure() throws IOException { verify(mockFile).transferTo(any(File.class)); verify(boardDao).saveImage(any(ImageEntity.class)); } + + @Test + @DisplayName("게시글_리스트_조회_성공") + void getPostListSuccess() { + given(boardDao.findPostList()).willReturn(postEntities); + + List postDtoList = new ArrayList<>(); + postDtoList.add(PostDto.toPostDto(postEntity)); + postDtoList.add(PostDto.toPostDto(postEntity)); + + BoardServiceImpl boardService = new BoardServiceImpl(boardDao); + Assertions.assertEquals(boardService.getPostList().toString(), postDtoList.toString()); + + verify(boardDao).findPostList(); + } + + @Test + @DisplayName("게시글_리스트_조회_실패") + void getPostListFailure() { + given(boardDao.findPostList()).willReturn(null); + + BoardServiceImpl boardService = new BoardServiceImpl(boardDao); + BoardException exception = Assertions.assertThrows(BoardException.class, () -> { + boardService.getPostList(); + }); + Assertions.assertEquals(exception.getMessage(), "목록을 불러오지 못했습니다."); + + verify(boardDao).findPostList(); + } + + @Test + @DisplayName("게시글_이미지_조회_성공") + void getPostImageSuccess() { + given(boardDao.findImageByPostNum(postNum)).willReturn(imageEntity); + + BoardServiceImpl boardService = new BoardServiceImpl(boardDao); + Assertions.assertEquals( + boardService.getPostImage(postNum).toString(), ImageDto.toImageDto(imageEntity).toString()); + + verify(boardDao).findImageByPostNum(postNum); + } + + @Test + @DisplayName("게시글_이미지_조회_실패") + void getPostImageFailure() { + given(boardDao.findImageByPostNum(postNum)).willReturn(null); + + ImageEntity defaultImage = ImageEntity.builder() + .postNum(postNum) + .imageName("default.png") + .uuid("default.png") + .build(); + + BoardServiceImpl boardService = new BoardServiceImpl(boardDao); + Assertions.assertEquals( + boardService.getPostImage(postNum).toString(), ImageDto.toImageDto(defaultImage).toString()); + + verify(boardDao).findImageByPostNum(postNum); + } } From 1a92ee4df043379f9dd25e6fc4100935b29227db Mon Sep 17 00:00:00 2001 From: Hyunuk Date: Thu, 19 Oct 2023 15:32:35 +0900 Subject: [PATCH 13/22] =?UTF-8?q?[tomato-market/plan#7]=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../market/controller/BoardController.java | 26 +++++++++++++++++-- .../java/com/tomato/market/dao/BoardDao.java | 5 ++-- .../tomato/market/dao/impl/BoardDaoImpl.java | 7 ++--- .../market/data/dto/PostListResponseDto.java | 1 + .../com/tomato/market/data/dto/SearchDto.java | 21 +++++++++++++++ .../data/repository/PostRepository.java | 6 ++--- .../tomato/market/service/BoardService.java | 4 ++- .../market/service/impl/BoardServiceImpl.java | 12 ++++----- 8 files changed, 64 insertions(+), 18 deletions(-) create mode 100644 src/main/java/com/tomato/market/data/dto/SearchDto.java diff --git a/src/main/java/com/tomato/market/controller/BoardController.java b/src/main/java/com/tomato/market/controller/BoardController.java index 545a53a..0d878f9 100644 --- a/src/main/java/com/tomato/market/controller/BoardController.java +++ b/src/main/java/com/tomato/market/controller/BoardController.java @@ -8,6 +8,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +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.MediaType; import org.springframework.web.bind.annotation.GetMapping; @@ -21,6 +25,7 @@ import com.tomato.market.data.dto.PostDto; import com.tomato.market.data.dto.PostListResponseDto; import com.tomato.market.data.dto.PostResponseDto; +import com.tomato.market.data.dto.SearchDto; import com.tomato.market.service.BoardService; import jakarta.validation.Valid; @@ -76,14 +81,30 @@ public PostResponseDto writePost( @GetMapping(value = "/board/getPostList") - public PostListResponseDto getPostList() throws MalformedURLException { // 리턴 타입을 리스트로? + public PostListResponseDto getPostList( + @PageableDefault(page = 0, size = 10, sort = "postNum", direction = Sort.Direction.DESC) Pageable pageable) + throws MalformedURLException { // 리턴 타입을 리스트로? // 모든 게시글 조회 -> 페이징 처리 예정, int page 받기 logger.info("BoardController.getPostList() is called"); + logger.info("BoardController.getPostList() page : " + pageable.getPageNumber()); // 게시글 리스트를 받음 - List postList = boardService.getPostList(); + Page postList = boardService.getPostList(pageable); logger.info("BoardController.getPostList() : 게시글 리스트를 찾음"); + int nowPage = postList.getPageable().getPageNumber() + 1; + int startPage = Math.max(nowPage - 2, 1); + int endPage = Math.min(nowPage + 2, postList.getTotalPages()); + int totalPage = postList.getTotalPages(); + + SearchDto searchDto = SearchDto.builder() + .nowPage(nowPage) + .startPage(startPage) + .endPage(endPage) + .totalPage(totalPage) + .build(); + + // 찾은 postList에서 각 Post의 ID로 Image를 찾음 List imageList = new ArrayList<>(); for (PostDto postDto : postList) { @@ -101,6 +122,7 @@ public PostListResponseDto getPostList() throws MalformedURLException { // 리 .message("게시글 리스트 불러오기 성공") .postList(postList) .imageList(imageList) + .page(searchDto) .build(); } diff --git a/src/main/java/com/tomato/market/dao/BoardDao.java b/src/main/java/com/tomato/market/dao/BoardDao.java index 09e5cca..753c833 100644 --- a/src/main/java/com/tomato/market/dao/BoardDao.java +++ b/src/main/java/com/tomato/market/dao/BoardDao.java @@ -1,6 +1,7 @@ package com.tomato.market.dao; -import java.util.List; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import com.tomato.market.data.entity.ImageEntity; import com.tomato.market.data.entity.PostEntity; @@ -10,7 +11,7 @@ public interface BoardDao { ImageEntity saveImage(ImageEntity imageEntity); - List findPostList(); + Page findPostList(Pageable pageable); ImageEntity findImageByPostNum(Integer postNum); diff --git a/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java b/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java index 20cd872..4505b47 100644 --- a/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java +++ b/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java @@ -1,11 +1,12 @@ package com.tomato.market.dao.impl; -import java.util.List; import java.util.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -60,9 +61,9 @@ public ImageEntity saveImage(ImageEntity imageEntity) { } @Override - public List findPostList() { + public Page findPostList(Pageable pageable) { // - List postEntities = postRepository.findAll(); // 페이징 여부에 따라 수정될 여지 있음 // findPostAll + Page postEntities = postRepository.findAll(pageable); // 페이징 여부에 따라 수정될 여지 있음 // findPostAll if (postEntities != null) { return postEntities; } else { diff --git a/src/main/java/com/tomato/market/data/dto/PostListResponseDto.java b/src/main/java/com/tomato/market/data/dto/PostListResponseDto.java index be81979..a4a0eb1 100644 --- a/src/main/java/com/tomato/market/data/dto/PostListResponseDto.java +++ b/src/main/java/com/tomato/market/data/dto/PostListResponseDto.java @@ -18,4 +18,5 @@ public class PostListResponseDto { Object message; Object postList; Object imageList; + Object page; } diff --git a/src/main/java/com/tomato/market/data/dto/SearchDto.java b/src/main/java/com/tomato/market/data/dto/SearchDto.java new file mode 100644 index 0000000..5663fdb --- /dev/null +++ b/src/main/java/com/tomato/market/data/dto/SearchDto.java @@ -0,0 +1,21 @@ +package com.tomato.market.data.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Builder +@Getter +@Setter +@ToString +@AllArgsConstructor +@NoArgsConstructor +public class SearchDto { + int nowPage; + int startPage; + int endPage; + int totalPage; +} diff --git a/src/main/java/com/tomato/market/data/repository/PostRepository.java b/src/main/java/com/tomato/market/data/repository/PostRepository.java index abae6bf..0c6e7ab 100644 --- a/src/main/java/com/tomato/market/data/repository/PostRepository.java +++ b/src/main/java/com/tomato/market/data/repository/PostRepository.java @@ -1,13 +1,13 @@ package com.tomato.market.data.repository; -import java.util.List; - +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import com.tomato.market.data.entity.PostEntity; public interface PostRepository extends JpaRepository { - List findAll(); + Page findAll(Pageable pageable); // findAll()? // int page // Optional> find(); diff --git a/src/main/java/com/tomato/market/service/BoardService.java b/src/main/java/com/tomato/market/service/BoardService.java index 94147b8..011c356 100644 --- a/src/main/java/com/tomato/market/service/BoardService.java +++ b/src/main/java/com/tomato/market/service/BoardService.java @@ -3,6 +3,8 @@ import java.io.IOException; import java.util.List; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.web.multipart.MultipartFile; import com.tomato.market.data.dto.ImageDto; @@ -13,7 +15,7 @@ public interface BoardService { void uploadImages(Integer postNum, List files) throws IOException; - List getPostList(); + Page getPostList(Pageable pageable); ImageDto getPostImage(Integer postNum); diff --git a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java index a00deb4..416faaa 100644 --- a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java +++ b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java @@ -1,7 +1,6 @@ package com.tomato.market.service.impl; import java.io.File; -import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -9,6 +8,8 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; @@ -91,10 +92,10 @@ public void uploadImages(Integer postNum, List files) { // 이미 } @Override - public List getPostList() { // 페이징 예정 + public Page getPostList(Pageable pageable) { // 페이징 예정 logger.info("BoardServiceImpl.getPostList() is called"); - List postEntities = boardDao.findPostList(); + Page postEntities = boardDao.findPostList(pageable); if (postEntities == null) { // 예외처리 logger.warn("BoardServiceImpl.getPostList() : 포스트 목록 조회 실패"); @@ -103,10 +104,7 @@ public List getPostList() { // 페이징 예정 logger.info("BoardServiceImpl.getPostList() : 포스트 목록 조회 성공"); // Entity -> DTO 전환 후 List에 추가 - List postList = new ArrayList<>(); - for (PostEntity postEntity : postEntities) { - postList.add(PostDto.toPostDto(postEntity)); - } + Page postList = postEntities.map(PostDto::toPostDto); return postList; } From a8c6edf984cf96c6404e13122a936ec0d563688a Mon Sep 17 00:00:00 2001 From: Hyunuk Date: Thu, 19 Oct 2023 18:15:16 +0900 Subject: [PATCH 14/22] =?UTF-8?q?[tomato-market/plan#7]=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../market/controller/BoardController.java | 24 ++++++++++++------- .../java/com/tomato/market/dao/BoardDao.java | 2 ++ .../tomato/market/dao/impl/BoardDaoImpl.java | 19 ++++++++++++++- .../data/dto/{SearchDto.java => PageDto.java} | 2 +- .../data/repository/PostRepository.java | 2 ++ .../tomato/market/service/BoardService.java | 2 ++ .../market/service/impl/BoardServiceImpl.java | 15 ++++++++++++ 7 files changed, 56 insertions(+), 10 deletions(-) rename src/main/java/com/tomato/market/data/dto/{SearchDto.java => PageDto.java} (92%) diff --git a/src/main/java/com/tomato/market/controller/BoardController.java b/src/main/java/com/tomato/market/controller/BoardController.java index 0d878f9..f9aa8d9 100644 --- a/src/main/java/com/tomato/market/controller/BoardController.java +++ b/src/main/java/com/tomato/market/controller/BoardController.java @@ -17,15 +17,16 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import com.tomato.market.data.dto.ImageDto; +import com.tomato.market.data.dto.PageDto; import com.tomato.market.data.dto.PostDto; import com.tomato.market.data.dto.PostListResponseDto; import com.tomato.market.data.dto.PostResponseDto; -import com.tomato.market.data.dto.SearchDto; import com.tomato.market.service.BoardService; import jakarta.validation.Valid; @@ -82,14 +83,21 @@ public PostResponseDto writePost( @GetMapping(value = "/board/getPostList") public PostListResponseDto getPostList( - @PageableDefault(page = 0, size = 10, sort = "postNum", direction = Sort.Direction.DESC) Pageable pageable) - throws MalformedURLException { // 리턴 타입을 리스트로? - // 모든 게시글 조회 -> 페이징 처리 예정, int page 받기 + @PageableDefault(page = 0, size = 10, sort = "postNum", direction = Sort.Direction.DESC) Pageable pageable, + @RequestParam(required = false) String keyword) throws MalformedURLException { logger.info("BoardController.getPostList() is called"); - logger.info("BoardController.getPostList() page : " + pageable.getPageNumber()); +// logger.info("BoardController.getPostList() page : " + pageable.getPageNumber()); // 게시글 리스트를 받음 - Page postList = boardService.getPostList(pageable); + Page postList = null; + if (keyword == null) { + postList = boardService.getPostList(pageable); + } else { + logger.info("BoardController.getPostList() : 검색 키워드 있음"); + postList = boardService.getPostSearchList(keyword, pageable); + } + + logger.info("BoardController.getPostList() : 게시글 리스트를 찾음"); int nowPage = postList.getPageable().getPageNumber() + 1; @@ -97,7 +105,7 @@ public PostListResponseDto getPostList( int endPage = Math.min(nowPage + 2, postList.getTotalPages()); int totalPage = postList.getTotalPages(); - SearchDto searchDto = SearchDto.builder() + PageDto pageDto = PageDto.builder() .nowPage(nowPage) .startPage(startPage) .endPage(endPage) @@ -122,7 +130,7 @@ public PostListResponseDto getPostList( .message("게시글 리스트 불러오기 성공") .postList(postList) .imageList(imageList) - .page(searchDto) + .page(pageDto) .build(); } diff --git a/src/main/java/com/tomato/market/dao/BoardDao.java b/src/main/java/com/tomato/market/dao/BoardDao.java index 753c833..b00b341 100644 --- a/src/main/java/com/tomato/market/dao/BoardDao.java +++ b/src/main/java/com/tomato/market/dao/BoardDao.java @@ -13,6 +13,8 @@ public interface BoardDao { Page findPostList(Pageable pageable); + Page findPostSearchList(String keyword, Pageable pageable); + ImageEntity findImageByPostNum(Integer postNum); } diff --git a/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java b/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java index 4505b47..d63a345 100644 --- a/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java +++ b/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java @@ -62,15 +62,32 @@ public ImageEntity saveImage(ImageEntity imageEntity) { @Override public Page findPostList(Pageable pageable) { -// + logger.info("BoardDaoImpl.findPostList() is called"); + Page postEntities = postRepository.findAll(pageable); // 페이징 여부에 따라 수정될 여지 있음 // findPostAll if (postEntities != null) { + logger.info("BoardDaoImpl.findPostList() : 데이터 목록 조회 성공"); return postEntities; } else { + logger.warn("BoardDaoImpl.findPostList() : 데이터 목록 조회 실패"); throw new BoardException("데이터 목록을 불러오지 못했습니다."); } } + @Override + public Page findPostSearchList(String keyword, Pageable pageable) { + logger.info("BoardDaoImpl.findPostSearchList() is called"); + + Page postEntities = postRepository.findByTitleContaining(keyword, pageable); + if (postEntities != null) { + logger.info("BoardDaoImpl.findPostSearchList() : 검색 목록 조회 성공"); + return postEntities; + } else { + logger.warn("BoardDaoImpl.findPostSearchList() : 검색 목록 조회 실패"); + throw new BoardException("검색 결과 목록을 불러오지 못했습니다."); + } + } + @Override public ImageEntity findImageByPostNum(Integer postNum) { Optional imageEntity = imageRepository.findImageByPostNum(postNum); diff --git a/src/main/java/com/tomato/market/data/dto/SearchDto.java b/src/main/java/com/tomato/market/data/dto/PageDto.java similarity index 92% rename from src/main/java/com/tomato/market/data/dto/SearchDto.java rename to src/main/java/com/tomato/market/data/dto/PageDto.java index 5663fdb..3d8de78 100644 --- a/src/main/java/com/tomato/market/data/dto/SearchDto.java +++ b/src/main/java/com/tomato/market/data/dto/PageDto.java @@ -13,7 +13,7 @@ @ToString @AllArgsConstructor @NoArgsConstructor -public class SearchDto { +public class PageDto { int nowPage; int startPage; int endPage; diff --git a/src/main/java/com/tomato/market/data/repository/PostRepository.java b/src/main/java/com/tomato/market/data/repository/PostRepository.java index 0c6e7ab..721f743 100644 --- a/src/main/java/com/tomato/market/data/repository/PostRepository.java +++ b/src/main/java/com/tomato/market/data/repository/PostRepository.java @@ -8,6 +8,8 @@ public interface PostRepository extends JpaRepository { Page findAll(Pageable pageable); + + Page findByTitleContaining(String keyword, Pageable pageable); // findAll()? // int page // Optional> find(); diff --git a/src/main/java/com/tomato/market/service/BoardService.java b/src/main/java/com/tomato/market/service/BoardService.java index 011c356..8c9c20e 100644 --- a/src/main/java/com/tomato/market/service/BoardService.java +++ b/src/main/java/com/tomato/market/service/BoardService.java @@ -17,6 +17,8 @@ public interface BoardService { Page getPostList(Pageable pageable); + Page getPostSearchList(String keyword, Pageable pageable); + ImageDto getPostImage(Integer postNum); } diff --git a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java index 416faaa..04b5f26 100644 --- a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java +++ b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java @@ -109,6 +109,21 @@ public Page getPostList(Pageable pageable) { // 페이징 예정 return postList; } + @Override + public Page getPostSearchList(String keyword, Pageable pageable) { + logger.info("BoardServiceImpl.getPostSearchList() is called"); + + Page postEntities = boardDao.findPostSearchList(keyword, pageable); + if (postEntities == null) { + logger.warn("BoardServiceImpl.getPostSearchList() : 검색 결과 목록 조회 실패"); + throw new BoardException("검색 결과 목록을 불러오지 못했습니다."); + } + logger.info("BoardServiceImpl.getPostSearchList() : 검색 결과 목록 조회 성공"); + + Page postList = postEntities.map(PostDto::toPostDto); + return postList; + } + @Override public ImageDto getPostImage(Integer postNum) { logger.info("BoardServiceImpl.getPostImage() is called"); From 5755038bffe2d2495bdbed0380c8c3af9ddc8166 Mon Sep 17 00:00:00 2001 From: Hyunuk Date: Thu, 19 Oct 2023 20:20:41 +0900 Subject: [PATCH 15/22] [tomato-market/plan#7] Controller Test --- .../market/controller/BoardController.java | 1 + .../controller/BoardControllerTest.java | 56 ++++++++- .../market/service/BoardServiceTest.java | 117 +++++++++--------- 3 files changed, 111 insertions(+), 63 deletions(-) diff --git a/src/main/java/com/tomato/market/controller/BoardController.java b/src/main/java/com/tomato/market/controller/BoardController.java index f9aa8d9..b21cb1a 100644 --- a/src/main/java/com/tomato/market/controller/BoardController.java +++ b/src/main/java/com/tomato/market/controller/BoardController.java @@ -91,6 +91,7 @@ public PostListResponseDto getPostList( // 게시글 리스트를 받음 Page postList = null; if (keyword == null) { + logger.info("BoardController.getPostList() : 검색 키워드 없음"); postList = boardService.getPostList(pageable); } else { logger.info("BoardController.getPostList() : 검색 키워드 있음"); diff --git a/src/test/java/com/tomato/market/controller/BoardControllerTest.java b/src/test/java/com/tomato/market/controller/BoardControllerTest.java index 1703426..69f2f6e 100644 --- a/src/test/java/com/tomato/market/controller/BoardControllerTest.java +++ b/src/test/java/com/tomato/market/controller/BoardControllerTest.java @@ -23,6 +23,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; import org.springframework.http.MediaType; import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.web.servlet.MockMvc; @@ -77,6 +81,12 @@ public class BoardControllerTest { private String imageName = "original.png"; private String uuid = "uuidoriginal.png"; + // Page + private Pageable pageable = PageRequest.of(0, 10); + private Page postPageList; + + // Search + private String keyword = "keyword"; @Autowired private WebApplicationContext ctx; @@ -113,6 +123,7 @@ void setUp() { postList.add(postDto); postList.add(postDto); + // 이미지 DB 정보 imageDto = ImageDto.builder() .postNum(postNum) @@ -124,6 +135,10 @@ void setUp() { imageList = new ArrayList<>(); imageList.add(imageDto); imageList.add(imageDto); + + // Page + postPageList = new PageImpl<>(postList, pageable, 2); + } @Test @@ -258,9 +273,10 @@ void saveImageInfoFailure() throws Exception { @Test @DisplayName("게시글_리스트_불러오기_성공") void getPostListSuccess() throws Exception { - given(boardService.getPostList()).willReturn(postList); + given(boardService.getPostList(any(Pageable.class))).willReturn(postPageList); given(boardService.getPostImage(postNum)).willReturn(imageDto); + mockMvc.perform(get("/api/board/getPostList")) .andExpect(status().isOk()) .andExpect(jsonPath("$.message", is("게시글 리스트 불러오기 성공"))) @@ -268,20 +284,52 @@ void getPostListSuccess() throws Exception { .andExpect(jsonPath("$.imageList").exists()) .andDo(print()); - verify(boardService).getPostList(); + verify(boardService).getPostList(any(Pageable.class)); verify(boardService, times(2)).getPostImage(postNum); } @Test @DisplayName("게시글_리스트_게시글_불러오기_실패") void getPostListFailure() throws Exception { - given(boardService.getPostList()).willThrow(new BoardException("목록을 불러오지 못했습니다.")); + given(boardService.getPostList(any(Pageable.class))).willThrow(new BoardException("목록을 불러오지 못했습니다.")); mockMvc.perform(get("/api/board/getPostList")) .andExpect(status().isOk()) .andExpect(content().string("{\"status\":\"OK\",\"message\":\"목록을 불러오지 못했습니다.\"}")) .andDo(print()); - verify(boardService).getPostList(); + verify(boardService).getPostList(any(Pageable.class)); + } + + @Test + @DisplayName("게시글_리스트_검색_성공") + void getPostSearchListSuccess() throws Exception { + given(boardService.getPostSearchList(any(String.class), any(Pageable.class))).willReturn(postPageList); + given(boardService.getPostImage(postNum)).willReturn(imageDto); + + mockMvc.perform(get("/api/board/getPostList").param("keyword", "keyword")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message", is("게시글 리스트 불러오기 성공"))) + .andExpect(jsonPath("$.postList").exists()) + .andExpect(jsonPath("$.imageList").exists()) + .andDo(print()); + + + verify(boardService).getPostSearchList(any(String.class), any(Pageable.class)); + verify(boardService, times(2)).getPostImage(postNum); + } + + @Test + @DisplayName("게시글_리스트_검색_실패") + void getPostSearchListFailure() throws Exception { + given(boardService.getPostSearchList(any(String.class), any(Pageable.class))).willThrow( + new BoardException("검색 결과 목록을 불러오지 못했습니다.")); + + mockMvc.perform(get("/api/board/getPostList").param("keyword", "keyword")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message", is("검색 결과 목록을 불러오지 못했습니다."))) + .andDo(print()); + + verify(boardService).getPostSearchList(any(String.class), any(Pageable.class)); } } diff --git a/src/test/java/com/tomato/market/service/BoardServiceTest.java b/src/test/java/com/tomato/market/service/BoardServiceTest.java index 9278e09..efae9a2 100644 --- a/src/test/java/com/tomato/market/service/BoardServiceTest.java +++ b/src/test/java/com/tomato/market/service/BoardServiceTest.java @@ -24,7 +24,6 @@ import org.springframework.web.multipart.MultipartFile; import com.tomato.market.dao.impl.BoardDaoImpl; -import com.tomato.market.data.dto.ImageDto; import com.tomato.market.data.dto.PostDto; import com.tomato.market.data.entity.ImageEntity; import com.tomato.market.data.entity.PostEntity; @@ -163,62 +162,62 @@ void saveImageInfoFailure() throws IOException { verify(boardDao).saveImage(any(ImageEntity.class)); } - @Test - @DisplayName("게시글_리스트_조회_성공") - void getPostListSuccess() { - given(boardDao.findPostList()).willReturn(postEntities); - - List postDtoList = new ArrayList<>(); - postDtoList.add(PostDto.toPostDto(postEntity)); - postDtoList.add(PostDto.toPostDto(postEntity)); - - BoardServiceImpl boardService = new BoardServiceImpl(boardDao); - Assertions.assertEquals(boardService.getPostList().toString(), postDtoList.toString()); - - verify(boardDao).findPostList(); - } - - @Test - @DisplayName("게시글_리스트_조회_실패") - void getPostListFailure() { - given(boardDao.findPostList()).willReturn(null); - - BoardServiceImpl boardService = new BoardServiceImpl(boardDao); - BoardException exception = Assertions.assertThrows(BoardException.class, () -> { - boardService.getPostList(); - }); - Assertions.assertEquals(exception.getMessage(), "목록을 불러오지 못했습니다."); - - verify(boardDao).findPostList(); - } - - @Test - @DisplayName("게시글_이미지_조회_성공") - void getPostImageSuccess() { - given(boardDao.findImageByPostNum(postNum)).willReturn(imageEntity); - - BoardServiceImpl boardService = new BoardServiceImpl(boardDao); - Assertions.assertEquals( - boardService.getPostImage(postNum).toString(), ImageDto.toImageDto(imageEntity).toString()); - - verify(boardDao).findImageByPostNum(postNum); - } - - @Test - @DisplayName("게시글_이미지_조회_실패") - void getPostImageFailure() { - given(boardDao.findImageByPostNum(postNum)).willReturn(null); - - ImageEntity defaultImage = ImageEntity.builder() - .postNum(postNum) - .imageName("default.png") - .uuid("default.png") - .build(); - - BoardServiceImpl boardService = new BoardServiceImpl(boardDao); - Assertions.assertEquals( - boardService.getPostImage(postNum).toString(), ImageDto.toImageDto(defaultImage).toString()); - - verify(boardDao).findImageByPostNum(postNum); - } +// @Test +// @DisplayName("게시글_리스트_조회_성공") +// void getPostListSuccess() { +// given(boardDao.findPostList()).willReturn(postEntities); +// +// List postDtoList = new ArrayList<>(); +// postDtoList.add(PostDto.toPostDto(postEntity)); +// postDtoList.add(PostDto.toPostDto(postEntity)); +// +// BoardServiceImpl boardService = new BoardServiceImpl(boardDao); +// Assertions.assertEquals(boardService.getPostList().toString(), postDtoList.toString()); +// +// verify(boardDao).findPostList(); +// } +// +// @Test +// @DisplayName("게시글_리스트_조회_실패") +// void getPostListFailure() { +// given(boardDao.findPostList()).willReturn(null); +// +// BoardServiceImpl boardService = new BoardServiceImpl(boardDao); +// BoardException exception = Assertions.assertThrows(BoardException.class, () -> { +// boardService.getPostList(); +// }); +// Assertions.assertEquals(exception.getMessage(), "목록을 불러오지 못했습니다."); +// +// verify(boardDao).findPostList(); +// } +// +// @Test +// @DisplayName("게시글_이미지_조회_성공") +// void getPostImageSuccess() { +// given(boardDao.findImageByPostNum(postNum)).willReturn(imageEntity); +// +// BoardServiceImpl boardService = new BoardServiceImpl(boardDao); +// Assertions.assertEquals( +// boardService.getPostImage(postNum).toString(), ImageDto.toImageDto(imageEntity).toString()); +// +// verify(boardDao).findImageByPostNum(postNum); +// } +// +// @Test +// @DisplayName("게시글_이미지_조회_실패") +// void getPostImageFailure() { +// given(boardDao.findImageByPostNum(postNum)).willReturn(null); +// +// ImageEntity defaultImage = ImageEntity.builder() +// .postNum(postNum) +// .imageName("default.png") +// .uuid("default.png") +// .build(); +// +// BoardServiceImpl boardService = new BoardServiceImpl(boardDao); +// Assertions.assertEquals( +// boardService.getPostImage(postNum).toString(), ImageDto.toImageDto(defaultImage).toString()); +// +// verify(boardDao).findImageByPostNum(postNum); +// } } From 44452eeae427fc2c3f05b2dc121f7dfb0dbe0f5c Mon Sep 17 00:00:00 2001 From: Hyunuk Date: Thu, 19 Oct 2023 20:36:00 +0900 Subject: [PATCH 16/22] [tomato-market/plan#7] Service Test --- .../market/service/BoardServiceTest.java | 159 +++++++++++------- 1 file changed, 101 insertions(+), 58 deletions(-) diff --git a/src/test/java/com/tomato/market/service/BoardServiceTest.java b/src/test/java/com/tomato/market/service/BoardServiceTest.java index efae9a2..2869ea3 100644 --- a/src/test/java/com/tomato/market/service/BoardServiceTest.java +++ b/src/test/java/com/tomato/market/service/BoardServiceTest.java @@ -21,9 +21,14 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; import org.springframework.web.multipart.MultipartFile; import com.tomato.market.dao.impl.BoardDaoImpl; +import com.tomato.market.data.dto.ImageDto; import com.tomato.market.data.dto.PostDto; import com.tomato.market.data.entity.ImageEntity; import com.tomato.market.data.entity.PostEntity; @@ -61,6 +66,14 @@ public class BoardServiceTest { private List postEntities; private List imageEntities; + private Pageable pageable = PageRequest.of(0, 10); + private Page postEntityList; + private String keyword = "keyword"; + private List postDtoList; + + private Page postDtoPage; + + @BeforeEach void setUp() { postDto = PostDto.builder().userId(userId).location(location).title(title).category(category).content(content) @@ -82,6 +95,13 @@ void setUp() { imageEntities.add(imageEntity); imageEntities.add(imageEntity); + postEntityList = new PageImpl<>(postEntities, pageable, 2); + + postDtoList = new ArrayList<>(); + postDtoList.add(PostDto.toPostDto(postEntity)); + postDtoList.add(PostDto.toPostDto(postEntity)); + + postDtoPage = new PageImpl<>(postDtoList, pageable, 2); } @Test @@ -162,62 +182,85 @@ void saveImageInfoFailure() throws IOException { verify(boardDao).saveImage(any(ImageEntity.class)); } -// @Test -// @DisplayName("게시글_리스트_조회_성공") -// void getPostListSuccess() { -// given(boardDao.findPostList()).willReturn(postEntities); -// -// List postDtoList = new ArrayList<>(); -// postDtoList.add(PostDto.toPostDto(postEntity)); -// postDtoList.add(PostDto.toPostDto(postEntity)); -// -// BoardServiceImpl boardService = new BoardServiceImpl(boardDao); -// Assertions.assertEquals(boardService.getPostList().toString(), postDtoList.toString()); -// -// verify(boardDao).findPostList(); -// } -// -// @Test -// @DisplayName("게시글_리스트_조회_실패") -// void getPostListFailure() { -// given(boardDao.findPostList()).willReturn(null); -// -// BoardServiceImpl boardService = new BoardServiceImpl(boardDao); -// BoardException exception = Assertions.assertThrows(BoardException.class, () -> { -// boardService.getPostList(); -// }); -// Assertions.assertEquals(exception.getMessage(), "목록을 불러오지 못했습니다."); -// -// verify(boardDao).findPostList(); -// } -// -// @Test -// @DisplayName("게시글_이미지_조회_성공") -// void getPostImageSuccess() { -// given(boardDao.findImageByPostNum(postNum)).willReturn(imageEntity); -// -// BoardServiceImpl boardService = new BoardServiceImpl(boardDao); -// Assertions.assertEquals( -// boardService.getPostImage(postNum).toString(), ImageDto.toImageDto(imageEntity).toString()); -// -// verify(boardDao).findImageByPostNum(postNum); -// } -// -// @Test -// @DisplayName("게시글_이미지_조회_실패") -// void getPostImageFailure() { -// given(boardDao.findImageByPostNum(postNum)).willReturn(null); -// -// ImageEntity defaultImage = ImageEntity.builder() -// .postNum(postNum) -// .imageName("default.png") -// .uuid("default.png") -// .build(); -// -// BoardServiceImpl boardService = new BoardServiceImpl(boardDao); -// Assertions.assertEquals( -// boardService.getPostImage(postNum).toString(), ImageDto.toImageDto(defaultImage).toString()); -// -// verify(boardDao).findImageByPostNum(postNum); -// } + @Test + @DisplayName("게시글_리스트_조회_성공") + void getPostListSuccess() { + given(boardDao.findPostList(pageable)).willReturn(postEntityList); + + BoardServiceImpl boardService = new BoardServiceImpl(boardDao); + + Assertions.assertEquals(boardService.getPostList(pageable).toString(), postDtoPage.toString()); + + verify(boardDao).findPostList(pageable); + } + + @Test + @DisplayName("게시글_리스트_조회_실패") + void getPostListFailure() { + given(boardDao.findPostList(pageable)).willReturn(null); + + BoardServiceImpl boardService = new BoardServiceImpl(boardDao); + BoardException exception = Assertions.assertThrows(BoardException.class, () -> { + boardService.getPostList(pageable); + }); + Assertions.assertEquals(exception.getMessage(), "목록을 불러오지 못했습니다."); + + verify(boardDao).findPostList(pageable); + } + + @Test + @DisplayName("게시글_이미지_조회_성공") + void getPostImageSuccess() { + given(boardDao.findImageByPostNum(postNum)).willReturn(imageEntity); + + BoardServiceImpl boardService = new BoardServiceImpl(boardDao); + Assertions.assertEquals( + boardService.getPostImage(postNum).toString(), ImageDto.toImageDto(imageEntity).toString()); + + verify(boardDao).findImageByPostNum(postNum); + } + + @Test + @DisplayName("게시글_이미지_조회_실패") + void getPostImageFailure() { + given(boardDao.findImageByPostNum(postNum)).willReturn(null); + + ImageEntity defaultImage = ImageEntity.builder() + .postNum(postNum) + .imageName("default.png") + .uuid("default.png") + .build(); + + BoardServiceImpl boardService = new BoardServiceImpl(boardDao); + Assertions.assertEquals( + boardService.getPostImage(postNum).toString(), ImageDto.toImageDto(defaultImage).toString()); + + verify(boardDao).findImageByPostNum(postNum); + } + + @Test + @DisplayName("게시글_리스트_검색_성공") + void getPostSearchSuccess() { + given(boardDao.findPostSearchList(any(String.class), any(Pageable.class))).willReturn(postEntityList); + + BoardServiceImpl boardService = new BoardServiceImpl(boardDao); + Assertions.assertEquals(boardService.getPostSearchList(keyword, pageable).toString(), postDtoPage.toString()); + + verify(boardDao).findPostSearchList(any(String.class), any(Pageable.class)); + } + + @Test + @DisplayName("게시글_리스트_검색_실패") + void getPostSearchFailure() { + given(boardDao.findPostSearchList(any(String.class), any(Pageable.class))).willThrow( + new BoardException("검색 결과 목록을 불러오지 못했습니다.")); + + BoardServiceImpl boardService = new BoardServiceImpl(boardDao); + BoardException exception = Assertions.assertThrows(BoardException.class, () -> { + boardService.getPostSearchList(keyword, pageable); + }); + Assertions.assertEquals(exception.getMessage(), "검색 결과 목록을 불러오지 못했습니다."); + + verify(boardDao).findPostSearchList(any(String.class), any(Pageable.class)); + } } From f7177ece57d1affc9c80f4af03f4d3e6b5023e78 Mon Sep 17 00:00:00 2001 From: Hyunuk Date: Sat, 21 Oct 2023 07:51:31 +0900 Subject: [PATCH 17/22] =?UTF-8?q?[tomato-market/plan#26]=20=EB=B8=8C?= =?UTF-8?q?=EB=9E=9C=EC=B9=98=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../market/controller/BoardController.java | 17 +++++++++++++---- .../tomato/market/data/dto/PostResponseDto.java | 2 ++ .../market/controller/BoardControllerTest.java | 11 +++++------ 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/tomato/market/controller/BoardController.java b/src/main/java/com/tomato/market/controller/BoardController.java index b21cb1a..50904ca 100644 --- a/src/main/java/com/tomato/market/controller/BoardController.java +++ b/src/main/java/com/tomato/market/controller/BoardController.java @@ -135,10 +135,19 @@ public PostListResponseDto getPostList( .build(); } -// @PostMapping("/board/registerPost") -// public void registerPost() { -// -// } + @GetMapping("/board/getPost") + public void getPost(Integer postNum) { // 게시글 조회 + logger.info("BoardController.getPost() is called"); + + // 특정 값(postNum?)을 받아 그 내용을 조회 -> front가 postNum을 알고 있나?? 알고있을듯 +// boardService.getPost(postNum); + + // postNum으로 Image 데이터(다수) 조회 +// boardService.getPostImageList(postNum); + + // return값으로 postDto, imageList 전달 +// return postResponseDto; ?? + } // @PostMapping("/board/registerImage") // public void uploadImage() { // 이미지 등록 메소드를 별도 처리? diff --git a/src/main/java/com/tomato/market/data/dto/PostResponseDto.java b/src/main/java/com/tomato/market/data/dto/PostResponseDto.java index d42f06d..6de812d 100644 --- a/src/main/java/com/tomato/market/data/dto/PostResponseDto.java +++ b/src/main/java/com/tomato/market/data/dto/PostResponseDto.java @@ -16,4 +16,6 @@ public class PostResponseDto { HttpStatus status; Object message; + Object postDto; + Object imageList; } diff --git a/src/test/java/com/tomato/market/controller/BoardControllerTest.java b/src/test/java/com/tomato/market/controller/BoardControllerTest.java index 69f2f6e..87c266b 100644 --- a/src/test/java/com/tomato/market/controller/BoardControllerTest.java +++ b/src/test/java/com/tomato/market/controller/BoardControllerTest.java @@ -10,7 +10,6 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -161,7 +160,7 @@ void writePostSuccess() throws Exception { .accept(MediaType.APPLICATION_JSON) ) .andExpect(status().isOk()) - .andExpect(content().string("{\"status\":\"OK\",\"message\":\"게시글 등록 성공\"}")) + .andExpect(jsonPath("$.message", is("게시글 등록 성공"))) .andDo(print()); } catch (Exception exception) { @@ -211,7 +210,7 @@ void writePostFailure() throws Exception { .accept(MediaType.APPLICATION_JSON) ) .andExpect(status().isOk()) - .andExpect(content().string("{\"status\":\"OK\",\"message\":\"게시글 등록에 실패했습니다.\"}")) + .andExpect(jsonPath("$.message", is("게시글 등록에 실패했습니다."))) .andDo(print()); // @@ -236,7 +235,7 @@ void uploadImageFailure() throws Exception { .accept(MediaType.APPLICATION_JSON) ) .andExpect(status().isOk()) - .andExpect(content().string("{\"status\":\"OK\",\"message\":\"1번째 이미지 저장에 실패했습니다.\"}")) + .andExpect(jsonPath("$.message", is("1번째 이미지 저장에 실패했습니다."))) .andDo(print()); // @@ -262,7 +261,7 @@ void saveImageInfoFailure() throws Exception { .accept(MediaType.APPLICATION_JSON) ) .andExpect(status().isOk()) - .andExpect(content().string("{\"status\":\"OK\",\"message\":\"1번째 이미지 정보 저장에 실패했습니다.\"}")) + .andExpect(jsonPath("$.message", is("1번째 이미지 정보 저장에 실패했습니다."))) .andDo(print()); // @@ -295,7 +294,7 @@ void getPostListFailure() throws Exception { mockMvc.perform(get("/api/board/getPostList")) .andExpect(status().isOk()) - .andExpect(content().string("{\"status\":\"OK\",\"message\":\"목록을 불러오지 못했습니다.\"}")) + .andExpect(jsonPath("$.message", is("목록을 불러오지 못했습니다."))) .andDo(print()); verify(boardService).getPostList(any(Pageable.class)); From 6b70cb0bd4739fda4fe3e10d76d4dc33dfa37d22 Mon Sep 17 00:00:00 2001 From: Hyunuk Date: Sat, 21 Oct 2023 08:22:03 +0900 Subject: [PATCH 18/22] =?UTF-8?q?[tomato-market/plan#26]=20=EA=B2=8C?= =?UTF-8?q?=EC=8B=9C=EA=B8=80=20=EC=A1=B0=ED=9A=8C=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../market/controller/BoardController.java | 18 +++++++--- .../java/com/tomato/market/dao/BoardDao.java | 5 +++ .../tomato/market/dao/impl/BoardDaoImpl.java | 32 ++++++++++++++++++ .../data/repository/ImageRepository.java | 3 ++ .../data/repository/PostRepository.java | 6 ++-- .../tomato/market/service/BoardService.java | 3 ++ .../market/service/impl/BoardServiceImpl.java | 33 +++++++++++++++++++ 7 files changed, 93 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/tomato/market/controller/BoardController.java b/src/main/java/com/tomato/market/controller/BoardController.java index 50904ca..bf6d5f8 100644 --- a/src/main/java/com/tomato/market/controller/BoardController.java +++ b/src/main/java/com/tomato/market/controller/BoardController.java @@ -136,17 +136,27 @@ public PostListResponseDto getPostList( } @GetMapping("/board/getPost") - public void getPost(Integer postNum) { // 게시글 조회 + public PostResponseDto getPost(Integer postNum) { // 게시글 조회 logger.info("BoardController.getPost() is called"); // 특정 값(postNum?)을 받아 그 내용을 조회 -> front가 postNum을 알고 있나?? 알고있을듯 -// boardService.getPost(postNum); + PostDto postDto = boardService.getPost(postNum); + logger.info("BoardController.getPost() : 게시글 불러오기 성공"); + // postNum으로 Image 데이터(다수) 조회 -// boardService.getPostImageList(postNum); + List imageList = boardService.getPostImageList(postNum); +// 애초에 Post에 image 포함 여부 항목이 있었어야 했다.. // 전부 수정하는 것은 너무 복잡 + logger.info("BoardController.getPost() : 이미지 리스트 불러오기 성공"); + // return값으로 postDto, imageList 전달 -// return postResponseDto; ?? + return PostResponseDto.builder() + .status(HttpStatus.OK) + .message("게시글 불러오기 성공") + .postDto(postDto) + .imageList(imageList) + .build(); } // @PostMapping("/board/registerImage") diff --git a/src/main/java/com/tomato/market/dao/BoardDao.java b/src/main/java/com/tomato/market/dao/BoardDao.java index b00b341..9b86ff6 100644 --- a/src/main/java/com/tomato/market/dao/BoardDao.java +++ b/src/main/java/com/tomato/market/dao/BoardDao.java @@ -1,5 +1,7 @@ package com.tomato.market.dao; +import java.util.List; + import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -17,4 +19,7 @@ public interface BoardDao { ImageEntity findImageByPostNum(Integer postNum); + PostEntity findPostByPostNum(Integer postNum); + + List findImageListByPostNum(Integer postNum); } diff --git a/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java b/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java index d63a345..fa2d716 100644 --- a/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java +++ b/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java @@ -1,5 +1,6 @@ package com.tomato.market.dao.impl; +import java.util.List; import java.util.Optional; import org.slf4j.Logger; @@ -90,11 +91,42 @@ public Page findPostSearchList(String keyword, Pageable pageable) { @Override public ImageEntity findImageByPostNum(Integer postNum) { + logger.info("BoardDaoImpl.findImageByPostNum() is called"); Optional imageEntity = imageRepository.findImageByPostNum(postNum); if (imageEntity.isPresent()) { // PostId로 이미지를 찾음 + logger.info("BoardDaoImpl.findImageByPostNum() : 이미지 조회 성공"); return imageEntity.get(); } else { // 이미지를 찾지 못함 or 애초에 없음 + logger.warn("BoardDaoImpl.findImageByPostNum() : 이미지 조회 실패"); return null; } } + + @Override + public PostEntity findPostByPostNum(Integer postNum) { + logger.info("BoardDaoImpl.findPostByPostNum() is called"); + + Optional postEntity = postRepository.findByPostNum(postNum); + if (postEntity.isPresent()) { + logger.info("BoardDaoImpl.findPostByPostNum() : 게시글 조회 성공"); + return postEntity.get(); + } else { + logger.warn("BoardDaoImpl.findPostByPostNum() : 게시글 조회 실패"); + return null; + } + } + + @Override + public List findImageListByPostNum(Integer postNum) { + logger.info("BoarDaoImpl.findImageListByPostNum() is called"); + + List imageEntities = imageRepository.findByPostNum(postNum); + if (imageEntities == null) { + logger.warn("BoarDaoImpl.findImageListByPostNum() : 이미지 리스트 조회 실패"); + return null; + } else { + logger.info("BoardDaoImpl.findImageListByPostNum() : 이미지 리스트 조회 성공"); + return imageEntities; + } + } } diff --git a/src/main/java/com/tomato/market/data/repository/ImageRepository.java b/src/main/java/com/tomato/market/data/repository/ImageRepository.java index 766b95d..4cb445e 100644 --- a/src/main/java/com/tomato/market/data/repository/ImageRepository.java +++ b/src/main/java/com/tomato/market/data/repository/ImageRepository.java @@ -1,5 +1,6 @@ package com.tomato.market.data.repository; +import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; @@ -8,4 +9,6 @@ public interface ImageRepository extends JpaRepository { Optional findImageByPostNum(Integer postNum); + + List findByPostNum(Integer postNum); } diff --git a/src/main/java/com/tomato/market/data/repository/PostRepository.java b/src/main/java/com/tomato/market/data/repository/PostRepository.java index 721f743..ccfd74e 100644 --- a/src/main/java/com/tomato/market/data/repository/PostRepository.java +++ b/src/main/java/com/tomato/market/data/repository/PostRepository.java @@ -1,5 +1,7 @@ package com.tomato.market.data.repository; +import java.util.Optional; + import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; @@ -10,8 +12,6 @@ public interface PostRepository extends JpaRepository { Page findAll(Pageable pageable); Page findByTitleContaining(String keyword, Pageable pageable); - // findAll()? // int page -// Optional> find(); -// Optional findImageByPostNum(Integer postNum); + Optional findByPostNum(Integer postNum); } diff --git a/src/main/java/com/tomato/market/service/BoardService.java b/src/main/java/com/tomato/market/service/BoardService.java index 8c9c20e..67ee661 100644 --- a/src/main/java/com/tomato/market/service/BoardService.java +++ b/src/main/java/com/tomato/market/service/BoardService.java @@ -21,4 +21,7 @@ public interface BoardService { ImageDto getPostImage(Integer postNum); + PostDto getPost(Integer postNum); + + List getPostImageList(Integer postNum); } diff --git a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java index 04b5f26..0df933f 100644 --- a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java +++ b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java @@ -1,6 +1,7 @@ package com.tomato.market.service.impl; import java.io.File; +import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -147,4 +148,36 @@ public ImageDto getPostImage(Integer postNum) { return ImageDto.toImageDto(imageEntity); } + @Override + public PostDto getPost(Integer postNum) { + logger.info("BoardServiceImpl.getPost() is called"); + + PostEntity postEntity = boardDao.findPostByPostNum(postNum); + if (postEntity == null) { + logger.warn("BoardServiceImpl.getPost() : 게시글 조회 실패"); + throw new BoardException("게시글을 찾을 수 없습니다."); + } + logger.info("BoardServiceImpl.getPost() : 게시글 조회 성공"); + + // Entity -> DTO 전환 + return PostDto.toPostDto(postEntity); + } + + @Override + public List getPostImageList(Integer postNum) { + logger.info("BoardServiceImpl.getPostImageList() is called"); + + List imageEntities = boardDao.findImageListByPostNum(postNum); + if ((imageEntities == null)) { + logger.warn("BoardServiceImpl.getPostImageList() : 이미지 조회 실패"); + throw new BoardException("이미지를 불러오지 못했습니다."); + } + + // Entity -> DTO 변환 + List imageList = new ArrayList<>(); + for (ImageEntity imageEntity : imageEntities) { + imageList.add(ImageDto.toImageDto(imageEntity)); + } + return imageList; + } } From baf121600dc515db5bec32e6d664aaccecb517a7 Mon Sep 17 00:00:00 2001 From: Hyunuk Date: Sat, 21 Oct 2023 12:25:01 +0900 Subject: [PATCH 19/22] =?UTF-8?q?[tomato-market/plan26]=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../market/service/impl/BoardServiceImpl.java | 6 +- .../controller/BoardControllerTest.java | 46 +++++++++++++++ .../market/service/BoardServiceTest.java | 59 ++++++++++++++++++- 3 files changed, 108 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java index 0df933f..996943d 100644 --- a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java +++ b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java @@ -168,11 +168,15 @@ public List getPostImageList(Integer postNum) { logger.info("BoardServiceImpl.getPostImageList() is called"); List imageEntities = boardDao.findImageListByPostNum(postNum); - if ((imageEntities == null)) { + if ((imageEntities == null)) { // 이미지가 없는 데이터라면? logger.warn("BoardServiceImpl.getPostImageList() : 이미지 조회 실패"); throw new BoardException("이미지를 불러오지 못했습니다."); } + if (imageEntities.size() == 0) { + logger.warn("BoardServiceImpl.getPostImageList() : 이미지가 0개인 게시글"); + } + // Entity -> DTO 변환 List imageList = new ArrayList<>(); for (ImageEntity imageEntity : imageEntities) { diff --git a/src/test/java/com/tomato/market/controller/BoardControllerTest.java b/src/test/java/com/tomato/market/controller/BoardControllerTest.java index 87c266b..469e29e 100644 --- a/src/test/java/com/tomato/market/controller/BoardControllerTest.java +++ b/src/test/java/com/tomato/market/controller/BoardControllerTest.java @@ -331,4 +331,50 @@ void getPostSearchListFailure() throws Exception { verify(boardService).getPostSearchList(any(String.class), any(Pageable.class)); } + + @Test + @DisplayName("게시글_조회_성공") + void getPostSuccess() throws Exception { + given(boardService.getPost(postNum)).willReturn(postDto); + given(boardService.getPostImageList(postNum)).willReturn(imageList); + + mockMvc.perform(get("/api/board/getPost").param("postNum", String.valueOf(postNum))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message", is("게시글 불러오기 성공"))) + .andExpect(jsonPath("$.postDto").exists()) + .andExpect(jsonPath("$.imageList").exists()) + .andDo(print()); + + verify(boardService).getPost(postNum); + verify(boardService).getPostImageList(postNum); + } + + @Test + @DisplayName("게시글_조회_실패") + void getPostFailure() throws Exception { + given(boardService.getPost(postNum)).willThrow(new BoardException("게시글을 찾을 수 없습니다.")); + + mockMvc.perform(get("/api/board/getPost").param("postNum", String.valueOf(postNum))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message", is("게시글을 찾을 수 없습니다."))) + .andDo(print()); + + verify(boardService).getPost(postNum); + + } + + @Test + @DisplayName("게시글_이미지_리스트_조회_실패") + void getPostImageFailure() throws Exception { + given(boardService.getPost(postNum)).willReturn(postDto); + given(boardService.getPostImageList(postNum)).willThrow(new BoardException("이미지를 불러오지 못했습니다.")); + + mockMvc.perform(get("/api/board/getPost").param("postNum", String.valueOf(postNum))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message", is("이미지를 불러오지 못했습니다."))) + .andDo(print()); + + verify(boardService).getPost(postNum); + verify(boardService).getPostImageList(postNum); + } } diff --git a/src/test/java/com/tomato/market/service/BoardServiceTest.java b/src/test/java/com/tomato/market/service/BoardServiceTest.java index 2869ea3..df5cc66 100644 --- a/src/test/java/com/tomato/market/service/BoardServiceTest.java +++ b/src/test/java/com/tomato/market/service/BoardServiceTest.java @@ -209,7 +209,7 @@ void getPostListFailure() { } @Test - @DisplayName("게시글_이미지_조회_성공") + @DisplayName("게시글_리스트_이미지_조회_성공") void getPostImageSuccess() { given(boardDao.findImageByPostNum(postNum)).willReturn(imageEntity); @@ -221,7 +221,7 @@ void getPostImageSuccess() { } @Test - @DisplayName("게시글_이미지_조회_실패") + @DisplayName("게시글_리스트_이미지_조회_실패") void getPostImageFailure() { given(boardDao.findImageByPostNum(postNum)).willReturn(null); @@ -263,4 +263,59 @@ void getPostSearchFailure() { verify(boardDao).findPostSearchList(any(String.class), any(Pageable.class)); } + + @Test + @DisplayName("게시글_조회_성공") + void getPostSuccess() { + given(boardDao.findPostByPostNum(postNum)).willReturn(postEntity); + + BoardServiceImpl boardService = new BoardServiceImpl(boardDao); + Assertions.assertEquals(PostDto.toPostDto(postEntity).toString(), boardService.getPost(postNum).toString()); + + verify(boardDao).findPostByPostNum(postNum); + } + + @Test + @DisplayName("게시글_조회_실패") + void getPostFailure() { + given(boardDao.findPostByPostNum(postNum)).willReturn(null); + + BoardServiceImpl boardService = new BoardServiceImpl(boardDao); + BoardException exception = Assertions.assertThrows(BoardException.class, () -> { + boardService.getPost(postNum); + }); + Assertions.assertEquals(exception.getMessage(), "게시글을 찾을 수 없습니다."); + + verify(boardDao).findPostByPostNum(postNum); + } + + @Test + @DisplayName("게시글_이미지_리스트_조회_성공") + void getPostImageListSuccess() { + given(boardDao.findImageListByPostNum(postNum)).willReturn(imageEntities); + + List imageList = new ArrayList<>(); + for (ImageEntity image : imageEntities) { + imageList.add(ImageDto.toImageDto(image)); + } + + BoardServiceImpl boardService = new BoardServiceImpl(boardDao); + Assertions.assertEquals(imageList.toString(), boardService.getPostImageList(postNum).toString()); + + verify(boardDao).findImageListByPostNum(postNum); + } + + @Test + @DisplayName("게시글_이미지_리스트_조회_실패") + void getPostImageListFailure() { + given(boardDao.findImageListByPostNum(postNum)).willReturn(null); + + BoardServiceImpl boardService = new BoardServiceImpl(boardDao); + BoardException exception = Assertions.assertThrows(BoardException.class, () -> { + boardService.getPostImageList(postNum); + }); + Assertions.assertEquals(exception.getMessage(), "이미지를 불러오지 못했습니다."); + + verify(boardDao).findImageListByPostNum(postNum); + } } From 7d014e2a3476b543d17ca0333eb7d89958508535 Mon Sep 17 00:00:00 2001 From: Hyunuk Date: Sat, 21 Oct 2023 15:38:11 +0900 Subject: [PATCH 20/22] =?UTF-8?q?[tomato-market/plan#26]=20ImageRepository?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 게시글 리스트의 썸네일을 불러올 때, 1개의 이미지 정보만 불러오도록 수정 --- src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java | 3 ++- .../com/tomato/market/data/repository/ImageRepository.java | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java b/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java index fa2d716..ea18d81 100644 --- a/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java +++ b/src/main/java/com/tomato/market/dao/impl/BoardDaoImpl.java @@ -92,7 +92,8 @@ public Page findPostSearchList(String keyword, Pageable pageable) { @Override public ImageEntity findImageByPostNum(Integer postNum) { logger.info("BoardDaoImpl.findImageByPostNum() is called"); - Optional imageEntity = imageRepository.findImageByPostNum(postNum); +// Optional imageEntity = imageRepository.findImageByPostNum(postNum); + Optional imageEntity = imageRepository.findTopByPostNumOrderByImageNum(postNum); if (imageEntity.isPresent()) { // PostId로 이미지를 찾음 logger.info("BoardDaoImpl.findImageByPostNum() : 이미지 조회 성공"); return imageEntity.get(); diff --git a/src/main/java/com/tomato/market/data/repository/ImageRepository.java b/src/main/java/com/tomato/market/data/repository/ImageRepository.java index 4cb445e..33f3a7c 100644 --- a/src/main/java/com/tomato/market/data/repository/ImageRepository.java +++ b/src/main/java/com/tomato/market/data/repository/ImageRepository.java @@ -8,7 +8,9 @@ import com.tomato.market.data.entity.ImageEntity; public interface ImageRepository extends JpaRepository { - Optional findImageByPostNum(Integer postNum); + // Optional findImageByPostNum(Integer postNum); + Optional findTopByPostNumOrderByImageNum(Integer postNum); + List findByPostNum(Integer postNum); } From 7e5e23846ec13143961573d44e6da246d9c54102 Mon Sep 17 00:00:00 2001 From: Hyunuk Date: Mon, 23 Oct 2023 19:14:01 +0900 Subject: [PATCH 21/22] =?UTF-8?q?[tomato-market/plan#26]=20createAt=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=ED=8F=AC=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/tomato/market/controller/BoardController.java | 2 +- src/main/java/com/tomato/market/data/dto/PostDto.java | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/tomato/market/controller/BoardController.java b/src/main/java/com/tomato/market/controller/BoardController.java index bf6d5f8..ea63950 100644 --- a/src/main/java/com/tomato/market/controller/BoardController.java +++ b/src/main/java/com/tomato/market/controller/BoardController.java @@ -135,7 +135,7 @@ public PostListResponseDto getPostList( .build(); } - @GetMapping("/board/getPost") + @GetMapping("/board/getPost") // {id} 형태로 받는게 나았을 수도? public PostResponseDto getPost(Integer postNum) { // 게시글 조회 logger.info("BoardController.getPost() is called"); diff --git a/src/main/java/com/tomato/market/data/dto/PostDto.java b/src/main/java/com/tomato/market/data/dto/PostDto.java index 377a6a2..0c6a7d8 100644 --- a/src/main/java/com/tomato/market/data/dto/PostDto.java +++ b/src/main/java/com/tomato/market/data/dto/PostDto.java @@ -1,5 +1,7 @@ package com.tomato.market.data.dto; +import java.util.Date; + import com.tomato.market.data.entity.PostEntity; import jakarta.validation.constraints.NotBlank; @@ -34,7 +36,8 @@ public class PostDto { Integer price; @NotBlank(message = "거래희망 장소를 입력하세요. ") String detailLocation; - Integer status; // 판매 상태 : 이것도 Enum? + Integer status; // 판매 상태 : 판매중(0), 예약중(1), 판매완료(2), 취소(3) + Date createAt; // 등록 시간 String boughtUserId; @@ -65,6 +68,7 @@ public static PostDto toPostDto(PostEntity postEntity) { .price(postEntity.getPrice()) .detailLocation(postEntity.getDetailLocation()) .status(postEntity.getStatus()) + .createAt(postEntity.getCreatedAt()) .boughtUserId(postEntity.getBoughtUserId()) .build(); } From ca7ec951202925d8770cdfaca111137798acc7c7 Mon Sep 17 00:00:00 2001 From: Hyunuk Date: Mon, 23 Oct 2023 20:13:04 +0900 Subject: [PATCH 22/22] =?UTF-8?q?[release/0.2.0]=20Release-0.2.0=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../market/controller/BoardController.java | 28 ++----------------- .../data/repository/ImageRepository.java | 2 -- .../market/service/impl/BoardServiceImpl.java | 4 +-- 3 files changed, 5 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/tomato/market/controller/BoardController.java b/src/main/java/com/tomato/market/controller/BoardController.java index ea63950..f2d5f49 100644 --- a/src/main/java/com/tomato/market/controller/BoardController.java +++ b/src/main/java/com/tomato/market/controller/BoardController.java @@ -76,7 +76,7 @@ public PostResponseDto writePost( .build(); } - // 조회 삭제 수정 : 각각 별도 이슈로 분리? + // 조회 삭제 수정 : 각각 별도 이슈로 분리 // PutMapping? // updatePost() {} @@ -125,7 +125,6 @@ public PostListResponseDto getPostList( // Return // 게시글 List 첨부 // 이미지 List 첨부 - // 하나의 응답 DTO로 변환하여 반환 return PostListResponseDto.builder() .status(HttpStatus.OK) .message("게시글 리스트 불러오기 성공") @@ -139,14 +138,14 @@ public PostListResponseDto getPostList( public PostResponseDto getPost(Integer postNum) { // 게시글 조회 logger.info("BoardController.getPost() is called"); - // 특정 값(postNum?)을 받아 그 내용을 조회 -> front가 postNum을 알고 있나?? 알고있을듯 + // 특정 값(postNum)을 받아 그 내용을 조회 PostDto postDto = boardService.getPost(postNum); logger.info("BoardController.getPost() : 게시글 불러오기 성공"); // postNum으로 Image 데이터(다수) 조회 List imageList = boardService.getPostImageList(postNum); -// 애초에 Post에 image 포함 여부 항목이 있었어야 했다.. // 전부 수정하는 것은 너무 복잡 + // 애초에 Post에 image 포함 여부 항목이 있었어야 했다.. // 전부 수정하는 것은 너무 복잡 logger.info("BoardController.getPost() : 이미지 리스트 불러오기 성공"); @@ -158,25 +157,4 @@ public PostResponseDto getPost(Integer postNum) { // 게시글 조회 .imageList(imageList) .build(); } - -// @PostMapping("/board/registerImage") -// public void uploadImage() { // 이미지 등록 메소드를 별도 처리? -// // 게시글 이미지 저장 관련 코드 -// // 이미지는 다른 controller 메소드 사용 -// // multiPartFile로 받음 .getOriginalFilename(), -// // 이미지는 각각 uuid를 가짐 -// // File 객체 생성, uuid+주소 -// // .transferTo()로 서버에 저장 -// -// // 경로를 기준, base64? -// -// -// // 게시글 이미지 조회 관련 코드 -// // List list = findPostImageListById(postId) -// // for() { list.add -// // if(image == null) { .add(default Image) -// -// } - - } diff --git a/src/main/java/com/tomato/market/data/repository/ImageRepository.java b/src/main/java/com/tomato/market/data/repository/ImageRepository.java index 33f3a7c..dde0f55 100644 --- a/src/main/java/com/tomato/market/data/repository/ImageRepository.java +++ b/src/main/java/com/tomato/market/data/repository/ImageRepository.java @@ -8,9 +8,7 @@ import com.tomato.market.data.entity.ImageEntity; public interface ImageRepository extends JpaRepository { - // Optional findImageByPostNum(Integer postNum); Optional findTopByPostNumOrderByImageNum(Integer postNum); - List findByPostNum(Integer postNum); } diff --git a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java index 996943d..45d1f1c 100644 --- a/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java +++ b/src/main/java/com/tomato/market/service/impl/BoardServiceImpl.java @@ -41,6 +41,7 @@ public BoardServiceImpl(BoardDao boardDao) { @Override public PostDto writePost(PostDto postDto) { logger.info("BoardServiceImpl.writePost() is called"); + // DTO -> Entity 전환 PostEntity postEntity = PostDto.toPostEntity(postDto); @@ -77,7 +78,7 @@ public void uploadImages(Integer postNum, List files) { // 이미 } logger.info("BoardServiceImpl.uploadImages() : 이미지 파일 저장 성공"); -// DB에 파일 정보 저장 + // DB에 파일 정보 저장 ImageEntity imageEntity = ImageEntity.builder().postNum(postNum).imageName(file.getOriginalFilename()).uuid(fileName).build(); ImageEntity saveResult = boardDao.saveImage(imageEntity); // 어떤 식으로 저장되는지 repository 분리? @@ -89,7 +90,6 @@ public void uploadImages(Integer postNum, List files) { // 이미 } logger.info("BoardServiceImpl.uploadImages() : 모든 이미지 저장 성공"); -// return null; } @Override