Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Release/0.2.0] 기본 거래 기능 #16

Merged
merged 29 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
9f398a6
Merge pull request #7 from tomato-market/release/0.1.0
Hyunuk17 Oct 9, 2023
9e85d6d
Merge pull request #9 from tomato-market/hotfix/0.1.1
Hyunuk17 Oct 9, 2023
4a50813
[tomato-market/plan#8] 브랜치 생성 및 기초 구성
Hyunuk17 Oct 8, 2023
defa73b
[tomato-market/plan#8] 게시글 등록 API
Hyunuk17 Oct 10, 2023
f504446
[tomato-market/plan#8] 이미지 경로 프로파일 분리
Hyunuk17 Oct 10, 2023
16e9542
[tomato-market/plan#8] 예외 처리
Hyunuk17 Oct 10, 2023
81fbe47
[tomato-market/plan#8] API 수정 및 Controller Test
Hyunuk17 Oct 11, 2023
44240d0
[tomato-market/plan#8] Service Test
Hyunuk17 Oct 12, 2023
31dd777
Merge pull request #12 from tomato-market/main
Hyunuk17 Oct 15, 2023
181528b
Merge branch 'dev' into feature/8_post
Hyunuk17 Oct 15, 2023
d5860ce
Merge pull request #13 from tomato-market/feature/8_post
Hyunuk17 Oct 15, 2023
6f3b6e2
[tomato-market/plan#7] 브랜치 생성
Hyunuk17 Oct 15, 2023
3d25943
[tomato-market/plan#7] 게시글 리스트 API 작성
Hyunuk17 Oct 16, 2023
5c6953d
[tomato-market/plan#7] 이미지 접근 방식 수정
Hyunuk17 Oct 17, 2023
9e8ff6b
[tomato-market/plan#7] findImage 수정
Hyunuk17 Oct 18, 2023
28da493
[tomato-market/plan#7] Controller Test
Hyunuk17 Oct 18, 2023
c5d764b
[tomato-market/plan#7] Service Test
Hyunuk17 Oct 18, 2023
1a92ee4
[tomato-market/plan#7] 페이징
Hyunuk17 Oct 19, 2023
a8c6edf
[tomato-market/plan#7] 검색 기능 추가
Hyunuk17 Oct 19, 2023
5755038
[tomato-market/plan#7] Controller Test
Hyunuk17 Oct 19, 2023
44452ee
[tomato-market/plan#7] Service Test
Hyunuk17 Oct 19, 2023
ed71096
Merge pull request #14 from tomato-market/feature/7_board
Hyunuk17 Oct 19, 2023
f7177ec
[tomato-market/plan#26] 브랜치 생성
Hyunuk17 Oct 20, 2023
6b70cb0
[tomato-market/plan#26] 게시글 조회 API
Hyunuk17 Oct 20, 2023
baf1216
[tomato-market/plan26] 테스트 코드 작성
Hyunuk17 Oct 21, 2023
7d014e2
[tomato-market/plan#26] ImageRepository 수정
Hyunuk17 Oct 21, 2023
7e5e238
[tomato-market/plan#26] createAt 데이터 포함
Hyunuk17 Oct 23, 2023
5722152
Merge pull request #15 from tomato-market/feature/26_post_detail
Hyunuk17 Oct 23, 2023
ca7ec95
[release/0.2.0] Release-0.2.0 생성
Hyunuk17 Oct 23, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/main/java/com/tomato/market/config/JpaAuditingConfig.java
Original file line number Diff line number Diff line change
@@ -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 {
}
34 changes: 34 additions & 0 deletions src/main/java/com/tomato/market/config/SwaggerConfig.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
}
}

}
1 change: 0 additions & 1 deletion src/main/java/com/tomato/market/config/WebConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
public class WebConfig implements WebMvcConfigurer {
// CORS 처리


@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // CORS를 적용할 URL 패턴
Expand Down
163 changes: 135 additions & 28 deletions src/main/java/com/tomato/market/controller/BoardController.java
Original file line number Diff line number Diff line change
@@ -1,53 +1,160 @@
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.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;
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.service.BoardService;

import jakarta.servlet.http.HttpSession;
import jakarta.validation.Valid;

@RestController
@RequestMapping("/api")
public class BoardController {
private final Logger logger = LoggerFactory.getLogger(BoardController.class);

private final BoardService boardService;

@Autowired
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<EnrolEntity>?? 반환
//
// // (임시) 세션이 잘 들어왔는지 확인
// 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(value = "/board/writePost", consumes = {MediaType.APPLICATION_JSON_VALUE,
MediaType.MULTIPART_FORM_DATA_VALUE})
public PostResponseDto writePost(
@RequestPart(value = "postDto") @Valid PostDto postDto,
@RequestPart(value = "images", required = false) List<MultipartFile> files)
throws IOException { // 추후 @Valid // 이미지도 받아와야 함
logger.info("BoardController.writePost() is called");
logger.info("BoardController.writerPost() : Validation 검증 성공");

// 게시글 등록
PostDto savedPost = boardService.writePost(postDto);
logger.info("BoardController.writePost() : 게시글 저장 성공");

Integer postNum = savedPost.getPostNum(); //

if (files != null) {
logger.info("BoardController.writePost() : 이미지 개수-" + files.size());
// postID와 연관하여 이미지 등록 // Image API를 따로 분리? : DB간 관계가 성립되지 않는 문제 있음
boardService.uploadImages(postNum, files);
logger.info("BoardController.writePost() : 이미지 저장 성공");
}

// 결과 리턴
return PostResponseDto.builder()
.status(HttpStatus.OK)
.message("게시글 등록 성공")
.build();
}

// 조회 삭제 수정 : 각각 별도 이슈로 분리
// PutMapping?
// updatePost() {}


@GetMapping(value = "/board/getPostList")
public PostListResponseDto getPostList(
@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());

// 게시글 리스트를 받음
Page<PostDto> postList = null;
if (keyword == null) {
logger.info("BoardController.getPostList() : 검색 키워드 없음");
postList = boardService.getPostList(pageable);
} else {
logger.info("BoardController.getPostList() : 검색 키워드 있음");
postList = boardService.getPostSearchList(keyword, 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();

PageDto pageDto = PageDto.builder()
.nowPage(nowPage)
.startPage(startPage)
.endPage(endPage)
.totalPage(totalPage)
.build();


// 찾은 postList에서 각 Post의 ID로 Image를 찾음
List<ImageDto> imageList = new ArrayList<>();
for (PostDto postDto : postList) {
// 썸네일로 사용할 Image 1개만 필요
imageList.add(boardService.getPostImage(postDto.getPostNum()));
}
logger.info("BoardController.getPostList() : 게시글의 이미지 정보를 찾음");

// Return
// 게시글 List 첨부
// 이미지 List 첨부
return PostListResponseDto.builder()
.status(HttpStatus.OK)
.message("게시글 리스트 불러오기 성공")
.postList(postList)
.imageList(imageList)
.page(pageDto)
.build();
}

@GetMapping("/board/getPost") // {id} 형태로 받는게 나았을 수도?
public PostResponseDto getPost(Integer postNum) { // 게시글 조회
logger.info("BoardController.getPost() is called");

// 특정 값(postNum)을 받아 그 내용을 조회
PostDto postDto = boardService.getPost(postNum);
logger.info("BoardController.getPost() : 게시글 불러오기 성공");


// postNum으로 Image 데이터(다수) 조회
List<ImageDto> imageList = boardService.getPostImageList(postNum);
// 애초에 Post에 image 포함 여부 항목이 있었어야 했다.. // 전부 수정하는 것은 너무 복잡
logger.info("BoardController.getPost() : 이미지 리스트 불러오기 성공");


// return값으로 postDto, imageList 전달
return PostResponseDto.builder()
.status(HttpStatus.OK)
.message("게시글 불러오기 성공")
.postDto(postDto)
.imageList(imageList)
.build();
}
}
25 changes: 25 additions & 0 deletions src/main/java/com/tomato/market/dao/BoardDao.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
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;

public interface BoardDao {
PostEntity save(PostEntity postEntity);

ImageEntity saveImage(ImageEntity imageEntity);

Page<PostEntity> findPostList(Pageable pageable);

Page<PostEntity> findPostSearchList(String keyword, Pageable pageable);

ImageEntity findImageByPostNum(Integer postNum);

PostEntity findPostByPostNum(Integer postNum);

List<ImageEntity> findImageListByPostNum(Integer postNum);
}
Loading