지난번에 다음에디터 기본 연동하는법에 대해서 포스팅 해보았습니다.
2014/10/30 - [코드저장소/다음에디터연동] - jQuery를 적용한 다음에디터 기본연동 및 서버에 입력내용 전송법
이번에는 사진첨부 기능을 이용하여
업로드한 사진들을 에디터 내에 출력되는 기능에 대하여
포스팅 하도록 하겠습니다.
사진첨부기능 구현하기전에 추가작업 부분은
파일을 ajax upload하여 json data를 callback으로 받아야 하기 때문에
jquery.form.js 다운로드를 하셔야 합니다.
2014/10/10 - [코드저장소/jQuery 플러그인] - jQuery Form플러그인 이용한 ajax 파일업로드하기 + FormData() 추가설명
상단을 참고하셔서 js파일을 다운로드 받으신후
/daumeditor/pages/trex/ 경로에 jquery.form.js파일을 include 합니다.
그리고 파일을 서버에 전달을 하여야 하므로
파일처리 라이브러리가 별도로 필요합니다.
해당 라이브러리 다운관련은
2014/10/29 - [코드저장소/스마트에디터연동] - 네이버 스마트에디터 사진첨부기능을 이용하여 에디터에 이미지 추가하기+다중파일업로드 포함
위 포스팅을 참고하셔서 commons-fileupload, commons-io 라이브러리 파일을 lib 디렉토리에 include 해주세요
다음과 같이 위치하면 되겠습니다.
위치에 관련 파일을들 위치하는 작업을 마쳤다면
본격적인 사진첨부기능 포스팅을 진행하도록 하겠습니다.
제일먼저 에디터에 붙어있는 사진버튼을 클릭하면
기본적으로 "/daumeditor/pages/trex/image.html" 페이지를
팝업창으로 띄워주는데 image.html 파일을 일부 수정하도록 하겠습니다.
추가로 필요한 JS파일을 INCLUDE 해주도록 합니다.
<script type="text/javascript" src="//code.jquery.com/jquery-1.11.0.min.js"></script> <script type="text/javascript" src="jquery.form.js"></script>
이어서 body 태그 일부분을 수정하였는데 그냥 body태그내에 모든 태그를 다음태그로 덮어쓰기 해주세요
<div class="wrapper"> <div class="header"> <h1>사진 첨부</h1> </div> <div class="body"> <dl class="alert"> <dt>사진 첨부 확인</dt> <dd> <form id="frm" action="/fileupload.jsp" method="post"> <input type="file" name="image_file"/> </form> </dd> </dl> </div> <div class="footer"> <ul> <li class="submit"><a href="#" id="saveBtn" title="등록" class="btnlink">등록</a> </li> <li class="cancel"><a href="#" onclick="closeWindow();" title="취소" class="btnlink">취소</a></li> </ul> </div> </div>
실실적으로 바뀐부분은 form태그를 기존 text 태그에서 교체를 해준것과 등록버튼 일부 변경이 된것입니다.
마지막으로 html 코드내에 정의되어있는 자바스크립트 done 함수와 initUploader함수가
정의되어있을텐데 일부를 변경하였으므로 통째로 덮어씌워주시면 되겠습니다.
$(function(){ $("#saveBtn").click(function(){ $("#frm").submit(); }) //ajax form submit $('#frm').ajaxForm({ beforeSubmit: function (data,form,option) { //validation체크 //막기위해서는 return false를 잡아주면됨 return true; }, success: function(response,status){ //성공후 서버에서 받은 데이터 처리 done(response); }, error: function(){ //에러발생을 위한 code페이지 alert("error!!"); } }); }) function done(response) { if (typeof(execAttach) == 'undefined') { //Virtual Function return; } var response_object = $.parseJSON( response ); execAttach(response_object); closeWindow(); } function initUploader(){ var _opener = PopupUtil.getOpener(); if (!_opener) { alert('잘못된 경로로 접근하셨습니다.'); return; } var _attacher = getAttacher('image', _opener); registerAction(_attacher); }
현재는 이미지 확장자 체크를 하지 않아 사진파일이 아니더라도 모든 파일이 업로드 가능합니다
하지만 에디터에 추가는되지만 깨진 이미지로 인식이 되겠죠?
확장자 체크를 하기위해서는 image.html 파일내 ajaxForm 함수를 적용한 스크립트부분이 있습니다.
beforeSubmit 내에서 확장자 validation 체크기능을 구현하시면 되겠습니다.
※ 사진버튼 클릭시 팝업창 넓이/높이 사이즈가 생각보다 넓습니다.
/daumeditor/js/trex/attacher/image.js 파일의 49번째줄을 보시면
features: { left:250, top:65, width:797, height:644 },
위코드의 속성값이 정해져있는데 width / height 속성값을 변경해주시면 되겠습니다.
저는 다음과 같이 사이즈를 절반정도 줄여주었습니다.
features: { left:250, top:65, width:350, height:300 },
마지막으로 파일처리를 해주는 fileupload.jsp 페이지내 코드를 작성해보도록 하겠습니다.
기존 스마트에디터 싱글사진업로드 기능과 유사한 코드이고 일부 다릅니다.
if (ServletFileUpload.isMultipartContent(request)){ ServletFileUpload uploadHandler = new ServletFileUpload(new DiskFileItemFactory()); //UTF-8 인코딩 설정 uploadHandler.setHeaderEncoding("UTF-8"); List<FileItem> items = uploadHandler.parseRequest(request); String realname = ""; Long size = 0L; //각 필드태그들을 FOR문을 이용하여 비교를 합니다. for (FileItem item : items) { //image.html 에서 file 태그의 name 명을 "image_file"로 지정해 주었으므로 if(item.getFieldName().equals("image_file")) { if(item.getSize() > 0) { String ext = item.getName().substring(item.getName().lastIndexOf(".")+1); //파일 기본경로 String defaultPath = request.getServletContext().getRealPath("/"); //파일 기본경로 _ 상세경로 String path = defaultPath + "upload" + File.separator; File file = new File(path); //디렉토리 존재하지 않을경우 디렉토리 생성 if(!file.exists()) { file.mkdirs(); } //서버에 업로드 할 파일명(한글문제로 인해 원본파일은 올리지 않는것이 좋음) realname = UUID.randomUUID().toString() + "." + ext; size = item.getSize(); ///////////////// 서버에 파일쓰기 ///////////////// InputStream is = item.getInputStream(); OutputStream os=new FileOutputStream(path + realname); 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(); ///////////////// 서버에 파일쓰기 ///////////////// } } } response.setContentType("text/plain; charset=UTF-8"); PrintWriter pw = response.getWriter(); //json string 값으로 callback //json 값으로 넘기는 필요 값 //imageurl, filename,filesize,imagealign pw.print("{\"imageurl\" : \"/upload/"+realname+"\",\"filename\":\""+realname+"\",\"filesize\": 600,\"imagealign\":\"C\"}"); pw.flush(); pw.close(); }
java.io.PrintWriter java.util.UUID java.io.File java.io.FileOutputStream java.io.OutputStream java.io.InputStream java.util.List org.apache.commons.fileupload.disk.DiskFileItemFactory org.apache.commons.fileupload.servlet.ServletFileUpload org.apache.commons.fileupload.FileItem
이걸로 다음에디터내에 이미지 첨부 샘플구현이 완료되었습니다.
그럼 실행결과를 끝으로 포스팅을 마무리 짓도록 하겠습니다.
다음에디터 실행
사진버튼 클릭후 팝업창띄우기
이미지 선택완료
에디터 이미지 삽입하기
Spring을 이용한 다음에디터 연동법 역시 추후에 포스팅 하도록 하겠습니다.
by 개발로짜
jQuery를 적용한 다음에디터 기본연동 및 서버에 입력내용 전송법 (5) | 2014.10.30 |
---|
스마트에디터 연동 및 사진 첨부 방법에 이어서
2014/10/29 - [코드저장소/스마트에디터연동] - 네이버 스마트에디터 기본연동법 및 서버에 입력값 전송하기
2014/10/29 - [코드저장소/스마트에디터연동] - 네이버 스마트에디터 사진첨부기능을 이용하여 에디터에 이미지 추가하기+다중파일업로드 포함
다음에디터 연동 및 서버에 컨텐츠 내용 전송하는 방법에 대하여 포스팅 하도록 하겠습니다.
https://github.com/daumcorp/DaumEditor
위사이트 접속하여 다운로드버튼을 클릭하여 에디터 압축파일을 다운받도록 합니다.
다운이 완료되었다면 압축해제 후 daumeditor 디렉토리를 들어가시면 하단 파일들이 존재합니다.
위에 있는 파일들중 네모친 파일들을 모두 본인의 프로젝트 경로에 include 하도록 합니다.
※ converting.html,editor.html,editor_multi.html 은 필요가 없으므로 넣어주셔도 되고 않넣어주셔도 됩니다.
저는 daumeditor라는 디렉토리를 생성후 하단에 모두 include 해주었습니다.
그리도 daumeditor 디렉토리 밑에 하단 파일을 include 해주세요.
스마트에디터의 경우 iframe 내에 에디터프레임을 그려주는데 비해
다음에디터의 경우는 html코드자체를 페이지 내에 직접 작성하므로
한페이지에 코드량이 상당히 길어집니다.
editor_frame.html 페이지에 별도로 에디터프레임 태그들만 넣어놓은 것입니다.
※ 만약 에디터 소스들을 넣어놓은 디렉토리명이 "daumeditor"가 아니라면
다운받아서 넣어주신 editor_frame.html 페이지내에 /daumeditor/ 경로를
자신의 경로에 맞춰주셔야 합니다.
이어서 에디터 출력코드를 작성하기 위한 html 파일을 하나 생성하겠습니다.
저는 index.html 파일을 WEB-ROOT에 생성하였습니다.
먼저 필요한 css파일 및 js파일을 include 해주도록 합니다.
<link rel="stylesheet" href="/daumeditor/css/editor.css" type="text/css" charset="utf-8"/> <script src="/daumeditor/js/editor_loader.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript" src="//code.jquery.com/jquery-1.11.0.min.js"></script>
이어서 HTML 폼구조를 다음과 같이 작성해줍니다.
<!-- 에디터 시작 --> <div> <form name="frm" id="frm" action="/send.jsp" method="post" accept-charset="utf-8"> <!-- 에디터프레임호출 영역 --> <div id="editor_frame"></div> <!-- 실제 값이 담겨져서 넘어갈 textarea 태그 --> <textarea name="daumeditor" id="daumeditor" rows="10" cols="100" style="width:766px; height:412px;display: none;"></textarea> <input type="button" id="save_button" value="내용전송"/> </form> </div> <!-- 에디터 끝 -->
마지막으로 editor_frame div태그내에
다음에디터프레임을 적용하기 위한 코드와
내용전송 버튼 클릭시 send.jsp 페이지로 다음에디터에 입력한
컨텐츠 내용값을 전송하기 위한 submit 기능에 대한 스크립트 코드입니다.
$(function(){ $.ajax({ url : "/daumeditor/editor_frame.html", success : function(data){ $("#editor_frame").html(data); // 에디터UI load var config = { /* 런타임 시 리소스들을 로딩할 때 필요한 부분으로, 경로가 변경되면 이 부분 수정이 필요. ex) http://xxx.xxx.com */ txHost: '', /* 런타임 시 리소스들을 로딩할 때 필요한 부분으로, 경로가 변경되면 이 부분 수정이 필요. ex) /xxx/xxx/ */ txPath: '', /* 수정필요없음. */ txService: 'sample', /* 수정필요없음. 프로젝트가 여러개일 경우만 수정한다. */ txProject: 'sample', /* 대부분의 경우에 빈문자열 */ initializedId: "", /* 에디터를 둘러싸고 있는 레이어 이름(에디터 컨테이너) */ wrapper: "tx_trex_container", /* 등록하기 위한 Form 이름 */ form: "frm", /*에디터에 사용되는 이미지 디렉터리, 필요에 따라 수정한다. */ 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 } }; //에디터내에 환경설정 적용하기 new Editor(config); } }); //form submit 버튼 클릭 $("#save_button").click(function(){ //다음에디터가 포함된 form submit Editor.save(); }) }) //Editor.save() 호출 한 다음에 validation 검증을 위한 함수 //validation 체크해줄 입력폼들을 이 함수에 추가 지정해줍니다. function validForm(editor) { var validator = new Trex.Validator(); var content = editor.getContent(); if (!validator.exists(content)) { alert('내용을 입력하세요'); return false; } return true; } //validForm 함수까지 true값을 받으면 이어서 form submit을 시켜주는 setForm함수 function setForm(editor) { var content = editor.getContent(); $("#daumeditor").val(content) return true; }
위에 코드중 다음에디터 SUBMIT 실행과정은 다음과 같습니다.
1. Editor.save()
submit기능의 첫단계
2. validForm()
다음에디터 내에 자체적으로 호출되는 함수입니다.
폼필드내에 입력태그들에 대한 validation 처리를 해당 함수에서 처리해주시면 되겠습니다.
3. setForm()
최종적으로 submit 전송전에 display:none 해놓은 실제로 컨텐츠 내용을 서버로 전송해 줄 textarea에
다음에디터에 입력된 내용을 넣어주는 작업함수입니다
그리고 /daumeditor/js/editor.js 파일을 보시면
약 89번째 라인에 "trex/attachbox/attachbox_ui.js", 라는 코드가 있는데
주석처리 해주십니다.
사진첨부가 되면 어떠한 박스내에 파일정보를 추가해주는건대
별 의미없는 기능이라 생각되어 사용하지 않기로 했습니다.
실행 해보시면 에디터 우측하단에 "DEVELOPMENT MODE" 라고 출력이 되는데 보기 싫습니다요잉~
출력을 원하지 않다면 "/daumeditor/js/development_environments.js" 파일 58번째 줄에 있는
indicator.innerHTML = "DEVELOPMENT MODE";
위 코드를 주석처리 해주세요.
그럼 문구가 사라집니다.
에디터 실행화면
에디터 서버 전송 결과
네이버 스마트와 동일하게 서버에 정상적으로 값이 전송된 것을 확인 할 수 있었습니다.
다음에는네이버 스마트에디터와 동일한 사진첨부 관련 포스팅을 진행하도록 하겠습니다.
by 개발로짜
jQuery Form 플러그인 + 다음에디터를 이용하여 에디터영역에 이미지업로드하기 (27) | 2014.10.30 |
---|
ExtJS에서 스토어는 상당히 자주 사용되는 ExtJS 클래스입니다.
앞으로 girdpanel,treepanel,combo 등...
다양한 컴포넌트에 store 클래스를 사용하게 되므로
이번 포스팅을 통하여 스토어 개념을 잡아보도록 하겠습니다.
가장 심플하게 구현이 가능한 콤보박스 컴포넌트를 예를들어 이해를 돕도록 하겠습니다.
데이터들을 담아주는 역할을 하는 클래스입니다.
HTML태그로 예를들자면 SELECT BOX에 목록을 출력시켜주려면 OPTION 태그가 필요합니다.
<select> <option value="1">첫번째값</option> <option value="2">두번째값</option> <option value="3">세번째값</option> </select>
option이 있어야 화면에 key값이 출력되고 value값이 선택되면 서버전송이 가능한 기능을 해줍니다.
만약 option 태그가 없다면 select 태그는 그저 빈 껍데기에 불과하겠죠?
이 option 태그와 같은 역할을 하는 기능이 store 클래스입니다.
store클래스를 사용하여 콤보박스를 구현해보도록 하겠습니다.
Ext.onReady(function(){ Ext.create('Ext.panel.Panel',{ renderTo : Ext.getBody(), width : 300, height : 300, title : '콤보박스예제코드', items : [{ //콤보박스 컴포넌트 선언 xtype : 'combo', //최초에는 빈값이 출력되므로 설정 emptyText : '선택', //화면에 보여주는 store data속성의 key값 displayField: 'display', //실제 선택되었을때의 store data속성의 key값 valueField: 'value', //default true값이여서 화면에 보여지는 displayField값 수정이 됩니다. //false로 지정해줘야 제대로된 콤보박스기능이 동작됩니다. editable : false, store : Ext.create("Ext.data.Store",{ //data 속성의 json object에 정의된 key 값들과 매칭시켜줍니다. fields : ['display','value'], //저장공간에 fix값으로 data 속성에 json array type으로 담아줍니다. data : [{ display : '보여주는화면1', value : '선택값1', },{ display : '보여주는화면2', value : '선택값2', },{ display : '보여주는화면3', value : '선택값3', },{ display : '보여주는화면4', value : '선택값4', },{ display : '보여주는화면5', value : '선택값5', }], //data 속성에 fix값이 정의되있으므로 type을 memory로 정해줍니다. proxy : { type : 'memory' } }) }] }) })
위 코드를 설명하자면 패널에 combo박스 컴포넌트를 생성(html 기준 select태그 생성)한 다음
store의 data 속성을 통하여 disply/value값(option 태그에 해당)을 선언해 주었습니다.
스토어 클래스에 fields의 key값을 data속성의 key값과 일치 시켜주어야 합니다.
fields 속성은 store의 model 속성에도 존재합니다.
fields 속성만을 사용해도 무관합니다.
간단하게나마 store 클래스의 fields 속성대신 model 속성을 적용해보도록 하겠습니다.
Ext.create("Ext.data.Store",{ //data 속성의 json object에 정의된 key 값들과 매칭시켜줍니다. model : Ext.create("Ext.data.Model",{ fields: ['display','value'] }), //저장공간에 fix값으로 data 속성에 json array type으로 담아줍니다. data : [{ display : '보여주는화면1', value : '선택값1', },{ display : '보여주는화면2', value : '선택값2', },{ display : '보여주는화면3', value : '선택값3', },{ display : '보여주는화면4', value : '선택값4', },{ display : '보여주는화면5', value : '선택값5', }], //data 속성에 fix값이 정의되있으므로 type을 memory로 정해줍니다. proxy : { type : 'memory' } })
실행화면 먼저 보고 설명을 진행하도록 하겠습니다.
콤보박스 초기화면
콤보박스 목록 OPEN
콤보박스 목록 선택
model 사용하는법이나 fields 사용하는 법이나 별 차이가 없습니다.
1회성으로 사용을 하여 model 속성에 직접적으로 create 해서 적용을 해주었습니다.
예를들어 콤보박스의 경우 보통 2개의 key/value fields 만 있으면 됩니다.
이럴경우, 계속 같은 fields인대 store 적용할때마다 create model을 해주어야 할까요?
그렇게 되면 같은코드도 반복되면서 소스자체가 길어지고 유지보수도 힘들어 지겠죠?
이럴경우 자주사용되는 model을 정의해놓은 후 만들어놓은 모델만 사용을 하게된다면 오히려 간결해지겠습니다.
나누는 부분에 대해서는 MVC구조에 대하여 포스팅때 진행하도록 하겠습니다.
MVC 구조로 나누게 되면 STORE 역시 정의하여 재활용이 가능합니다.
뭐... 우선은 "아 그렇구나~" 라는 정도만 알고계시라고요 ㅎㅎ
이번 포스팅은 proxy type을 memory에대하여 설명하였는데
다음 장은 proxy type이 ajax에 대하여 포스팅 하도록 하겠습니다.
by 개발로짜
ExtJS 강좌 - 그리드패널을 출력시키기 위하여 이해를 한 후 출력시켜보자 (0) | 2014.11.03 |
---|---|
ExtJS 강좌 - 데이터스토어(store)의 proxy ajax를 통하여 콤보박스 목록 출력시켜보기 (0) | 2014.10.30 |
ExtJS 강좌 - ExtJS 사이트에서 제공하는 API DOCUMENT문서 사용하는 방법 (0) | 2014.10.28 |
ExtJS 강좌 - 파일필드를 이용하여 파일업로드하기(html5를 이용한 다중파일 포함) (17) | 2014.10.28 |
ExtJS 강좌 - xtype을 이용하여 html의 입력태그들과 HTML에디터 컴포넌트를 출력시켜보자 (0) | 2014.10.27 |