Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
public enum BBSErrorCode implements ErrorCode {

FAILED_GET_BBS_LIST(HttpStatus.NO_CONTENT.value(), "BMC001", "게시판 목록을 찾을 수 없음."),
FAILED_GET_BBS_VIEW(HttpStatus.NO_CONTENT.value(), "BMC002", "게시글을 찾을 수 없음.");
FAILED_GET_BBS_VIEW(HttpStatus.NO_CONTENT.value(), "BMC002", "게시글을 찾을 수 없음."),
UNSUPPORTED_API_VERSION(HttpStatus.BAD_REQUEST.value(), "BMC003", "지원하지않는 API버전. API 버전을 다시 확인하세요.");

private final int status;
private final String code;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,54 +8,76 @@
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

@RestController
@RequiredArgsConstructor
@RequestMapping("/bbs")
public class BBSController {
private final BBSService bbsService;

@GetMapping("/bbs")
public ResponseEntity<ApiResponse<Page<BBSListDto>>> getBBS(
@GetMapping("/v1")
public ResponseEntity<ApiResponse<Page<BBSListDto>>> getBBSv1(
@RequestParam(value = "type", defaultValue = "") String type,
@RequestParam(value = "keyword", required = false) String keyword, Pageable pageable
@RequestParam(value = "keyword", required = false) String keyword,
Pageable pageable
){
Page<BBSListDto> result = bbsService.getBBSWithCondition(type, keyword, pageable);

return ApiResponse.toResponseEntity(BBSBusinessCode.SUCCESS_REQUEST_GET_BBS, result);
return ApiResponse.toResponseEntity(BBSBusinessCode.SUCCESS_REQUEST_GET_BBS, bbsService.getBBSWithConditionByPage(type, keyword, pageable));
}

@GetMapping("/bbs/{bbsNo}")
@GetMapping("/v2")
public ResponseEntity<ApiResponse<Slice<BBSListDto>>> getBBSv2(
@RequestParam(value = "type", defaultValue = "") String type,
@RequestParam(value = "keyword", required = false) String keyword,
Pageable pageable
){

return ApiResponse.toResponseEntity(BBSBusinessCode.SUCCESS_REQUEST_GET_BBS, bbsService.getBBSWithConditionBySlice(type, keyword, pageable));
}

@GetMapping("/{bbsNo}")
public ResponseEntity<ApiResponse<BBSDto>> getBBSView(@PathVariable Long bbsNo){

return ApiResponse.toResponseEntity(BBSBusinessCode.SUCCESS_REQUEST_GET_BBS_VIEW, bbsService.getBBSView(bbsNo));
}

@GetMapping("/bbs/reply")
@GetMapping("/reply")
public ResponseEntity<ApiResponse<Page<BBSDto>>> getBBSReply(@RequestParam Long upperNo, Pageable pageable){

return ApiResponse.toResponseEntity(BBSBusinessCode.SUCCESS_REQUEST_GET_BBS_VIEW, bbsService.getBBSReply(upperNo, pageable));
}

@PostMapping("/bbs")
public ResponseEntity<ApiResponse<BBSDto>> saveBBS(@RequestBody BBSDto bbsDto, @RequestHeader("Id") String id){

bbsService.saveBBS(bbsDto, id);
@PostMapping("")
public ResponseEntity<ApiResponse<BBSDto>> saveBBS(
@RequestPart BBSDto bbsDto,
@RequestHeader("Id") String id,
@RequestPart(required = false) List<MultipartFile> files
){
bbsService.saveBBS(bbsDto, id, files);

return ApiResponse.toResponseEntity(BBSBusinessCode.SUCCESS_REQUEST_CREATED_BBS);
}

@PatchMapping("/bbs")
public ResponseEntity<ApiResponse<BBSDto>> modifyBBS(@RequestBody BBSDto bbsDto, @RequestHeader("Id") String id){
@PatchMapping("")
public ResponseEntity<ApiResponse<BBSDto>> modifyBBS(
@RequestPart BBSDto bbsDto,
@RequestHeader("Id") String id,
@RequestPart(required = false) List<MultipartFile> files
){

bbsService.saveBBS(bbsDto, id);
bbsService.saveBBS(bbsDto, id, files);

return ApiResponse.toResponseEntity(BBSBusinessCode.SUCCESS_REQUEST_MODIFIED_BBS);
}

@DeleteMapping("/bbs")
public ResponseEntity<ApiResponse<BBSDto>> deleteBBS(@RequestParam Long bbsNo){
@DeleteMapping("/{bbsNo}")
public ResponseEntity<ApiResponse<BBSDto>> deleteBBS(@PathVariable Long bbsNo){

bbsService.deleteBBS(bbsNo);

Expand Down
30 changes: 12 additions & 18 deletions module-api/src/main/java/com/kernel360/bbs/dto/BBSDto.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package com.kernel360.bbs.dto;

import com.kernel360.bbs.entity.BBS;
import com.kernel360.file.entity.File;
import com.kernel360.member.dto.MemberDto;

import java.time.LocalDateTime;
import java.util.List;

/**
* DTO for {@link com.kernel360.bbs.entity.BBS}
*/
public record BBSDto(

Long bbsNo,
Long upperNo,
String type,
Expand All @@ -20,7 +23,8 @@ public record BBSDto(
LocalDateTime modifiedAt,
String modifiedBy,
Long viewCount,
MemberDto memberDto
MemberDto memberDto,
List<File> files
) {

public static BBSDto of(
Expand All @@ -35,7 +39,8 @@ public static BBSDto of(
LocalDateTime modifiedAt,
String modifiedBy,
Long viewCount,
MemberDto memberDto
MemberDto memberDto,
List<File> files
){
return new BBSDto(
bbsNo,
Expand All @@ -49,11 +54,12 @@ public static BBSDto of(
modifiedAt,
modifiedBy,
viewCount,
memberDto
memberDto,
files
);
}

public static BBSDto from(BBS entity){
public static BBSDto from(BBS entity, List<File> byReferenceTypeAndReferenceNo){
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

byReferenceTypeAndReferenceNo 대신에 좀 더 '파일 리스트'인 게 드러나는 변수명이 좋지 않을까요?

return new BBSDto(
entity.getBbsNo(),
entity.getUpperNo(),
Expand All @@ -66,21 +72,9 @@ public static BBSDto from(BBS entity){
entity.getModifiedAt(),
entity.getModifiedBy(),
entity.getViewCount(),
MemberDto.from(entity.getMember())
MemberDto.from(entity.getMember()),
byReferenceTypeAndReferenceNo
);
}


// public BBS toEntity() {
// return BBS.create(
// this.bbsNo(),
// this.upperNo(),
// this.title(),
// this.contents()
//
// );
// }



}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
import com.kernel360.bbs.entity.BBS;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;

public interface BBSRepository extends BBSRepositoryJPA, BBSRepositoryDSL {
Page<BBSListDto> getBBSWithCondition(String type, String keyword, Pageable pageable);
Page<BBSListDto> getBBSWithConditionByPage(String type, String keyword, Pageable pageable);
Slice<BBSListDto> getBBSWithConditionBySlice(String type, String keyword, Pageable pageable);
Comment on lines +10 to +11
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

페이지를 반환하는 메서드와 슬라이스를 반환하는 메서드를 둘 다 만들어 두는 점 좋은 것 같습니다.


BBS findOneByBbsNo(Long bbsNo);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
import com.kernel360.bbs.dto.BBSListDto;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;

public interface BBSRepositoryDSL {
Page<BBSListDto> getBBSWithCondition(String bbsType, String keyword, Pageable pageable);
Page<BBSListDto> getBBSWithConditionByPage(String bbsType, String keyword, Pageable pageable);

Slice<BBSListDto> getBBSWithConditionBySlice(String bbsType, String keyword, Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,9 @@
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.*;

import java.util.List;
import java.util.Objects;

import static com.kernel360.bbs.entity.QBBS.bBS;
import static com.kernel360.member.entity.QMember.member;
Expand All @@ -25,20 +22,20 @@ public class BBSRepositoryDSLImpl implements BBSRepositoryDSL {
private final JPAQueryFactory queryFactory;

@Override
public Page<BBSListDto> getBBSWithCondition(String type, String keyword, Pageable pageable) {
public Page<BBSListDto> getBBSWithConditionByPage(String type, String keyword, Pageable pageable) {

Predicate finalPredicate = bBS.isVisible.eq(true)
.and(bBS.type.eq(BBSType.valueOf(type).name()));
.and(bBS.type.eq(BBSType.valueOf(type).name()));

List<BBSListDto> bbs = getBBSListWithMember().
where(
finalPredicate,
keywordContains(keyword)
)
.orderBy(bBS.createdAt.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
where(
finalPredicate,
keywordContains(keyword)
)
.orderBy(bBS.createdAt.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize() + 1)
.fetch();

Long totalCount = queryFactory
.select(bBS.count())
Expand All @@ -52,6 +49,32 @@ public Page<BBSListDto> getBBSWithCondition(String type, String keyword, Pageabl
return new PageImpl<>(bbs, pageable, totalCount);
}

@Override
public Slice<BBSListDto> getBBSWithConditionBySlice(String type, String keyword, Pageable pageable) {

Predicate finalPredicate = bBS.isVisible.eq(true)
.and(bBS.type.eq(BBSType.valueOf(type).name()));

List<BBSListDto> bbs = getBBSListWithMember().
where(
finalPredicate,
keywordContains(keyword)
)
.orderBy(bBS.createdAt.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize() + 1)
.fetch();

boolean hasNext = false;
int pageSize = pageable.getPageSize();
if(bbs.size() > pageSize){
bbs.remove(pageSize);
hasNext = true;
}

return new SliceImpl<>(bbs, pageable, hasNext);
}

Comment on lines +52 to +77
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slice 적용 시 참고하겠습니다~

private JPAQuery<BBSListDto> getBBSListWithMember() {
return queryFactory
.select(fields(BBSListDto.class,
Expand All @@ -61,8 +84,8 @@ private JPAQuery<BBSListDto> getBBSListWithMember() {
bBS.createdAt,
bBS.createdBy,
bBS.viewCount,
bBS.member.memberNo,
bBS.member.id
member.memberNo,
member.id
Comment on lines -64 to +88
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분에서 성능 개선이 있었군요!

)

)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,48 +1,96 @@
package com.kernel360.bbs.service;

import com.kernel360.bbs.code.BBSErrorCode;
import com.kernel360.bbs.dto.BBSDto;
import com.kernel360.bbs.dto.BBSListDto;
import com.kernel360.bbs.entity.BBS;
import com.kernel360.bbs.repository.BBSRepository;
import com.kernel360.exception.BusinessException;
import com.kernel360.file.entity.File;
import com.kernel360.file.entity.FileReferType;
import com.kernel360.file.repository.FileRepository;
import com.kernel360.member.code.MemberErrorCode;
import com.kernel360.member.dto.MemberDto;
import com.kernel360.member.service.MemberService;
import com.kernel360.utils.file.FileUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;
import java.util.Objects;
import java.util.Optional;

@Slf4j
@Service
@RequiredArgsConstructor
public class BBSService {
private final FileUtils fileUtils;
private final BBSRepository bbsRepository;
private final MemberService memberService;
private final FileRepository fileRepository;

@Value("${aws.s3.bucket.url}")
private String bucketUrl;
private static final String REFERENCE_TYPE = "BBS";

public Page<BBSListDto> getBBSWithConditionByPage(String type, String keyword, Pageable pageable) {

public Page<BBSListDto> getBBSWithCondition(String type, String keyword, Pageable pageable) {
return bbsRepository.getBBSWithConditionByPage(type, keyword, pageable);
}

public Slice<BBSListDto> getBBSWithConditionBySlice(String type, String keyword, Pageable pageable) {

return bbsRepository.getBBSWithCondition(type, keyword, pageable);
return bbsRepository.getBBSWithConditionBySlice(type, keyword, pageable);
}

public BBSDto getBBSView(Long bbsNo) {
BBS entity = Optional.of(bbsRepository.findOneByBbsNo(bbsNo))
.orElseThrow(() -> new BusinessException(BBSErrorCode.FAILED_GET_BBS_VIEW));

BBSDto result = BBSDto.from(entity, fileRepository.findByReferenceTypeAndReferenceNo(REFERENCE_TYPE, entity.getBbsNo()));

return BBSDto.from(bbsRepository.findOneByBbsNo(bbsNo));
return result;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

바로 리턴 하셔도 괜찮을거 같습니다~

}

public Page<BBSDto> getBBSReply(Long upperNo, Pageable pageable) {

return bbsRepository.findAllByUpperNo(upperNo, pageable).map(BBSDto::from);
return bbsRepository.findAllByUpperNo(upperNo, pageable).map(entity -> BBSDto.from(entity, fileRepository.findByReferenceTypeAndReferenceNo(REFERENCE_TYPE, entity.getBbsNo())));
}

@Transactional
public void saveBBS(BBSDto bbsDto, String id) {
public void saveBBS(BBSDto bbsDto, String id, List<MultipartFile> files) {

MemberDto memberDto = memberService.findByMemberId(id);
MemberDto memberDto = Optional.of(memberService.findByMemberId(id))
.orElseThrow(() -> new BusinessException(MemberErrorCode.FAILED_FIND_MEMBER_INFO));

bbsRepository.save(BBS.save(bbsDto.bbsNo(), bbsDto.upperNo(), bbsDto.type(), bbsDto.title(), bbsDto.contents(), true, 0L, memberDto.toEntity()));
BBS bbs = bbsRepository.save(BBS.save(bbsDto.bbsNo(), bbsDto.upperNo(), bbsDto.type(), bbsDto.title(), bbsDto.contents(), true, 0L, memberDto.toEntity()));

if(Objects.nonNull(files)){
uploadFiles(files, bbs.getBbsNo());
}
}

@Transactional
public void deleteBBS(Long bbsNo) {

bbsRepository.deleteByBbsNo(bbsNo);
}

private void uploadFiles(List<MultipartFile> files, Long bbsNo) {
files.stream().forEach(file -> {
String path = String.join("/", FileReferType.BBS.getDomain(), bbsNo.toString());
String fileKey = fileUtils.upload(path, file);
String fileUrl = String.join("/", bucketUrl, fileKey);

File fileInfo = fileRepository.save(File.of(null, file.getOriginalFilename(), fileKey, fileUrl, FileReferType.BBS.getCode(), bbsNo));
log.info("게시판 파일 등록 -> file_no {}", fileInfo.getFileNo());
});
}
}
Loading