JAVA/spring

ckeditor5 사용법

lavender1122 2024. 4. 26. 15:39

ckeditor5-build-classic-39.0.1.zip
1.85MB

 

파일 압축 풀기

ckeditor5 파일 이름 변경하기 ⇒ 위치 찾기 편리하게 하기 위해서 변경함

src>main>webapp>resources 위치에 ckeditor5 넣기

맨위에 코드 넣기

<link type="text/css" href="/resources/ckeditor5/sample/css/sample.css" rel="stylesheet" media="screen" />
<script type="text/javascript" src="/resources/js/jquery.min.js"></script>
<script type="text/javascript" src="/resources/ckeditor5/ckeditor.js"></script>

<div id> 태그 넣기

ckeditor5 적용되서 웹에서만 보임

 

<script type="text/javascript">
/*
ClassicEditor : ckeditor5.js에서 제공해주는 객체
uploadUrl : 이미지 업로드를 수행할 URL
window.editor-editor : editor 객체를 window.editor라고 부름
 */
ClassicEditor.create(document.querySelector('#ckMessage'),{ckfinder:{uploadUrl:'/image/upload?${_csrf.parameterName}=${_csrf.token}'}})
 .then(editor=>{window.editor=editor;})
 .catch(err=>{console.error(err.stack);});
 $(function(){
	 //ckeditor 내용 => textarea 로 복사
	 $(".ck-blurred").keydown(function(){
		 console.log("str : ", window.editor.getData());
		 $("#message").val(window.editor.getData());
	 })
	 $(".ck-blurred").on("focusout",function(){ //focusout되면   $("#message").val 값 복사
		 $("#message").val(window.editor.getData());
	 })
 })
</script>

editor 만드는 div 설정

ClassicEditor.create(document.querySelector('#ckMessage'),{ckfinder:{uploadUrl:'/image/upload?${_csrf.parameterName}=${_csrf.token}'}})
 .then(editor=>{window.editor=editor;})
 .catch(err=>{console.error(err.stack);});

ckeditor 내용 => textarea 로 복사

 $(".ck-blurred").keydown(function(){
		 console.log("str : ", window.editor.getData());
		 $("#message").val(window.editor.getData());
	 })

focusout 되면   $("#message").val 값 복사

$(".ck-blurred").on("focusout",function(){
		 $("#message").val(window.editor.getData());
	 })

파일업로드

/image/upload

ckeditor는 이미지 업로드 후 이미지 표시하기 위해 uploaded 와 url을 json 형식으로 받아야 함

시큐리티 적용시

uploadUrl:''/image/upload 에서

?${_csrf.parameterName}=${_csrf.token}'  붙여야 한다

ModelAndView 객체 생성

ModelAndView 사용하여 json 형시으로 보내기 위해 ModelAndView 생성자 매개변수로 "jsonView" 라고 써줌

ModelAndView mav = new ModelAndView("jsonView");

「jsonView 라고 쓴다고 무조건 json 형식으로 가는건 아니고 @Configuration 어노테이션을 단 
WebConfig 파일에 MappingJackson2JsonView 객체를 리턴하는 jsonView 매서드를 만들어서 bean으로 등록해야 함」

⇒@Controller 이용해서 @Configuration 굳이 사용할 필요가 없다


원본

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>
<link type="text/css" href="/resources/ckeditor5/sample/css/sample.css" rel="stylesheet" media="screen" />
<script type="text/javascript" src="/resources/js/jquery.min.js"></script>
<script type="text/javascript" src="/resources/ckeditor5/ckeditor.js"></script>
<section class="content">
	<!-- 
	   요청URI : /contUs/createPost
	   요청파라미터 : {name=개똥이,email=test@test.com,subject=궁금해요,message=궁금한게 궁금해요}
	   요청방식 : post
   -->
	<form id="frm" name="frm" action="/contUs/createPost?${_csrf.parameterName}=${_csrf.token}" method="post" enctype="multipart/form-data">
	<div class="card">
		<div class="card-body row">
			<div
				class="col-5 text-center d-flex align-items-center justify-content-center"
				id = "pImg">
			</div>
			<div class="col-7">
				<div class="form-group">
					<label for="name">Name</label> 
					<input type="text" maxlength="30" name="name"
						id="name" class="form-control" placeholder="작성자" required/>
				</div>
				<div class="form-group">
					<label for="email">E-Mail</label> 
					<input type="email" maxlength="50" name="email"
						id="email" class="form-control" placeholder="이메일" required />
				</div>
				<div class="form-group">
					<label for="subject">Subject</label> 
					<input type="text" name="subject"
						id="subject" class="form-control" placeholder="제목" required />
				</div>
				<div class="form-group">
					<label for="subject">file</label> 
					<input type="file" name="uploadFiles"
						id="uploadFiles" class="form-control" placeholder="파일"  multiple/>
				</div>
				<div class="form-group">
					<label for="message">Message</label>
					<div id="ckMessage"></div>
					<textarea id="message" name="message" class="form-control" rows="4" cols="30" 
					placeholder="문의글을 입력해주세요"></textarea>
				</div>
				<div class="form-group">
					<input type="reset" class="btn btn-secondary" value="초기화" />
					<input type="submit" id="btnSubmit" class="btn btn-primary"  value="문의하기" />
				</div>
			</div>
		</div>
	</div>
	<sec:csrfInput />
	</form>
</section>
<script type="text/javascript">
/*
ClassicEditor : ckeditor5.js에서 제공해주는 객체
uploadUrl : 이미지 업로드를 수행할 URL
window.editor-editor : editor 객체를 window.editor라고 부름
 */
ClassicEditor.create(document.querySelector('#ckMessage'),{ckfinder:{uploadUrl:'/image/upload?${_csrf.parameterName}=${_csrf.token}'}})
 .then(editor=>{window.editor=editor;})
 .catch(err=>{console.error(err.stack);});
 $(function(){
	 //ckeditor 내용 => textarea 로 복사
	 $(".ck-blurred").keydown(function(){
		 console.log("str : ", window.editor.getData());
		 $("#message").val(window.editor.getData());
	 })
	 $(".ck-blurred").on("focusout",function(){ //focusout되면   $("#message").val 값 복사
		 $("#message").val(window.editor.getData());
	 })
	 $("#uploadFiles").on("change",handleImg); //이미지 미리보기
	 $("#btnSubmit").on("click",function(){
		//일반데이터 
		 let name=$("#name").val();
		 let email=$("#email").val();
		 let subject=$("#subject").val();
		 let message=$("#message").val();
		 
		 let formData = new FormData();
						//"name",value
		 formData.append("name",name);//vo랑 같게 써야된다
		 formData.append("email",email);//vo랑 같게 써야된다
		 formData.append("subject",subject);//vo랑 같게 써야된다
		 formData.append("message",message);//vo랑 같게 써야된다
		 //폼데이터 
		 let fileObj =$("#uploadFiles");
		 console.log("fileObj: ",fileObj); //ok
		 //선택한 파일객체들
		 let files = fileObj[0].files;
		 console.log("files.lentgh: ",files.length);

		 for(let i =0;i<files.length;i++){
			formData.append("uploadFiles",files[i]);
			console.log(files[i]);//ok
		 }
// 		 $.ajax({
// 			url:"/contUs/createFormData",
// 			processData:false,
// 			contentType:false,
// 			data:formData,
// 			type:"post",
// 			dataType:"text",
// 			success:function(result){
// 				console.log("result:",result);
// 			}
// 		 })
	 })
 })
//e : onchange 이벤트
function handleImg(e){
   //<p id="pImg"></p> 영역에 이미지 미리보기를 해보자
   //이벤트가 발생 된 타겟 안에 들어있는 이미지 파일들을 가져와보자
   let files = e.target.files;
   //이미지가 여러개가 있을 수 있으므로 이미지들을 각각 분리해서 배열로 만듦
   let fileArr = Array.prototype.slice.call(files);
   //파일 타입의 배열 반복. f : 배열 안에 들어있는 각각의 이미지 파일 객체
   /*
   let arr = ["피자","떡볶이","탕수육"];
   //*******
   arr.forEach(function(str){
      console.log("str : " + str);
   });
   
   $.each(arr,function(idx,str){
      console.log("str[" + idx + "] : " + str);
   });
   */
   fileArr.forEach(function(f){
      //이미지 파일이 아닌 경우 이미지 미리보기 실패 처리(MIME타입)
      if(!f.type.match("image.*")){
         alert("이미지 확장자만 가능합니다.");
         //함수 종료
         return;
      }
      //이미지 객체를 읽을 자바스크립트의 reader 객체 생성
      let reader = new FileReader();
      
      $("#pImg").html("");
      
      //e : reader가 이미지 객체를 읽는 이벤트
      reader.onload = function(e){
         //e.target : f(이미지 객체)
         //e.target.result : reader가 이미지를 다 읽은 결과
         let img_html = "<img src=\"" + e.target.result + "\" style='width:50%;' />";
         //p 사이에 이미지가 렌더링되어 화면에 보임
         //객체.append : 누적, .html : 새로고침, .innerHTML : J/S
         $("#pImg").append(img_html);
      }
      //f : 이미지 파일 객체를 읽은 후 다음 이미지 파일(f)을 위해 초기화 함
      reader.readAsDataURL(f);
   });//end forEach
}
</script>

파일업로드 => java @controller에서 작성

@ResponseBody
	@PostMapping("/image/upload")
	public Map<String,Object> image(MultipartHttpServletRequest request) throws IllegalStateException, IOException{
		ModelAndView mav = new ModelAndView("jsonView");//json 형식으로 보내기위해 모델앤뷰 생성자 매개변수로 jsonView 라고 써줌
		// ckeditor 에서 파일을 보낼 때 upload : [파일] 형식으로 해서 넘어오기 때문에 upload라는 키의 밸류를 받아서
	    // uploadFile에 저장함
		MultipartFile uploadFile = request.getFile("upload");
		log.info("uploadFile:"+uploadFile);
		
		//파일명
		String originalFileName = uploadFile.getOriginalFilename();
		log.info("originalFileName: "+originalFileName);
		
		//originalFileName : 개똥이.jpg -> .jpg (확장자)
		String ext = originalFileName.substring(originalFileName.indexOf("."));//확장자.의 위치
		
		// 서버에 저장될 때 중복된 파일 이름인 경우를 방지하기 위해 UUID에 확장자를 붙여 새로운 파일 이름을 생성
		//asdfsdf.jpg
		String newFileName=UUID.randomUUID()+ext;
		
		File f = new File(uploadFolderDirect);
		if(f.exists()==false) {
			f.mkdirs();
		}
		
		
		//저장 경로로 파일 객체를 저장하겠다라는 계획
		// \\업로드 경로\\asdffasdf.jsp
		File file = new File(uploadFolderDirect,newFileName);
		
		//파일복사
		uploadFile.transferTo(file);//복사
		// 브라우저에서 이미지 불러올 때 절대 경로로 불러오면 보안의 위험 있어 상대경로를 쓰거나 이미지 불러오는 jsp 또는 클래스 파일을 만들어
	    // 가져오는 식으로 우회해야 함
	    // 때문에 savePath와 별개로 상대 경로인 uploadPath 만들어줌
		String uploadPath ="/resources/upload/"+newFileName;
		
		// uploaded, url 값을 modelandview를 통해 보냄
//      mav.addObject("uploaded", true); // 업로드 완료
//      mav.addObject("url", uploadPath); // 업로드 파일의 경로
		Map<String,Object> map = new HashMap<String,Object>();
		map.put("uploaded", true);
		map.put("url", uploadPath);
		
		log.info("map:"+map);
		
		return map;
	}