Skip to content

Commit

Permalink
Merge pull request #31 from SQUAD-D/feature#18/image-update
Browse files Browse the repository at this point in the history
test code
  • Loading branch information
songhaechan authored Dec 15, 2023
2 parents 34486c3 + 73253b9 commit 133b112
Show file tree
Hide file tree
Showing 12 changed files with 166 additions and 27 deletions.
40 changes: 38 additions & 2 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,44 @@
## Project Architecture
## 프로젝트 아키텍처

![pja.png](mdimg%2Fpja.png)

## Project Preview
## 프로젝트 요구사항

- 로그인
- 회원 Session 방식 로그인 지원
- Session Clustering 구축 [Redis]

- 게시글
- 기본적인 게시글 CRUD
- 원작자/외부자에 대한 수정, 삭제 예외 처리
- 볼드체, 이텔릭체, 삭선, UL/LI 기능
- 게시글 페이징 처리
- 게시글 (제목+내용) , (제목) 검색기능 [MySQL n-gram]
- 이미지 업로드 기능 [S3]
- 이미지는 여러 개 업로드 가능
- 이미지 확장자/크기 예외처리

- 댓글
- 기본적인 댓글 CRUD
- 원작자/외부자에 대한 수정, 삭제 예외 처리
- 대댓글은 1개까지 가능

- 로드밸런싱
- Nignx를 이용한 RoundRobin 방식의 로드밸런싱

- CI/CD
- GitHub Action으로 PR, Push 시 EC2에 자동 배포
- Docker Compose를 이용한 다중 컨테이너 설정

- Monitoring
- Prometheus를 이용한 Redis 모니터링
- Scouter를 이용한 Tomcat/JVM 모니터링

## 프로젝트 미리보기

### 주소

https://haechan.store/

- Main

Expand Down
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ dependencies {
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
implementation 'org.springframework.boot:spring-boot-starter-quartz:2.7.5'
implementation 'org.apache.commons:commons-collections4:4.0'
testImplementation 'org.assertj:assertj-core:3.24.2'
}

tasks.named('test') {
Expand Down
25 changes: 22 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
version: '3'
services:
grafana:
image: grafana/grafana
ports:
- 3000:3000
prometheus:
image: prom/prometheus
ports:
- 9090:9090
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
spring_app1:
container_name: Spring-Tomcat-1
image: haechansomg/simple-board:was01
Expand All @@ -11,8 +21,17 @@ services:
ports:
- 8081:8081
redis:
image: redis:latest
image: "redis:latest"
container_name: redis
hostname: redis
expose:
- "6379"
ports:
- 6379:6379
redis-exporter:
image: oliver006/redis_exporter
ports:
- 9121:9121
environment:
REDIS_ADDR: "redis:6379"
links:
- redis
- prometheus
10 changes: 10 additions & 0 deletions prometheus.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: prometheus
static_configs:
- targets: [ 'localhost:9090' ]
- job_name: redis-exporter
static_configs:
- targets: [ 'redis-exporter:9121' ]
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ public ContentListResponse<CommentResponse> findAllComments(
// 댓글 삭제
@DeleteMapping("/comments/{commentId}")
@CommentWriterAuth
public void deleteComment(@PathVariable Long commentId, @SessionAttribute Long memberId) {
commentService.deleteComment(commentId, memberId);
public void deleteComment(@PathVariable Long commentId) {
commentService.deleteComment(commentId);
}

// 댓글 수정
Expand All @@ -55,13 +55,14 @@ public void updateComment(
@PathVariable Long commentId,
@SessionAttribute Long memberId,
@RequestBody CommentUpdateRequest commentUpdateRequest) {
commentService.updateComment(commentId, memberId, commentUpdateRequest);
commentService.updateComment(commentId, commentUpdateRequest);
}

// 대댓글 리스트
@GetMapping("/{boardId}/childComments/{parentCommentId}")
public ContentListResponse<CommentResponse> getChildComment(
@PathVariable Long boardId,
@SessionAttribute Long memberId,
@PathVariable Long parentCommentId
) {
return commentService.getChildComment(boardId, parentCommentId);
Expand Down
18 changes: 9 additions & 9 deletions src/main/java/squad/board/dto/Pagination.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package squad.board.dto;

import lombok.Getter;
import lombok.Setter;
import squad.board.exception.board.BoardException;
import squad.board.exception.board.BoardStatus;

@Getter
public class Pagination {
private final Long defaultPageSize = 10L;
private Long requestPageSize = 10L;
private Long totalContent;
private Long totalPages;
private Long currentPage;
Expand All @@ -18,6 +17,7 @@ public Pagination(Long requestPage, Long totalContent, Long size) {
this.currentPage = requestPage;
this.totalContent = totalContent;
this.totalPages = calculateTotalPages(size);
this.requestPageSize = size;
// 페이지 범위를 벗어난 요청 예외처리
if ((totalPages < requestPage || requestPage <= 0) && totalContent != 0) {
throw new BoardException(BoardStatus.INVALID_PAGE_NUMBER);
Expand All @@ -36,21 +36,21 @@ public Long calculateTotalPages(Long size) {
}

public void calculatePageList() {
final long diffFirstAndLast = defaultPageSize - 1;
final long diffFirstAndLast = requestPageSize - 1;

// 첫 페이지 연산 로직
long currentPageQuotient = currentPage / defaultPageSize;
long currentPageRemainder = currentPage % defaultPageSize;
long currentPageQuotient = currentPage / requestPageSize;
long currentPageRemainder = currentPage % requestPageSize;
this.firstPage = (currentPageRemainder == 1) ? currentPage : currentPage - (currentPageRemainder - 1);

if (currentPageRemainder == 0) {
this.firstPage = defaultPageSize * currentPageQuotient - diffFirstAndLast;
this.firstPage = requestPageSize * currentPageQuotient - diffFirstAndLast;
}

// 마지막 페이지 연산 로직
long totalPagesQuotient = totalPages / defaultPageSize;
long totalPagesRemainder = totalPages % defaultPageSize;
this.lastPage = (totalPagesQuotient == 0) ? totalPages : firstPage + defaultPageSize - 1;
long totalPagesQuotient = totalPages / requestPageSize;
long totalPagesRemainder = totalPages % requestPageSize;
this.lastPage = (totalPagesQuotient == 0) ? totalPages : firstPage + requestPageSize - 1;

if (lastPage > totalPages) {
this.lastPage = firstPage + totalPagesRemainder - 1;
Expand Down
8 changes: 6 additions & 2 deletions src/main/java/squad/board/dto/board/CreateBoardRequest.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package squad.board.dto.board;

import jakarta.validation.constraints.NotEmpty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.collections4.CollectionUtils;
import squad.board.domain.board.Board;

import java.time.LocalDateTime;
Expand Down Expand Up @@ -32,4 +31,9 @@ public Board toEntity(Long memberId) {
.modifiedDate(null)
.build();
}

public boolean isImageExist() {
return CollectionUtils.isNotEmpty(imageInfo);
}

}
8 changes: 3 additions & 5 deletions src/main/java/squad/board/service/BoardService.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,14 @@ public class BoardService {
private static final String TEMP_FOLDER_NAME = "tmp";
private static final String ORIGINAL_FOLDER_NAME = "original";
private static final String IMAGE_EXTENSION_EXTRACT_REGEX = "(.png|.jpg|.jpeg)$";

public CommonIdResponse createBoard(Long memberId, CreateBoardRequest createBoard) {
// 게시글 저장
Board board = createBoard.toEntity(memberId);
boardMapper.save(board);
// 이미지 정보 저장
List<ImageInfoRequest> imageInfoRequests = createBoard.getImageInfo();
if (CollectionUtils.isNotEmpty(imageInfoRequests)) {
// DB에 이미지 정보 저장
saveImageInfo(board.getBoardId(), imageInfoRequests);
if (createBoard.isImageExist()) {
saveImageInfo(board.getBoardId(), createBoard.getImageInfo());
}
return new CommonIdResponse(board.getBoardId());
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/squad/board/service/CommentService.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ public ContentListResponse<CommentResponse> getCommentList(Long boardId, Long si
return new ContentListResponse<>(commentMapper.findAllCommentsWithNickName(boardId, size, offset, memberId), commentPaging);
}

public void deleteComment(Long commentId, Long memberId) {
public void deleteComment(Long commentId) {
commentMapper.deleteByCommentId(commentId);
}

public void updateComment(Long commentId, Long memberId, CommentUpdateRequest commentUpdateRequest) {
public void updateComment(Long commentId, CommentUpdateRequest commentUpdateRequest) {
commentMapper.updateByCommentId(commentId, commentUpdateRequest.getContent(), LocalDateTime.now());
}

Expand Down
3 changes: 2 additions & 1 deletion src/main/resources/static/js/board/createBoard.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ writeBtn.addEventListener("click", () => {
axios.post(`${homeUrl}/api/boards`, data
).then(response => {
const statusCode = response.status;
const data = response.data;
// 게시글 작성 성공
if (statusCode === 200) {
window.location.href = '/boards';
window.location.href = `/boards/${data.id}`;
}
}).catch(error => {
const data = error.response.data;
Expand Down
39 changes: 39 additions & 0 deletions src/test/java/squad/board/dto/PaginationTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package squad.board.dto;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import squad.board.exception.board.BoardException;

class PaginationTest {

@Test
@DisplayName("전체 게시글이 100건에 한 페이지당 10건의 게시글을 보여줘야한다면 총 페이지수는 10페이지다.")
public void 총_페이지수연산() {
//given
Pagination pagination = new Pagination(1L, 100L, 10L);
//when
Long totalPageSize = pagination.calculateTotalPages(pagination.getRequestPageSize());
//then
Assertions.assertThat(totalPageSize).isEqualTo(10);
}

@Test
@DisplayName("전체 게시글이 101건에 한 페이지당 10건의 게시글을 보여줘야한다면 총 페이지수는 11페이지다.")
public void 총_페이지수연산2() {
//given
Pagination pagination = new Pagination(1L, 101L, 10L);
//when
Long totalPageSize = pagination.calculateTotalPages(pagination.getRequestPageSize());
//then
Assertions.assertThat(totalPageSize).isEqualTo(11);
}

@Test
@DisplayName("총 페이지 수를 벗어난 요청은 예외를 발생시킨다.")
public void 페이지_접근_예외() {
// Pagination 은 존재하지않는 페이지 정보
Assertions.assertThatExceptionOfType(BoardException.class).isThrownBy(() -> new Pagination(5L, 10L, 5L));
}

}
30 changes: 30 additions & 0 deletions src/test/java/squad/board/dto/board/BoardUpdateRequestTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package squad.board.dto.board;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

class BoardUpdateRequestTest {

@Test
@DisplayName("사용자의 Content에 존재하는 이미지와 DB에 존재하는 이미지가 불일치한다면 추출에 성공한다.")
public void checkDeleteImage() {
//given
String imageUUID1 = UUID.randomUUID().toString();
String imageUUID2 = UUID.randomUUID().toString();
String imageUUID3 = UUID.randomUUID().toString();
String content = "original/" + imageUUID1 + "\"" + "foo/" + "original/" + imageUUID2 + "\"" + "foo";
List<ImageInfoRequest> imageInfoRequests = new ArrayList<>();
BoardUpdateRequest boardUpdateRequest = new BoardUpdateRequest("test", content, imageInfoRequests);
List<String> originalUUID = List.of(imageUUID1, imageUUID2, imageUUID3);
//when
List<String> result = boardUpdateRequest.checkDeletedImage(originalUUID);
//then
Assertions.assertThat(result).asList().contains(imageUUID3);
}

}

0 comments on commit 133b112

Please sign in to comment.