통합검색 작업완료.

master
강석 최 2021-12-21 17:02:38 +09:00
parent ef51c429ff
commit 2dd5496f84
9 changed files with 260 additions and 118 deletions

View File

@ -2,6 +2,7 @@ package com.dbnt.kcgfilemanager.controller;
import com.dbnt.kcgfilemanager.config.LogStatus;
import com.dbnt.kcgfilemanager.model.*;
import com.dbnt.kcgfilemanager.service.BoardCategoryService;
import com.dbnt.kcgfilemanager.service.BoardService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@ -19,9 +20,6 @@ import java.net.URLEncoder;
import java.security.Principal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@ -32,6 +30,7 @@ import java.util.zip.ZipOutputStream;
public class BoardController {
private final BoardService boardService;
private final BoardCategoryService boardCategoryService;
@GetMapping("/contentWrite")
public ModelAndView contentWrite(@AuthenticationPrincipal UserInfo loginUser, Board content) {
@ -62,7 +61,7 @@ public class BoardController {
@GetMapping("/contentList")
public ModelAndView contentList(Board board){
ModelAndView mav = new ModelAndView("board/contentList");
mav.addObject("pageTitle", boardService.getPageTitle(board.getCategorySeq()));
mav.addObject("pageTitle", boardCategoryService.getPageTitle(board.getCategorySeq()));
board.setQueryInfo();
mav.addObject("contentList", boardService.selectContentList(board));
board.setContentCnt(boardService.selectContentListCnt(board));
@ -71,12 +70,15 @@ public class BoardController {
return mav;
}
@GetMapping("/fullSearchBoardContent")
public ModelAndView fullSearchBoardContent(Board board,
@RequestParam(value = "categorySeq", required = false) List<Integer> categorySeqList,
@RequestParam(value = "tagName", required = false) List<String> tagNameList){
@PostMapping("/fullSearchBoardContent")
@ResponseBody
public ModelAndView fullSearchBoardContent(
Board board,
@RequestParam(value = "searchCategorySeq", required = false) List<Integer> categorySeqList,
@RequestParam(value = "tagName", required = false) List<String> tagNameList
){
ModelAndView mav = new ModelAndView("board/contentSearchResult");
mav.addObject("boardList", boardService.fullSearchBoardContent(categorySeqList, board, tagNameList));
return mav;
}

View File

@ -39,6 +39,9 @@ public class Board extends BaseModel{
@Column(name = "CREATE_DATE")
private LocalDateTime createDate;
@Transient
private String originalName;
@Transient
private String createName;
@Transient
@ -48,6 +51,8 @@ public class Board extends BaseModel{
private List<FileInfo> childFileList;
@Transient
private List<HashTag> hashTagList;
@Transient
private List<BoardCategory> categoryList;
@Transient
private String hashTagStr;

View File

@ -0,0 +1,14 @@
package com.dbnt.kcgfilemanager.model;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
public class SearchResult {
private String searchCategoryName;
private List<Board> contentList;
}

View File

@ -60,4 +60,20 @@ public class BoardCategoryService {
}
boardCategoryRepository.deleteAll(childList);
}
public String getPageTitle(Integer categorySeq) {
BoardCategory category = boardCategoryRepository.findById(categorySeq).orElse(null);
if(category.getParentSeq()==null){
return category.getCategoryName();
}
return getPageTitle(category.getParentSeq())+" > "+category.getCategoryName();
}
public String makeFilePath(Integer categorySeq){
BoardCategory category = boardCategoryRepository.findById(categorySeq).orElse(null);
if(category.getParentSeq()==null){
return "D:\\kcgFileManager\\"+category.getCategoryName();
}
return makeFilePath(category.getParentSeq())+"\\"+category.getCategoryName();
}
}

View File

@ -20,15 +20,49 @@ import java.util.UUID;
@RequiredArgsConstructor
public class BoardService {
private final BoardMapper boardMapper;
private final BoardRepository boardRepository;
private final BoardCategoryRepository boardCategoryRepository;
private final BoardCategoryService boardCategoryService;
private final BoardLogRepository boardLogRepository;
private final FileInfoRepository fileInfoRepository;
private final HashTagRepository hashTagRepository;
private final HashTagLinkRepository hashTagLinkRepository;
private final FileInfoRepository fileInfoRepository;
private final BoardCategoryRepository boardCategoryRepository;
private final BoardMapper boardMapper;
private final UserInfoRepository userInfoRepository;
public List<SearchResult> fullSearchBoardContent(List<Integer> categorySeqList, Board board, List<String> tagNameList) {
board.setRowCnt(Integer.MAX_VALUE);
List<HashTag> tagList = new ArrayList<>();
for(String tagName: tagNameList){
HashTag tag = new HashTag();
tag.setTagName(tagName);
tagList.add(tag);
}
board.setHashTagList(tagList);
List<SearchResult> results = new ArrayList<>();
for(int categorySeq : categorySeqList){
SearchResult searchResult = new SearchResult();
BoardCategory category = boardCategoryRepository.findById(categorySeq).orElse(null);
searchResult.setSearchCategoryName(boardCategoryService.getPageTitle(categorySeq));
if(category.getDepth() != 4){
category.setChildCategoryList(boardCategoryService.selectBoardCategoryAll(categorySeq, category.getDepth()+1));
board.setCategoryList(setboardCategoryToLastDepth(new ArrayList<>(), category));
}else{
board.setCategoryList(new ArrayList<>());
board.getCategoryList().add(category);
}
searchResult.setContentList(boardMapper.selectContentList(board));
results.add(searchResult);
}
return results;
}
@Transactional
public Integer saveContent(Board content){
Integer contentSeq = boardRepository.save(content).getContentSeq();
@ -92,7 +126,7 @@ public class BoardService {
int fileSeq = lastFileInfo==null?1:(lastFileInfo.getFileSeq()+1);
for(MultipartFile file : content.getFileList()){
String saveName = UUID.randomUUID().toString();
String path = makeFilePath(content.getCategorySeq());
String path = boardCategoryService.makeFilePath(content.getCategorySeq());
File saveFile = new File(path+"\\"+saveName);
if(file.getSize()!=0){ // 저장될 파일 확인
@ -126,14 +160,6 @@ public class BoardService {
}
}
public String getPageTitle(Integer categorySeq) {
BoardCategory category = boardCategoryRepository.findById(categorySeq).orElse(null);
if(category.getParentSeq()==null){
return category.getCategoryName();
}
return getPageTitle(category.getParentSeq())+" > "+category.getCategoryName();
}
public List<Board> selectContentList(Board board) {
return boardMapper.selectContentList(board);
}
@ -207,6 +233,16 @@ public class BoardService {
return contentSeq;
}
private List<BoardCategory> setboardCategoryToLastDepth(List<BoardCategory> categoryList, BoardCategory category){
for(BoardCategory child: category.getChildCategoryList()){
if(child.getDepth()==4){
categoryList.add(child);
}
setboardCategoryToLastDepth(categoryList, child);
}
return categoryList;
}
private void deleteHashTagLink(int contentSeq){
List<HashTagLink> tagLinkList = hashTagLinkRepository.findByContentSeq(contentSeq);
hashTagLinkRepository.deleteAll(tagLinkList);
@ -234,13 +270,6 @@ public class BoardService {
File deleteFile = new File(savePath, conversionName);
deleteFile.delete();
}
private String makeFilePath(Integer categorySeq){
BoardCategory category = boardCategoryRepository.findById(categorySeq).orElse(null);
if(category.getParentSeq()==null){
return "D:\\kcgFileManager\\"+category.getCategoryName();
}
return makeFilePath(category.getParentSeq())+"\\"+category.getCategoryName();
}
private String calculationFileSize(Long fileSize){
String[] units = {"bytes", "KB", "MB"};
double unitSelector = Math.floor(Math.log(fileSize)/Math.log(1024));

View File

@ -18,7 +18,48 @@
FROM FILE_INFO
GROUP BY CONTENT_SEQ ) C
ON A.CONTENT_SEQ = C.CONTENT_SEQ
WHERE A.CATEGORY_SEQ = #{categorySeq}
<where>
<if test="categorySeq != null and categorySeq != ''">
AND A.CATEGORY_SEQ = #{categorySeq}
</if>
<if test="title != null and title != ''">
AND A.TITLE LIKE CONCAT('%', #{title}, '%')
</if>
<if test="createName != null and createName != ''">
AND B.NAME LIKE CONCAT('%', #{createName}, '%')
</if>
<if test="startDate != null and startDate != ''">
AND A.CREATE_DATE >= CONCAT(#{startDate}, ' 00:00:00')
</if>
<if test="endDate != null and endDate != ''">
AND A.CREATE_DATE &lt;= CONCAT(#{endDate}, ' 23:59:59')
</if>
<if test="hashTagList != null and hashTagList.size != 0">
AND A.CONTENT_SEQ IN (
SELECT B.CONTENT_SEQ
FROM HASH_TAG A
INNER JOIN HASH_TAG_LINK B ON A.TAG_SEQ = B.TAG_SEQ
<where>
<foreach collection="hashTagList" item="hashTag">
OR A.TAG_NAME LIKE CONCAT('%',#{hashTag.tagName},'%')
</foreach>
</where>
)
</if>
<if test="categoryList != null and categoryList.size != 0">
AND A.CATEGORY_SEQ IN
<foreach collection="categoryList" item="category" open="(" separator="," close=")">
#{category.categorySeq}
</foreach>
</if>
<if test="originalName != null and originalName != ''">
AND A.CONTENT_SEQ IN (
SELECT DISTINCT CONTENT_SEQ
FROM FILE_INFO
WHERE ORIGINAL_NAME LIKE CONCAT('%', #{originalName}, '%')
)
</if>
</where>
ORDER BY A.CREATE_DATE DESC
LIMIT #{rowCnt} OFFSET #{firstIndex}
</select>

View File

@ -36,75 +36,62 @@ $(document).on('click', '#categoryUpBtn', function (){
$(document).on('click', '#categorySelectBtn', function (){
const selectedCategory = $(".selectedCategory");
let boardCategory = "";
let categorySeq = "";
let categoryNames = "";
selectedCategory.each(function (idx, el){
boardCategory += $(el).attr("data-categoryseq")+","+$(el).attr("data-depth")+"|";
categorySeq += $(el).attr("data-categoryseq")+",";
categoryNames += $(el).attr("data-categoryName")+", ";
})
$("#boardCategoryAry").val(boardCategory.slice(0, -1));
$("#searchCategorySeq").val(categorySeq.slice(0, -1));
$("#categoryName").val(categoryNames.slice(0, -2));
$("#categorySelectModal").find(".btn-close").click();
})
$(document).on('click', '#searchBtn', function (){
const param = getSearchParam();
$.ajax({
url: '/board/fullSearchBoardContent',
data: param,
type: 'GET',
processData: false,
contentType: false,
dataType:"html",
success: function(html){
$("#searchResultDiv").empty().append(html)
},
error:function(){
if(searchParamCheck()){
const formData = new FormData($("#searchForm")[0])
$.ajax({
type: "POST",
url: '/board/fullSearchBoardContent',
data: formData,
processData: false,
contentType: false,
beforeSend: function (xhr){
xhr.setRequestHeader($("[name='_csrf_header']").val(), $("[name='_csrf']").val());
},
success: function (html) {
$("#searchResultDiv").empty().append(html)
},
error: function () {
}
});
}
});
}
})
function getSearchParam(){
const param = {board: {}};
let boardCategoryAry = $("#boardCategoryAry").val();
if(boardCategoryAry){
boardCategoryAry = boardCategoryAry.split('|');
param.boardCategoryList = [];
boardCategoryAry.forEach((value) => {
const boardCategory = value.split(',');
param.boardCategoryList.push({categorySeq: boardCategory[0], depth: boardCategory[1]});
})
function searchParamCheck(){
let emptyCnt = 0;
if(!$("#title").val()){
emptyCnt++;
}
const title = $("#title").val();
if(title){
param.board.title = title;
if(!$("#createName").val()){
emptyCnt++;
}
const createName = $("#createName").val();
if(createName){
param.board.createName = createName;
if(!$("#tagName").val()){
emptyCnt++;
}
let tagNameAry = $("#tagName").val();
if(tagNameAry){
tagNameAry = tagNameAry.split(',')
param.hasTagList = [];
tagNameAry.forEach((value => {
param.hasTagList.push({tagName: value})
}))
if(!$("#startDate").val() || !$("#endDate").val()){
emptyCnt++;
}
const startDate = $("#startDate").val();
if(startDate){
param.board.startDate = startDate;
if(!$("#originalName").val()){
emptyCnt++;
}
const endDate = $("#endDate").val();
if(endDate){
param.board.endDate = endDate;
if(emptyCnt>3){
alert("분류를 제외한 5가지 조건 중 2가지 이상 입력해주세요.")
return false;
}else{
return true;
}
const originalName = $("#originalName").val();
if(originalName){
param.board.searchFileName = originalName;
}
return param;
}
function parentCheck(categorySeq){

View File

@ -11,61 +11,65 @@
</th:block>
<div layout:fragment="content">
<main class="pt-3">
<input type="hidden" name="_csrf_header" th:value="${_csrf.headerName}"/>
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
<h4>통합 검색</h4>
<div class="row mx-0">
<div class="col-12 card text-center">
<div class="col-12 card">
<div class="card-body">
<div class="row justify-content-start">
<div class="col-7">
<div class="card">
<div class="card-body row">
<div class="col-10">
<div class="row mb-1">
<label for="categoryName" class="col-sm-2 col-form-label">분류</label>
<div class="col-sm-8 pe-0">
<input type="hidden" id="boardCategoryAry">
<input type="text" class="form-control form-control-sm" id="categoryName" placeholder="오른쪽 분류 선택 버튼으로 등록" readonly>
</div>
<div class="col-sm-2 px-0">
<input type="button" class="btn btn-info btn-sm" id="categorySelectModalBtn" data-bs-toggle="modal" data-bs-target="#categorySelectModal" value="분류 선택">
</div>
</div>
<div class="row mb-1">
<label for="title" class="col-sm-2 col-form-label">제목</label>
<div class="col-sm-4">
<input type="text" class="form-control form-control-sm" id="title">
</div>
<label for="createName" class="col-sm-2 col-form-label">작성자</label>
<div class="col-sm-4">
<input type="text" class="form-control form-control-sm" id="createName">
</div>
</div>
<div class="row mb-1">
<label for="title" class="col-sm-2 col-form-label">해시태그</label>
<div class="col-sm-4">
<input type="text" class="form-control form-control-sm" id="tagName" placeholder="# 없이 ,로 구분하여 태그 입력">
</div>
<label for="startDate" class="col-sm-2 col-form-label">작성일</label>
<div class="col-sm-4">
<div class="col-auto input-group w-auto input-daterange" id="dateSelectorDiv">
<input type="text" class="form-control form-control-sm" id="startDate" placeholder="시작일" autocomplete="off">
<input type="text" class="form-control form-control-sm" id="endDate" placeholder="종료일" autocomplete="off">
<form action="#" method="post" id="searchForm">
<div class="row mb-1">
<label for="categoryName" class="col-sm-2 col-form-label">분류</label>
<div class="col-sm-8 pe-0">
<input type="hidden" id="searchCategorySeq" name="searchCategorySeq">
<input type="text" class="form-control form-control-sm" id="categoryName" placeholder="오른쪽 분류 선택 버튼으로 등록" readonly>
</div>
<div class="col-sm-2 px-0">
<input type="button" class="btn btn-info btn-sm" id="categorySelectModalBtn" data-bs-toggle="modal" data-bs-target="#categorySelectModal" value="분류 선택">
</div>
</div>
</div>
<div class="row">
<label for="title" class="col-sm-2 col-form-label">첨부파일</label>
<div class="col-sm-4">
<input type="text" class="form-control form-control-sm" id="originalName">
<div class="row mb-1">
<label for="title" class="col-sm-2 col-form-label">제목</label>
<div class="col-sm-4">
<input type="text" class="form-control form-control-sm" id="title" name="title">
</div>
<label for="createName" class="col-sm-2 col-form-label">작성자</label>
<div class="col-sm-4">
<input type="text" class="form-control form-control-sm" id="createName" name="createName">
</div>
</div>
</div>
<div class="row mb-1">
<label for="title" class="col-sm-2 col-form-label">해시태그</label>
<div class="col-sm-4">
<input type="text" class="form-control form-control-sm" id="tagName" name="tagName" placeholder="# 없이 ,로 구분하여 태그 입력">
</div>
<label for="startDate" class="col-sm-2 col-form-label">작성일</label>
<div class="col-sm-4">
<div class="col-auto input-group w-auto input-daterange" id="dateSelectorDiv">
<input type="text" class="form-control form-control-sm" id="startDate" name="startDate" placeholder="시작일" autocomplete="off">
<input type="text" class="form-control form-control-sm" id="endDate" name="endDate" placeholder="종료일" autocomplete="off">
</div>
</div>
</div>
<div class="row">
<label for="title" class="col-sm-2 col-form-label">첨부파일</label>
<div class="col-sm-4">
<input type="text" class="form-control form-control-sm" id="originalName" name="originalName">
</div>
</div>
</form>
</div>
<div class="col-2 m-auto">
<button class="btn btn-primary px-5 py-3" id="searchBtn" style="white-space: nowrap;"><i class="bi bi-search"></i><br>검색</button>
</div>
</div>
</div>
<div class="row-cols-6" id="searchResultDiv">
<div class="row" id="searchResultDiv">
</div>
</div>

View File

@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<th:block th:each="board:${boardList}">
<div class="col-12 py-2">
<h5><i class="bi bi-dot"></i><span th:text="${board.searchCategoryName}"></span></h5>
<table class="table table-striped text-center">
<thead>
<tr>
<th></th>
<th>제목</th>
<th>파일 수</th>
<th>작성자</th>
<th>작성일</th>
<th>조회수</th>
</tr>
</thead>
<tbody>
<th:block th:if="${board.contentList.size()==0}">
<tr>
<td colspan="6">검색 결과가 없습니다.</td>
</tr>
</th:block>
<th:block th:unless="${board.contentList.size()==0}">
<tr class="contentTr" th:each="content:${board.contentList}">
<td>
<input type="checkbox" class="contentCheckBox" th:value="${content.contentSeq}">
</td>
<td th:text="${content.title}"></td>
<td th:text="${content.fileCnt}"></td>
<td th:text="${content.createName}"></td>
<th:block th:if="${#dates.format(#dates.createNow(), 'yyyy-MM-dd')} == ${#temporals.format(content.createDate, 'yyyy-MM-dd')}">
<td th:text="${#temporals.format(content.createDate, 'HH:mm:ss')}"></td>
</th:block>
<th:block th:if="${#dates.format(#dates.createNow(), 'yyyy-MM-dd')} != ${#temporals.format(content.createDate, 'yyyy-MM-dd')}">
<td th:text="${#temporals.format(content.createDate, 'yyyy-MM-dd')}"></td>
</th:block>
<td class="viewCntTd" th:text="${content.viewCnt}"></td>
</tr>
</th:block>
</tbody>
</table>
</div>
</th:block>
</html>