This commit is contained in:
lunaticbum 2024-10-08 14:43:49 +09:00
parent c5de7a3548
commit 9e4597890b
3 changed files with 97 additions and 43 deletions

View File

@ -2,10 +2,16 @@ package kr.lunaticbum.back.lun.controllers
import jakarta.servlet.http.HttpServletRequest import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse import jakarta.servlet.http.HttpServletResponse
import kr.lunaticbum.back.lun.model.FileSaveResult
import kr.lunaticbum.back.lun.model.ResponceResult
import kr.lunaticbum.back.lun.utils.LogService import kr.lunaticbum.back.lun.utils.LogService
import kr.lunaticbum.back.lun.utils.getFileExtension import kr.lunaticbum.back.lun.utils.getFileExtension
import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value import org.springframework.beans.factory.annotation.Value
import org.springframework.core.io.Resource
import org.springframework.core.io.UrlResource
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.* import org.springframework.web.bind.annotation.*
import org.springframework.web.multipart.MultipartFile import org.springframework.web.multipart.MultipartFile
import org.springframework.web.servlet.ModelAndView import org.springframework.web.servlet.ModelAndView
@ -40,47 +46,63 @@ class BlogController() {
private val resourceHandler: String? = null private val resourceHandler: String? = null
@ResponseBody
@GetMapping("/post/images/{fileName}")
fun getImage(@PathVariable fileName : String) : Resource {
val imgUploadPath = ("file:" +uploadPath + File.separator + fileName)
return UrlResource.from(imgUploadPath)
}
@PostMapping("/post/imageUpload") @PostMapping("/post/imageUpload")
fun postImage(@RequestPart("file") upload: MultipartFile, res: HttpServletResponse, req: HttpServletRequest) { fun postImage(@RequestPart("file") upload: MultipartFile, res: HttpServletResponse, req: HttpServletRequest) : ResponseEntity<FileSaveResult> {
var lResultCode = 0
var lResultMsg = "Suscces"
var out: OutputStream? = null var out: OutputStream? = null
var printWriter: PrintWriter? = null var printWriter: PrintWriter? = null
var targetFile : File? = null
logService.log("imgUploadPath ${upload.originalFilename}") logService.log("imgUploadPath ${upload.originalFilename}")
res.characterEncoding = "utf-8" res.characterEncoding = "utf-8"
res.contentType = "text/html;charset=utf-8" res.contentType = "text/html;charset=utf-8"
var uuid = UUID.randomUUID()
val extension: String = getFileExtension(upload.originalFilename) ?: ""
try { try {
val uuid = UUID.randomUUID()
logService.log("imgUploadPath ${uuid.toString()}")
val extension: String = getFileExtension(upload.originalFilename) ?: "" logService.log("imgUploadPath ${uuid.toString()}")
val bytes = upload.bytes val bytes = upload.bytes
var f = File(uploadPath) var f = File(uploadPath)
// logService.log("imgUploadPath ${f.parentFile.parentFile.parentFile.parentFile.absoluteFile}")
// logService.log("imgUploadPath ${f.parentFile.parentFile.parentFile.absoluteFile}")
// logService.log("imgUploadPath ${f.parentFile.parentFile.absoluteFile}")
// logService.log("imgUploadPath ${f.parentFile.absoluteFile}")
logService.log("imgUploadPath ${f.exists()}") logService.log("imgUploadPath ${f.exists()}")
logService.log("imgUploadPath ${f.absolutePath}")
if (f.exists() == false) f.mkdirs() if (f.exists() == false) f.mkdirs()
// 실제 이미지 저장 경로 // 실제 이미지 저장 경로
val imgUploadPath = (uploadPath + File.separator + uuid).toString() + "." + extension val imgUploadPath = (uploadPath + File.separator + uuid).toString() + "." + extension
logService.log("imgUploadPath $imgUploadPath") logService.log("imgUploadPath $imgUploadPath")
File(imgUploadPath).parentFile.mkdirs() targetFile = File(imgUploadPath)
if(targetFile.parentFile.exists() == false)targetFile.parentFile.mkdirs()
// 이미지 저장 // 이미지 저장
out = FileOutputStream(imgUploadPath) out = FileOutputStream(imgUploadPath)
out.write(bytes) out.write(bytes)
out.flush() out.flush()
// ckEditor 로 전송 // ckEditor 로 전송
printWriter = res.writer // printWriter = res.writer
val callback = req.getParameter("CKEditorFuncNum") // val callback = req.getParameter("CKEditorFuncNum")
val fileUrl = "/blog/post/image/$uuid.$extension" // val fileUrl = "/blog/post/image/$uuid.$extension"
printWriter.println( // printWriter.println(
("<script type='text/javascript'>" // ("<script type='text/javascript'>"
+ "window.parent.CKEDITOR.tools.callFunction(" // + "window.parent.CKEDITOR.tools.callFunction("
+ callback + ",'" + fileUrl + "','이미지를 업로드하였습니다.')" // + callback + ",'" + fileUrl + "','이미지를 업로드하였습니다.')"
+ "</script>") // + "</script>")
) // )
//
printWriter.flush() // printWriter.flush()
logService.log("imgUploadPath $imgUploadPath") logService.log("imgUploadPath $imgUploadPath")
logService.log("imgUploadPath ${File(imgUploadPath).exists()}") logService.log("imgUploadPath ${File(imgUploadPath).exists()}")
} catch (e: IOException) { } catch (e: IOException) {
@ -88,11 +110,17 @@ class BlogController() {
} finally { } finally {
try { try {
out?.close() out?.close()
printWriter?.close() printWriter?.close()
} catch (e: IOException) { } catch (e: IOException) {
e.printStackTrace() e.printStackTrace()
} }
} }
val responce = ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(FileSaveResult().apply {
this.resultCode = lResultCode
this.resultMsg = lResultMsg
this.fileName = "$uuid.$extension"
})
return responce
} }
} }

View File

@ -4,7 +4,12 @@ import lombok.Getter
@Getter @Getter
class ResponceResult { open class ResponceResult {
var resultCode: Int = 0 var resultCode: Int = 0
var resultMsg: String? = null var resultMsg: String? = null
} }
@Getter
class FileSaveResult : ResponceResult() {
var fileName : String? = null
}

View File

@ -5,6 +5,8 @@
layout:decorate="~{layout/default_layout}"> layout:decorate="~{layout/default_layout}">
<th:block layout:fragment="head"> <th:block layout:fragment="head">
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- TOAST UI Editor CDN(JS) --> <!-- TOAST UI Editor CDN(JS) -->
<!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"/>--> <!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"/>-->
<!-- <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>--> <!-- <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>-->
@ -13,32 +15,50 @@
<script type="text/javascript" src="https://uicdn.toast.com/editor/latest/toastui-editor-all.min.js"></script> <script type="text/javascript" src="https://uicdn.toast.com/editor/latest/toastui-editor-all.min.js"></script>
<!-- TOAST UI Editor CDN(CSS) --> <!-- TOAST UI Editor CDN(CSS) -->
<link rel="stylesheet" href="https://uicdn.toast.com/editor/latest/toastui-editor.min.css" /> <link rel="stylesheet" href="https://uicdn.toast.com/editor/latest/toastui-editor.min.css" />
<link rel="stylesheet" href="https://uicdn.toast.com/editor/latest/toastui-editor-dark.css" />
<title>Spring Boot</title> <title>Spring Boot</title>
<script th:inline="javascript"> <script th:inline="javascript">
let editor
function onLoaded() { function onLoaded() {
// const onChange = () => { var h = document.querySelector('#content').getBoundingClientRect().height + 'px'
// const editorHtml = editor.getHTML(); editor = new toastui.Editor({
// setHtml(editorHtml);
// };
const editor = new toastui.Editor({
el: document.querySelector('#editor'), el: document.querySelector('#editor'),
previewStyle: 'vertical', previewStyle: 'tab',
height: '500px', height: '500px',
width:'100%',
theme:'dark',
usageStatistics : false, usageStatistics : false,
initialValue: "", toolbar:null,
initialValue:
"# 제목 " +"\n" +
"평문 사이에 **볼드체** *이탤릭체*"+"\n" +
"~~어디쓰지~~"+"\n" +
"***"+"\n" +
"### 모라모라 " +"\n" +
"> 으흐흠..." +"\n" +
"* 쓸까?" +"\n" +
"1. 첫번째" +"\n" +
"* [x] 체크하자" +"\n" +
"* [ ] 체크하자" +"\n" +
" \|dd\|cc\|ff\|\n" +
" \|\-\-\-\|\-\-\-\|\-\-\-\|\n" +
" \|aa\|s\|s\|" +"\n" +
"[링크다](https://youtube.com)" +"\n" +
"`var test = 'real test'`" +"\n" +
"```\n" +
"let test= = 'real test'\n" +
"```"
,
initialEditType:"wysiwyg",
// events : { // events : {
// change : this.onChange // change : this.onChange
// }, // },
hooks: { hooks: {
addImageBlobHook: (blob, callback) => { addImageBlobHook: (blob, callback) => {
// blob : Java Script 파일 객체
//console.log(blob);
const formData = new FormData(); const formData = new FormData();
formData.append('file', blob); formData.append('file', blob);
let url = '/files/'; let url = 'blog/post/images/';
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
enctype: 'multipart/form-data', enctype: 'multipart/form-data',
@ -50,17 +70,10 @@
cache: false, cache: false,
timeout: 600000, timeout: 600000,
success: function (data) { success: function (data) {
//console.log('ajax 이미지 업로드 성공');
url += data.fileName; url += data.fileName;
fileIds += data.id + ",";
// callback : 에디터(마크다운 편집기)에 표시할 텍스트, 뷰어에는 imageUrl 주소에 저장된 사진으로 나옴
// 형식 : ![대체 텍스트](주소)
callback(url, '사진 대체 텍스트 입력'); callback(url, '사진 대체 텍스트 입력');
}, },
error: function (e) { error: function (e) {
//console.log('ajax 이미지 업로드 실패');
//console.log(e.abort([statusText]));
callback('image_load_fail', '사진 대체 텍스트 입력'); callback('image_load_fail', '사진 대체 텍스트 입력');
} }
}); });
@ -68,6 +81,9 @@
} }
}); });
} }
function save() {
console.log(editor.getMarkdown())
}
</script> </script>
<link th:href="@{/css/common.css}" rel="stylesheet" /> <link th:href="@{/css/common.css}" rel="stylesheet" />
<script type="text/javascript" th:src="@{/js/common.js}"></script> <script type="text/javascript" th:src="@{/js/common.js}"></script>
@ -75,12 +91,17 @@
</th:block> </th:block>
<body onload="onLoaded()"> <body onload="onLoaded()">
<th:block layout:fragment="header" th:include="@{/fragments/header}"></th:block> <th:block layout:fragment="header" th:include="@{/fragments/header}"></th:block>
<div layout:fragment='content' class='content' id='content'> <div layout:fragment='content' class='content' id='content' style="padding: 10px">
<div id="editor"> <input id="title_layer" style="width:100%; height:50px; font-size:30px; border-width: 1px; align-content: center; margin: 10px"/>
<div id="editor" style="width:90%; font-size:15px; border-width: 0px; align-content: center"></div>
</div> <div id="hashtag_layer">
<select style="width:40%; height:30px; font-size:15px; border-width: 0px"> </select>
<input id="hashtag" style="width:40%; height:30px; font-size:15px; border-width: 0px"/>
</div> </div>
<div id="controll_layer" style="width: 100%">
<button onclick="save()">asdsad</button>
</div>
</div>
<th:block layout:fragment="footer" th:include="@{/fragments/footer}"></th:block> <th:block layout:fragment="footer" th:include="@{/fragments/footer}"></th:block>
</body> </body>
</html> </html>