之前一直用ueditor作為富文本編輯器,想要實現圖片上傳到ftp的功能,網上搜索了一圈,發現都感覺講的不是很明白,而且有不少要引入其他的java代碼,最近自己試了一下,終於調通了,希望能幫到各位。廢話不多說,查看步驟。(注意,這個是springboot版本,其實springmvc的也差不多,有一點點不同,最后我會說明)
1.將utf8-jsp的整個文件夾復制到resources的static目錄下,打開之后目錄如下。


2.寫兩個controller,代碼如下(請忽略樓主潦草的代碼,自己拿回去調整一下,修改一下UploadController中ftp的地址,密碼即可,總共有三個地方)
1.UploadController
package com.wang.controller; import lombok.extern.slf4j.Slf4j; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPConnectionClosedException; import org.apache.commons.net.ftp.FTPReply; 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.bind.annotation.ResponseBody; import javax.imageio.ImageIO; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.awt.image.BufferedImage; import java.io.*; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.*; @RequestMapping("/ueditor/file") @Controller @Slf4j public class UploadController { private FTPClient ftpClient = new FTPClient(); private Logger logger = LoggerFactory.getLogger(UploadController.class); //上傳圖片並回顯 @RequestMapping("/uploadImg") @ResponseBody public Map<String,Object> upload(HttpServletRequest request) throws Exception { Map<String ,Object> map = new HashMap<>(); // 判斷enctype屬性是否為multipart/form-data boolean isMultipart = ServletFileUpload.isMultipartContent(request); if (!isMultipart) throw new IllegalArgumentException( "上傳內容不是有效的multipart/form-data類型."); // Create a factory for disk-based file items DiskFileItemFactory factory = new DiskFileItemFactory(); // Create a new file upload handler ServletFileUpload upload = new ServletFileUpload(factory); // Parse the request List<FileItem> items = upload.parseRequest(request); Iterator iter = items.iterator(); while (iter.hasNext()) { FileItem item = (FileItem) iter.next(); // 如果是文件字段 String fieldName = item.getFieldName(); String orginFileName = item.getName(); String imgSunffix = orginFileName.substring(orginFileName.lastIndexOf(".")); String uuid = UUID.randomUUID().toString().replaceAll("-", ""); String fileName = uuid+imgSunffix; // String contentType = item.getContentType(); // boolean isInMemory = item.isInMemory(); // long sizeInBytes = item.getSize(); // String filePath = STORE_FILE_DIR + fileName; //寫入文件到當前服務器磁盤 // File uploadedFile = new File(filePath); SimpleDateFormat formatPath = new SimpleDateFormat("yyMMdd"); SimpleDateFormat fromahhPath = new SimpleDateFormat("HH"); String yyMMdd = formatPath.format(new Date()); String hours = fromahhPath.format(new Date()); String ftpfilePath = yyMMdd + "/" + hours; // FileInputStream fileInputStream = (FileInputStream) item.getInputStream(); InputStream inputStream = item.getInputStream(); BufferedInputStream bufferedInputStream = null; bufferedInputStream = new BufferedInputStream(inputStream); FTPClient ftp = new FTPClient(); try { int reply; ftp.connect("11111", 21);// 連接FTP服務器 // 如果采用默認端口,可以使用ftp.connect(url)的方式直接連接FTP服務器 ftp.login("11111", "11111");// 登錄 ftp.setFileType(FTP.BINARY_FILE_TYPE); ftp.setFileTransferMode(FTP.STREAM_TRANSFER_MODE); reply = ftp.getReplyCode(); if(!FTPReply.isPositiveCompletion(reply)){ ftp.disconnect(); throw new IOException("ftp登錄失敗"); } for (String str:ftpfilePath.split("/")){ ftp.makeDirectory(str); ftp.changeWorkingDirectory(str); } boolean tag = ftp.appendFile(fileName,bufferedInputStream); if(!tag){ throw new Exception("保存到FTP失敗"); } }catch (Exception e){ e.printStackTrace(); }finally { try { inputStream.close(); ftp.logout(); } catch (IOException e) { e.printStackTrace(); } if(ftp.isConnected()){ try { ftp.disconnect(); }catch (IOException e){ e.printStackTrace(); } } } String path = "/"+ftpfilePath+"/"+fileName; // item.write(uploadedFile); map.put("state","SUCCESS"); map.put("url",path); map.put("title",orginFileName); map.put("original",orginFileName); } // response.setCharacterEncoding("UTF-8"); // response.getWriter().println("上傳成功"); return map; } //回顯圖片 @RequestMapping("/getImg.do") @ResponseBody public void getImg( HttpServletResponse response,@RequestParam("path")String imgPath) { FTPClient ftp = null; InputStream in = null; // imgPath = "ftpfile\\upload\\11.png"; OutputStream os = null; ftp = new FTPClient(); ftp.setConnectTimeout(1000 * 30);//設置連接超時時間 ftp.setControlEncoding("utf-8");//設置ftp字符集 ftp.enterLocalPassiveMode();//設置被動模式,文件傳輸端口設置 try { int reply; ftp.connect("11111", 21);// 連接FTP服務器 // 如果采用默認端口,可以使用ftp.connect(url)的方式直接連接FTP服務器 ftp.login("11111", "11111");// 登錄 ftp.setFileType(FTP.BINARY_FILE_TYPE); ftp.setFileTransferMode(FTP.STREAM_TRANSFER_MODE); reply = ftp.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { ftp.disconnect(); throw new IOException("FTP登錄失敗"); } //下載文件 FTP協議里面,規定文件名編碼為iso-8859-1,所以讀取時要將文件名轉碼為iso-8859-1 //如果沒有設置按照UTF-8讀,獲取的流是空值null in = ftp.retrieveFileStream(new String(imgPath.getBytes("UTF-8"), "iso-8859-1")); String picType = imgPath.split("\\.")[1]; BufferedImage bufImg = null; bufImg = ImageIO.read(in); os = response.getOutputStream(); ImageIO.write(bufImg, picType, os); } catch (IOException e) { e.printStackTrace(); } finally { try { in.close();// 在這里關閉,保證一定要關閉 ftp.logout();// 在這里登出,保證一定要登出 } catch (IOException e) { e.printStackTrace(); } if (ftp.isConnected()) { try { ftp.disconnect(); } catch (IOException ioe) { } } } response.setContentType("image/jpg"); } /** * 下載文件到瀏覽器 * @param response * @throws IOException */ @RequestMapping("/downloadFile.do") @ResponseBody public void downFile(@RequestParam("path")String path, HttpServletResponse response) throws IOException { // 獲取ftp信息 // 獲取文件名稱 String[] strs = path.split("/"); String downloadFile = strs[strs.length - 1]; try { // 設置文件ContentType類型,這樣設置,會自動判斷下載文件類型 response.setContentType("application/x-msdownload"); // 設置文件頭:最后一個參數是設置下載的文件名並編碼為UTF-8 response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(downloadFile, "UTF-8")); // 建立連接 connectToServer(); ftpClient.enterLocalPassiveMode(); // 設置傳輸二進制文件 int reply = ftpClient.getReplyCode(); // ftpClient.changeWorkingDirectory("./home/ftp"); if(!FTPReply.isPositiveCompletion(reply)) { ftpClient.disconnect(); throw new IOException("failed to connect to the FTP Server:"+21); } // 此句代碼適用Linux的FTP服務器 String newPath = new String(path.getBytes("GBK"),"ISO-8859-1"); // ftp文件獲取文件 InputStream is = null; BufferedInputStream bis = null; try { is = ftpClient.retrieveFileStream(newPath); bis = new BufferedInputStream(is); OutputStream out = response.getOutputStream(); byte[] buf = new byte[1024]; int len = 0; while ((len = bis.read(buf)) > 0) { out.write(buf, 0, len); } out.flush(); } catch (Exception e) { e.printStackTrace(); } finally { closeConnect(); if (bis != null) { try { bis.close(); } catch (IOException e) { e.printStackTrace(); } } if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } } catch (FTPConnectionClosedException e) { logger.error("ftp連接被關閉!", e); throw e; } catch (Exception e) { logger.error("ERR : upload file "+ downloadFile+ " from ftp : failed!", e); } } /** * 連接到ftp服務器 */ private void connectToServer() throws Exception { // ftpClient.connect(server,21); if (!ftpClient.isConnected()) { int reply; try { ftpClient=new FTPClient(); ftpClient.connect("111111", 21);// 連接FTP服務器 // 如果采用默認端口,可以使用ftp.connect(url)的方式直接連接FTP服務器 ftpClient.login("111111", "111111");// 登錄 reply = ftpClient.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { ftpClient.disconnect(); logger.info("connectToServer FTP server refused connection."); } }catch(FTPConnectionClosedException ex){ logger.error("服務器:IP:"+21+"沒有連接數!there are too many connected users,please try later", ex); throw ex; }catch (Exception e) { logger.error("登錄ftp服務器【"+21+"】失敗", e); throw e; } } } /** * * 功能:關閉連接 */ public void closeConnect() { try { if (ftpClient != null) { ftpClient.logout(); ftpClient.disconnect(); } } catch (Exception e) { logger.error("ftp連接關閉失敗!", e); } } }
2.ServerController
package com.wang.controller; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baidu.ueditor.ActionEnter; import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Controller; import org.springframework.util.ClassUtils; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; //ueditor單獨上傳的controller @Controller public class ServerController { @RequestMapping("/configNew") public void config(HttpServletRequest request, HttpServletResponse response){ response.setContentType("application/json"); // String res = ClassUtils.getDefaultClassLoader().getResource("km").getPath(); // System.out.println("res:"+res); System.out.println("路徑:"+ClassUtils.getDefaultClassLoader().getResource("").getPath()); // String rootPath = ClassUtils.getDefaultClassLoader().getResource("../../").getPath() + "static/ueditor/jsp"; String rootPath = ClassUtils.getDefaultClassLoader().getResource("").getPath() + "static/ueditor/jsp"; System.out.println("root路徑:"+rootPath); try { response.setCharacterEncoding("UTF-8"); String exec = new ActionEnter(request, rootPath).exec(); System.out.println(exec); PrintWriter writer = response.getWriter(); writer.write(new ActionEnter(request, rootPath).exec()); writer.flush(); writer.close(); } catch (IOException e) { e.printStackTrace(); } } // public void getUEConfig(HttpServletRequest request, HttpServletResponse response){ // org.springframework.core.io.Resource res = new ClassPathResource("config.json"); // InputStream is = null; // response.setHeader("Content-Type" , "text/html"); // try { // is = new FileInputStream(res.getFile()); // StringBuffer sb = new StringBuffer(); // byte[] b = new byte[1024]; // int length=0; // while(-1!=(length=is.read(b))){ // sb.append(new String(b,0,length,"utf-8")); // } // String result = sb.toString().replaceAll("/\\*(.|[\\r\\n])*?\\*/",""); // JSONObject json = JSON.parseObject(result); // PrintWriter out = response.getWriter(); // out.print(json.toString()); // } catch (IOException e) { // e.printStackTrace(); // }finally { // try { // is.close(); // } catch (IOException e) { // e.printStackTrace(); // } // } // } }
3.修改ueditor.config.js
var URL = window.UEDITOR_HOME_URL || getUEBasePath(); var server_url = window.location.protocol+"//"+window.location.hostname+":"+window.location.port; /** * 配置項主體。注意,此處所有涉及到路徑的配置別遺漏URL變量。 */ window.UEDITOR_CONFIG = { //為編輯器實例添加一個路徑,這個不能被注釋 UEDITOR_HOME_URL: URL // 服務器統一請求接口路徑 // , serverUrl: URL + "jsp/controller.jsp" , serverUrl: server_url+"/configNew"
4.修改ueditor的jsp目錄下的config.json文件 目錄圖片如下
打開這個文件之后修改大概7.8個地方的參數,都是xxxUrlPrefix,反正只要是圖片注釋就換成Ueditortxtcontroller中的getIMg路徑,文件就換成downloadFile路徑
圖片
文件路徑
5.關鍵一步,記得在你的啟動類application中排除掉有關文件上傳的自動配置。
如果是springmvc,那就是在xml文件中注釋掉multipartfile這個bean了
6.然后是改造的你的編輯器的訪問頁面index.html。
在ue.ready方法中換掉相關原有的訪問路徑即可
這是樓主的html頁面,如果要用的話,記得把那個juqery-3.5.1.min.js和一個保存saveContent的方法排除掉就可以了
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>完整demo</title> <link REL="shortcut icon" href="/favicon.ico" type="image/ico"/> <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/> <script type="text/javascript" charset="utf-8" src="/ueditor/ueditor.config.js"></script> <script type="text/javascript" charset="utf-8" src="/ueditor/ueditor.all.min.js"> </script> <script type="text/javascript" charset="utf-8" src="/js/jquery-3.5.1.min.js"> </script> <!--建議手動加在語言,避免在ie下有時因為加載語言失敗導致編輯器加載失敗--> <!--這里加載的語言文件會覆蓋你在配置項目里添加的語言類型,比如你在配置項目里配置的是英文,這里加載的中文,那最后就是中文--> <script type="text/javascript" charset="utf-8" src="/ueditor/lang/zh-cn/zh-cn.js"></script> <style type="text/css"> div{ width:100%; } </style> </head> <body> <div> <h1>完整demo</h1> <script id="editor" type="text/plain" style="width:1024px;height:500px;"></script> </div> <div id="btns"> <div> <button onclick="saveContent()">保存</button> <button onclick="getAllHtml()">獲得整個html的內容</button> <button onclick="getContent()">獲得內容</button> <button onclick="setContent()">寫入內容</button> <button onclick="setContent(true)">追加內容</button> <button onclick="getContentTxt()">獲得純文本</button> <button onclick="getPlainTxt()">獲得帶格式的純文本</button> <button onclick="hasContent()">判斷是否有內容</button> <button onclick="setFocus()">使編輯器獲得焦點</button> <button onmousedown="isFocus(event)">編輯器是否獲得焦點</button> <button onmousedown="setblur(event)" >編輯器失去焦點</button> </div> <div> <button onclick="getText()">獲得當前選中的文本</button> <button onclick="insertHtml()">插入給定的內容</button> <button id="enable" onclick="setEnabled()">可以編輯</button> <button onclick="setDisabled()">不可編輯</button> <button onclick=" UE.getEditor('editor').setHide()">隱藏編輯器</button> <button onclick=" UE.getEditor('editor').setShow()">顯示編輯器</button> <button onclick=" UE.getEditor('editor').setHeight(300)">設置高度為300默認關閉了自動長高</button> </div> <div> <button onclick="getLocalData()" >獲取草稿箱內容</button> <button onclick="clearLocalData()" >清空草稿箱</button> </div> </div> <div> <button onclick="createEditor()"> 創建編輯器</button> <button onclick="deleteEditor()"> 刪除編輯器</button> </div> <script type="text/javascript"> //實例化編輯器 //建議使用工廠方法getEditor創建和引用編輯器實例,如果在某個閉包下引用該編輯器,直接調用UE.getEditor('editor')就能拿到相關的實例 var ue = UE.getEditor('editor'); ue.ready(function () { UE.Editor.prototype._bkGetActionUrl=UE.Editor.prototype.getActionUrl; UE.Editor.prototype.getActionUrl=function(action){ if (action == 'uploadimage' ||action== 'uploadscrawl' || action == 'uploadimage') { return "/ueditor/file/uploadImg"; } else if(action =='uploadvideo') { return "/ueditor/file/uploadImg"; } else if(action == 'listimage'){ return "/ueditor/file/uploadImg"; } else if(action == 'uploadfile'){ return "/ueditor/file/uploadImg"; } else{ return this._bkGetActionUrl.call(this, action); } } }); function isFocus(e){ alert(UE.getEditor('editor').isFocus()); UE.dom.domUtils.preventDefault(e) } function setblur(e){ UE.getEditor('editor').blur(); UE.dom.domUtils.preventDefault(e) } function insertHtml() { var value = prompt('插入html代碼', ''); UE.getEditor('editor').execCommand('insertHtml', value) } function createEditor() { enableBtn(); UE.getEditor('editor'); } function getAllHtml() { alert(UE.getEditor('editor').getAllHtml()) } function saveContent() { var arr = []; arr.push(UE.getEditor('editor').getContent()); $.ajax({ type : 'post', dataType : 'json', url : '/ueditortxt/save', data:{ content: arr.join("\n") }, success:function(datas){ alert("添加成功"); }, error:function(a,b,c){ alert("添加失敗"); } }); } function getContent() { var arr = []; arr.push("使用editor.getContent()方法可以獲得編輯器的內容"); arr.push("內容為:"); arr.push(UE.getEditor('editor').getContent()); alert(arr.join("\n")); } function getPlainTxt() { var arr = []; arr.push("使用editor.getPlainTxt()方法可以獲得編輯器的帶格式的純文本內容"); arr.push("內容為:"); arr.push(UE.getEditor('editor').getPlainTxt()); alert(arr.join('\n')) } function setContent(isAppendTo) { var arr = []; arr.push("使用editor.setContent('歡迎使用ueditor')方法可以設置編輯器的內容"); UE.getEditor('editor').setContent('歡迎使用ueditor', isAppendTo); alert(arr.join("\n")); } function setDisabled() { UE.getEditor('editor').setDisabled('fullscreen'); disableBtn("enable"); } function setEnabled() { UE.getEditor('editor').setEnabled(); enableBtn(); } function getText() { //當你點擊按鈕時編輯區域已經失去了焦點,如果直接用getText將不會得到內容,所以要在選回來,然后取得內容 var range = UE.getEditor('editor').selection.getRange(); range.select(); var txt = UE.getEditor('editor').selection.getText(); alert(txt) } function getContentTxt() { var arr = []; arr.push("使用editor.getContentTxt()方法可以獲得編輯器的純文本內容"); arr.push("編輯器的純文本內容為:"); arr.push(UE.getEditor('editor').getContentTxt()); alert(arr.join("\n")); } function hasContent() { var arr = []; arr.push("使用editor.hasContents()方法判斷編輯器里是否有內容"); arr.push("判斷結果為:"); arr.push(UE.getEditor('editor').hasContents()); alert(arr.join("\n")); } function setFocus() { UE.getEditor('editor').focus(); } function deleteEditor() { disableBtn(); UE.getEditor('editor').destroy(); } function disableBtn(str) { var div = document.getElementById('btns'); var btns = UE.dom.domUtils.getElementsByTagName(div, "button"); for (var i = 0, btn; btn = btns[i++];) { if (btn.id == str) { UE.dom.domUtils.removeAttributes(btn, ["disabled"]); } else { btn.setAttribute("disabled", "true"); } } } function enableBtn() { var div = document.getElementById('btns'); var btns = UE.dom.domUtils.getElementsByTagName(div, "button"); for (var i = 0, btn; btn = btns[i++];) { UE.dom.domUtils.removeAttributes(btn, ["disabled"]); } } function getLocalData () { alert(UE.getEditor('editor').execCommand( "getlocaldata" )); } function clearLocalData () { UE.getEditor('editor').execCommand( "clearlocaldata" ); alert("已清空草稿箱") } </script> </body> </html>
7.現在就可以訪問這個頁面然后上傳文件、圖片、視頻並且回顯了
文件
效果
圖片
效果:
視頻:
效果:
這里有個問題,就是如果連續點擊這個按鈕,頁面會回顯不了視頻,我發現可以把那個Ueditor的XSS過濾關掉就可以(注意,這個操作我也不知道會導致什么問題,慎重操作)
關掉XSS過濾,修改ueditor.config.js中的三個參數為false即可
至此就完成了,如果是springmvc的話怎么辦呢?
三步不同
1.將serverController中上半部分代碼注釋掉,放開下半部分中注釋掉的代碼
2.將改造過后的config.json文件放到resource下面
3.pom文件中放開對json文件的限制,以便target中能夠找到該文件
項目地址:https://gitee.com/wl173/ueditorupload.git 看readme就行了