게시물 수정기능 작업중.

master
강석 최 2021-12-17 18:36:26 +09:00
parent bde144db79
commit 06df11d99d
6 changed files with 133 additions and 37 deletions

View File

@ -36,11 +36,16 @@ public class BoardController {
private final BoardService boardService; private final BoardService boardService;
@GetMapping("/contentWrite") @GetMapping("/contentWrite")
public ModelAndView contentWrite(Principal principal) { public ModelAndView contentWrite(@AuthenticationPrincipal UserInfo loginUser, Board content) {
ModelAndView mav = new ModelAndView("board/contentWrite"); ModelAndView mav = new ModelAndView("board/contentWrite");
UserInfo loginUser = ((UserInfo)((UsernamePasswordAuthenticationToken) principal).getPrincipal()); if(content == null) {
mav.addObject("type", "new");
mav.addObject("userId", loginUser.getUserId()); mav.addObject("userId", loginUser.getUserId());
mav.addObject("userName", loginUser.getName()); mav.addObject("userName", loginUser.getName());
}else{
mav.addObject("type", "modify");
mav.addObject("content", boardService.selectContentModifyInfo(content.getContentSeq()));
}
return mav; return mav;
} }
@ -50,6 +55,13 @@ public class BoardController {
return boardService.saveContent(content); return boardService.saveContent(content);
} }
@PostMapping("/updateContent")
public Integer updateContent(Board content, @RequestParam(value = "fileSeq") List<Integer> deleteFileSeq, MultipartHttpServletRequest request, @AuthenticationPrincipal UserInfo loginUser){
content.setFileList(request.getMultiFileMap().get("uploadFiles"));
return 0;
// return boardService.updateContent(content, loginUser);
}
@GetMapping("/contentList") @GetMapping("/contentList")
public ModelAndView contentList(Board board){ public ModelAndView contentList(Board board){
ModelAndView mav = new ModelAndView("board/contentList"); ModelAndView mav = new ModelAndView("board/contentList");
@ -66,7 +78,7 @@ public class BoardController {
public ModelAndView selectBoardContent(Board content, @AuthenticationPrincipal UserInfo loginUser){ public ModelAndView selectBoardContent(Board content, @AuthenticationPrincipal UserInfo loginUser){
ModelAndView mav = new ModelAndView("board/contentDetail"); ModelAndView mav = new ModelAndView("board/contentDetail");
Board target = boardService.selectContentByContentSeqAndViewCntUp(content.getContentSeq()); Board target = boardService.selectContentByContentSeqAndViewCntUp(content.getContentSeq());
mav.addObject("content", boardService.SelectContentForeignAttribute(target)); mav.addObject("content", boardService.selectContentForeignAttribute(target));
mav.addObject("loginUser", loginUser); mav.addObject("loginUser", loginUser);
return mav; return mav;
} }

View File

@ -27,6 +27,7 @@ public class BoardService {
private final FileInfoRepository fileInfoRepository; private final FileInfoRepository fileInfoRepository;
private final BoardCategoryRepository boardCategoryRepository; private final BoardCategoryRepository boardCategoryRepository;
private final BoardMapper boardMapper; private final BoardMapper boardMapper;
private final UserInfoRepository userInfoRepository;
@Transactional @Transactional
public Integer saveContent(Board content){ public Integer saveContent(Board content){
@ -37,6 +38,17 @@ public class BoardService {
return contentSeq; return contentSeq;
} }
@Transactional
public Integer updateContent(Board updateContent, UserInfo userInfo) {
int contentSeq = updateContent.getContentSeq();
Board savedContent = boardRepository.findById(contentSeq).orElse(null);
savedContent.setCategorySeq(updateContent.getCategorySeq());
savedContent.setTitle(updateContent.getTitle());
savedContent.setDescription(updateContent.getDescription());
saveBoardLog(contentSeq, LogStatus.MODIFY, null, userInfo.getUserId());
return contentSeq;
}
private void saveBoardLog(Integer contentSeq, LogStatus status, String description, String createId){ private void saveBoardLog(Integer contentSeq, LogStatus status, String description, String createId){
BoardLog lastLog = boardLogRepository.findTopByContentSeqOrderByLogSeqDesc(contentSeq).orElse(null); BoardLog lastLog = boardLogRepository.findTopByContentSeqOrderByLogSeqDesc(contentSeq).orElse(null);
BoardLog log = new BoardLog(); BoardLog log = new BoardLog();
@ -125,13 +137,30 @@ public class BoardService {
@Transactional @Transactional
public Board selectContentByContentSeqAndViewCntUp(Integer contentSeq) { public Board selectContentByContentSeqAndViewCntUp(Integer contentSeq) {
Board target = boardRepository.findById(contentSeq).orElse(null); Board target = selectContent(contentSeq);
if(target.getStatus()==null){ if(target.getStatus()==null){
target.setViewCnt(target.getViewCnt()+1); target.setViewCnt(target.getViewCnt()+1);
} }
return target; return target;
} }
public Board selectContent(int contentSeq){
Board content = boardRepository.findById(contentSeq).orElse(null);
content.setCreateName(userInfoRepository.findByUserId(content.getCreateId()).orElse(null).getUserId());
return content;
}
public Board selectContentModifyInfo(int contentSeq){
Board content = selectContent(contentSeq);
content = selectContentForeignAttribute(content);
StringBuilder hashTagStr = new StringBuilder();
for(HashTag tag : content.getHashTagList()){
hashTagStr.append("#").append(tag.getTagName()).append(", ");
}
if(!hashTagStr.toString().equals("")) {
hashTagStr = new StringBuilder(hashTagStr.substring(0, hashTagStr.length() - 2));
content.setHashTagStr(hashTagStr.toString());
}
return content;
}
public List<FileInfo> selectDownloadFileInfoList(Integer contentSeq, List<Integer> fileSeqList, String userId) { public List<FileInfo> selectDownloadFileInfoList(Integer contentSeq, List<Integer> fileSeqList, String userId) {
List<FileInfo> fileList = fileInfoRepository.findByContentSeqOrderByFileSeqAsc(contentSeq); List<FileInfo> fileList = fileInfoRepository.findByContentSeqOrderByFileSeqAsc(contentSeq);
List<FileInfo> targetList = new ArrayList<>(); List<FileInfo> targetList = new ArrayList<>();
@ -153,7 +182,7 @@ public class BoardService {
return boardMapper.selectBoardLogFromContentSeq(contentSeq); return boardMapper.selectBoardLogFromContentSeq(contentSeq);
} }
public Board SelectContentForeignAttribute(Board target) { public Board selectContentForeignAttribute(Board target) {
target.setHashTagList(boardMapper.selectHashTagListFromContentSeq(target.getContentSeq())); target.setHashTagList(boardMapper.selectHashTagListFromContentSeq(target.getContentSeq()));
target.setChildFileList(fileInfoRepository.findByContentSeqOrderByFileSeqAsc(target.getContentSeq())); target.setChildFileList(fileInfoRepository.findByContentSeqOrderByFileSeqAsc(target.getContentSeq()));
return target; return target;

View File

@ -69,7 +69,7 @@ $(document).on('click', '#deleteBtn', function (){
} }
}) })
$(document).on('click', '#modifyBtn', function (){ $(document).on('click', '#modifyBtn', function (){
location.href = "/board/contentWrite?contentSeq="+Number($(this).attr("data-contentseq"));
}) })
function getContentSeq(){ function getContentSeq(){
return $(".contentCheckBox:checked").val(); return $(".contentCheckBox:checked").val();

View File

@ -1,6 +1,11 @@
const files = []; const files = [];
$(function(){ $(function(){
if(pageType === "modify"){
$(".categorySelector").removeAttr("disabled");
setParentCategory(4, $("#categorySeq").find("[selected]").attr("data-parentseq"));
}
$("#uploadDiv").on("dragenter", function(e) { $("#uploadDiv").on("dragenter", function(e) {
// $(this).addClass('drag-over'); // $(this).addClass('drag-over');
}).on("dragleave", function(e) { }).on("dragleave", function(e) {
@ -15,7 +20,7 @@ $(function(){
setFileDiv(file, files.push(file)); setFileDiv(file, files.push(file));
} }
}).on('click', function (e){ }).on('click', function (e){
if(e.target.className.indexOf("fileDelete")<0){ if(e.target.className.indexOf("ileDelete")<0){
$("#fileInputer").click(); $("#fileInputer").click();
} }
}); });
@ -48,18 +53,33 @@ $(document).on('click', '.fileDelete', function (){
uploadDiv.append("<br>파일을 업로드 해주세요."); uploadDiv.append("<br>파일을 업로드 해주세요.");
} }
}) })
$(document).on('click', '.uploadedFileDelete', function (){
const target = $(this).parent().find("span")[0];
if(target.className===""){
target.className = "text-decoration-line-through";
}else{
target.className = "";
}
})
$(document).on('click', '#saveBtn', function (){ $(document).on('click', '#saveBtn', function (){
if(contentCheck()){ if(contentCheck()){
if(confirm("저장하시겠습니까?")){ if(confirm("저장하시겠습니까?")){
let ajaxUrl = "/board/saveContent";
const formData = new FormData($("#contentForm")[0]); const formData = new FormData($("#contentForm")[0]);
for(const file of files) { for(const file of files) {
if(!file.isDelete) if(!file.isDelete)
formData.append('uploadFiles', file, file.name); formData.append('uploadFiles', file, file.name);
} }
if(pageType==='modify'){
ajaxUrl = "/board/updateContent";
$(".text-decoration-line-through").each(function (idx, el){
formData.append('fileSeq', $(el).attr("data-fileseq"));
})
}
$.ajax({ $.ajax({
type : 'POST', type : 'POST',
data : formData, data : formData,
url : "/board/saveContent", url : ajaxUrl,
processData: false, processData: false,
contentType: false, contentType: false,
success : function(result) { success : function(result) {
@ -112,6 +132,22 @@ function selectorDisabler(depth){
}) })
} }
function setParentCategory(depth, parentSeq){
$("[data-depth='"+depth+"']").children().each(function (){
const option = $(this)
if(parentSeq === option.attr("data-parentseq")){
option.removeAttr("style");
}else{
option.css("display", "none");
}
})
const nextTarget = $("[value='"+parentSeq+"']");
nextTarget.attr("selected", "selected");
if(depth!==1){
setParentCategory(depth-1, nextTarget.attr("data-parentseq"));
}
}
function setFileDiv(file, idx){ function setFileDiv(file, idx){
const uploadDiv = $("#uploadDiv"); const uploadDiv = $("#uploadDiv");
if(files.length===1){ if(files.length===1){
@ -134,6 +170,7 @@ function contentCheck(){
alert("제목을 입력해주세요.") alert("제목을 입력해주세요.")
flag = false; flag = false;
} }
if(pageType === "new"){
if($(".fileDelete ").length===0){ if($(".fileDelete ").length===0){
alert("업로드 할 파일이 없습니다.") alert("업로드 할 파일이 없습니다.")
flag = false; flag = false;
@ -150,6 +187,7 @@ function contentCheck(){
if(totalSize>104857600){ if(totalSize>104857600){
alert("첨부파일의 용량 합은 100MB를 넘길 수 없습니다.") alert("첨부파일의 용량 합은 100MB를 넘길 수 없습니다.")
} }
}
return flag; return flag;
} }

View File

@ -12,11 +12,14 @@
</style> </style>
</th:block> </th:block>
<th:block layout:fragment="script"> <th:block layout:fragment="script">
<script type="text/javascript">
const pageType = '[[${type}]]';
</script>
<script type="text/javascript" th:src="@{/js/board/contentWrite.js}"></script> <script type="text/javascript" th:src="@{/js/board/contentWrite.js}"></script>
</th:block> </th:block>
<div layout:fragment="content"> <div layout:fragment="content">
<main class="pt-3"> <main class="pt-3">
<h4>자료 등록</h4> <h4 th:text="${type=='new'?'자료 등록':'자료 수정'}"></h4>
<div class="row mx-0"> <div class="row mx-0">
<div class="col-7 card"> <div class="col-7 card">
<div class="card-body"> <div class="card-body">
@ -26,6 +29,9 @@
</div> </div>
</div> </div>
<form id="contentForm" th:action="@{/board/saveContent}" method="post"> <form id="contentForm" th:action="@{/board/saveContent}" method="post">
<th:block th:if="${type!='new'}">
<input type="hidden" name="contentSeq" th:value="${content.contentSeq}">
</th:block>
<div class="row mb-3"> <div class="row mb-3">
<label for="title" class="col-sm-2 col-form-label">분류 선택</label> <label for="title" class="col-sm-2 col-form-label">분류 선택</label>
<div class="col-sm"> <div class="col-sm">
@ -60,12 +66,13 @@
</div> </div>
<div class="col-sm"> <div class="col-sm">
<select class="form-select categorySelector" data-depth="4" name="categorySeq" id="categorySeq" disabled> <select class="form-select categorySelector" data-depth="4" name="categorySeq" id="categorySeq" disabled>
<option value="" selected>분류를 선택해주세요</option> <option value="" th:selected="${type=='new'}">분류를 선택해주세요</option>
<th:block th:each="depth1:${session.categoryList}"> <th:block th:each="depth1:${session.categoryList}">
<th:block th:each="depth2:${depth1.childCategoryList}"> <th:block th:each="depth2:${depth1.childCategoryList}">
<th:block th:each="depth3:${depth2.childCategoryList}"> <th:block th:each="depth3:${depth2.childCategoryList}">
<th:block th:each="depth4:${depth3.childCategoryList}"> <th:block th:each="depth4:${depth3.childCategoryList}">
<option th:value="${depth4.categorySeq}" th:data-parentseq="${depth4.parentSeq}" th:text="${depth4.categoryName}"></option> <option th:value="${depth4.categorySeq}" th:data-parentseq="${depth4.parentSeq}"
th:text="${depth4.categoryName}" th:selected="${type=='modify' && content.categorySeq == depth4.categorySeq}"></option>
</th:block> </th:block>
</th:block> </th:block>
</th:block> </th:block>
@ -76,25 +83,34 @@
<div class="row mb-3"> <div class="row mb-3">
<label for="title" class="col-sm-2 col-form-label">제목</label> <label for="title" class="col-sm-2 col-form-label">제목</label>
<div class="col-sm-10"> <div class="col-sm-10">
<input type="text" class="form-control" id="title" name="title" autocomplete="off"> <input type="text" class="form-control" id="title" name="title" autocomplete="off" th:value="${type!='new'?content.title:''}">
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<label for="createName" class="col-sm-2 col-form-label">작성자</label> <label for="createName" class="col-sm-2 col-form-label">작성자</label>
<div class="col-sm-4"> <div class="col-sm-4">
<input type="hidden" name="createId" th:value="${userId}"> <input type="hidden" name="createId" th:value="${type!='new'?content.createId:userId}">
<input type="text" class="form-control" id="createName" th:value="${userName}" readonly> <input type="text" class="form-control" id="createName" th:value="${type!='new'?content.createName:userName}" readonly>
</div> </div>
<label for="createDate" class="col-sm-2 col-form-label">작성일</label> <label for="createDate" class="col-sm-2 col-form-label">작성일</label>
<div class="col-sm-4"> <div class="col-sm-4">
<input type="text" class="form-control" id="createDate" value="저장시 생성" readonly> <input type="text" class="form-control" id="createDate"
th:value="${type!='new'?(#temporals.format(content.createDate, 'yyyy-MM-dd HH:mm:dd')):'저장시 생성'}" readonly>
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<label for="fileInputer" class="col-sm-2 col-form-label">업로드 자료</label> <label for="fileInputer" class="col-sm-2 col-form-label">업로드 자료</label>
<div class="col-sm-10" style="min-height: 70px;"> <div class="col-sm-10" style="min-height: 70px;">
<div class="w-100 h-100 border border-info rounded text-center" id="uploadDiv"> <div class="w-100 h-100 border border-info rounded text-center" id="uploadDiv">
<th:block th:if="${type=='new'}">
<br>파일을 업로드 해주세요. <br>파일을 업로드 해주세요.
</th:block>
<th:block th:if="${type=='modify'}">
<div class='row-col-6' th:each="fileInfo:${content.childFileList}">
<span th:data-fileseq="${fileInfo.fileSeq}" th:text="|${fileInfo.originalName}.${fileInfo.extention} ${fileInfo.fileSize}|"></span>
<a href='#' class='uploadedFileDelete text-danger text-decoration-none'>삭제</a>
</div>
</th:block>
</div> </div>
</div> </div>
<input type="file" class="d-none" id="fileInputer" multiple> <input type="file" class="d-none" id="fileInputer" multiple>
@ -102,13 +118,14 @@
<div class="row mb-3"> <div class="row mb-3">
<label for="description" class="col-sm-2 col-form-label">설명</label> <label for="description" class="col-sm-2 col-form-label">설명</label>
<div class="col-sm-10"> <div class="col-sm-10">
<textarea id="description" name="description"></textarea> <textarea id="description" name="description" th:text="${type!='new'?content.description:''}"></textarea>
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<label for="hashTag" class="col-sm-2 col-form-label">해시태그</label> <label for="hashTag" class="col-sm-2 col-form-label">해시태그</label>
<div class="col-sm-10"> <div class="col-sm-10">
<input type="text" class="form-control" id="hashTag" name="hashTagStr" placeholder="태그는 앞에 #을 붙여 띄어쓰기 없이 작성해주세요. ex) #태그1, #태그2, ..." autocomplete="off"> <input type="text" class="form-control" id="hashTag" name="hashTagStr" th:value="${type!='new'?content.hashTagStr:''}"
placeholder="태그는 앞에 #을 붙여 띄어쓰기 없이 작성해주세요. ex) #태그1, #태그2, ..." autocomplete="off">
</div> </div>
</div> </div>
</form> </form>

View File

@ -54,9 +54,9 @@
</head> </head>
<body class="d-flex flex-column h-100"> <body class="d-flex flex-column h-100">
<header th:replace="fragments/header :: headerFragment"></header> <header th:replace="fragments/header :: headerFragment"></header>
<div sec:authorize="isAnonymous()" layout:fragment="content"></div> <div class="h-100" sec:authorize="isAnonymous()" layout:fragment="content"></div>
<div sec:authorize="isAuthenticated()" class="row mx-0 "> <div sec:authorize="isAuthenticated()" class="row mx-0 h-100">
<div class="col-2 centerDiv"> <div class="col-2 centerDiv border-end">
<div th:replace="fragments/leftMenu :: leftMenuFragment"></div> <div th:replace="fragments/leftMenu :: leftMenuFragment"></div>
</div> </div>
<div class="col-10 centerDiv"> <div class="col-10 centerDiv">