1. tika 라이브러리 추가
<dependency> <groupId>org.apache.tika</groupId> <artifactId>tika-core</artifactId> <version>2.7.0</version> </dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.11.0</version> </dependency>
2. 컨트롤
Ckeditor 4, Ckeditor 5 통합
Ckeditor 5는 post 방식
import javax.servlet.http.HttpServletRequest; import org.apache.commons.io.IOUtils; import org.apache.tika.Tika; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.util.FileCopyUtils; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import lineage.choco.util.config.MediaUtils; @Controller public class FileUploadController { @Value("${upload.path}") public String uploadDirectory; @ResponseBody @RequestMapping("/displayFile") public ResponseEntity<byte[]> displyFile(String fileName) throws Exception { if (fileName == null || !StringUtils.hasText(fileName)) { return new ResponseEntity<byte[]>("0".getBytes(), HttpStatus.BAD_REQUEST); } InputStream in = null; ResponseEntity<byte[]> entity = null; try { String formatName = fileName.substring(fileName.lastIndexOf(".") + 1); MediaType mType = MediaUtils.getMediaType(formatName); HttpHeaders headers = new HttpHeaders(); in = new FileInputStream(uploadDirectory + fileName); if (mType != null) { headers.setContentType(mType); } else { fileName = fileName.substring(fileName.indexOf("_") + 1); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); headers.add("Content-Disposition", "attachment; filename=\"" + new String(fileName.getBytes("UTF-8"), "ISO-8859-1") + "\""); } entity = new ResponseEntity<byte[]>(IOUtils.toByteArray(in), headers, HttpStatus.CREATED); } catch (Exception e) { e.printStackTrace(); } finally { try { in.close(); } catch (Exception e) { e.printStackTrace(); } } return entity; } @RequestMapping(value="/ckeditor/image/upload") @ResponseBody public Map<String, Object> ckeditor4(HttpServletRequest request, @RequestParam MultipartFile upload ) throws Exception{ Map<String, Object> map=new HashMap<>(); InputStream inputStream = upload.getInputStream(); if(isPermisionFileMimeType(inputStream)) { String uploadFile=ckuploadFile(uploadDirectory, upload.getOriginalFilename(), upload.getBytes()); String fileUrl = request.getContextPath()+"/displayFile?fileName=" + uploadFile; map.put("uploaded", 1); map.put("fileName", upload.getOriginalFilename()); map.put("url", fileUrl); return map; } return null; } /** * Tika 로 업로드 파일 검사 */ private boolean isPermisionFileMimeType( InputStream inputStream ) throws Exception { final String[] PERMISSION_FILE_MIME_TYPE = {"image/gif", "image/jpeg", "image/png", "image/bmp"}; String mimeType = new Tika().detect(inputStream); for( int i = 0; i < PERMISSION_FILE_MIME_TYPE.length; i++ ) { if( PERMISSION_FILE_MIME_TYPE[i].equals(mimeType) ) { return true; } } return false; } // 1.파일의 저장 경로(uploadPath), 2.원본 파일의 이름(originalName), 3.파일 데이터(byte[]) private 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); 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(); } } } }
3. 화면처리
1)ckeditor 4
ckeditor 4 다운드 받은 후 분리하기 귀찮으면 통으로 resources 파일 위치에 업로드 후 다음과 같이 적용.
글쓴이는 Full Package ckeditor 4 를 다운로드 받은후 스프링부트의 static 위치 디렉토리에서 lib/ckeditor/ 디렉토리 만든후 통으로 업로드 처리.
https://ckeditor.com/ckeditor-4/download/
파일을 다운로드 받으면 config.js 있는데 해당 파일에 옵션값을 넣어주면 된다.
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Nanum+Gothic:wght@400;700;800&family=Noto+Sans+KR:wght@300;400;500;700;900&display=swap" rel="stylesheet">
/** * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved. * For licensing, see https://ckeditor.com/legal/ckeditor-oss-license */ CKEDITOR.editorConfig = function( config ) { // Define changes to default configuration here. For example: // config.language = 'fr'; // config.uiColor = '#AADC6E'; config.language = 'ko'; config.uiColor = '#aeb8e3'; config.height = 700; config.toolbarCanCollapse = true; //config.font_defaultLabel ='나눔'; config.fontSize_defaultLabel ='12px'; config.font_names = '나눔/Nanum Gothic;노토산/Noto Sans KR;굴림/Gulim;돋움/Dotum;바탕/Batang;궁서/Gungsuh;맑은 고딕/Malgun;Arial/arial;Comic Sans MS/comic;Courier New/cour;Georgia/georgia;Lucida Sans/LSANS;Tahoma/tahoma;Times New Roman/times;Trebuchet MS/trebuc;Verdana/verdana;'; // 사용 가능한 폰트 설정 };
<script src="/resources/lib/ckeditor/ckeditor.js"></script> <textarea id="content" name="content"></textarea> <scirpt> CKEDITOR.replace('content', { filebrowserUploadUrl:'/ckeditor/image/upload' } ); <script>
내용입력 CKEDITOR.instances.content.setData('<p>데이터</p>') 내용가져오기 CKEDITOR.instances.content.getData()
2 ) ckeditor 5는 cdn 적용
<script src="https://cdn.ckeditor.com/ckeditor5/36.0.1/classic/ckeditor.js"></script> <script src="https://cdn.ckeditor.com/ckeditor5/36.0.1/classic/translations/ko.js"></script> <textarea id="content" name="content"></textarea> <script> let ckeditor; ClassicEditor.create(document.querySelector('#content'), { ckfinder: { uploadUrl: `/ckeditor/image/upload` }, language: 'ko' }) .then(editor => { ckeditor = editor; }) .catch(error => { console.error(error); }); </script>
내용 가져오기 const content = ckeditor.getData();
댓글 ( 4)
댓글 남기기