๐ ํ๊ฒฝ
Spring Tool Suite 3 (STS3)
์คํ๋ง ๋ ๊ฑฐ์ ํ๋ก์ ํธ
๐ ํ๋ฆ
1. summernote api๋ฅผ ์ถ๊ฐํ๋ค.
1-1. ๋ถํธ์คํธ๋ฉ๊ณผ ์ถฉ๋์ด ์ผ์ด๋ ์ ์์ผ๋ฏ๋ก ๋ถํธ์คํธ๋ฉ์ ์ฌ์ฉํ์ง ์๋ summernote lite๋ฅผ ์ฌ์ฉํ๋ค.
2. ํ์ผ ์ ๋ก๋๋ฅผ ์ํด `pom.xml`์ `gson` `common-io` `commons-fileupload` ์์กด์ฑ์ ์ถ๊ฐํ๋ค.
3. `textarea` id๋ฅผ summernote๋ก ์์ฑํ๋ฉด summernote ์๋ํฐ๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
์ด๋จธ ๋ฏธ์น ํ๊ทธ๊ฐ ๋์ํด๋ฒ๋ฆผ
`<textarea id="summernote"></textarea>`
4. ๋ด๊ฐ ์ํ๋ ์์น์ ์ด๋ฏธ์ง๋ฅผ ์ ๋ก๋ํ๊ธฐ ์ํด ์๋ํฐ์ summernote์์ ์ ๊ณตํ๋ callbakcs ํจ์๋ฅผ ์ฌ์ฉํ๋ค.
5. ajax๋ก Controller ๋ฉ์๋๋ฅผ ํธ์ถํด ํ์ผ์ ์ ๋ก๋ํ๋ค. ์ด๋ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ๊ตฌํํ ์ ์๋ค.
๐ ๊ตฌํ
1. summernote api๋ฅผ ์ถ๊ฐํ๋ค.
1-1. summernote๋ ํ๊ทธ ์์ฒด๋ฅผ ๋ชฝ๋ ์ ์ฅํ๋ ์๋ํฐ๋ก ์ฝ์ด์ฌ ๋ ํ์ด์ง์์ ์ฌ์ฉํ๋ ๋ถํธ์คํธ๋ฉ๊ณผ ์ถฉ๋์ด ์ผ์ด๋ ์ ์์ผ๋ฏ๋ก ๋ถํธ์คํธ๋ฉ์ ์ฌ์ฉํ์ง ์๋ summernote lite๋ฅผ ์ฌ์ฉํ๋ค.
Summernote - Super Simple WYSIWYG editor
Super Simple WYSIWYG Editor on Bootstrap Summernote is a JavaScript library that helps you create WYSIWYG editors online.
summernote.org
Getting Started๋ฅผ ๋๋ฅด๋ฉด ๋ค์ด๋ก๋ํ ์ ์๋ค.
`summernote-lite.css`
`summetnote-lite.js`
`lang` ํด๋ ๋ด `summetnote-ko-KR.js`
`font` ํด๋ ์ ์ฒด
์๋ ๊ฒ ๋ค๊ฐ์ง๋ง ์ฌ์ฉํ ๊ฑฐ๋ค!
`resources`์ ๋ฃ์ด์ฃผ๊ณ ์ฌ์ฉํ ํ์ด์ง์์ script ํ๊ทธ๋ฅผ ์ถ๊ฐํด์ค๋ค.
`css`๋ ํค๋์, `script`๋ `</body>` ํ๊ทธ ๋ฐ๋ก ์์ ๋ฃ์ด์ค๋น
<!-- summernote -->
<link rel="stylesheet" href="${contextPath }/resources/summernote/summernote-lite.css">
.
.
.
<!-- summernote -->
<script src="${contextPath }/resources/summernote/summernote-lite.js"></script>
<script src="${contextPath }/resources/summernote/lang/summernote-ko-KR.js"></script>
2. ํ์ผ ์ ๋ก๋๋ฅผ ์ํด `pom.xml`์ `gson` `common-io` `commons-fileupload` ์์กด์ฑ์ ์ถ๊ฐํ๋ค.
<!-- ํ์ผ ์
๋ก๋ -->
<!-- json : gson -->
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.9</version>
</dependency>
<!-- fileutils -->
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<!-- commons-fileupload -->
<!-- multipart๋ฑ์ ์ฌ์ฉํ ์ ์์ -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
3. `textarea` id๋ฅผ summernote๋ก ์์ฑํ๋ฉด summernote ์๋ํฐ๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
<form method="post" action="${contextPath }/insert">
<input class="form-control" placeholder="์ ๋ชฉ" style="width:100%" name="title" required/>
<textarea id="summernote" name="content" required></textarea>
<button class="btn btn-primary">์์ฑ</button>
</form>
4. ๋ด๊ฐ ์ํ๋ ์์น์ ์ด๋ฏธ์ง๋ฅผ ์ ๋ก๋ํ๊ธฐ ์ํด ์๋ํฐ์ summernote์์ ์ ๊ณตํ๋ callbacks ํจ์๋ฅผ ์ฌ์ฉํ๋ค.
5. ajax๋ก Controller ๋ฉ์๋๋ฅผ ํธ์ถํด ํ์ผ์ ์ ๋ก๋ํ๋ค. ์ด๋ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ๊ตฌํํ ์ ์๋ค.
onImageUpload๋ ์๋ํฐ์ ์ด๋ฏธ์ง๊ฐ ์ ๋ก๋๋๋ฉด ์คํ๋๋ค.
ajax์ insertImage๋ ์๋ํฐ์ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ด๋ฏธ์ง๋ฅผ ๋ถ์ฌ์ฃผ๋ ํจ์.
$(document).ready(function() {
// summernote ์๋ํฐ ์ค์
$('#summernote').summernote({
height: 300,
minHeight: null,
maxHeight: null,
focus: true,
lang: "ko-KR",
placeholder: '๋ด์ฉ์ ์
๋ ฅํ์ธ์.',
// ์๋ํฐ ๋ฆฌ์ฌ์ด์ฆ ๊ธ์ง
disableResizeEditor : true,
// ์ฝ๋ฐฑ ํจ์
// omImageUpload ์ด๋ฏธ์ง๊ฐ ์
๋ก๋ ๋์์ ๋ ์คํ๋๋ ํจ์
callbacks : {
onImageUpload: function (files, editor, welEditable){
// ์ฌ๋ฌ๊ฐ์ ์ด๋ฏธ์ง ์
๋ก๋
for (var i = files.length - 1; i >= 0; i--) {
var fileName = files[i].name
uploadSummernoteImageFile(files[i], this, fileName)
}// for
}// onImageUpload
}// callbacks
}); // summernote
}
// ์ด๋ฏธ์ง ์
๋ก๋ ajax
function uploadSummernoteImageFile(file, el, caption) {
data = new FormData()
data.append('file', file)
$.ajax({
data: data,
type: 'POST',
url: 'uploadSummernoteImageFile',
contentType: false,
enctype: 'multipart/form-data',
processData: false,
dataType : 'json',
success: function (data) {
console.log(data);
console.log(data.url);
console.log(data.responseCode);
$("#summernote").summernote(
'insertImage', data.url
);
},
})
}
`UploadController.java`
// summernote ์ด๋ฏธ์ง ์
๋ก๋
@PostMapping("/uploadSummernoteImageFile")
@ResponseBody
public String uploadSummernoteImageFile(@RequestParam("file")MultipartFile multipartFile, HttpServletRequest request){
// json ๊ฐ์ฒด ์ป๊ธฐ
// JSONObject์ ๋ค๋ฅธ ํด๋์ค์
// JSONObject == org.json.simple
// JsonObject == com.google.json
JsonObject jsonObject = new JsonObject();
// ์ ์ฅ ๊ฒฝ๋ก ์ค์ (์ ๋๊ฒฝ๋ก)
String uploadPath = request.getSession().getServletContext().getRealPath("resources");
String fileRoot = uploadPath + "/images";
// ์
๋ก๋ ํ์ผ ์๋ณธ ์ด๋ฆ, ํ์ฅ์ ์ถ์ถ
String originalFileName = multipartFile.getOriginalFilename();
String extension = originalFileName.substring(originalFileName.lastIndexOf("."));
// ์๋ก์ด ํ์ผ๋ช
์์ฑ(์ค๋ณต ๋ฐฉ์ง) ๋๋ค UUID
// ํ์ผ๋ช
์ ํ๊ธ์ด ๋ค์ด๊ฐ๋ฉด ์ค๋ฅ, ๊ฐ์ ์ด๋ฆ์ ๋ค๋ฅธ ํ์ผ์ด ๋ค์ด์์ ๊ฒฝ์ฐ ๋ฎ์ด์จ์ง๋ ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํจ
String saveFileName = UUID.randomUUID() + "";
File targetFile = new File(fileRoot + saveFileName);
try {
// ์
๋ก๋ ํ์ผ์ inputstream ์ป๊ธฐ
InputStream fileStream = multipartFile.getInputStream();
// ํ์ผ์ ์ง์ ๋ ๊ฒฝ๋ก(uploadPath)์ ์ ์ฅ
FileUtils.copyInputStreamToFile(fileStream, targetFile);
// Json ๊ฐ์ฒด์ ์ด๋ฏธ์ง url๊ณผ ์๋ต ์ฝ๋ ์ถ๊ฐ
// ํ๋ก์ ํธ resources์ ๋ฃ์์ผ๋๊น ํด๋น ๊ฒฝ๋ก๋ฅผ ๋ถ๋ฌ์ด
// {"url" : ํ๋ก์ ํธ๋ช
/resources/images/ํ์ผ๋ช
}
jsonObject.addProperty("url", "/ํ๋ก์ ํธ๋ช
/resources/images/" + saveFileName);
jsonObject.addProperty("responseCode", "success");
} catch (IOException e) {
// ํ์ผ ์ ์ฅ ์ค ์ค๋ฅ ๋ฐ์ํ๋ฉด ํด๋น ํ์ผ ์ญ์ , ์๋ฌ ์ฝ๋ ์ถ๊ฐ
FileUtils.deleteQuietly(targetFile);
jsonObject.addProperty("responseCode", "error");
e.printStackTrace();
}
return jsonObject.toString();
}
request.getSession().getServletContext().getRealPath("resources");
์ ๋ ๊ฒฝ๋ก๋ฅผ ๋ถ๋ฌ์จ๋ค. ํ๋ก์ ํธ์์ ํ์ธํ ์ ์๊ณ `.metadata`์ ๋ค์ด๊ฐ.
๋งฅ์์๋ command + shift + . ์ผ๋ก ์จ๊ฒจ์ง ํด๋๋ฅผ ๋ณผ ์ ์๋ค.
์คํํ์ ๋ ๊ฐ๋ฐ์ ๋๊ตฌ ์ฝ์์ ์๋ ๊ฒ ๋จ๋ฉด ์ฑ๊ณต
@PostMapping("insert")
public String noticeInsert(HttpSession session, Board board) {
Member member = (Member)session.getAttribute("member");
board.setId(member.getId());
board.setNickname(member.getNickname());
int result = boardService.insert(board);
return "redirect:/listAll";
}
์ด๊ฑด form ์ก์ ๋๋ฉด ์คํ๋๋ ํจ์(๊ธ ์์ฑ ํจ์)
form ํ๊ทธ์์ input์ ์์ฑํ๋ name์ผ๋ก getter๊ฐ ๋์ํ๋ฉด์ ๊ฐ์ฒด๋ฅผ ๋งคํํด์ฃผ๊ธฐ ๋๋ฌธ์ ํ๋ผ๋ฏธํฐ๋ฅผ `Board`๋ก ๋ฐ์์ฌ ์ ์์.
๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ์ ๊ตฌํ๋๋ ๊ฒ์ ๋ณผ ์ ์๋น
๐ ์ฐธ๊ณ
[์ธ๋จธ๋ ธํธ] ์ธ๋จธ๋ ธํธ ์๋ํฐ์ ์ ๋ก๋ํ ์ด๋ฏธ์ง๋ฅผ ์ํ๋ ๋ด๋ถ ๊ฒฝ๋ก์ ์ ์ฅํ๊ณ ๊ฒฝ๋ก๊ฐ์ DB์
ํด๋น ๊ฒ์๋ฌผ์ ๋ณธ์ธ์ ์ดํด๋ฅผ ๋ฐํ์ผ๋ก ์์ฑ๋์์ผ๋ฏ๋ก ํ๋ฆฐ ๋ถ๋ถ์ด ์์ ์ ์์ต๋๋ค. ๋๊ธ๋ก ์๋ ค์ฃผ์ ๋ค๋ฉด ๊ฐ์ฌํ๊ฒ ์ต๋๋ค! ---------------------------------------------------- Spring์ด๋ summernote๋ ์ ํ
mabb.tistory.com
Summernote ์ฌ์ฉ๋ฒ , ์ธ๋จธ๋ ธํธ ์ฌ์ฉ๋ฒ - ์ฝ์ง์ค์ธ ๊ฐ๋ฐ์
- ์ธ๋จธ๋ ธํธ์ฌ์ฉ๋ฒ ์ ๋ฆฌ - ํํ์ด์ง์์ ๊ธ์ ์ฐ๋ ๋ถ๋ถ์ ์ผ๋ฐ ํ ์คํธ ํํ์ ๊ธ ์ฐ๊ธฐ๋ง ์ง์ํ๋ค๋ฉด ์ฌ์ฉ์๊ฐ ์ฌ์ฉํ๊ธฐ ๋ถํธํ๋ค. ์ด๋ฌํ ์ ๋๋ฌธ์ ๋๋ถ๋ถ์ ํํ์ด์ง์์๋ ์น์๋ํฐ๋ฅผ ์ง์
programmer93.tistory.com
Summernote[์ธ๋จธ๋ ธํธ] (1) : ์น ์๋ํฐ ๊ธฐ๋ณธ ์ค์ ๊ณผ ์ฌ์ฉ ๋ฐฉ๋ฒ Blog(6)
์ธ๋จธ๋ ธํธ[Summernote] ํด๋ฐ ๊ตฌ์ฑ์์์ ์์ฑ ์ค์ ๋ฐฉ๋ฒ ๊ทธ๋ฆฌ๊ณ ์ถํ ์์ ์ด๋ฏธ์ง ์ ๋ก๋์ ๋ํ ์๊ณ ๋ด์ฉ์ด ๋ด๊ฒจ ์์ต๋๋ค.
sirobako.co.kr
'Java > Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[SpringBoot/JPA] Spring Data JPA๋ฅผ ์ฌ์ฉํ ๊ฒ์ํ CRUD (0) | 2024.03.12 |
---|---|
[SpringBoot] Querydsl ์ค์ ์ ์ค๋ฅ (0) | 2024.03.11 |
[Spring] ์คํ๋ง์ ์ ์ (3) - Spring MVC (0) | 2024.01.01 |
[Spring] ์คํ๋ง์ ์ ์ (2) - ์์ฒญ๊ณผ ์๋ต (0) | 2023.12.31 |
[Spring] ์คํ๋ง์ ์ ์ (1) ์ด๊ธฐ ์ค์ (0) | 2023.12.30 |