게시판의 본문을 블로그 작성하듯 도와주는 소프트웨어로 네이버에서 제공하는 스마트에디터가 있다. 이것을 스프링 MVC 프로젝트에서 적용하는 방법을 기술한다.
1. 이클립스에서 File>New>Spring Legacy Project>Spring MVC Project로 새로운 스프링 프로젝트 se를 생성한다.
- 새로 만든 스프링 프로젝트는 기본적으로 "/"가 HomeController에서 동작하여 home.jsp를 처움에 보여준다.
2. home.jsp를 "게시글 쓰기" 형태로 수정한다.
1 <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
2 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
3 <%@ page session="false" %>
4 <html>
5 <head>
6 <title>Home</title>
7 <script type="text/javascript" src="<c:url value="/resources/js/jquery-1.11.3.min.js"/>"></script>
8 <script type="text/javascript" src="<c:url value="/resources/smarteditor/js/HuskyEZCreator.js"/>" charset="utf-8"></script>
9 <script type="text/javascript" charset="utf-8" src="<c:url value="/resources/js/writeForm.js"/>"></script>
10 <link rel="stylesheet" href="<c:url value="/resources/css/common.css"/>"/>
11 <script type="text/javascript" charset="utf-8">
12 sessionStorage.setItem("contextpath", "${pageContext.request.contextPath}");
13 </script>
14 </head>
15 <body>
16 <form action="write" method="post" id="frm">
17 <table>
18 <tr>
19 <td>제목</td>
20 <td><input type="text" name="title" id="title" placeholder="제목"></td>
21 </tr>
22 <tr>
23 <td style="margin:0; padding:0;" colspan="2"><textarea name="smarteditor" id="smarteditor" rows="10" cols="100" style="width:100%; height:412px;"></textarea></td>
24 </tr>
26 </table>
27 <input id="addBtn" type="submit" value="전송">
28 </form>
29 </body>
30 </html>
1줄 : pageEncoding을 UTF-8로 설정
7줄 : Ajax Operation을 위해 jquery js (jquery-1.11.3.min.js)를 사용
8줄 : 스마트에디터를 사용하기 위해 필요
9줄 : javascript를 정의하기 위해 writeForm.js를 사용
10줄 : 디자인을 깨끗하게 하기 위해 common.css를 사용
11줄~13줄 : contextPath를 javascript에서 사용하기 위해 sessionStorage에 저장
16줄 : form을 사용. "전송" 버튼을 누르면 javascript에서 textarea에 입력된 데이터를 가져와 request에 추가하도록 처리를 한다. 이후 서버로 입력 파라미터들이 전달되고 action=write가 서버에서 수행됨.
23줄 : 스마트에디터를 사용하여 본문을 입력하도록 정의해 준다.
27줄 : 전송 버튼을 누르면 javascript가 동작
3. smarteditor 파일들 : http://naver.github.io/smarteditor2/user_guide/ 참조
- SmartEditor Basic 2.0은 JavaScript로 구현된 웹 기반의 WYSIWYG 편집기이다. 글꼴, 글자 크기, 줄 간격 등을 자유롭게 설정할 수 있으며, 단어 찾기/바꾸기와 같은 편리한 기능을 제공한다.
- https://github.com/naver/smarteditor2에서 최신 버전을 다운로드
-> 이 버전은 사진(이미지) 업로드 기능이 삭제된 것이다. 무슨 이유인지 모르겠지만 네이버가 이 기능을 배포판에서 빼 버렸다.
+ src/main/webapp/resources/smarteditor 디렉토리 밑에 다음과 같은 파일이 존재
# attach_photo.js // 사진 추가에 대한 javascript 처리 (서버와 연동하여 파일 저장)
# callback.html // 사진 추가에 대한 결과 처리
# file_uploader.php // 다중 사진(이미지) 본문 추가에 대한 서버 처리 루틴 (PHP 방식)
# file_uploader_html5.php // 단일 사진(이미지) 본문 추가에 대한 서버 처리 루틴 (PHP 방식)
# photo_uploader.html // popup 창에 대한 HTML 파일
+ 일부 파일 생략 (...)
4. writeForm.js
1 $(function() {
2 //전역변수선언
3 var editor_object = [];
4 var ctx = getContextPath();
5
6 nhn.husky.EZCreator.createInIFrame({ // 입력 창을 구성하는 부분을 구동
7 oAppRef: editor_object,
8 elPlaceHolder: "smarteditor",
9 sSkinURI: ctx + "/resources/smarteditor/SmartEditor2Skin.html",
10 htParams : {
11 // 툴바 사용 여부 (true:사용/ false:사용하지 않음)
12 bUseToolbar : true,
13 // 입력창 크기 조절바 사용 여부 (true:사용/ false:사용하지 않음)
14 bUseVerticalResizer : true,
15 // 모드 탭(Editor | HTML | TEXT) 사용 여부 (true:사용/ false:사용하지 않음)
16 bUseModeChanger : true,
17 fOnBeforeUnload : function(){
18
19 }
20 }
21 });
22
23 //전송버튼 클릭이벤트
24 $("#addBtn").click(function(){
25 //id가 smarteditor인 textarea에 에디터에서 대입
26 editor_object.getById["smarteditor"].exec("UPDATE_CONTENTS_FIELD", []);
27
28 // 이부분에 에디터 validation 검증 : 때에 따라 가비지 correction 등에 대한 처리 필요
29 var el = document.createElement('html');
30 el.innerHTML = editor_object.getById["smarteditor"].elPlaceHolder.value; // 본문 정보 넣기
31 //폼 submit
32 $("#frm").submit(); // 서버로 전송 (게시글 추가 처리 요청)
33 });
34
35 function getContextPath() {
36 return sessionStorage.getItem("contextpath");
37 }
38 });
6~21줄 : home.jsp에서 사용한 textarea 부분을 구성해 주는 부분
23~33줄 : textarea에 입력한 정보를 "smarteditor"란 parameter에 넣어주고 form 형태로 서버로 전송
5. 사진(이미지) 추가에 대한 동작 처리 : smarteditor/photo_uploader/popup/attach_photo.js
- 사진(이미지)를 추가하는 방법은 하나의 이미지만 추가 하는 방법과 여러 개의 사진을 추가하는 방법으로 두 가지를 제공한다. 필요에 따라 자신에게 맞는 방법을 선택한다.
+ 아래 처럼 bSupportDragAndDropAPI 값을 true/false로 설정함에 따라 다르게 설정된다.
//File API 지원 여부로 결정
function checkDragAndDropAPI(){
try{
if( !oNavigator.ie ){
if(!!oNavigator.safari && oNavigator.version <= 5){
bSupportDragAndDropAPI = false;
}else{
bSupportDragAndDropAPI = true; // multiple 파일 업로드
// bSupportDragAndDropAPI = false; // single 파일 업로드
}
} else {
bSupportDragAndDropAPI = false;
}
}catch(e){
bSupportDragAndDropAPI = false;
}
}
- function html5Upload() // 하나의 사진 이미지 추가에 대한 처리
+ popup 창이 뜨고, 다음을 선택한 후 확인 버튼을 누르면, 선택한 사진을 서버로 전송하는 부분
+ sUploadURL = '/se/file_uploader_html5'; // 사진 업로드 URL
- function callFileUploader() // 다중 사진 이미지 추가에 대한 처리
+ sUrl : '/se/file_uploader', // 서버에서 처리하는 URL
+ sCallback : '/resources/smarteditor/photo_uploader/popup/callback.html', // 처리 결과 응답
6. HomeController.java // 사진 이미지 추가에 대한 처리
- resources/upload 디렉토리에 사진 이미지 저장 (실제 저장되는 폴더는 workspace/.metadata/.plugins/\org.eclipse.wst.server.core\tmp1\wtpwebapps\se\resources\upload 밑에 저장됨
@RequestMapping(value="/file_uploader", method=RequestMethod.POST)
public void file_uploader(HttpServletRequest request, HttpServletResponse response) throws IOException, FileUploadException {
request.setCharacterEncoding("utf-8");
String return1="";
String return2="";
String return3="";
String name = "";
if (ServletFileUpload.isMultipartContent(request)){
ServletFileUpload uploadHandler = new ServletFileUpload(new DiskFileItemFactory());
//UTF-8 인코딩 설정
uploadHandler.setHeaderEncoding("UTF-8");
List<FileItem> items = uploadHandler.parseRequest(request);
//각 필드태그들을 FOR문을 이용하여 비교를 합니다.
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")) {
//FILE 태그가 1개이상일 경우
if(item.getSize() > 0) {
name = item.getName();
String ext = item.getName().substring(item.getName().lastIndexOf(".")+1);
//파일 기본경로
String defaultPath = context.getRealPath("/");
//파일 기본경로 _ 상세경로
String path = defaultPath + "upload" + File.separator;
File file = new File(path);
//디렉토리 존재하지 않을경우 디렉토리 생성
if(!file.exists()) {
file.mkdirs();
}
//서버에 업로드 할 파일명(한글문제로 인해 원본파일은 올리지 않는것이 좋음)
String realname = UUID.randomUUID().toString() + "." + ext;
///////////////// 서버에 파일쓰기 /////////////////
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();
///////////////// 서버에 파일쓰기 /////////////////
String root = request.getContextPath();
return3 += "&bNewLine=true&sFileName="+name+"&sFileURL=" + root + "/upload/"+realname; // by ksseo
}else {
return3 += "&errstr=error";
}
}
}
}
response.sendRedirect(return1+return2+return3);
}
- 추후 가비지 correction이 진행되어야 함. (사진 이미지를 추가한 후 삭제할 경우, 또는 사진을 추가하면서 글을 작성하다가 다른 창으로 이동할 경우 등) -> writeForm.js에서 처리해 주어야 함
- form에 대한 처리 : 데이터베이스에 게시글 정보 저장 (여기서는 생략...)
@RequestMapping(value = "/write", method = RequestMethod.POST)
public ModelAndView write(HttpServletRequest request) throws IOException, FileUploadException {
String title = request.getParameter("title");
String smarteditor = request.getParameter("smarteditor");
ModelAndView model = new ModelAndView("write");
model.addObject("title", title);
model.addObject("smarteditor", smarteditor);
return model;
}
7. pom.xml 고려사항 : file upload dependency 추가
<!-- file upload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
8. servlet-context.xml 고려사항 : multipartResolver 추가
<beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<beans:property name="maxUploadSize" value="52428800"></beans:property>
</beans:bean>
9. write.jsp : 게시글 추가 결과를 보여주는 뷰
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>홈 페이지</title>
</head>
<body>
게시글 작성 완료
제목 : ${title}<br>
본문 : <br>
${smarteditor}
</body>
</html>
10. common.css : 게시글 쓰기 CSS 파일
@CHARSET "UTF-8";
* {
margin: 0px;
padding: 0px;
border: 0;
}
html[lang^="ko"] {
font-family: "Nanum Gothic", "나눔 고딕", "NanumGothic", sans-serif;
}
/* content */
body {
width: 980px;
margin: 0 auto;
margin-top: 5px;
min-height: 770px;
}
form {
margin-top: 20px;
line-height: 2;
}
#addBtn {
width: 200px;
font-size: 14px;
padding: 10px;
background-color: blue;
color: white;
border-radius: 5px 5px 5px 5px;
margin-top:30px;
}
table {
border: 1px solid black;
border-collapse: collapse;
border-spacing: 0px;
margin-top: 20px;
width: 100%;
}
td {
border: 1px solid black;
border-collapse: collapse;
border-spacing: 0px;
padding: 5px;
line-height: 1.5;
}
가비지 correction 과정은 추후 기술한다.
수고 하셨습니다.
참고 : http://hellogk.tistory.com/63
'웹개발' 카테고리의 다른 글
게시판 관리기능 : 여러 개의 게시판이 필요할 때 (1/5) (0) | 2017.03.04 |
---|---|
개인정보를 암호화해서 저장하는 방법(JSP) (0) | 2017.03.03 |
PhoneGap 개발 환경 설치 (Adobe PhoneGap 사이트 참조) (0) | 2017.02.09 |
sample 프로젝트 소스 코드 (0) | 2017.02.07 |
스프링 MVC 프로젝트에 ojdbc6.jar 파일을 적용하는 방법 (0) | 2017.02.06 |