Summernote Editor 다운로드 주소
https://summernote.org/#google_vignette
화살표를 클릭하거나
해당 메뉴에 들어가서 다운로드하면 된다
폴더 경로
현재 Bootstrap을 적용 중이라
' /resources/static/bootstrap/js/summernote ' 위치에 파일을 넣었는데
' /resources/static/ ' 경로 안에만 넣으면 된다
html
<div class="form-group">
// Summernote 적용시킬 textarea 태그
<textarea class="form-control" id="summernote" name="content" type="text"></textarea>
</div>
<!-- thymeleaf 용 -->
<!-- summernote -->
<script th:src="@{/bootstrap/js/summernote/summernote-lite.js}"></script>
<script th:src="@{/bootstrap/js/summernote/lang/summernote-ko-KR.js}"></script>
<link rel="stylesheet" th:href="@{/bootstrap/js/summernote/summernote-lite.css}">
<!-- thymeleaf 해제 -->
<!-- summernote -->
<script src="/bootstrap/js/summernote/summernote-lite.js"></script>
<script src="/bootstrap/js/summernote/lang/summernote-ko-KR.js"></script>
<link rel="stylesheet" href="/bootstrap/js/summernote/summernote-lite.css">
javascript
// 이미지 업로드
function imageUpload(file){
let formData = new FormData();
formData.append("file", file);
$.ajax({
url : "/upload/imageUpload",
type : "POST",
data : formData,
// contentType, processData 설정 안하면 TypeError: Illegal invocation 오류가 발생한다
contentType: false,
processData: false,
encType : "multipart/form-data",
success : function (data) {
// 글에 이미지 넣을때 크기 설정
// $("#summernote").summernote("insertImage", "/uploadPath/image/"+data, function (data){
// data.css("width" , "100%");
// });
// 글에 이미지 넣기
$("#summernote").summernote("insertImage", "/uploadPath/image/"+data);
},
error(e){
console.log("error : "+ e);
}
});
}
// 이미지 삭제
function deleteFile(fileName) {
let formData = new FormData();
formData.append("file", fileName);
$.ajax({
url : "/upload/imageDelete",
type : "POST",
data : formData,
// contentType, processData 설정 안하면 TypeError: Illegal invocation 오류가 발생한다
contentType: false,
processData: false,
encType : "multipart/form-data"
});
}
$(document).ready(function (){
// textarea summernote 적용하기
$("#summernote").summernote({
codeviewFilter: false, // 코드 보기 필터 비활성화
codeviewIframeFilter: false, // 코드 보기 iframe 필터 비활성화
height: 400, // 에디터 높이
minHeight: null, // 최소 높이
maxHeight: null, // 최대 높이
lang: "ko-KR", // 에디터 한글 설정
focus : true, // 에디터 포커스 설정
toolbar: [
['fontname', ['fontname']], // 글꼴 설정
['fontsize', ['fontsize']], // 글자 크기
['style', ['bold', 'italic', 'underline','strikethrough', 'clear']], // 글자 스타일 설정
['color', ['forecolor','color']], // 글자색
['table', ['table']], // 표 생성
['insert', ['picture', 'link','video']], // 이미지, 링크 , 동영상
['para', ['ul', 'ol', 'paragraph']], // 문단 스타일 설정
['height', ['height']], // 줄간격
['view', ['codeview','fullscreen', 'help']] // 코드보기, 전체화면, 도움말
],
fontNames: ['Arial', 'Arial Black', 'Comic Sans MS', 'Courier New','맑은 고딕','궁서','굴림체','굴림','돋음체','바탕체'], // 추가한 글꼴
fontSizes: ['8','9','10','11','12','14','16','18','20','22','24','28','30','36','50','72'], // 추가한 폰트사이즈
callbacks : {
// 파일 업로드
onImageUpload : function (files) {
for(let i=0; i < files.length; i++){
// 이미지가 여러개일 경우
imageUpload(files[i]);
}
},
// 파일 삭제
onMediaDelete: function ($target){
if(confirm("이미지를 삭제하시겠습니까?")){
let fileName = $target.attr('src').split('/').pop();
deleteFile(fileName);
}
}
}
});
});
Controller
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;
@RestController
@Tag(name="Swagger upload", description = "upload")
@RequestMapping("/upload/*")
public class ImageUpload {
// 파일 업로드 경로
final Path FILE_ROOT = Paths.get("./").toAbsolutePath().normalize();
private String uploadPath = FILE_ROOT.toString() + "/upload/image/";
@Operation(summary = "이미지 업로드 ", description = "이미지를 서버에 업로드한다.")
@PostMapping("/imageUpload")
public ResponseEntity<?> imageUpload(@RequestParam MultipartFile file) throws Exception{
System.err.println("이미지 업로드");
try {
// 업로드 파일의 이름
String originalFileName = file.getOriginalFilename();
// 업로드 파일의 확장자
String fileExtension = originalFileName.substring(originalFileName.lastIndexOf("."));
// 업로드 된 파일이 중복될 수 있어서 파일 이름 재설정
String reFileName = UUID.randomUUID().toString() + fileExtension;
// 업로드 경로에 파일명을 변경하여 저장
file.transferTo(new File(uploadPath, reFileName));
// 파일이름을 재전송
return ResponseEntity.ok(reFileName);
}catch (Exception e) {
e.printStackTrace();
return ResponseEntity.badRequest().body("업로드 에러");
}
}
@Operation(summary = "이미지 삭제 ", description = "서버에 저장된 이미지를 삭제한다.")
@PostMapping("/imageDelete")
public void imageDelete(@RequestParam String file) throws Exception{
System.err.println("이미지 삭제");
try {
Path path = Paths.get(uploadPath, file);
Files.delete(path);
}catch (Exception e) {
e.printStackTrace();
}
}
}
파일 업로드 경로 설정에 관한 건 여기를 참고하길 바란다
https://greed-yb.tistory.com/253
application.properties
# file upload
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB
파일 업로드 용량 설정
TEST
또는
파일 드랍이 가능하다
1. 이미지 업로드
2. 이미지 삭제
3. 서버로 데이터 전송
{title='이것은 제목!!', content='<p>첫줄은 글</p><p><img src="/uploadPath/image/d4eea150-a37f-4f50-a9a3-e9e57afeef23.png" style="font-size: 1rem; width: 142px;"></p><p>장마로 인해서 너무 습해!</p><p><img src="/uploadPath/image/4b0f2e9e-9338-4a9e-be33-b5bade5b8537.png" style="width: 144px;"></p><p>에어컨 때문에 추워!</p>'}
이미지는 업로드된 경로 주소로 들어가 있고
작성한 글도 다 확인이 되고 있다
(서버로 데이터 전송 코드는 올려두지 않았다)
처음에 CKEditor 로 설정을 잡다가 계속 오류가 나서
Summernote 를 처음 사용해 보았는데 매우 만족이었다
https://greed-yb.tistory.com/266
다음글 - 목록 및 상세보기
'개발 > Spring' 카테고리의 다른 글
[SpringBoot] Summernote Editor(게시판 글 수정하기) 적용하기 - 3 (0) | 2024.07.15 |
---|---|
[SpringBoot] Summernote Editor(게시판 글 상세보기) 적용하기 - 2 (0) | 2024.07.15 |
[SpringBoot] 로그인 시 아이디 기억하기(쿠키 적용) (1) | 2024.07.10 |
[SpringBoot] 카카오(다음) 주소 API 적용하기 (0) | 2024.07.09 |
[SpringBoot] Swagger 적용하기(SpringBoot 3.x.x 이상) (0) | 2024.07.05 |
댓글