diff --git a/docker-compose.yml b/docker-compose.yml index 789eafd7..c8bf84c5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,54 +1,29 @@ version: '3' services: redis: - container_name: redis + container_name: redis_test image: redis:latest ports: - - "6379:6379" + - "6375:6379" networks: - db_network - ## deploy - 무중단 - nginx: - image: nginx:1.15-alpine - container_name: nginx-container - restart: always - ports: - - "80:80" - volumes: - - ./nginx:/etc/nginx/conf.d + mysql: + container_name: mysql_test + image: mysql:latest + environment: + MYSQL_ROOT_PASSWORD: root_pw + MYSQL_DATABASE: test_db + MYSQL_USER: test + MYSQL_PASSWORD: test_pw command: - "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'" - networks: - - backbone - - green: - build: . - image: green - container_name: green - restart: always + - --default-authentication-plugin=mysql_native_password ports: - - "8081:8080" - volumes: - - ./:/home/ubuntu - - /etc/localtime:/etc/localtime + - "3302:3306" networks: - - backbone + - db_network - blue: - build: . - container_name: blue - restart: always - ports: - - "8082:8080" - volumes: - - ./:/home/ubuntu - - /etc/localtime:/etc/localtime - networks: - - backbone networks: db_network: - driver: bridge - backbone: driver: bridge \ No newline at end of file diff --git a/src/docs/asciidoc/board.adoc b/src/docs/asciidoc/board.adoc index ad28170e..f21c7af4 100644 --- a/src/docs/asciidoc/board.adoc +++ b/src/docs/asciidoc/board.adoc @@ -19,6 +19,10 @@ include::{snippets}/intro-board-create/http-request.adoc[] include::{snippets}/intro-board-create/http-response.adoc[] ==== 4. 게시글 리스트 조회 ( 페이징 처리 ) + +==== prefix : 필수값 +==== category, search, order(default : RECENT) : 선택값 + ===== Request include::{snippets}/get-board/http-request.adoc[] ===== Response @@ -48,25 +52,4 @@ include::{snippets}/board-category/http-request.adoc[] ===== Response include::{snippets}/board-category/http-response.adoc[] -==== 9. 게시글 검색 - 게시판 ( 자유 | 홍보 | 소개 ) - -본 API는 게시판별 게시글 목록 조회 기능을 수행합니다. name 값에 `DEFAULT`, `INTRO`, `ADVERTISEMENT` 값 중 하나를 입력해야 합니다. - -keyword는 필수값은 아니며, 검색어를 통해 게시글의 작성자, 제목, 내용에 대해 검색합니다. - -===== Request -include::{snippets}/board-prefix-search/http-request.adoc[] -===== Response -include::{snippets}/board-prefix-search/http-response.adoc[] -===== 10.게시글 검색 - 말머리 - -본 API는 말머리별 게시글 목록 조회 기능을 수행합니다. name 값에 말머리 조회를 통해 얻은 code 데이터 중 하나를 입력해야 합니다. - -keyword는 필수값은 아니며, 검색어를 통해 게시글의 작성자, 제목, 내용에 대해 검색합니다. - -===== Request -include::{snippets}/board-category-search/http-request.adoc[] - -===== Response -include::{snippets}/board-category-search/http-response.adoc[] \ No newline at end of file diff --git a/src/main/kotlin/com/example/jhouse_server/domain/board/controller/BoardController.kt b/src/main/kotlin/com/example/jhouse_server/domain/board/controller/BoardController.kt index a79bddca..e588d67d 100644 --- a/src/main/kotlin/com/example/jhouse_server/domain/board/controller/BoardController.kt +++ b/src/main/kotlin/com/example/jhouse_server/domain/board/controller/BoardController.kt @@ -5,6 +5,7 @@ import com.example.jhouse_server.domain.board.service.BoardService import com.example.jhouse_server.domain.user.entity.User import com.example.jhouse_server.global.annotation.Auth import com.example.jhouse_server.global.annotation.AuthUser +import com.example.jhouse_server.global.aop.log.logger import com.example.jhouse_server.global.response.ApplicationResponse import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable @@ -36,12 +37,13 @@ class BoardController( return ApplicationResponse.ok(boardService.updateBoard(boardId, req, user)) } + @GetMapping fun getBoardAll( - @RequestParam category: String, - @PageableDefault(size=8) pageable: Pageable - ) : ApplicationResponse> { - return ApplicationResponse.ok(boardService.getBoardAll(category, pageable)) + @ModelAttribute boardListDto: BoardListDto, + @PageableDefault(size=8, page=0) pageable: Pageable + ): ApplicationResponse> { + return ApplicationResponse.ok(boardService.getBoardAll(boardListDto, pageable)) } @GetMapping("/{boardId}") @@ -69,23 +71,5 @@ class BoardController( return ApplicationResponse.ok(boardService.getCategory(name)) } - // name : prefix category - @GetMapping("/category/search") - fun getBoardAllWithPrefixCategory( - @RequestParam name : String, - @RequestParam keyword : String, - @PageableDefault pageable: Pageable - ) : ApplicationResponse> { - return ApplicationResponse.ok(boardService.getBoardAllWithPrefixCategory(name, keyword, pageable)); - } - // name : category - @GetMapping("/board-category/search") - fun getBoardAllWithBoardCategory( - @RequestParam name : String, - @RequestParam keyword : String, - @PageableDefault pageable: Pageable - ) : ApplicationResponse> { - return ApplicationResponse.ok(boardService.getBoardAllWithBoardCategory(name, keyword, pageable)); - } } \ No newline at end of file diff --git a/src/main/kotlin/com/example/jhouse_server/domain/board/dto/BoardReqDto.kt b/src/main/kotlin/com/example/jhouse_server/domain/board/dto/BoardReqDto.kt index ff14287f..32149127 100644 --- a/src/main/kotlin/com/example/jhouse_server/domain/board/dto/BoardReqDto.kt +++ b/src/main/kotlin/com/example/jhouse_server/domain/board/dto/BoardReqDto.kt @@ -5,7 +5,10 @@ import com.example.jhouse_server.domain.board.entity.BoardCategory import com.example.jhouse_server.domain.comment.dto.CommentResDto import org.slf4j.LoggerFactory import java.sql.Timestamp +import java.text.Normalizer import java.util.* +import java.util.regex.Matcher +import java.util.regex.Pattern import javax.validation.constraints.NotNull import kotlin.streams.toList @@ -32,7 +35,8 @@ data class BoardResDto( val imageUrl: String?, val commentCount: Int, val category: String, - val prefixCategory: String + val prefixCategory: String, + val fixed: Boolean ) data class BoardUpdateReqDto( @@ -61,23 +65,32 @@ data class BoardResOneDto( val commentCount : Int, val comments : List ) + +data class BoardListDto( + val prefix: String, + val category: String?, + val search: String?, + val order: String? +) fun toListDto(board : Board) : BoardResDto { val oneLineContent = sliceContentWithRegex(board.content) if (board.imageUrls.isEmpty()) { - return BoardResDto(board.id, board.title, board.boardCode.code, oneLineContent, board.user.nickName, Timestamp.valueOf(board.createdAt), null, board.comment.size, board.category.name, board.prefixCategory.name) + return BoardResDto(board.id, board.title, board.boardCode.code, oneLineContent, board.user.nickName, Timestamp.valueOf(board.createdAt), null, board.comment.size, board.category.name, board.prefixCategory.name, board.fixed) } - return BoardResDto(board.id, board.title, board.boardCode.code, oneLineContent, board.user.nickName, Timestamp.valueOf(board.createdAt), board.imageUrls[0], board.comment.size, board.category.name, board.prefixCategory.name) + return BoardResDto(board.id, board.title, board.boardCode.code, oneLineContent, board.user.nickName, Timestamp.valueOf(board.createdAt), board.imageUrls[0], board.comment.size, board.category.name, board.prefixCategory.name, board.fixed) } fun toDto(board: Board) : BoardResOneDto { return BoardResOneDto(board.id, board.title, board.boardCode.code, board.user.nickName, Timestamp.valueOf(board.createdAt), board.imageUrls, board.love.size, board.category.name, board.prefixCategory.name, board.comment.size, board.comment.stream().map { com.example.jhouse_server.domain.comment.dto.toDto(it) }.toList()) } fun sliceContentWithRegex(content : String) : String { - val pattern = Regex("^[a-zA-Z가-힣].*[.!?]$") - val validatedString = pattern.find(content)?.value ?: "" - if (validatedString.length >= 200) - return validatedString.take(200) - return validatedString +// val pattern = Regex("^[a-zA-Z가-힣].*[.!?]$") +// val validatedString = pattern.find(content)?.value ?: "" + return if (content.length >= 200) { + content.take(200) + } else { + content + } } data class CodeResDto( diff --git a/src/main/kotlin/com/example/jhouse_server/domain/board/repository/BoardRepositoryCustom.kt b/src/main/kotlin/com/example/jhouse_server/domain/board/repository/BoardRepositoryCustom.kt index dff976fd..dcef61c5 100644 --- a/src/main/kotlin/com/example/jhouse_server/domain/board/repository/BoardRepositoryCustom.kt +++ b/src/main/kotlin/com/example/jhouse_server/domain/board/repository/BoardRepositoryCustom.kt @@ -1,6 +1,7 @@ package com.example.jhouse_server.domain.board.repository import com.example.jhouse_server.admin.board.dto.AdminBoardSearch +import com.example.jhouse_server.domain.board.BoardListDto import com.example.jhouse_server.domain.board.PrefixCategory import com.example.jhouse_server.domain.board.entity.Board import com.example.jhouse_server.domain.board.entity.BoardCategory @@ -10,7 +11,7 @@ import org.springframework.data.domain.Pageable interface BoardRepositoryCustom { fun getFixableBoardListWithPaging(adminBoardSearch: AdminBoardSearch, pageable: Pageable): Page fun getDeletableBoardListWithPaging(adminBoardSearch: AdminBoardSearch, pageable: Pageable): Page - fun getBoardAllWithPrefixCategory(name: PrefixCategory, keyword: String, pageable: Pageable): Page - abstract fun getBoardAllWithBoardCategory(name: BoardCategory, keyword: String, pageable: Pageable): Page + + fun getBoardAll(boardListDto: BoardListDto, pageable: Pageable): Page } \ No newline at end of file diff --git a/src/main/kotlin/com/example/jhouse_server/domain/board/repository/BoardRepositoryImpl.kt b/src/main/kotlin/com/example/jhouse_server/domain/board/repository/BoardRepositoryImpl.kt index 4e23c38c..82275899 100644 --- a/src/main/kotlin/com/example/jhouse_server/domain/board/repository/BoardRepositoryImpl.kt +++ b/src/main/kotlin/com/example/jhouse_server/domain/board/repository/BoardRepositoryImpl.kt @@ -2,13 +2,20 @@ package com.example.jhouse_server.domain.board.repository import com.example.jhouse_server.admin.board.dto.AdminBoardSearch import com.example.jhouse_server.admin.board.dto.SearchFilter +import com.example.jhouse_server.domain.board.BoardListDto import com.example.jhouse_server.domain.board.PrefixCategory import com.example.jhouse_server.domain.board.entity.Board import com.example.jhouse_server.domain.board.entity.BoardCategory import com.example.jhouse_server.domain.board.entity.QBoard.board +import com.example.jhouse_server.domain.board.entity.QBoardCode.boardCode +import com.example.jhouse_server.domain.comment.entity.QComment +import com.example.jhouse_server.domain.comment.entity.QComment.* +import com.example.jhouse_server.domain.love.entity.QLove.* import com.example.jhouse_server.domain.user.entity.QUser.user +import com.querydsl.core.types.OrderSpecifier import com.querydsl.core.types.dsl.BooleanExpression import com.querydsl.jpa.impl.JPAQueryFactory +import org.hibernate.sql.ordering.antlr.OrderingSpecification import org.springframework.data.domain.Page import org.springframework.data.domain.PageImpl import org.springframework.data.domain.Pageable @@ -50,38 +57,45 @@ class BoardRepositoryImpl( return PageableExecutionUtils.getPage(result, pageable) {countQuery.fetch().size.toLong()} } - override fun getBoardAllWithPrefixCategory(name: PrefixCategory, keyword: String, pageable: Pageable): Page { + + override fun getBoardAll(boardListDto: BoardListDto, pageable: Pageable): Page { val result = jpaQueryFactory - .select(board) - .from(board) - .where(searchWithPrefixCategory(name), searchWithKeyword(keyword), board.useYn.eq(true)) + .selectFrom(board) + .join(board.boardCode, boardCode).fetchJoin() + .join(board.user, user).fetchJoin() + .where(board.useYn.eq(true), board.prefixCategory.eq(PrefixCategory.valueOf(boardListDto.prefix)),searchWithBoardCategory(boardListDto.category),searchWithKeyword(boardListDto.search)) + .orderBy(board.fixed.desc(), searchWithOrder(boardListDto.order)) + .limit(pageable.pageSize.toLong()) + .offset(pageable.offset) .fetch() - return PageImpl(result, pageable, result.size.toLong()) - } + val countQuery = jpaQueryFactory + .selectFrom(board) + .where(board.useYn.eq(true), board.prefixCategory.eq(PrefixCategory.valueOf(boardListDto.prefix)),searchWithBoardCategory(boardListDto.category),searchWithKeyword(boardListDto.search)) - override fun getBoardAllWithBoardCategory( - name: BoardCategory, - keyword: String, - pageable: Pageable - ): Page { - val result = jpaQueryFactory - .select(board) - .from(board) - .where(searchWithBoardCategory(name), searchWithKeyword(keyword), board.useYn.eq(true)) - .fetch() - return PageImpl(result, pageable, result.size.toLong()) + return PageableExecutionUtils.getPage(result, pageable) {countQuery.fetch().size.toLong()} } - private fun searchWithBoardCategory(name: BoardCategory): BooleanExpression? { - return board.category.eq(name) + + private fun searchWithBoardCategory(category: String?): BooleanExpression? { + return if(category == null) null else board.category.eq(BoardCategory.valueOf(category)) } - private fun searchWithKeyword(keyword: String): BooleanExpression? { - return board.content.contains(keyword) + private fun searchWithKeyword(keyword: String?): BooleanExpression? { + return if(keyword == null) null else board.content.contains(keyword) .or(board.title.contains(keyword)) - .or(board.user.nickName.eq(keyword)) } + + private fun searchWithOrder(order: String?): OrderSpecifier<*>?{ + return when(order){ + null -> board.updatedAt.desc() + "RECENT" -> board.updatedAt.desc() + "POPULAR" -> board.love.size().desc() + else -> null + } + } + + private fun searchFilter(adminBoardSearch: AdminBoardSearch) : BooleanExpression? { return when (adminBoardSearch.filter) { SearchFilter.TITLE -> board.title.contains(adminBoardSearch.keyword) diff --git a/src/main/kotlin/com/example/jhouse_server/domain/board/service/BoardService.kt b/src/main/kotlin/com/example/jhouse_server/domain/board/service/BoardService.kt index f118e697..35ede534 100644 --- a/src/main/kotlin/com/example/jhouse_server/domain/board/service/BoardService.kt +++ b/src/main/kotlin/com/example/jhouse_server/domain/board/service/BoardService.kt @@ -8,11 +8,10 @@ import org.springframework.data.domain.Pageable interface BoardService { fun createBoard(req: BoardReqDto, user: User): Long fun updateBoard(boardId: Long, req: BoardUpdateReqDto, user: User): Long - fun getBoardAll(category: String, pageable: Pageable): Page +// fun getBoardAll(category: String, pageable: Pageable): Page + fun getBoardAll(boardListDto: BoardListDto, pageable: Pageable): Page fun getBoardOne(boardId: Long): BoardResOneDto fun deleteBoard(boardId: Long, user: User) fun getCategory(name: String): List - fun getBoardAllWithPrefixCategory(name: String, keyword: String, pageable: Pageable): Page - abstract fun getBoardAllWithBoardCategory(name: String, keyword: String, pageable: Pageable): Page } \ No newline at end of file diff --git a/src/main/kotlin/com/example/jhouse_server/domain/board/service/BoardServiceImpl.kt b/src/main/kotlin/com/example/jhouse_server/domain/board/service/BoardServiceImpl.kt index 94bce41b..adbe6e91 100644 --- a/src/main/kotlin/com/example/jhouse_server/domain/board/service/BoardServiceImpl.kt +++ b/src/main/kotlin/com/example/jhouse_server/domain/board/service/BoardServiceImpl.kt @@ -54,12 +54,10 @@ class BoardServiceImpl( ).id } - override fun getBoardAll(category: String, pageable: Pageable): Page { - return boardRepository.findAllByPrefixCategoryAndUseYn( - PrefixCategory.valueOf(category), - useYn = true, - pageable = pageable - ).map{ toListDto(it) } + + override fun getBoardAll(boardListDto: BoardListDto, pageable: Pageable): Page { + return boardRepository.getBoardAll(boardListDto, pageable) + .map { toListDto(it) } } override fun getBoardOne(boardId: Long): BoardResOneDto { @@ -79,19 +77,6 @@ class BoardServiceImpl( return BoardCategory.values().filter { it.superCategory.name == name }.map { CodeResDto(it.value, it.name) } } - override fun getBoardAllWithPrefixCategory(name: String, keyword: String, pageable: Pageable): Page { - val prefixCategoryName = PrefixCategory.valueOf(name) - return boardRepository.getBoardAllWithPrefixCategory(prefixCategoryName, keyword, pageable).map { toListDto(it) } - } - - override fun getBoardAllWithBoardCategory( - name: String, - keyword: String, - pageable: Pageable - ): Page { - val boardCategoryName = BoardCategory.valueOf(name) - return boardRepository.getBoardAllWithBoardCategory(boardCategoryName, keyword, pageable).map{ toListDto(it) } - } fun getContent(code: String): String { var str = code diff --git a/src/main/resources/static/docs/board.html b/src/main/resources/static/docs/board.html index 323105bc..cbc73ff3 100644 --- a/src/main/resources/static/docs/board.html +++ b/src/main/resources/static/docs/board.html @@ -4,23 +4,25 @@ - + Board API