728x90
https://summernote.org/deep-dive/
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
Pom.xml
<!-- 대용량 파일 처리 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<!-- gson java인스턴스를 JSN타입의 문자열로 변환해야하는 일 -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2.1</version>
</dependency>
application.xml ( 업로드 크기 제한 )
<!-- 스프링에서 기본으로 제공하는 multipartResolver는 CommonsMultipartResolver 이므로,
순수한 multipartResolver를 사용하기 위해 빈 이름으로 "multipartResolver"를 등록해야함 +
프로퍼티를 이용 최대 가능한 업로드 사이즈 지정함 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="100000000"></property>
</bean>
JSP
<!-- 서머노트 CDN -->
<link href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote.min.js"></script>
<script src=" https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.18/lang/summernote-ko-KR.min.js"></script>
<form id="articleForm">
<h3 style="margin-bottom: 25px;"></h3>
<div class="form-group">
<input type="text" class="form-control" name="title" id="title" placeholder="제목" maxlength="30" required>
</div>
<div class="form-group">
<div id="test_cnt">( 0 / 1000 )</div>
<textarea class="form-control" name="content" id="summernote"></textarea>
</div>
</form>
<button class="btn btn-primary pull-right" onclick="boardWrite()">저장</button>
<script>
$("#summernote").summernote({
// 에디터 높이
height: 600,
placeholder:"1000자 까지 가능",
// 에디터 한글 설정
lang: "ko-KR",
// 에디터에 커서 이동 (input창의 autofocus라고 생각하시면 됩니다.)
focus : true,
toolbar: [
// 글꼴 설정
['fontname', ['fontname']],
// 글자 크기 설정
['fontsize', ['fontsize']],
// 굵기, 기울임꼴, 밑줄,취소 선, 서식지우기
['style', ['bold', 'italic', 'underline','strikethrough', 'clear']],
// 글자색
['color', ['forecolor','color']],
// 표만들기
['table', ['table']],
// 글머리 기호, 번호매기기, 문단정렬
['para', ['ul', 'ol', 'paragraph']],
// 줄간격
['height', ['height']],
// 그림첨부, 링크만들기, 동영상첨부
['insert',['picture','link','video']]
// 코드보기, 확대해서보기, 도움말
//['view', ['codeview','fullscreen', 'help']]
],
callbacks : {
onImageUpload : function(files, editor, welEditable) { // 파일 업로드(다중업로드를 위해 반복문 사용)
for (var i = files.length - 1; i >= 0; i--) {
uploadSummernoteImageFile(files[i], this);
}
},
onChange:function(contents, $editable){ //텍스트 글자수 및 이미지등록개수
setContentsLength(contents, 0);
}
},
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']
});
</script>
JSP include JS
// 서머노트 파일 업로드
function uploadSummernoteImageFile(file, el) {
let data = new FormData();
data.append("file", file);
$.ajax({
data : data,
type : "POST",
url : "/board/uploadSummernoteImageFile",
contentType : false,
enctype : 'multipart/form-data',
processData : false,
success : function(data) {
if(data.responseCode == "success") {
setTimeout(function () {
$(el).summernote('insertImage', data.url, function ($image) {
$image.css('width', "20%");
});
}, 2000);
}else if(data.responseCode == "extension"){
showModal("alertModal","gif,jpg,png만 가능합니다.");
return false;
}else{
showModal("alertModal","파일 업로드에 실패 하였습니다.");
return false;
}
}
});
}
//글자수 체크 //태그와 줄바꿈, 공백을 제거하고 텍스트 글자수만 가져옵니다.
function setContentsLength(str, index) {
var textCnt = 0; //총 글자수
var maxCnt = 1000; //최대 글자수
var editorText = f_SkipTags_html(str); //에디터에서 태그를 삭제하고 내용만 가져오기
//editorText = editorText.replace(/\s/gi,""); //줄바꿈 제거
//editorText = editorText.replace(/ /gi, ""); //공백제거
textCnt = editorText.length;
if(maxCnt > 0) {
if(textCnt > maxCnt) {
$('#summernote').summernote('code', str.slice(0 , -1 ));
return false;
}else{
$("#test_cnt").html( "( "+ textCnt + " / " + maxCnt + " )");
}
}
}
//에디터 내용 텍스트 제거
function f_SkipTags_html(input, allowed) { // 허용할 태그는 다음과 같이 소문자로 넘겨받습니다. (<a><b><c>)
allowed = (((allowed || "") + "").toLowerCase().match(/<[a-z][a-z0-9]*>/g) || []).join('');
var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi,
commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;
return input.replace(commentsAndPhpTags, '').replace(tags, function ($0, $1) {
return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
});
}
// 글저장하기
function boardWrite(){
if($("#title").val() == ""){
showModal("alertModal","제목을 입력하세요");
return false;
}
if ($('#summernote').summernote('isEmpty')) {
showModal("alertModal","내용을 입력하세요");
return false;
}
var formData = $("#articleForm").serialize();
$.ajax({
type: "POST",
enctype: 'multipart/form-data',
processData: false,
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
url: "/board/insertBoard",
data: formData,
dataType: "json",
async : false,
success : function(data) {
alert(data);
}
});
}
Controller
/** 게시판 - 자유게시판 쓰기 :: 서머노트 이미지 파일 저장 */
@RequestMapping(value="/uploadSummernoteImageFile", produces = "application/json; charset=utf8")
@ResponseBody
public String uploadSummernoteImageFile( @RequestParam("file") MultipartFile multipartFile, HttpServletRequest request ) {
JsonObject jsonObject = new JsonObject();
/* String fileRoot = "C:\\summernote_image\\"; // 외부경로로 저장을 희망할때. */
String fileRoot = request.getServletContext().getRealPath("resources/images/board/"); // 내부경로로 저장
String originalFileName = multipartFile.getOriginalFilename(); //오리지널 파일명
String extension = originalFileName.substring(originalFileName.lastIndexOf(".")); //파일 확장자
final String[] ALLOW_EXTENSION = {".gif",".GIF", ".jpg",".JPG",".png",".PNG",".jepg",".JEPG"}; //확장자 검사
if(!Arrays.asList(ALLOW_EXTENSION).contains(extension)){
jsonObject.addProperty("responseCode", "extension");
String a = jsonObject.toString();
return a;
}
String savedFileName = UUID.randomUUID() + extension; // 파일 이름이 한글로 들어왔을 때 그걸 다시 영어와 숫자로 이루어진 문자열로 만들기 위해서 쓰는 것 : UUTID이다
File targetFile = new File(fileRoot + savedFileName);
try {
InputStream fileStream = multipartFile.getInputStream();
FileUtils.copyInputStreamToFile(fileStream, targetFile);
// 파일 저장
jsonObject.addProperty("url", "/resources/images/board/"+ savedFileName); // contextroot + resources + 저장할 내부 폴더명
jsonObject.addProperty("responseCode", "success");
} catch (IOException e) {
FileUtils.deleteQuietly(targetFile); //저장된 파일 삭제
jsonObject.addProperty("responseCode", "error");
e.printStackTrace();
}
String a = jsonObject.toString();
return a;
}
/** 게시판 - 자유게시판 쓰기 :: 글 저장하기 */
@ResponseBody
@PostMapping("/insertBoard")
public String insertBoard( HttpSession session, @ModelAttribute("boardVo") BoardDTO boardDTO){
String user_id = (String)session.getAttribute("user_id");
String user_nm = (String)session.getAttribute("user_nm");
boardDTO.setWriter(user_nm);
boardDTO.setWriter_id(user_id);
int idx = boardService.insertBoard(boardDTO);
if(idx > 0){ return "success"; }
else{ return "fail"; }
}
728x90