기존 JAVA/JSP 버전을 이용하여 네이버 스마트에디터를 연동법을 소개했었다
이번에는 기존 포스팅 코드를 응용하여 spring 으로 포스팅을 해보도록 하겠다
처음부터 끝까지 상세하게 설명은 하지 않도록 하겠음
기존에 포스팅한 내용을 응용하였기 때문임
우선 스프링 기반의 에디터 구조는 다음과 같다
에디터에 들어있는 파일들은 리소스 파일이므로 /resources/editor 폴더내에 스마트에디터 관련 파일들을 붙여놓았다
스프링의 리소스 연동은 위 포스팅을 참고하도록 하자
다음으로 기본적인 에디터 연동에 대한 포스팅은
해당 포스팅을 참고하도록 하자
물론 include하는 경로는 설정해놓은 path를 적용하도록 하자
본인의 에디터 경로는 다음과 같다
spring 연동시 필수록 있어야 할 pom.xml의 dependency 및 xml 설정
pom.xml 필요 라이브러리
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency>
mvc-config.xml 파일관련 및 리소스 적용 설정
<mvc:resources mapping="/resources/**" location="/resources/" /> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />
/resources/editor/photo_uploader/popup/attach_photo.js 설정
○ callFileUploader 함수 - IE 이하 HTML5 지원 불가 버전을 위한 일반 파일업로드시
필요한 부분 변경
sUrl - 업로드 처리를 해줄 CONTROLLER URL 적용
sCallback - callback.html의 경로 지정
본인의 경우 다음처럼 적용했음
oFileUploader = new jindo.FileUploader(jindo.$("uploadInputBox"),{ sUrl : '/file_uploader', //샘플 켠트롤러입니다. sCallback : '/resources/editor/photo_uploader/popup/callback.html', //업로드 이후에 iframe이 redirect될 콜백페이지의 주소 sFiletype : "*.jpg;*.png;*.bmp;*.gif", //허용할 파일의 형식. ex) "*", "*.*", "*.jpg", 구분자(;) sMsgNotAllowedExt : 'JPG, GIF, PNG, BMP 확장자만 가능합니다', //허용할 파일의 형식이 아닌경우에 띄워주는 경고창의 문구 bAutoUpload : false, //파일이 선택됨과 동시에 자동으로 업로드를 수행할지 여부 (upload 메소드 수행) bAutoReset : true // 업로드한 직후에 파일폼을 리셋 시킬지 여부 (reset 메소드 수행) })
○ html5Upload 함수 URL 변경 - 드래그앤드롭으로 파일첨부가 가능한 함수이다
sUploadURL변수에 본인이 정한 다중파일업로드 처리 컨트롤러 URL을 정의한다
sUploadURL= '/file_uploader_html5'; //upload URL
본인은 위와같이 정해주었다
컨트롤러 + VO에 대한 구조는 다음과 같이 잡아주었으며 각 클래스의 코드는 다음과 같다
/model/Editor.java
public class Editor { private MultipartFile Filedata; public MultipartFile getFiledata() { return Filedata; } public void setFiledata(MultipartFile filedata) { Filedata = filedata; } }
/controller/EditorController.java
○ 일반 파일업로드의 컨트롤러 - /file_uploader
@RequestMapping("/file_uploader") public String file_uploader(HttpServletRequest request, HttpServletResponse response, Editor editor){ String return1=request.getParameter("callback"); String return2="?callback_func=" + request.getParameter("callback_func"); String return3=""; String name = ""; try { if(editor.getFiledata() != null && editor.getFiledata().getOriginalFilename() != null && !editor.getFiledata().getOriginalFilename().equals("")) { // 기존 상단 코드를 막고 하단코드를 이용 name = editor.getFiledata().getOriginalFilename().substring(editor.getFiledata().getOriginalFilename().lastIndexOf(File.separator)+1); String filename_ext = name.substring(name.lastIndexOf(".")+1); filename_ext = filename_ext.toLowerCase(); String[] allow_file = {"jpg","png","bmp","gif"}; int cnt = 0; for(int i=0; i<allow_file.length; i++) { if(filename_ext.equals(allow_file[i])){ cnt++; } } if(cnt == 0) { return3 = "&errstr="+name; } else { //파일 기본경로 String dftFilePath = request.getSession().getServletContext().getRealPath("/"); //파일 기본경로 _ 상세경로 String filePath = dftFilePath + "resources"+ File.separator + "editor" + File.separator +"upload" + File.separator; File file = new File(filePath); if(!file.exists()) { file.mkdirs(); } String realFileNm = ""; SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss"); String today= formatter.format(new java.util.Date()); realFileNm = today+UUID.randomUUID().toString() + name.substring(name.lastIndexOf(".")); String rlFileNm = filePath + realFileNm; ///////////////// 서버에 파일쓰기 ///////////////// editor.getFiledata().transferTo(new File(rlFileNm)); ///////////////// 서버에 파일쓰기 ///////////////// return3 += "&bNewLine=true"; return3 += "&sFileName="+ name; return3 += "&sFileURL=/resources/editor/upload/"+realFileNm; } }else { return3 += "&errstr=error"; } } catch (Exception e) { e.printStackTrace(); } return "redirect:"+return1+return2+return3; }
○ HTML5 멀티파일업로드 컨트롤러 - /file_uploader_html5
@RequestMapping("/file_uploader_html5") public void file_uploader_html5(HttpServletRequest request, HttpServletResponse response){ try { //파일정보 String sFileInfo = ""; //파일명을 받는다 - 일반 원본파일명 String filename = request.getHeader("file-name"); //파일 확장자 String filename_ext = filename.substring(filename.lastIndexOf(".")+1); //확장자를소문자로 변경 filename_ext = filename_ext.toLowerCase(); //이미지 검증 배열변수 String[] allow_file = {"jpg","png","bmp","gif"}; //돌리면서 확장자가 이미지인지 int cnt = 0; for(int i=0; i<allow_file.length; i++) { if(filename_ext.equals(allow_file[i])){ cnt++; } } //이미지가 아님 if(cnt == 0) { PrintWriter print = response.getWriter(); print.print("NOTALLOW_"+filename); print.flush(); print.close(); } else { //이미지이므로 신규 파일로 디렉토리 설정 및 업로드 //파일 기본경로 String dftFilePath = request.getSession().getServletContext().getRealPath("/"); //파일 기본경로 _ 상세경로 String filePath = dftFilePath + "resources" + File.separator + "editor" + File.separator +"multiupload" + File.separator; File file = new File(filePath); if(!file.exists()) { file.mkdirs(); } String realFileNm = ""; SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss"); String today= formatter.format(new java.util.Date()); realFileNm = today+UUID.randomUUID().toString() + filename.substring(filename.lastIndexOf(".")); String rlFileNm = filePath + realFileNm; ///////////////// 서버에 파일쓰기 ///////////////// InputStream is = request.getInputStream(); OutputStream os=new FileOutputStream(rlFileNm); int numRead; byte b[] = new byte[Integer.parseInt(request.getHeader("file-size"))]; while((numRead = is.read(b,0,b.length)) != -1){ os.write(b,0,numRead); } if(is != null) { is.close(); } os.flush(); os.close(); ///////////////// 서버에 파일쓰기 ///////////////// // 정보 출력 sFileInfo += "&bNewLine=true"; // img 태그의 title 속성을 원본파일명으로 적용시켜주기 위함 sFileInfo += "&sFileName="+ filename;; sFileInfo += "&sFileURL="+"/resources/editor/multiupload/"+realFileNm; PrintWriter print = response.getWriter(); print.print(sFileInfo); print.flush(); print.close(); } } catch (Exception e) { e.printStackTrace(); } }
위의 각 종류별로 정상 동작하는지 테스트 해보도록 하자
● 기본 단일 파일업로드
● HTML5 를 이용한 에디터 멀티업로드 실행화면
1. 지속적인 구독을 원하신다면 네이버 이웃추가 부탁드립니다
2. 도움이 되셨다면 공감한번 꾹! 눌러주세요
3. 궁금하신점이 있으시다면 댓글 GOGO
한페이지에 스마트에디터 여러개 띄우고 각각 이미지 첨부하기 (2) | 2014.08.20 |
---|---|
스마트에디터(smarteditor)의 싱글/멀티 이미지업로드하기 - JAVA/JSP 버전 (73) | 2014.07.25 |
네이버의 스마트에디터를 연동해보고 서버에 내용을 전달해보자 (12) | 2014.07.17 |
장상휘님께서 질문하신 한페이지에 에디터 2개를 띄울경우, 사진첨부를 에디터마다 할수 있는지에 대한
문의를 해주셔서 간단하게나마 샘플링을 올리게 되었습니다.
2014/07/17 - [에디터연동/NAVER-스마트에디터] - 네이버의 스마트에디터를 연동해보고 서버에 내용을 전달해보자
2014/07/25 - [에디터연동/NAVER-스마트에디터] - 스마트에디터(smarteditor)의 싱글/멀티 이미지업로드하기 - JAVA/JSP 버전
위 두 포스팅의 방법으로 연동이 되었다 가정한 다음에 진행 하도록 하겠음.
기존 wirte.jsp 스크립트 코드(추가부분 주석표시)
var oEditors = []; ////////////추가 var oEditors2 = []; $(function(){ nhn.husky.EZCreator.createInIFrame({ oAppRef: oEditors, elPlaceHolder: "ir1", sSkinURI: "/editor/SmartEditor2Skin.html", htParams : { // 툴바 사용 여부 (true:사용/ false:사용하지 않음) bUseToolbar : true, // 입력창 크기 조절바 사용 여부 (true:사용/ false:사용하지 않음) bUseVerticalResizer : true, // 모드 탭(Editor | HTML | TEXT) 사용 여부 (true:사용/ false:사용하지 않음) bUseModeChanger : true, fOnBeforeUnload : function(){ } }, fOnAppLoad : function(){ //기존 저장된 내용의 text 내용을 에디터상에 뿌려주고자 할때 사용 oEditors.getById["ir1"].exec("PASTE_HTML", ["기존 DB에 저장된 내용을 에디터에 적용할 ㅁ"]); }, fCreator: "createSEditor2" }); ////////////추가 nhn.husky.EZCreator.createInIFrame({ oAppRef: oEditors2, elPlaceHolder: "ir2", sSkinURI: "/editor/SmartEditor2Skin.html", htParams : { // 툴바 사용 여부 (true:사용/ false:사용하지 않음) bUseToolbar : true, // 입력창 크기 조절바 사용 여부 (true:사용/ false:사용하지 않음) bUseVerticalResizer : true, // 모드 탭(Editor | HTML | TEXT) 사용 여부 (true:사용/ false:사용하지 않음) bUseModeChanger : true, fOnBeforeUnload : function(){ } }, fOnAppLoad : function(){ //기존 저장된 내용의 text 내용을 에디터상에 뿌려주고자 할때 사용 oEditors2.getById["ir2"].exec("PASTE_HTML", ["에디터 두번째!!!"]); }, fCreator: "createSEditor2" }); $("#save").click(function(){ oEditors.getById["ir1"].exec("UPDATE_CONTENTS_FIELD", []); ////////////추가 oEditors2.getById["ir2"].exec("UPDATE_CONTENTS_FIELD", []); $("#frm").submit(); }) })
BODY태그내 HTML 코드
<form id="frm" action="/insert.jsp" method="post"> <table width="100%"> <tr> <td>제목</td> <td><input type="text" name="title" /></td> </tr> <tr> <td>내용</td> <td> <textarea rows="10" cols="30" id="ir1" name="content" style="width:766px; height:412px; "></textarea> </td> </tr> <!-- 추가 --> <tr> <td>내용2</td> <td> <textarea rows="10" cols="30" id="ir2" name="content2" style="width:766px; height:412px; "></textarea> </td> </tr> <tr> <td colspan="2"> <input type="button" id="save" value="저장"/> <input type="button" value="취소"/> </td> </tr> </table> </form>
insert.jsp 추가 코드
※ 화면에서 서버페이지로 정상적으로 에디터값이 넘어오는지 확인하기 위함
//제대로 utf-8환경이 아니라 한글 깨짐 그래서 임의로 추가 request.setCharacterEncoding("utf-8"); System.out.println("제목:"+request.getParameter("title")); System.out.println("내용:"+request.getParameter("content")); System.out.println("내2용:"+request.getParameter("content2"));
실 행 결 과
1) 첫번째 에디터 사진첨부
2) 첫번째 에디터 추가완료
3) 두번째 에디터 사진첨부
4) 두번째 에디터 추가완료
5) 저장버튼 클릭후 서버페이지에서 받은 데이터값
정상적으로 각에디터에 사진첨부 와 데이터 전송이 각각 잘되는것을 확인하였음
Spring3을 이용한 스마트에디터(smarteditor) 이미지업로드(+html5) 적용하기 (50) | 2014.09.21 |
---|---|
스마트에디터(smarteditor)의 싱글/멀티 이미지업로드하기 - JAVA/JSP 버전 (73) | 2014.07.25 |
네이버의 스마트에디터를 연동해보고 서버에 내용을 전달해보자 (12) | 2014.07.17 |
스마트 에디터에 이어 다음에디터 연동을 하도록 하겠음
다음에디터 역시 웹접근성을 위해서 꾸준히 버전업 중인거 같다...
1. 연동할 에디터를 다운받도록 하자
다음에디터는 github에서 별도로 repository를 생성하여 운영하는중이다.
다음에디터 다운로드 URL : https://github.com/daumcorp/DaumEditor
하단 순서대로 작업을 하도록 하자
※ 링크 URL 자체로 받으면 MASTER ZIP 파일이 받아지는데 위와 같은 방식으로 하면
모든 버전을 다운받을 수 있더라...
DaumEditor-gh-pages.zip 파일이 다운로드 받았다.
다운 ZIP 파일을 압축해제 하면 DaumEditor-gh-pages\download\내에 버전별 압축파일이 존재한다.
현재 날짜 기준으로 가장최신은 daumeditor-7.4.22.zip 이므로 해당 버전으로 진행 하도록 하겠음.
위 압축파일을 한번 더 해제하여 압축해제 된 폴더 및 파일들을 모두 신규 프로젝트에 include 해주도록 하자
구조는 다음과 같다.
editor.html을 호출을 하더라도 샘플 화면을 확인이 가능하다.
스마트에디터와 동일하게 게시판 글쓰기 화면에 에디터를 적용한다 가정하고 jsp 페이지를 만들어 보도록 하겠음.
본인은 write.jsp로 파일생성!
변경된 전체 폴더 구조
1차적으로 write.jsp에 기본 태그를 적용해보도록 하자
<form name="tx_editor_form" id="tx_editor_form" action="/insert.jsp" method="post" accept-charset="utf-8"> <table width="100%"> <tr> <td>제목</td> <td><input type="text" id="title" name="title" /></td> </tr> <tr> <td>내용</td> <td id="editorTd"></td> </tr> <tr> <td colspan="2"> <input type="button" id="save" value="저장"/> <input type="button" value="취소"/> </td> </tr> </table> </form>
뭐전문적으로 화면을 구성할것이 아니라 대충 table 태그로 구조 뚝딱뚝딱
구성은 90% 이상 스마트 에디터랑 비슷하지만 내부 구조가 틀리므로 -_- 그냥 textarea태그를
없앴음
그리고는 별도의 템플릿 html 페이지를 daumeditor 디렉토리내에 생성(editor_template.html)
하였다.
코드는 다음과 같다. /daumeditor/ << 로 검색하여 본인의 경로에 맞추어서 변경하시길..
- editor_template.html
<div class="body"> <!-- 에디터 시작 --> <!-- @decsription 등록하기 위한 Form으로 상황에 맞게 수정하여 사용한다. Form 이름은 에디터를 생성할 때 설정값으로 설정한다. --> <!-- 에디터 컨테이너 시작 --> <div id="tx_trex_container" class="tx-editor-container"> <!-- 사이드바 --> <div id="tx_sidebar" class="tx-sidebar"> <div class="tx-sidebar-boundary"> <!-- 사이드바 / 첨부 --> <ul class="tx-bar tx-bar-left tx-nav-attach"> <!-- 이미지 첨부 버튼 시작 --> <!-- @decsription <li></li> 단위로 위치를 이동할 수 있다. --> <li class="tx-list"> <div unselectable="on" id="tx_image" class="tx-image tx-btn-trans"> <a href="javascript:;" title="사진" class="tx-text">사진</a> </div> </li> <!-- 이미지 첨부 버튼 끝 --> <li class="tx-list"> <div unselectable="on" id="tx_file" class="tx-file tx-btn-trans"> <a href="javascript:;" title="파일" class="tx-text">파일</a> </div> </li> <li class="tx-list"> <div unselectable="on" id="tx_media" class="tx-media tx-btn-trans"> <a href="javascript:;" title="외부컨텐츠" class="tx-text">외부컨텐츠</a> </div> </li> <li class="tx-list tx-list-extra"> <div unselectable="on" class="tx-btn-nlrbg tx-extra"> <a href="javascript:;" class="tx-icon" title="버튼 더보기">버튼 더보기</a> </div> <ul class="tx-extra-menu tx-menu" style="left:-48px;" unselectable="on"> <!-- @decsription 일부 버튼들을 빼서 레이어로 숨기는 기능을 원할 경우 이 곳으로 이동시킬 수 있다. --> </ul> </li> </ul> <!-- 사이드바 / 우측영역 --> <ul class="tx-bar tx-bar-right"> <li class="tx-list"> <div unselectable="on" class="tx-btn-lrbg tx-fullscreen" id="tx_fullscreen"> <a href="javascript:;" class="tx-icon" title="넓게쓰기 (Ctrl+M)">넓게쓰기</a> </div> </li> </ul> <ul class="tx-bar tx-bar-right tx-nav-opt"> <li class="tx-list"> <div unselectable="on" class="tx-switchtoggle" id="tx_switchertoggle"> <a href="javascript:;" title="에디터 타입">에디터</a> </div> </li> </ul> </div> </div> <!-- 툴바 - 기본 시작 --> <!-- @decsription 툴바 버튼의 그룹핑의 변경이 필요할 때는 위치(왼쪽, 가운데, 오른쪽) 에 따라 <li> 아래의 <div>의 클래스명을 변경하면 된다. tx-btn-lbg: 왼쪽, tx-btn-bg: 가운데, tx-btn-rbg: 오른쪽, tx-btn-lrbg: 독립적인 그룹 드롭다운 버튼의 크기를 변경하고자 할 경우에는 넓이에 따라 <li> 아래의 <div>의 클래스명을 변경하면 된다. tx-slt-70bg, tx-slt-59bg, tx-slt-42bg, tx-btn-43lrbg, tx-btn-52lrbg, tx-btn-57lrbg, tx-btn-71lrbg tx-btn-48lbg, tx-btn-48rbg, tx-btn-30lrbg, tx-btn-46lrbg, tx-btn-67lrbg, tx-btn-49lbg, tx-btn-58bg, tx-btn-46bg, tx-btn-49rbg --> <div id="tx_toolbar_basic" class="tx-toolbar tx-toolbar-basic"><div class="tx-toolbar-boundary"> <ul class="tx-bar tx-bar-left"> <li class="tx-list"> <div id="tx_fontfamily" unselectable="on" class="tx-slt-70bg tx-fontfamily"> <a href="javascript:;" title="글꼴">굴림</a> </div> <div id="tx_fontfamily_menu" class="tx-fontfamily-menu tx-menu" unselectable="on"></div> </li> </ul> <ul class="tx-bar tx-bar-left"> <li class="tx-list"> <div unselectable="on" class="tx-slt-42bg tx-fontsize" id="tx_fontsize"> <a href="javascript:;" title="글자크기">9pt</a> </div> <div id="tx_fontsize_menu" class="tx-fontsize-menu tx-menu" unselectable="on"></div> </li> </ul> <ul class="tx-bar tx-bar-left tx-group-font"> <li class="tx-list"> <div unselectable="on" class=" tx-btn-lbg tx-bold" id="tx_bold"> <a href="javascript:;" class="tx-icon" title="굵게 (Ctrl+B)">굵게</a> </div> </li> <li class="tx-list"> <div unselectable="on" class=" tx-btn-bg tx-underline" id="tx_underline"> <a href="javascript:;" class="tx-icon" title="밑줄 (Ctrl+U)">밑줄</a> </div> </li> <li class="tx-list"> <div unselectable="on" class=" tx-btn-bg tx-italic" id="tx_italic"> <a href="javascript:;" class="tx-icon" title="기울임 (Ctrl+I)">기울임</a> </div> </li> <li class="tx-list"> <div unselectable="on" class=" tx-btn-bg tx-strike" id="tx_strike"> <a href="javascript:;" class="tx-icon" title="취소선 (Ctrl+D)">취소선</a> </div> </li> <li class="tx-list"> <div unselectable="on" class=" tx-slt-tbg tx-forecolor" id="tx_forecolor"> <a href="javascript:;" class="tx-icon" title="글자색">글자색</a> <a href="javascript:;" class="tx-arrow" title="글자색 선택">글자색 선택</a> </div> <div id="tx_forecolor_menu" class="tx-menu tx-forecolor-menu tx-colorpallete" unselectable="on"></div> </li> <li class="tx-list"> <div unselectable="on" class=" tx-slt-brbg tx-backcolor" id="tx_backcolor"> <a href="javascript:;" class="tx-icon" title="글자 배경색">글자 배경색</a> <a href="javascript:;" class="tx-arrow" title="글자 배경색 선택">글자 배경색 선택</a> </div> <div id="tx_backcolor_menu" class="tx-menu tx-backcolor-menu tx-colorpallete" unselectable="on"></div> </li> </ul> <ul class="tx-bar tx-bar-left tx-group-align"> <li class="tx-list"> <div unselectable="on" class=" tx-btn-lbg tx-alignleft" id="tx_alignleft"> <a href="javascript:;" class="tx-icon" title="왼쪽정렬 (Ctrl+,)">왼쪽정렬</a> </div> </li> <li class="tx-list"> <div unselectable="on" class=" tx-btn-bg tx-aligncenter" id="tx_aligncenter"> <a href="javascript:;" class="tx-icon" title="가운데정렬 (Ctrl+.)">가운데정렬</a> </div> </li> <li class="tx-list"> <div unselectable="on" class=" tx-btn-bg tx-alignright" id="tx_alignright"> <a href="javascript:;" class="tx-icon" title="오른쪽정렬 (Ctrl+/)">오른쪽정렬</a> </div> </li> <li class="tx-list"> <div unselectable="on" class=" tx-btn-rbg tx-alignfull" id="tx_alignfull"> <a href="javascript:;" class="tx-icon" title="양쪽정렬">양쪽정렬</a> </div> </li> </ul> <ul class="tx-bar tx-bar-left tx-group-tab"> <li class="tx-list"> <div unselectable="on" class=" tx-btn-lbg tx-indent" id="tx_indent"> <a href="javascript:;" title="들여쓰기 (Tab)" class="tx-icon">들여쓰기</a> </div> </li> <li class="tx-list"> <div unselectable="on" class=" tx-btn-rbg tx-outdent" id="tx_outdent"> <a href="javascript:;" title="내어쓰기 (Shift+Tab)" class="tx-icon">내어쓰기</a> </div> </li> </ul> <ul class="tx-bar tx-bar-left tx-group-list"> <li class="tx-list"> <div unselectable="on" class="tx-slt-31lbg tx-lineheight" id="tx_lineheight"> <a href="javascript:;" class="tx-icon" title="줄간격">줄간격</a> <a href="javascript:;" class="tx-arrow" title="줄간격">줄간격 선택</a> </div> <div id="tx_lineheight_menu" class="tx-lineheight-menu tx-menu" unselectable="on"></div> </li> <li class="tx-list"> <div unselectable="on" class="tx-slt-31rbg tx-styledlist" id="tx_styledlist"> <a href="javascript:;" class="tx-icon" title="리스트">리스트</a> <a href="javascript:;" class="tx-arrow" title="리스트">리스트 선택</a> </div> <div id="tx_styledlist_menu" class="tx-styledlist-menu tx-menu" unselectable="on"></div> </li> </ul> <ul class="tx-bar tx-bar-left tx-group-etc"> <li class="tx-list"> <div unselectable="on" class=" tx-btn-lbg tx-emoticon" id="tx_emoticon"> <a href="javascript:;" class="tx-icon" title="이모티콘">이모티콘</a> </div> <div id="tx_emoticon_menu" class="tx-emoticon-menu tx-menu" unselectable="on"></div> </li> <li class="tx-list"> <div unselectable="on" class=" tx-btn-bg tx-link" id="tx_link"> <a href="javascript:;" class="tx-icon" title="링크 (Ctrl+K)">링크</a> </div> <div id="tx_link_menu" class="tx-link-menu tx-menu"></div> </li> <li class="tx-list"> <div unselectable="on" class=" tx-btn-bg tx-specialchar" id="tx_specialchar"> <a href="javascript:;" class="tx-icon" title="특수문자">특수문자</a> </div> <div id="tx_specialchar_menu" class="tx-specialchar-menu tx-menu"></div> </li> <li class="tx-list"> <div unselectable="on" class=" tx-btn-bg tx-table" id="tx_table"> <a href="javascript:;" class="tx-icon" title="표만들기">표만들기</a> </div> <div id="tx_table_menu" class="tx-table-menu tx-menu" unselectable="on"> <div class="tx-menu-inner"> <div class="tx-menu-preview"></div> <div class="tx-menu-rowcol"></div> <div class="tx-menu-deco"></div> <div class="tx-menu-enter"></div> </div> </div> </li> <li class="tx-list"> <div unselectable="on" class=" tx-btn-rbg tx-horizontalrule" id="tx_horizontalrule"> <a href="javascript:;" class="tx-icon" title="구분선">구분선</a> </div> <div id="tx_horizontalrule_menu" class="tx-horizontalrule-menu tx-menu" unselectable="on"></div> </li> </ul> <ul class="tx-bar tx-bar-left"> <li class="tx-list"> <div unselectable="on" class=" tx-btn-lbg tx-richtextbox" id="tx_richtextbox"> <a href="javascript:;" class="tx-icon" title="글상자">글상자</a> </div> <div id="tx_richtextbox_menu" class="tx-richtextbox-menu tx-menu"> <div class="tx-menu-header"> <div class="tx-menu-preview-area"> <div class="tx-menu-preview"></div> </div> <div class="tx-menu-switch"> <div class="tx-menu-simple tx-selected"><a><span>간단 선택</span></a></div> <div class="tx-menu-advanced"><a><span>직접 선택</span></a></div> </div> </div> <div class="tx-menu-inner"> </div> <div class="tx-menu-footer"> <img class="tx-menu-confirm" src="/daumeditor/images/icon/editor/btn_confirm.gif?rv=1.0.1" alt=""/> <img class="tx-menu-cancel" hspace="3" src="/daumeditor/images/icon/editor/btn_cancel.gif?rv=1.0.1" alt=""/> </div> </div> </li> <li class="tx-list"> <div unselectable="on" class=" tx-btn-bg tx-quote" id="tx_quote"> <a href="javascript:;" class="tx-icon" title="인용구 (Ctrl+Q)">인용구</a> </div> <div id="tx_quote_menu" class="tx-quote-menu tx-menu" unselectable="on"></div> </li> <li class="tx-list"> <div unselectable="on" class=" tx-btn-bg tx-background" id="tx_background"> <a href="javascript:;" class="tx-icon" title="배경색">배경색</a> </div> <div id="tx_background_menu" class="tx-menu tx-background-menu tx-colorpallete" unselectable="on"></div> </li> <li class="tx-list"> <div unselectable="on" class=" tx-btn-rbg tx-dictionary" id="tx_dictionary"> <a href="javascript:;" class="tx-icon" title="사전">사전</a> </div> </li> </ul> <ul class="tx-bar tx-bar-left tx-group-undo"> <li class="tx-list"> <div unselectable="on" class=" tx-btn-lbg tx-undo" id="tx_undo"> <a href="javascript:;" class="tx-icon" title="실행취소 (Ctrl+Z)">실행취소</a> </div> </li> <li class="tx-list"> <div unselectable="on" class=" tx-btn-rbg tx-redo" id="tx_redo"> <a href="javascript:;" class="tx-icon" title="다시실행 (Ctrl+Y)">다시실행</a> </div> </li> </ul> <ul class="tx-bar tx-bar-right"> <li class="tx-list"> <div unselectable="on" class="tx-btn-nlrbg tx-advanced" id="tx_advanced"> <a href="javascript:;" class="tx-icon" title="툴바 더보기">툴바 더보기</a> </div> </li> </ul> </div></div> <!-- 툴바 - 기본 끝 --> <!-- 툴바 - 더보기 시작 --> <div id="tx_toolbar_advanced" class="tx-toolbar tx-toolbar-advanced"><div class="tx-toolbar-boundary"> <ul class="tx-bar tx-bar-left"> <li class="tx-list"> <div class="tx-tableedit-title"></div> </li> </ul> <ul class="tx-bar tx-bar-left tx-group-align"> <li class="tx-list"> <div unselectable="on" class="tx-btn-lbg tx-mergecells" id="tx_mergecells"> <a href="javascript:;" class="tx-icon2" title="병합">병합</a> </div> <div id="tx_mergecells_menu" class="tx-mergecells-menu tx-menu" unselectable="on"></div> </li> <li class="tx-list"> <div unselectable="on" class="tx-btn-bg tx-insertcells" id="tx_insertcells"> <a href="javascript:;" class="tx-icon2" title="삽입">삽입</a> </div> <div id="tx_insertcells_menu" class="tx-insertcells-menu tx-menu" unselectable="on"></div> </li> <li class="tx-list"> <div unselectable="on" class="tx-btn-rbg tx-deletecells" id="tx_deletecells"> <a href="javascript:;" class="tx-icon2" title="삭제">삭제</a> </div> <div id="tx_deletecells_menu" class="tx-deletecells-menu tx-menu" unselectable="on"></div> </li> </ul> <ul class="tx-bar tx-bar-left tx-group-align"> <li class="tx-list"> <div id="tx_cellslinepreview" unselectable="on" class="tx-slt-70lbg tx-cellslinepreview"> <a href="javascript:;" title="선 미리보기"></a> </div> <div id="tx_cellslinepreview_menu" class="tx-cellslinepreview-menu tx-menu" unselectable="on"></div> </li> <li class="tx-list"> <div id="tx_cellslinecolor" unselectable="on" class="tx-slt-tbg tx-cellslinecolor"> <a href="javascript:;" class="tx-icon2" title="선색">선색</a> <div class="tx-colorpallete" unselectable="on"></div> </div> <div id="tx_cellslinecolor_menu" class="tx-cellslinecolor-menu tx-menu tx-colorpallete" unselectable="on"></div> </li> <li class="tx-list"> <div id="tx_cellslineheight" unselectable="on" class="tx-btn-bg tx-cellslineheight"> <a href="javascript:;" class="tx-icon2" title="두께">두께</a> </div> <div id="tx_cellslineheight_menu" class="tx-cellslineheight-menu tx-menu" unselectable="on"></div> </li> <li class="tx-list"> <div id="tx_cellslinestyle" unselectable="on" class="tx-btn-bg tx-cellslinestyle"> <a href="javascript:;" class="tx-icon2" title="스타일">스타일</a> </div> <div id="tx_cellslinestyle_menu" class="tx-cellslinestyle-menu tx-menu" unselectable="on"></div> </li> <li class="tx-list"> <div id="tx_cellsoutline" unselectable="on" class="tx-btn-rbg tx-cellsoutline"> <a href="javascript:;" class="tx-icon2" title="테두리">테두리</a> </div> <div id="tx_cellsoutline_menu" class="tx-cellsoutline-menu tx-menu" unselectable="on"></div> </li> </ul> <ul class="tx-bar tx-bar-left"> <li class="tx-list"> <div id="tx_tablebackcolor" unselectable="on" class="tx-btn-lrbg tx-tablebackcolor" style="background-color:#9aa5ea;"> <a href="javascript:;" class="tx-icon2" title="테이블 배경색">테이블 배경색</a> </div> <div id="tx_tablebackcolor_menu" class="tx-tablebackcolor-menu tx-menu tx-colorpallete" unselectable="on"></div> </li> </ul> <ul class="tx-bar tx-bar-left"> <li class="tx-list"> <div id="tx_tabletemplate" unselectable="on" class="tx-btn-lrbg tx-tabletemplate"> <a href="javascript:;" class="tx-icon2" title="테이블 서식">테이블 서식</a> </div> <div id="tx_tabletemplate_menu" class="tx-tabletemplate-menu tx-menu tx-colorpallete" unselectable="on"></div> </li> </ul> </div></div> <!-- 툴바 - 더보기 끝 --> <!-- 편집영역 시작 --> <!-- 에디터 Start --> <div id="tx_canvas" class="tx-canvas"> <div id="tx_loading" class="tx-loading"><div><img src="/daumeditor/images/icon/editor/loading2.png" width="113" height="21" align="absmiddle"/></div></div> <div id="tx_canvas_wysiwyg_holder" class="tx-holder" style="display:block;"> <iframe id="tx_canvas_wysiwyg" name="tx_canvas_wysiwyg" allowtransparency="true" frameborder="0"></iframe> </div> <div class="tx-source-deco"> <div id="tx_canvas_source_holder" class="tx-holder"> <textarea id="tx_canvas_source" rows="30" cols="30"></textarea> </div> </div> <div id="tx_canvas_text_holder" class="tx-holder"> <textarea id="tx_canvas_text" rows="30" cols="30"></textarea> </div> </div> <!-- 높이조절 Start --> <div id="tx_resizer" class="tx-resize-bar"> <div class="tx-resize-bar-bg"></div> <img id="tx_resize_holder" src="/daumeditor/images/icon/editor/skin/01/btn_drag01.gif" width="58" height="12" unselectable="on" alt="" /> </div> <div class="tx-side-bi" id="tx_side_bi"> <div style="text-align: right;"> <img hspace="4" height="14" width="78" align="absmiddle" src="/daumeditor/images/icon/editor/editor_bi.png" /> </div> </div> <!-- 편집영역 끝 --> <!-- 첨부박스 시작 --> <!-- 파일첨부박스 Start --> <div id="tx_attach_div" class="tx-attach-div"> <div id="tx_attach_txt" class="tx-attach-txt">파일 첨부</div> <div id="tx_attach_box" class="tx-attach-box"> <div class="tx-attach-box-inner"> <div id="tx_attach_preview" class="tx-attach-preview"><p></p><img src="/daumeditor/images/icon/editor/pn_preview.gif" width="147" height="108" unselectable="on"/></div> <div class="tx-attach-main"> <div id="tx_upload_progress" class="tx-upload-progress"><div>0%</div><p>파일을 업로드하는 중입니다.</p></div> <ul class="tx-attach-top"> <li id="tx_attach_delete" class="tx-attach-delete"><a>전체삭제</a></li> <li id="tx_attach_size" class="tx-attach-size"> 파일: <span id="tx_attach_up_size" class="tx-attach-size-up"></span>/<span id="tx_attach_max_size"></span> </li> <li id="tx_attach_tools" class="tx-attach-tools"> </li> </ul> <ul id="tx_attach_list" class="tx-attach-list"></ul> </div> </div> </div> </div> <!-- 첨부박스 끝 --> </div> <!-- 에디터 컨테이너 끝 --> </div>
이어서 css파일과 js파일들을 include 해주도록 하자
<link rel="stylesheet" href="/daumeditor/css/editor.css" type="text/css" charset="utf-8"/> <script src="/daumeditor/js/editor_loader.js?environment=development" type="text/javascript" charset="utf-8"></script> <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.js"></script>
이어서 에디터 환경설정을 위한 setConfig 함수를 정의
function setConfig(){ var config = { txHost: '', /* 런타임 시 리소스들을 로딩할 때 필요한 부분으로, 경로가 변경되면 이 부분 수정이 필요. ex) http://xxx.xxx.com */ txPath: '', /* 런타임 시 리소스들을 로딩할 때 필요한 부분으로, 경로가 변경되면 이 부분 수정이 필요. ex) /xxx/xxx/ */ txService: 'sample', /* 수정필요없음. */ txProject: 'sample', /* 수정필요없음. 프로젝트가 여러개일 경우만 수정한다. */ initializedId: "", /* 대부분의 경우에 빈문자열 */ wrapper: "tx_trex_container", /* 에디터를 둘러싸고 있는 레이어 이름(에디터 컨테이너) */ form: 'tx_editor_form'+"", /* 등록하기 위한 Form 이름 */ txIconPath: "/daumeditor/images/icon/editor/", /*에디터에 사용되는 이미지 디렉터리, 필요에 따라 수정한다. */ txDecoPath: "/daumeditor/images/deco/contents/", /*본문에 사용되는 이미지 디렉터리, 서비스에서 사용할 때는 완성된 컨텐츠로 배포되기 위해 절대경로로 수정한다. */ canvas: { styles: { color: "#123456", /* 기본 글자색 */ fontFamily: "굴림", /* 기본 글자체 */ fontSize: "10pt", /* 기본 글자크기 */ backgroundColor: "#fff", /*기본 배경색 */ lineHeight: "1.5", /*기본 줄간격 */ padding: "8px" /* 위지윅 영역의 여백 */ }, showGuideArea: false }, events: { preventUnload: false }, sidebar: { attachbox: { show: true, confirmForDeleteAll: true } }, size: { contentWidth: 700 /* 지정된 본문영역의 넓이가 있을 경우에 설정 */ } }; EditorJSLoader.ready(function(Editor) { editor = new Editor(config); }); }
마지막으로 jquery ajax를 이용하여 template html 파일을 load 후 setConfig 함수를 호출하도록
하자!!
$(function(){ $.ajax({ type:"POST", url: "/daumeditor/editor_template.html", success: function(data){ $("#editorTd").html(data); setConfig(); }, error : function(request, status, error) { alert("에러"); } }); })
기초 공사는 마무리가 되었으니 실행!!
입력도 잘되고 편집도 잘된다.
이제는 저장 버튼 클릭시 서버 전송을 해야 한다.
화면상으로는 에디터에 편집이 되서 일반 submit을 해도 될거 같지만
별도로 daumeditor 방식으로 editor 부분은 처리를 해주어야 한다.
마지막으로 2가지 function을 추가해주도록 하자
// submit 전 다음에디터 validation체크 function validForm(editor) { var validator = new Trex.Validator(); var content = editor.getContent(); if (!validator.exists(content)) { alert('내용을 입력하세요'); return false; } return true; } //validForm 함수가 true로 return된 후에 동작하는 함수 function setForm(editor) { var form = editor.getForm(); var content = editor.getContent(); var textarea = document.createElement('textarea'); //textarea를 생성하여 해당태그에 에디터 입력값들을 신규생성 textarea에 담는다 textarea.name = 'content'; textarea.value = content; form.createField(textarea); return true; }
위 함수를 추가하였다면 저장버튼 클릭시 submit 해주는 이벤트를 구현해주도록 하자
$(function(){}) << 될수있으면 내부에 선언해주도록 하자
$("#save").click(function(){ Editor.save(); })
이걸로 폼관련 설정을 마무리가 되었다.
값이 제대로 출력이 되나 확인해야 하므로
insert.jsp 페이지를 생성 후 title / content 에 대한 값을 콘솔에 찍어보도록 확인 하겠다.
- insert.jsp
//제대로 utf-8환경이 아니라 한글 깨짐 그래서 임의로 추가 request.setCharacterEncoding("utf-8"); System.out.println("제목:"+request.getParameter("title")); System.out.println("내용:"+request.getParameter("content"));
폼화면에서 제목/내용 입력후 서버 전송한 결과값을 서버 콘솔에서 확인한 결과값이다
잘 나온것이 확인 되었다.
다음포스팅에는 스마트에디터와동일하게 파일첨부 관련하여 포스팅해보도록 하겠음
※ 에디터내에 DEVELOPMENT MODE 라는 텍스트가 들어가있을수있는데 이럴경우
development_environments.js -> 맨하단에 EditorJSLoader.ready(addEditorEnvIndicator);
를 제거하도록 하자
아 이놈때문에 반나절 삽질한듯... -_-
일반 싱글 이미지업로드는 성공하였는데 html5 드래그앤드롭에서 삽질시작...
에디터샘플소스에 이미지 업로드 관련 php 소스는 있지만 java/jsp 소스가 없는거 같아 포스팅
하도록 한다.
싱글/멀티 이미지 업로드 모두포스팅 하였음!!!
이건 단순 출력물을 뽑기위해 대충 코딩 한것이므로 정리는 알아서들 하시길... ㅜ.ㅜ
스프링으로 파일처리는 쉬운대... ㅠㅠ jsp로 간만에 하려니ㅋㅋ gg.....
* 스마트에디터 버전 - SE2.3.10.O11329
우선 지난 포스팅에 이어서 에디터 우측상단을 보게 된다면 사진이라는 버튼이 존재할 것임.
2014/07/17 - [에디터연동/NAVER-스마트에디터] - 네이버의 스마트에디터를 연동해보고 서버에 내용을 전달해보자
각 브라우저별로 버튼 클릭시 업로드 기능에 대한 유형이 틀리다.
IE11 미만 버전에서는 싱글 멀티파트 업로드화면을 출력시키고
IE11, 크롬, 사파리 등에서는 드래그앤드롭기능으로 멀티파일 업로드(드래그앤드롭) 폼을 출력
시킨다.
1) 싱글업로드 화면
2) 멀티플업로드 화면(드래그앤드롭)
우선 파일 처리를 위해 라이브러리 2개를 다운받자
(본인은 dynamic web project로 하고, 별도의 프레임워크 연동없이 jsp코드예제다)
어짜피 내부로직 비슷하고 프레임워크별로 특정 부분만 수정하면되니...
위 jar파일들을 lib 폴더에 넣도록 하자
maven 이용자은 dependency 추가하자 (버전은 알아서 맞추자..)
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency>
spring 사용자는 파일처리를 위해 멀티파트 빈을 등록하면 될것이고...
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />
이걸로 파일업로드 기초공사는 끝났으니... 에디터 디렉토리 -> photo_uploader -> popup
디렉토리내의 소스 2가지를 수정해주도록 하자
1. photo_uploader.html
해당 form의 action은 무의미 한듯 -_- action="xxxxx" 자체를 삭제!
<form id="editor_upimage" name="editor_upimage" action="FileUploader.php" method="post" enctype="multipart/form-data" onSubmit="return false;>
2. attach_photo.js
변경함수 : callFileUploader() , html5Upload()
첫번째로 싱글파일 업로드를 먼저 처리 하도록 하자
관련 함수는 callFileUploader() 함수이다.
변경 속성은 sUrl, sCallback이다
본인은 WebContent경로 바로 밑에 file_uploader.jsp 를 생성하였다.
위 jsp에 대한 내용은 하단에 기술하도록 하겠음...
기존 file_uploader.php -> jsp로 변경만 한것뿐이다.
callback.html은 editor -> photo_uploader -> popup -> callback.html 의 경로를 절대경로로
지정해줌
두가지 속성값을 하단처럼 변경함
sUrl : '/file_uploader.jsp', //샘플 URL입니다. sCallback : '/editor/photo_uploader/popup/callback.html', //업로드 이후에 iframe이 redirect될 콜백페이지의 주소
다음으로 멀티이미지업로드를 위해 html5Upload() 함수내의 변수값 변경을 하도록 하자
헤더에 정보를 담는거 같은대 .. -0- 그냥 분석까지는 하기 싫으므로
sUploadURL= 'file_uploader_html5.php'; //upload URL
이부분의 url을 jsp로 변경하도록 하자
sUploadURL= '/file_uploader_html5.jsp'; //upload URL
물론 file_uploader_html5.jsp로 WebContent 하단에 파일 생성함
오예 이제 jsp 코드 2개만 작성하면 끝난다!!
간단하지 않은가~~~
(1) file_uploader_html.jsp
import 클래스는 다음과 같다.
<%@page import="java.io.FileOutputStream"%>
<%@page import="java.io.OutputStream"%>
<%@page import="java.io.InputStream"%>
<%@page import="java.util.UUID"%>
<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.io.File"%>
<%@page import="org.apache.commons.fileupload.FileItem"%>
<%@page import="java.util.List"%>
<%@page import="org.apache.commons.fileupload.disk.DiskFileItemFactory"%>
<%@page import="org.apache.commons.fileupload.servlet.ServletFileUpload"%>
String return1=""; String return2=""; String return3=""; //변경 title 태그에는 원본 파일명을 넣어주어야 하므로 String name = ""; if (ServletFileUpload.isMultipartContent(request)){ ServletFileUpload uploadHandler = new ServletFileUpload(new DiskFileItemFactory()); uploadHandler.setHeaderEncoding("UTF-8"); List<FileItem> items = uploadHandler.parseRequest(request); for (FileItem item : items) { if(item.getFieldName().equals("callback")) { return1 = item.getString("UTF-8"); } else if(item.getFieldName().equals("callback_func")) { return2 = "?callback_func="+item.getString("UTF-8"); } else if(item.getFieldName().equals("Filedata")) { if(item.getSize() > 0) { //String name = item.getName().substring(item.getName().lastIndexOf(File.separator)+1); // 기존 상단 코드를 막고 하단코드를 이용 name = item.getName().substring(item.getName().lastIndexOf(File.separator)+1); String filename_ext = name.substring(name.lastIndexOf(".")+1); filename_ext = filename_ext.toLowerCase(); String[] allow_file = {"jpg","png","bmp","gif"}; int cnt = 0; for(int i=0; i<allow_file.length; i++) { if(filename_ext.equals(allow_file[i])){ cnt++; } } if(cnt == 0) { return3 = "&errstr="+name; } else { //파일 기본경로 String dftFilePath = request.getServletContext().getRealPath("/"); //파일 기본경로 _ 상세경로 String filePath = dftFilePath + "editor" + File.separator +"upload" + File.separator; File file = null; file = new File(filePath); if(!file.exists()) { file.mkdirs(); } String realFileNm = ""; SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss"); String today= formatter.format(new java.util.Date()); realFileNm = today+UUID.randomUUID().toString() + name.substring(name.lastIndexOf(".")); String rlFileNm = filePath + realFileNm; ///////////////// 서버에 파일쓰기 ///////////////// InputStream is = item.getInputStream(); OutputStream os=new FileOutputStream(rlFileNm); int numRead; byte b[] = new byte[(int)item.getSize()]; while((numRead = is.read(b,0,b.length)) != -1){ os.write(b,0,numRead); } if(is != null) { is.close(); } os.flush(); os.close(); ///////////////// 서버에 파일쓰기 ///////////////// return3 += "&bNewLine=true"; // img 태그의 title 옵션에 들어갈 원본파일명 return3 += "&sFileName="+ name; return3 += "&sFileURL=/editor/upload/"+realFileNm; } }else { return3 += "&errstr=error"; } } } } response.sendRedirect(return1+return2+return3);
하단은 멀티이미지업로드를 위한 샘플 코드이다
(2) file_uploader_html5.jsp
import 클래스는 다음과 같다.
<%@page import="java.io.*"%>
<%@page import="java.util.UUID"%>
<%@page import="java.text.SimpleDateFormat"%>
//파일정보 String sFileInfo = ""; //파일명을 받는다 - 일반 원본파일명 String filename = request.getHeader("file-name"); //파일 확장자 String filename_ext = filename.substring(filename.lastIndexOf(".")+1); //확장자를소문자로 변경 filename_ext = filename_ext.toLowerCase(); //이미지 검증 배열변수 String[] allow_file = {"jpg","png","bmp","gif"}; //돌리면서 확장자가 이미지인지 int cnt = 0; for(int i=0; i<allow_file.length; i++) { if(filename_ext.equals(allow_file[i])){ cnt++; } } //이미지가 아님 if(cnt == 0) { out.println("NOTALLOW_"+filename); } else { //이미지이므로 신규 파일로 디렉토리 설정 및 업로드 //파일 기본경로 String dftFilePath = request.getServletContext().getRealPath("/"); //파일 기본경로 _ 상세경로 String filePath = dftFilePath + "editor" + File.separator +"multiupload" + File.separator; File file = new File(filePath); if(!file.exists()) { file.mkdirs(); } String realFileNm = ""; SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss"); String today= formatter.format(new java.util.Date()); realFileNm = today+UUID.randomUUID().toString() + filename.substring(filename.lastIndexOf(".")); String rlFileNm = filePath + realFileNm; ///////////////// 서버에 파일쓰기 ///////////////// InputStream is = request.getInputStream(); OutputStream os=new FileOutputStream(rlFileNm); int numRead; byte b[] = new byte[Integer.parseInt(request.getHeader("file-size"))]; while((numRead = is.read(b,0,b.length)) != -1){ os.write(b,0,numRead); } if(is != null) { is.close(); } os.flush(); os.close(); ///////////////// 서버에 파일쓰기 ///////////////// // 정보 출력 sFileInfo += "&bNewLine=true"; //sFileInfo += "&sFileName="+ realFileNm;; // img 태그의 title 속성을 원본파일명으로 적용시켜주기 위함 sFileInfo += "&sFileName="+ filename;; sFileInfo += "&sFileURL="+"/editor/multiupload/"+realFileNm; out.println(sFileInfo); }
이걸로 에디터 + 이미지 업로드 연동 끝!!!
spring framework는 좀더 심플한대.... 연동 성공하시길 빌겠습돠~
실행동작을 보고 스마트에디터 연동은 이걸로 끝~
1) 단일 이미지 업로드
1) 다중 이미지 업로드(드래그앤드롭 파일첨부)
아하~ 잘 연동되는것이 확인되었다 ^^
Spring3을 이용한 스마트에디터(smarteditor) 이미지업로드(+html5) 적용하기 (50) | 2014.09.21 |
---|---|
한페이지에 스마트에디터 여러개 띄우고 각각 이미지 첨부하기 (2) | 2014.08.20 |
네이버의 스마트에디터를 연동해보고 서버에 내용을 전달해보자 (12) | 2014.07.17 |
보통 웹개발을 할때 주로 네이버의 스마트 에디터 또는 다음의 다음에디터를 연동한다.
현재까지 100%에 대한 웹접근성 지원은 아닌거 같다... -0-;;
그럼, 네이버에서 제공해주는 스마트 에디터 연동법에 대하여 설명을 진행하도록 하겠음
1. 우선 연동할 에디터를 다운로드 받도록 하자
스마트에디터 다운로드 : http://dev.naver.com/projects/smarteditor/download
뭐 아무거나 받아도 상관없으나 본인은 최신버전으로 다운받도록 하겠다
현재까지 나온 버전은 2.3.10.11329 버전이다.
클릭하면 버그 수정내용 및 업데이트에 대한 내용이 존재한다.
그리고 다운로드 버튼이 존재하는데 클릭하여 다운을 받도록 하자
압축해제를 하면 파일들을 전부다 프로젝트 내에 넣도록 해보자
구조는 다음과 같고 SmartEditor2.html만 호출하더라도 샘플 화면은 출력이 된다.
위 구조에서 게시판 글쓰기 화면에 에디터를 적용한다 가정하고 jsp페이지 하나를 만들어 보도록
하겠다. 본인은 write.jsp 라고 생성하였음
방금 프로젝트에 추가한 스마트 에디터 폴더및 소스들을 모두 editor 폴더내에 넣었음
변경된 전체 폴더 구조
우선 기본구조 태그
<form id="frm" action="/insert.jsp" method="post" > <table width="100%"> <tr> <td>제목</td> <td><input type="text" id="title" /></td> </tr> <tr> <td>내용</td> <td> <textarea rows="10" cols="30" id="ir1" name="content" style="width:766px; height:412px; "></textarea> </td> </tr> <tr> <td colspan="2"> <input type="button" id="save" value="저장"/> <input type="button" value="취소"/> </td> </tr> </table> </form>
뭐전문적으로 화면을 구성할것이 아니라 대충 table 태그로 구조 뚝딱뚝딱
화면출력해보자
음~ 볼품없다...
어쨋든, 내용에 해당하는 textarea 태그에 에디터를 씌우는 작업을 진행 하도록 하겠음
1. 필요파일 include
<script type="text/javascript" src="/editor/js/HuskyEZCreator.js" charset="utf-8"></script> <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.js"></script>
<head></head> 태그안에 위와같이 선언을 해주고 textarea태그 바로 밑에 다음과 같이
스크립트코드를 추가함 어짜피 기본 샘플링을 토대로 만든것
본인은 body태그내에 특별하지 않는이상 스크립트 코드를 잘 넣지 않으려고 한다.
그래서 onload시 에디터생성 함수를 호출하였다.
<script type="text/javascript"> var oEditors = []; $(function(){ nhn.husky.EZCreator.createInIFrame({ oAppRef: oEditors, elPlaceHolder: "ir1", //SmartEditor2Skin.html 파일이 존재하는 경로 sSkinURI: "/editor/SmartEditor2Skin.html", htParams : { // 툴바 사용 여부 (true:사용/ false:사용하지 않음) bUseToolbar : true, // 입력창 크기 조절바 사용 여부 (true:사용/ false:사용하지 않음) bUseVerticalResizer : true, // 모드 탭(Editor | HTML | TEXT) 사용 여부 (true:사용/ false:사용하지 않음) bUseModeChanger : true, fOnBeforeUnload : function(){ } }, fOnAppLoad : function(){ //기존 저장된 내용의 text 내용을 에디터상에 뿌려주고자 할때 사용 oEditors.getById["ir1"].exec("PASTE_HTML", ["기존 DB에 저장된 내용을 에디터에 적용할 문구"]); }, fCreator: "createSEditor2" }); }); </script>
위와같이 작성을 해주었다.
연동된 화면
에디터는 우선 나왔고~~
신규 글쓰기시에는 별 필요 없지만 마냥 내용 수정 화면에 에디터를 쓸경우 필요한 함수는 fOnAppLoad 함수이다.
마지막으로 저장버튼 클릭시 서버로 제목과 내용의 입력값들을 서버에 넘겨 주어야 하는데
현재 상황에서는 에디터에 껍데기만 씌워진 상태라 서버에서 각각의 값을 받게 된다면 제목값만
받게 될것이다.
해당 코드는 저장버튼 클릭시 form submit 하는 단순 코드이다.
$("#save").click(function(){ oEditors.getById["ir1"].exec("UPDATE_CONTENTS_FIELD", []); $("#frm").submit(); })
이어서 데이터들을 받을 insert.jsp 페이지를 생성하고
title / content 에 대한 값을 콘솔에 찍어보도록 하겠다
- insert.jsp
//제대로 utf-8환경이 아니라 한글 깨짐 그래서 임의로 추가 request.setCharacterEncoding("utf-8"); System.out.println("제목:"+request.getParameter("title")); System.out.println("내용:"+request.getParameter("content"));
폼화면에서 제목/내용 입력후 서버 전송한 결과값을 서버 콘솔에서 확인한 결과값이다.
잘나왔도다~
다음시간에는 에디터내에 파일첨부 관련에 대하여 다루어 볼까 생각중이다..
도움이 되셨다면 공감클릭! 궁금하신점은 댓글!!
Spring3을 이용한 스마트에디터(smarteditor) 이미지업로드(+html5) 적용하기 (50) | 2014.09.21 |
---|---|
한페이지에 스마트에디터 여러개 띄우고 각각 이미지 첨부하기 (2) | 2014.08.20 |
스마트에디터(smarteditor)의 싱글/멀티 이미지업로드하기 - JAVA/JSP 버전 (73) | 2014.07.25 |