참조 :
http://macaronics.net/index.php/m01/java/view/143
* Smart Editor, WYSIWYG Editor(위지윅 에디터, what you see is what you get)
- 사용자가 현재 화면에서 보고 있는 내용과 동일한 html code를 생성하는 에디터
- 네이버, 다음 에디터, CKEditor, SummerNote 등
* CKEditor
- Standard Package 다운로드
- 이미지 업로드를 위해서는 별도의 작업이 필요함
- 적용 예
* SummerNote
- 이미지를 텍스트 형식으로 저장함, 이미지 링크 방식의 업로드를 위해서는 별도의 작업이 필요함
- 적용 예
CKeditor 업로드 설정은 다음 4가지만 고려하면 된다.
1. CKEditor 에서 파일을 넘겨주는 이름이 upload 로 설정 되어 있다. 반드시 upload 로 설정
@RequestMapping(value="/ckeditorupload")
public void imageUpload(HttpServletRequest request, HttpServletResponse response,
@RequestParam MultipartFile upload ) throws Exception{
2. 물리적 실제 저장소 설정
1)
servlet-context.xml
<!-- 서버의 파일 저장 경로 설정 --> <beans:bean id="uploadPath" class="java.lang.String"> <beans:constructor-arg value="D:\dev\spring_simple_blog\.metadata\.plugins\org.eclipse.wst.server.core\tmp1\wtpwebapps\upload" /> </beans:bean>
//파일 디렉토리 사용시 @Resource(name="uploadPath") private String uploadPath;
UploadFileUtils
ckeditor 전용 파일 업로드를 만들었다.
썸네일 주소를 반환하는 것이 아닌 실제 이미지지 주소 반환
/**
* <pre>
* 1. 패키지명 : net.macaronics.web.controller
* 2. 타입명 : test2.java
* 3. 작성일 : 2017. 10. 24. 오후 7:40:39
* 4. 저자 : 최준호
*
* </pre>
*
*/
package config.upload;
import java.awt.image.BufferedImage;
import java.io.File;
import java.text.DecimalFormat;
import java.util.Calendar;
import java.util.UUID;
import javax.imageio.ImageIO;
import org.imgscalr.Scalr;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.FileCopyUtils;
public class UploadFileUtils {
private static final Logger logger = LoggerFactory.getLogger(UploadFileUtils.class);
private static Integer WIDTH_SIZE = 100;
public static Integer getWIDTH_SIZE() {
return WIDTH_SIZE;
}
public static void setWIDTH_SIZE(Integer wIDTH_SIZE) {
WIDTH_SIZE = wIDTH_SIZE;
}
// 1.파일의 저장 경로(uploadPath), 2.원본 파일의 이름(originalName), 3.파일 데이터(byte[])
public static String uploadFile(String uploadPath, String originalName, byte[] fileData) throws Exception {
// ★ 1. 고유값 생성
UUID uid = UUID.randomUUID();
String savedName = uid.toString() + "_" + originalName;
// ★ 2. 년/월/일' 정보 생성
String savedPath = calcPath(uploadPath);
// ★ 3. 원본파일 저장
File target = new File(uploadPath + savedPath, savedName);
FileCopyUtils.copy(fileData, target);
// ★ 4. 이미지 일경우 썸네일 이미지 생성 후 url 주소로 반환
String formatName = originalName.substring(originalName.lastIndexOf(".") + 1);
String uploadedFileName = null;
if (MediaUtils.getMediaType(formatName) != null) {
// 이미지일 경우 썸네일 생성 후 이미지 이름 반환 ( 경로+년월일+s_이름)
uploadedFileName = makeThumbnail(uploadPath, savedPath, savedName);
} else {
uploadedFileName = makeIcon(uploadPath, savedPath, savedName);
}
// 파일 경로를 -> url 경로로 변경해서 반환
return uploadedFileName;
}
// ckeditor 전용 업로드 파일 반환 된값이 썸네일이 아닌 원본 이미지
// 1.파일의 저장 경로(uploadPath), 2.원본 파일의 이름(originalName), 3.파일 데이터(byte[])
public static String ckuploadFile(String uploadPath, String originalName, byte[] fileData) throws Exception {
// ★ 1. 고유값 생성
UUID uid = UUID.randomUUID();
String savedName = uid.toString() + "_" + originalName;
// ★ 2. 년/월/일' 정보 생성
String savedPath = calcPath(uploadPath);
// ★ 3. 원본파일 저장
File target = new File(uploadPath + savedPath, savedName);
FileCopyUtils.copy(fileData, target);
// ★ 4. 이미지 생성 후 url 주소로 반환
String uploadedFileName = makeIcon(uploadPath, savedPath, savedName);
// 파일 경로를 -> url 경로로 변경해서 반환
return uploadedFileName;
}
// 이미지가 아닐경우 단지 파일 경로를 -> url 경로로 변경해서 반환
private static String makeIcon(String uploadPath, String savedPath, String savedName) {
String iconName = uploadPath + savedPath + File.separator + savedName;
return iconName.substring(uploadPath.length()).replace(File.separatorChar, '/');
}
// 파일이 저장될 '년/월/일' 정보 생성
private static String calcPath(String uploadPath) {
Calendar cal = Calendar.getInstance();
// 역슬래시 + 2017
String yearPath = File.separator + cal.get(Calendar.YEAR);
// /2017 +/+ 10 한자리 월 일경우 01, 02 형식으로 포멧
String monthPath = yearPath + File.separator + new DecimalFormat("00").format(cal.get(Calendar.MONTH) + 1);
// /2017/10 +/ + 22
String datePath = monthPath + File.separator + new DecimalFormat("00").format(cal.get(Calendar.DATE));
// 년월일 폴더 생성하기
makeDir(uploadPath, yearPath, monthPath, datePath);
logger.info(" datePath - {}", datePath);
return datePath;
}
// 실질 적인 날짜 폴더 생성
private static void makeDir(String uploadPath, String... paths) {
if (new File(paths[paths.length - 1]).exists()) {
// 년 월 일 에서 일 배열 paths 에서 paths -1 은 일 즉 해당일의 폴더가 존재하면 return
return;
}
for (String path : paths) {
File dirPath = new File(uploadPath + path);
if (!dirPath.exists()) {
// 년 월일에 대한 해당 폴더가 존재하지 않으면 폴더 생성
dirPath.mkdir();
}
}
}
// 썸네일 이미지 생성하기
// 1.파일 경로 2. 년월일 경로, 3. 파일 이름
private static String makeThumbnail(String uploadPath, String path, String fileName) throws Exception {
// 파일 존재하는 이미지를 메모리상 이미지에 올려 붙인다. 즉 메모리에 로딩시킨다.
BufferedImage sourceImg = ImageIO.read(new File(uploadPath + path, fileName));
// 메모리상 이미지를 정해진 크기에 맞게 복사한다.
BufferedImage destImage = Scalr.resize(sourceImg, Scalr.Method.AUTOMATIC, Scalr.Mode.FIT_TO_HEIGHT, WIDTH_SIZE);
// 썸네일 이미지 이름을 정한다. 썸네일 이미지를 앞에 s_ 붙인다.
String thumbnailName = uploadPath + path + File.separator + "s_" + fileName;
// 파일 경로의 객체를 생성한다.
File newFile = new File(thumbnailName);
// 경로의 마지막 에 . 으로 중심으로 분리해서 .jpg, png, jpeg gif 의 문자를 추출한다.
String formatName = fileName.substring(fileName.lastIndexOf(".") + 1);
// 실질적인 썸네일 이미지를 복사한다.
ImageIO.write(destImage, formatName.toUpperCase(), newFile);
// 파일 경로인 역슬러시를 url 의 경로인 슬러시로 변경해서 해서 반환시킨다.
return thumbnailName.substring(uploadPath.length()).replace(File.separatorChar, '/');
}
}
2) 스프링의 resources 폴더를 사용할 경우
package config.upload;
import java.io.File;
import javax.servlet.http.HttpServletRequest;
public class UploadPath {
public static String attach_path = "resources/upload/";
public static String path(HttpServletRequest request) {
String uploadPath = "";
try {
String root_path = request.getServletContext().getRealPath("/");
uploadPath = root_path + attach_path.replace('/', File.separatorChar);
} catch (Exception e) {
e.printStackTrace();
}
return uploadPath;
}
}
3. url 보여줄 주소 설정
public ResponseEntity<byte[]> disPlay(String fileName, String uploadPath) throws Exception{
//fileName 은 /년/월/일/파일명의 형태로 입력을 받는다.
InputStream in=null;
//ResponseEntity<byte[]> 로 결과는 실제로 파일의 데이터가 된다.
//컨트롤에서 @ResponseBody 를 이용해야 하며
//byte[] 데이터가 그대로 전송될 것임을 명시한다.
ResponseEntity<byte[]> entity=null;
logger.info("File NAME : "+ fileName);
try{
String formatName =fileName.substring(fileName.lastIndexOf(".")+1);
MediaType mType =MediaUtils.getMediaType(formatName);
HttpHeaders headers =new HttpHeaders();
// 경로 +/년/월/일 /파일이름
in =new FileInputStream(uploadPath+fileName);
if(mType!=null){
//이미지인 경우
headers.setContentType(mType);
}else{
//이미지가 아닌 경우
//MIME 타입을 다운로드 용으로 사용되는 'application/octet-stream 으로 지정한다.
//브라우저는 이 MIME 타입을 보고 사용자에게 자동으로 다운로드 창을 열어 준다.
fileName=fileName.substring(fileName.indexOf("_")+1);
//한글 깨짐 방지 설정
//다운로드 할 때 사용자에게 보이는 파일의 이름이므로 한글 처리를 해서
// 전송합니다. 한글 파일의 경우 다운로드 하면 파일의 이름이 깨져서
// 나오기 반드시 인코딩 처리를 할 필요가 있다.
String attach="\""+new String(fileName.getBytes("UTF-8"), "ISO-8859-1")+"\"";
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.add("Content-Disposition", "attachment; filename="+attach);
}
//실제로 데이터를 읽는 부분은 commons 라이브러리의 기능을 활용해서 대상
// 파일에서 데이터를 읽어내는 IOUtils.toByteArray() 이다.
entity=new ResponseEntity<byte[]>(IOUtils.toByteArray(in), headers, HttpStatus.CREATED);
}catch(Exception e){
e.printStackTrace();
entity=new ResponseEntity<byte[]>(HttpStatus.BAD_REQUEST);
}finally{
in.close();
}
return entity;
}
@ResponseBody
@RequestMapping("/displayFile")
public ResponseEntity<byte[]> displayFile(String fileName) throws Exception{
UploadFileDisplay display=UploadFileDisplay.getInstance();
return display.disPlay(fileName, uploadPath);
}
4. 반환될 자바스크립트 설정
응답해서 보여줄 자바스크립트는 다음과 같다.
샘프로 코드는 php 이다.
<script type='text/javascript'> window.parent.CKEDITOR.tools.callFunction($callback, $url, $message); </script>
callback 값은 다음과 같은 파라미터로 가져오면 된다.
String callback =request.getParameter("CKEditorFuncNum");
url 은 파일을 저장 후에 이미지를 출력해주는 url 을 적으면 된다.
출력 글은 바로 앞 글에서 적었다.
<a href='/displayFile?fileName="+년월일 이미지명+"' ><img src='/displayFile?fileName="+년월일 이미지명+"'/></a>
message =이미지를 업로드 했습니다.
전체 소스
UploadPath
/**
* <pre>
* 1. 패키지명 : config.upload
* 2. 타입명 : UploadPath.java
* 3. 작성일 : 2017. 10. 24. 오후 8:32:41
* 4. 저자 : 최준호
*
* </pre>
*
*/
package config.upload;
import java.io.File;
import javax.servlet.http.HttpServletRequest;
public class UploadPath {
public static String attach_path = "resources/upload/";
public static String path(HttpServletRequest request) {
String uploadPath = "";
try {
String root_path = request.getServletContext().getRealPath("/");
uploadPath = root_path + attach_path.replace('/', File.separatorChar);
} catch (Exception e) {
e.printStackTrace();
}
return uploadPath;
}
}
UploadFileUtils
/**
* <pre>
* 1. 패키지명 : net.macaronics.web.controller
* 2. 타입명 : test2.java
* 3. 작성일 : 2017. 10. 24. 오후 7:40:39
* 4. 저자 : 최준호
*
* </pre>
*
*/
package config.upload;
import java.awt.image.BufferedImage;
import java.io.File;
import java.text.DecimalFormat;
import java.util.Calendar;
import java.util.UUID;
import javax.imageio.ImageIO;
import org.imgscalr.Scalr;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.FileCopyUtils;
public class UploadFileUtils {
private static final Logger logger = LoggerFactory.getLogger(UploadFileUtils.class);
private static Integer WIDTH_SIZE = 100;
public static Integer getWIDTH_SIZE() {
return WIDTH_SIZE;
}
public static void setWIDTH_SIZE(Integer wIDTH_SIZE) {
WIDTH_SIZE = wIDTH_SIZE;
}
// 1.파일의 저장 경로(uploadPath), 2.원본 파일의 이름(originalName), 3.파일 데이터(byte[])
public static String uploadFile(String uploadPath, String originalName, byte[] fileData) throws Exception {
// ★ 1. 고유값 생성
UUID uid = UUID.randomUUID();
String savedName = uid.toString() + "_" + originalName;
// ★ 2. 년/월/일' 정보 생성
String savedPath = calcPath(uploadPath);
// ★ 3. 원본파일 저장
File target = new File(uploadPath + savedPath, savedName);
FileCopyUtils.copy(fileData, target);
// ★ 4. 이미지 일경우 썸네일 이미지 생성 후 url 주소로 반환
String formatName = originalName.substring(originalName.lastIndexOf(".") + 1);
String uploadedFileName = null;
if (MediaUtils.getMediaType(formatName) != null) {
// 이미지일 경우 썸네일 생성 후 이미지 이름 반환 ( 경로+년월일+s_이름)
uploadedFileName = makeThumbnail(uploadPath, savedPath, savedName);
} else {
uploadedFileName = makeIcon(uploadPath, savedPath, savedName);
}
// 파일 경로를 -> url 경로로 변경해서 반환
return uploadedFileName;
}
// ckeditor 전용 업로드 파일 반환 된값이 썸네일이 아닌 원본 이미지
// 1.파일의 저장 경로(uploadPath), 2.원본 파일의 이름(originalName), 3.파일 데이터(byte[])
public static String ckuploadFile(String uploadPath, String originalName, byte[] fileData) throws Exception {
// ★ 1. 고유값 생성
UUID uid = UUID.randomUUID();
String savedName = uid.toString() + "_" + originalName;
// ★ 2. 년/월/일' 정보 생성
String savedPath = calcPath(uploadPath);
// ★ 3. 원본파일 저장
File target = new File(uploadPath + savedPath, savedName);
FileCopyUtils.copy(fileData, target);
// ★ 4. 이미지 생성 후 url 주소로 반환
String uploadedFileName = makeIcon(uploadPath, savedPath, savedName);
// 파일 경로를 -> url 경로로 변경해서 반환
return uploadedFileName;
}
// 이미지가 아닐경우 단지 파일 경로를 -> url 경로로 변경해서 반환
private static String makeIcon(String uploadPath, String savedPath, String savedName) {
String iconName = uploadPath + savedPath + File.separator + savedName;
return iconName.substring(uploadPath.length()).replace(File.separatorChar, '/');
}
// 파일이 저장될 '년/월/일' 정보 생성
private static String calcPath(String uploadPath) {
Calendar cal = Calendar.getInstance();
// 역슬래시 + 2017
String yearPath = File.separator + cal.get(Calendar.YEAR);
// /2017 +/+ 10 한자리 월 일경우 01, 02 형식으로 포멧
String monthPath = yearPath + File.separator + new DecimalFormat("00").format(cal.get(Calendar.MONTH) + 1);
// /2017/10 +/ + 22
String datePath = monthPath + File.separator + new DecimalFormat("00").format(cal.get(Calendar.DATE));
// 년월일 폴더 생성하기
makeDir(uploadPath, yearPath, monthPath, datePath);
logger.info(" datePath - {}", datePath);
return datePath;
}
// 실질 적인 날짜 폴더 생성
private static void makeDir(String uploadPath, String... paths) {
if (new File(paths[paths.length - 1]).exists()) {
// 년 월 일 에서 일 배열 paths 에서 paths -1 은 일 즉 해당일의 폴더가 존재하면 return
return;
}
for (String path : paths) {
File dirPath = new File(uploadPath + path);
if (!dirPath.exists()) {
// 년 월일에 대한 해당 폴더가 존재하지 않으면 폴더 생성
dirPath.mkdir();
}
}
}
// 썸네일 이미지 생성하기
// 1.파일 경로 2. 년월일 경로, 3. 파일 이름
private static String makeThumbnail(String uploadPath, String path, String fileName) throws Exception {
// 파일 존재하는 이미지를 메모리상 이미지에 올려 붙인다. 즉 메모리에 로딩시킨다.
BufferedImage sourceImg = ImageIO.read(new File(uploadPath + path, fileName));
// 메모리상 이미지를 정해진 크기에 맞게 복사한다.
BufferedImage destImage = Scalr.resize(sourceImg, Scalr.Method.AUTOMATIC, Scalr.Mode.FIT_TO_HEIGHT, WIDTH_SIZE);
// 썸네일 이미지 이름을 정한다. 썸네일 이미지를 앞에 s_ 붙인다.
String thumbnailName = uploadPath + path + File.separator + "s_" + fileName;
// 파일 경로의 객체를 생성한다.
File newFile = new File(thumbnailName);
// 경로의 마지막 에 . 으로 중심으로 분리해서 .jpg, png, jpeg gif 의 문자를 추출한다.
String formatName = fileName.substring(fileName.lastIndexOf(".") + 1);
// 실질적인 썸네일 이미지를 복사한다.
ImageIO.write(destImage, formatName.toUpperCase(), newFile);
// 파일 경로인 역슬러시를 url 의 경로인 슬러시로 변경해서 해서 반환시킨다.
return thumbnailName.substring(uploadPath.length()).replace(File.separatorChar, '/');
}
}
CkeditorUploadController
/**
* <pre>
* 1. 패키지명 : config.upload
* 2. 타입명 : CkeditorUploadController.java
* 3. 작성일 : 2017. 10. 24. 오후 7:56:02
* 4. 저자 : 최준호
*
* </pre>
*
*/
package config.upload;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
@Controller
public class CkeditorUploadController {
private static final Logger logger = LoggerFactory.getLogger(CkeditorUploadController.class);
//파일 디렉토리 사용시
@Resource(name="uploadPath")
private String uploadPath;
//1.파일 디렉토리 사용
@RequestMapping(value="/ckeditorupload")
public void imageUpload(HttpServletRequest request, HttpServletResponse response,
@RequestParam MultipartFile upload ) throws Exception{
//1.CKEditor 에서 파일을 넘겨주는 이름이 upload 로 설정 되어 있다. 반드시 upload 로 설정
//헤더 설정
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=utf-8");
PrintWriter printWriter =response.getWriter();
String uploadFile="";
String fileUrl="";
String message="";
//2. 물리적 실제 저장소 에 저장하기
// 보안상 , jpg, jpeg, png, gif, 만 업로드 되도록 수정
if(UploadSecurity.check(upload)){
uploadFile=UploadFileUtils.ckuploadFile(uploadPath, upload.getOriginalFilename(), upload.getBytes());
logger.info(" uploadFile - {}" ,uploadFile);
//3.URL 상에서 볼수 있는 이미지 경로
// /displayFile?fileName="+ fileName;
fileUrl ="/displayFile?fileName="+ uploadFile;
message="'이미지를 업로드 했습니다.'";
}else{
message="'이미지 파일이 아닙니다.'";
}
String callback =request.getParameter("CKEditorFuncNum");
//4.스크립트 작성
StringBuffer sbuffer =new StringBuffer();
sbuffer.append("<script>window.parent.CKEDITOR.tools.callFunction(");
sbuffer.append(callback);
sbuffer.append(", '");
sbuffer.append(fileUrl);
sbuffer.append(" ' , "+message);
sbuffer.append(") </script>");
printWriter.println(sbuffer.toString());
printWriter.flush();
}
//년월일 별로 분리하지않고 이미지 보안 처리 안하고 그냥 업로드 - request.getServletContext().getRealPath("/") 사용
@RequestMapping(value="/ckeditorupload2")
public void imageUpload2(HttpServletRequest request, HttpServletResponse response,
@RequestParam MultipartFile upload ) throws Exception{
//CKEditor 에서 파일을 넘겨주는 이름이 upload 로 설정 되어 있다. 반드시 upload 로 설정
//헤더 설정
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=utf-8");
OutputStream out =null;
PrintWriter printWriter =null;
String fileName =upload.getOriginalFilename(); //첨부 파일 이름
byte[] bytes =upload.getBytes(); //첨부파일을 바이트 배열로 저장
//String uploadPath ="업로드할 디렉토리 경로" + fileName; //물리적 실제 저장소
//UploadPath 를 사용시
String uploadPath =UploadPath.path(request) +fileName;
out=new FileOutputStream(new File(uploadPath));
out.write(bytes); //서버에 파일 업로드
String callback =request.getParameter("CKEditorFuncNum");
printWriter=response.getWriter();
//URL 상에서 볼수 있는 이미지 경로
// String fileUrl =request.getContextPath()+"/upload/"+ fileName;
String fileUrl ="/resources/upload/"+ fileName;
String script="<script>window.parent.CKEDITOR.tools.callFunction(";
script +=callback;
script +=", '";
script +=fileUrl;
script +=" ' , '이미지를 업로드 했습니다.'";
script +=") </script>";
printWriter.println(script);
printWriter.flush();
}
//3.년월일 별로 분리및 보안 처리 사용 - request.getServletContext().getRealPath("/") 사용
// 1번과 차이점은 UploadPath.path(request) 의 물리적 주소와 와
// fileUrl ="/resources/upload/"+ uploadFile; url 상의
//경로 차이뿐이 없다.
@RequestMapping(value="/ckeditorupload3")
public void imageUpload3(HttpServletRequest request, HttpServletResponse response,
@RequestParam MultipartFile upload ) throws Exception{
//1.CKEditor 에서 파일을 넘겨주는 이름이 upload 로 설정 되어 있다. 반드시 upload 로 설정
//헤더 설정
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=utf-8");
PrintWriter printWriter =response.getWriter();
String uploadFile="";
String fileUrl="";
String message="";
//2. 물리적 실제 저장소 에 저장하기
// 보안상 , jpg, jpeg, png, gif, 만 업로드 되도록 수정
if(UploadSecurity.check(upload)){
uploadFile=UploadFileUtils.ckuploadFile(UploadPath.path(request), upload.getOriginalFilename(), upload.getBytes());
logger.info(" uploadFile - {}" ,uploadFile);
//3.URL 상에서 볼수 있는 이미지 경로
// /displayFile?fileName="+ fileName
fileUrl ="/resources/upload/"+ uploadFile;
message="'이미지를 업로드 했습니다.'";
}else{
message="'이미지 파일이 아닙니다.'";
}
String callback =request.getParameter("CKEditorFuncNum");
//4.스크립트 작성
StringBuffer sbuffer =new StringBuffer();
sbuffer.append("<script>window.parent.CKEDITOR.tools.callFunction(");
sbuffer.append(callback);
sbuffer.append(", '");
sbuffer.append(fileUrl);
sbuffer.append(" ' , "+message);
sbuffer.append(") </script>");
printWriter.println(sbuffer.toString());
printWriter.flush();
}
@RequestMapping(value="/ckeditorform")
public String ckeditorTest(){
return "test/ckeditor";
}
}
ckeditor.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Macaronics.net</title>
<!-- 합쳐지고 최소화된 최신 CSS -->
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<!-- 부가적인 테마 -->
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css">
<!-- 합쳐지고 최소화된 최신 자바스크립트 -->
<script
src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<script src="//cdn.ckeditor.com/4.7.3/standard/ckeditor.js"></script>
</head>
<body>
<h1> </h1>
<div class="row">
<div class="col-xl-2 col-sm-2"></div>
<div class="col-xl-8 col-sm-8">
<table class="table">
<tr>
<td>내용</td>
<td class="span12"><textarea rows="5" class="form-control" name="content"></textarea>
<!-- textarea 를 ckeditor 로 변경 시킴 -->
</tr>
</table>
</div>
</div>
<script>
CKEDITOR.replace("content", {
filebrowserUploadUrl : "/ckeditorupload3"
// filebrowserImageUploadUrl: 'MacaronicsServlet?command=ckeditor_upload'
});
</script>
</body>
</html>
제작 : macaronics.net - Developer Jun Ho Choi
소스 : 소스가 필요한 분은 비밀 댓글로 작성해 주세요.


















댓글 ( 7)
댓글 남기기