說來慚愧,這個應用調試,折騰了我一整天,google了很多帖子,才算整明白,今天在這里做個記錄和分享吧,也作為自己后續的參考!
第一步,ckeditor(本博文論及的ckeditor版本4.5.6)的配置圖片文件上傳功能,默認這個是沒有開啟的,就不用多說,ckeditor官網上也說的很清楚!http://docs.ckeditor.com
下面簡單的說下配置(配置文件algoConfig.js):
1 CKEDITOR.editorConfig = function( config ) { 2 config.toolbarGroups = [ 3 { name: 'document', groups: [ 'mode', 'document', 'doctools' ] }, 4 { name: 'clipboard', groups: [ 'clipboard', 'undo' ] }, 5 { name: 'editing', groups: [ 'find', 'selection', 'spellchecker', 'editing' ] }, 6 { name: 'forms', groups: [ 'forms' ] }, 7 '/', 8 { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] }, 9 { name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi', 'paragraph' ] }, 10 { name: 'links', groups: [ 'links' ] }, 11 { name: 'insert', groups: [ 'insert' ] }, 12 '/', 13 { name: 'styles', groups: [ 'styles' ] }, 14 { name: 'colors', groups: [ 'colors' ] }, 15 { name: 'tools', groups: [ 'tools' ] }, 16 { name: 'others', groups: [ 'others' ] }, 17 { name: 'about', groups: [ 'about' ] } 18 ]; 19 20 config.removeButtons = 'Source,Save,NewPage,Scayt'; 21 config.image_previewText=' '; //預覽區域顯示內容 22 config.filebrowserImageBrowseUrl = '/browse/mgmt/img'; 23 config.filebrowserImageUploadUrl = '/upload/mgmt/img'; 24 };
上圖中,背景顏色加高亮的為關鍵配置。等號左邊的是key,等號右邊的,則對應於web應用中的一個url,這個是配合后台應用中一個controller的處理,也就是一個servlet的操作。具體如何處理,后面再說!
再多羅嗦一下,我的這個配置中,涉及到圖片預覽區的那堆看不懂的文字的去除處理。我將其清掉了!如上面的21行的配置。另外,我的ckeditor工具欄中,去掉了一部分的button。具體如何操作,可以參考ckeditor的samples下面的toolbarconfigurator里面有個index.html,在瀏覽器里打開,可以參照着說明即可定制自己的工具欄。
在應用的js文件中作如下的配置,即可以enable定制的CKeditor。
1 /** 2 * 下面是用CKeditor進行編輯文件 3 */ 4 CKEDITOR.replace( 'practice_content', // practice_content是html文件中的對應的textarea編輯區的ID名稱,注意不要寫成#practice_content 5 { 6 language: 'zh-cn', 7 uiColor: '#c3c8d1', 8 customConfig: '/js/ckeditor/algoConfig.js' //自定義自己的toobar風格 9 });
到現在為止,定制的CKeditor的圖片上傳配置部分算是結束了。
此時,可以看到頁面上的ckeditor的狀態為下圖所示:

說明下: 圖中1標記對應配置:config.filebrowserImageUploadUrl = '/upload/mgmt/img';
圖中2標記對應配置:config.filebrowserImageBrowseUrl = '/browse/mgmt/img';
圖中3標記對應配置:config.image_previewText=' ';
第二步,就是圖片文件上傳的后台處理了,這步就是添加url /upload/mgmt/img的后台響應。由於ckeditor的文件上傳是采用的表單form以post的方式提交enctype為multipart/form-data的文件到后台服務器(此數據可以從html頁面debug方式查看,如下圖所示),那么對應的后台文件接受,則也采用Multipartfile的形式。

所以,后台的程序,應該也不是很難實現的事情。我就直接貼代碼了,有興趣的,自己可以看看!
1 @RequestMapping(value="/upload/mgmt/img", method=RequestMethod.POST) 2 public void handleFileUpload(User user, @RequestParam("upload") MultipartFile file, 3 HttpServletRequest request, HttpServletResponse response){ 4 String name = ""; 5 if (!file.isEmpty()) { 6 try { 7 response.setContentType("text/html; charset=UTF-8"); 8 response.setHeader("Cache-Control", "no-cache"); 9 response.setHeader("X-Frame-Options", "SAMEORIGIN"); 10 PrintWriter out = response.getWriter(); 11 12 String fileClientName = getFileName(file.getOriginalFilename()); 13 String fileFix = StringUtils.substring(fileClientName, 14 fileClientName.lastIndexOf(".") + 1); 15 if (!StringUtils.equalsIgnoreCase(fileFix, "jpg") 16 && !StringUtils.equalsIgnoreCase(fileFix, "jpeg") 17 && !StringUtils.equalsIgnoreCase(fileFix, "bmp") 18 && !StringUtils.equalsIgnoreCase(fileFix, "gif") 19 && !StringUtils.equalsIgnoreCase(fileFix, "png")) { 20 logger.error("Incorrect format of the uploading file -- " + fileFix); 21 return; 22 } 23 24 if (logger.isInfoEnabled()) { 25 logger.info("Begin uploading: " + file.getName()); 26 } 27 28 // 為了客戶端已經設置好了圖片名稱在服務器繼續能夠明確識別,這里不改名稱 29 // 獲取目錄 30 File floder = buildFolder(user, request, FileType.IMAGE); 31 if (null == floder) { 32 logger.info("folder is null"); 33 return; 34 } 35 36 File newfile = new File(floder, fileClientName); 37 byte[] bytes = file.getBytes(); 38 BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(newfile)); 39 stream.write(bytes); 40 stream.close(); 41 42 if (logger.isInfoEnabled()) { 43 logger.info("Uploading done,floder: " + newfile.getPath()); 44 } 45 46 // 組裝返回url,以便於ckeditor定位圖片 47 String fileUrl = request.getContextPath() + MueasConstants.APP_RUNNING_FILES_DIR; 48 fileUrl += IMAGE_DIR + File.separator + newfile.getName(); 49 fileUrl = StringUtils.replace(fileUrl, "//", "/"); 50 51 // 將上傳的圖片的url返回給ckeditor 52 String callback = request.getParameter("CKEditorFuncNum"); 53 String script = "<script type=\"text/javascript\">window.parent.CKEDITOR.tools.callFunction(" + callback + ", '" + fileUrl + "');</script>"; 54 55 out.println(script); 56 out.flush(); 57 out.close(); 58 } catch (Exception e) { 59 logger.info("You failed to upload " + name + " => " + e.getMessage()); 60 } 61 } else { 62 logger.info("You failed to upload " + name + " because the file was empty."); 63 } 64 }
其中,代碼里面的紅色部分比較值得注意,其他都不是太難的事情。
第一處紅色部分是為了解決下面的錯誤:
| Refused to display 'http://localhost:8080/upload/mgmt/img?CKEditor=practice_content&CKEditorFuncNum=1&langCode=zh-cn' in a frame because it set 'X-Frame-Options' to 'DENY'. |
第二處(30行)和第三處(47-49行)是為了讓上傳上來的文件存放的位置和ckeditor上傳文件獲取的URL地址(GET方式)的一致性。
這里再上傳一下創建存放文件的目錄的代碼:
1 private File buildFolder(User user, HttpServletRequest request, FileType type) { 2 3 String realPath = request.getSession().getServletContext().getRealPath(MueasConstants.APP_RUNNING_FILES_DIR); 4 String folderdir = ""; 5 //如果不存在,創建 6 switch(type){ 7 case IMAGE: 8 folderdir += realPath + IMAGE_DIR; 9 break; 10 case FILE: 11 folderdir += realPath + FILE_DIR; 12 break; 13 case FLASH: 14 folderdir += realPath + FLASH_DIR; 15 break; 16 case VIDEO: 17 folderdir += realPath + VIDEO_DIR; 18 break; 19 } 20 21 File floder = new File(folderdir); 22 if (!floder.exists()) { 23 if (!floder.mkdirs()) { 24 logger.error("Create folder failed! path=" + folderdir); 25 return null; 26 } 27 } 28 return floder; 29 }
這里,根據文件類型,創建不同的子目錄。其中重點是request.getSession().getServletContext().getRealPath(MueasConstants.APP_RUNNING_FILES_DIR);這個,大家若不是很明白,可以查看一下文檔。
另外,就是配合使用的request.getContextPath() + MueasConstants.APP_RUNNING_FILES_DIR;總之,就是為了讓地址一致,存放文件的位置地址要讓取文件的GET指令能夠得到文件即可。
最后說下,為了控制上傳文件的大小,在spring-boot的配置文件中添加下面的信息:
| multipart.maxFileSize = 3Mb |
運行起來后,可以做測試圖片文件上傳的功能了,效果如下圖所示:

此時,點擊“確定”按鈕,圖片文件就會顯示在自己設計的textarea的區域了。是不是不那么難?
話說回來,調通了是覺得不難,但是,在沒有調通的時候,就那個x-options-frame的問題,就讓我很頭疼。
其次,在后台處理的代碼中,起初,我采用的是commons-fileupload插件中的代碼處理的,但是總不成功,一下午,google了很多外文帖子,也不湊效,遂改成上面的代碼處理。其commons-fileupload關鍵參考代碼如下:
1 DiskFileItemFactory factory = new DiskFileItemFactory(); 2 // maximum size that will be stored in memory 3 factory.setSizeThreshold(maxMemSize); 4 5 // Create a new file upload handler 6 ServletFileUpload upload = new ServletFileUpload(factory); 7 // maximum file size to be uploaded. 8 9 upload.setSizeMax(maxFileSize); 10 11 List<FileItem> fileItems = upload.parseRequest(request);
測試過程中,總是遇到列表filetems為空的問題,其實request中是有上傳過來的文件信息的。折騰了很久,還是沒有找到原因。算一個Open Point吧,若有高人或者過來人,可以給我指點一下。
