關於富文本編輯器—UEditor(java版)的使用,以及如何將UEditor的文件/圖片上傳路徑改成絕對路徑

来源:https://www.cnblogs.com/sunshine6/archive/2018/09/29/9721856.html
-Advertisement-
Play Games

突然發現好久沒寫博客了,感覺變懶了,是要讓自己養成經常寫文章的習慣才行。既可以分享自己的所學,和所想,和大家一起討論,發現自己的不足的問題。 大家可能經常會用到富文本編輯器,今天我要說的是UEditor的使用,這是一個簡單易用的開源富文本編輯器。但是對於沒有用過的同學而言還是需要稍微瞭解一下的。 可 ...


突然發現好久沒寫博客了,感覺變懶了,是要讓自己養成經常寫文章的習慣才行。既可以分享自己的所學,和所想,和大家一起討論,發現自己的不足的問題。

大家可能經常會用到富文本編輯器,今天我要說的是UEditor的使用,這是一個簡單易用的開源富文本編輯器。但是對於沒有用過的同學而言還是需要稍微瞭解一下的。

可能有些人也知道,UEditor是百度的開源富文本編輯器,當然也有一些其他優秀的富文本編輯器,比如kindeditor,ckeditor之類的,大家可以對比一下使用,但是我今天主要是講java版的UEditor。

大家可以通過 https://ueditor.baidu.com/website/download.html 選擇自己想使用的版本下載。

首先介紹一下它的目錄層級:

                   

  • dialogs: 彈出對話框對應的資源和JS文件
  • jsp或php或asp或net: 涉及到伺服器端操作的後臺文件
  • lang: 編輯器國際化顯示的文件
  • themes: 樣式圖片和樣式文件
  • third-party: 第三方插件(包括代碼高亮,源碼編輯等組件)
  • ueditor.all.js: 開發版代碼合併的結果,目錄下所有文件的打包文件
  • ueditor.all.min.js: ueditor.all.js文件的壓縮版,建議在正式部署時採用
  • ueditor.config.js: 編輯器的配置文件,建議和編輯器實例化頁面置於同一目錄
  • ueditor.parse.js: 編輯的內容顯示頁面引用,會自動載入表格、列表、代碼高亮等樣式

我們把UEditor拷貝到我們的項目路徑下,與你的頁面是在同一個目錄下就可以了。

在需要用到UEditor的頁面引入下麵的文件即可,根據自己的實際路徑引入:

    <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" src="../../ueditor/lang/zh-cn/zh-cn.js"></script>  

在頁面需要展示富文本編輯器的位置這樣引入:

 1           <!-- 載入編輯器的容器 -->
 2                 <div class="k-field" style="width:1024px;">
 3                     <script id="article_content" name="article_content" type="text/plain" style="width:1024px;height:400px;">
 4                         在這裡輸入您的內容......
 5                     </script>
 6                 </div>
 7                 <!-- 實例化編輯器 -->
 8                 <script type="text/javascript">
 9                     var ue = UE.getEditor('article_content',{
10                         <!-- 根據個人需要配置,不配置則按預設的 -->
11                         maximumWords:50000,
12                         enableAutoSave:true,
13                         saveInterval:500
14                     });
15                 </script>   

 

除此之外我們還要引入UEditor所需要的jar包 在 UEditor目錄下的  jsp/lib 下有,如果你有引入這些包的話,則無需引入。

如果你的不是maven項目的話,直接把所有包拷貝到項目下麵的lib目錄下就可以自動引入了,但是如果是maven項目的話,maven庫里沒有ueditor的包,那就不能按照平常的方式引入了,可以把ueditor的包拷貝到項目的lib目錄下之後,在pom.xml中這樣引入:

1         <dependency>
2             <groupId>com.baidu.ueditor</groupId>
3             <artifactId>ueditor</artifactId>
4             <version>1.1.2</version>
5             <scope>system</scope>
6             <systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/ueditor-1.1.2.jar</systemPath>
7         </dependency>

 

上面的步驟都完成之後就可以去對應的頁面試一下效果如何。如果沒有做任何改動的話就是下麵的效果:

 

以上就完成了最簡單的UEditor富文本編輯器引入方式,可以體驗一下上傳圖片和文件,都可以正常上傳。

但是當你重新部署項目之後會發現,怎麼之前上傳的文件和圖片下載不了也看不到了呢。這就是因為UEditor原生上傳文件和圖片的方式是上傳到項目路徑下,那重新部署項目,那不就把原來上傳的文件和圖片覆蓋了咯。

所以為了避免這樣的情況發生,我們接下來稍微修改一下UEditor的代碼。可能步驟有點多,但是耐心地跟著我的步驟一步步去理解,應該可以很快就知道怎麼修改。

通過查看源碼,下麵我們一步步來追蹤:

1. 上傳圖片或文件時最開始會進入“ueditor/jsp/controller.jsp”,我們查看其代碼:

 1 <%@ page language="java" contentType="text/html; charset=UTF-8"
 2     import="com.baidu.ueditor.ActionEnter"
 3     pageEncoding="UTF-8"%>
 4 <%@ page trimDirectiveWhitespaces="true" %>
 5 <%
 6 
 7     request.setCharacterEncoding( "utf-8" );
 8     response.setHeader("Content-Type" , "text/html");
 9     String rootPath = application.getRealPath( "/" );
10     out.write( new ActionEnter( request, rootPath ).exec() );
11     
12 %>
第9行中的rootPath 是獲取 項目的實際路徑,並作為 ActionEnter 構造函數的參數之一實例化對象,在這個構造函數中(如下麵的代碼)會去初始化改類的成員變數以及通過“ConfigManager.getInstance”獲取配置,
其實是獲取 ueditor/jsp/config.json 的配置信息。大家可以去看一下裡面配置了一些什麼內容,裡面也有註釋,我這裡粘貼圖片的配置內容:
1     public ActionEnter(HttpServletRequest request, String rootPath) {
2         this.request = request;
3         this.rootPath = rootPath;
4         this.actionType = request.getParameter("action");
5         this.contextPath = request.getContextPath();
6         this.configManager = ConfigManager.getInstance(this.rootPath, this.contextPath, request.getRequestURI());
7     }
 1     /* 上傳圖片配置項 */
 2     "imageActionName": "uploadimage", /* 執行上傳圖片的action名稱 */
 3     "imageFieldName": "upfile", /* 提交的圖片表單名稱 */
 4     "imageMaxSize": 2048000, /* 上傳大小限制,單位B */
 5     "imageAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 上傳圖片格式顯示 */
 6     "imageCompressEnable": true, /* 是否壓縮圖片,預設是true */
 7     "imageCompressBorder": 1600, /* 圖片壓縮最長邊限制 */
 8     "imageInsertAlign": "none", /* 插入的圖片浮動方式 */
 9     "imageUrlPrefix": "", /* 圖片訪問路徑首碼 */
10     "imagePathFormat": "/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上傳保存路徑,可以自定義保存路徑和文件名格式 */
11                                 /* {filename} 會替換成原文件名,配置這項需要註意中文亂碼問題 */
12                                 /* {rand:6} 會替換成隨機數,後面的數字是隨機數的位數 */
13                                 /* {time} 會替換成時間戳 */
14                                 /* {yyyy} 會替換成四位年份 */
15                                 /* {yy} 會替換成兩位年份 */
16                                 /* {mm} 會替換成兩位月份 */
17                                 /* {dd} 會替換成兩位日期 */
18                                 /* {hh} 會替換成兩位小時 */
19                                 /* {ii} 會替換成兩位分鐘 */
20                                 /* {ss} 會替換成兩位秒 */
21                                 /* 非法字元 \ : * ? " < > | */
22                                 /* 具請體看線上文檔: fex.baidu.com/ueditor/#use-format_upload_filename */

 

2. 總共也就幾行代碼,發現會調用 ActionEnter 類的 exec() 方法,我進入該方法:

1     public String exec() {
2         String callbackName = this.request.getParameter("callback");
3         if (callbackName != null) {
4             return !this.validCallbackName(callbackName) ? (new BaseState(false, 401)).toJSONString() : callbackName + "(" + this.invoke() + ");";
5         } else {
6             return this.invoke();
7         }
8     }

3. 發現這個方法會調用 該類的 invoke() 方法,我們繼續看invoke() 方法:

 1     public String invoke() {
 2         if (this.actionType != null && ActionMap.mapping.containsKey(this.actionType)) {
 3             if (this.configManager != null && this.configManager.valid()) {
 4                 State state = null;
 5                 int actionCode = ActionMap.getType(this.actionType);
 6                 Map<String, Object> conf = null;
 7                 switch(actionCode) {
 8                 case 0:
 9                     return this.configManager.getAllConfig().toString();
10                 case 1:
11                 case 2:
12                 case 3:
13                 case 4:
14                     conf = this.configManager.getConfig(actionCode);
15                     state = (new Uploader(this.request, conf)).doExec();
16                     break;
17                 case 5:
18                     conf = this.configManager.getConfig(actionCode);
19                     String[] list = this.request.getParameterValues((String)conf.get("fieldName"));
20                     state = (new ImageHunter(conf)).capture(list);
21                     break;
22                 case 6:
23                 case 7:
24                     conf = this.configManager.getConfig(actionCode);
25                     int start = this.getStartIndex();
26                     state = (new FileManager(conf)).listFile(start);
27                 }
28 
29                 return state.toJSONString();
30             } else {
31                 return (new BaseState(false, 102)).toJSONString();
32             }
33         } else {
34             return (new BaseState(false, 101)).toJSONString();
35         }
36     }

在上面的這個方法中我們發現,在第7行代碼中有一個switch,根據 “actionCode” 的值的不同做一些不同的事情,我們看一下這個值從哪裡來的,發現這個值是 通過調用這 個 方法 而得到 “ActionMap.getType(this.actionType)”,我們進去getType方法會發現 只是返回一個map的velue值,這個value值就是上的 mapping 里的值,我們通過第1步的配置文件可以知道上傳圖片的是“uploadimage”

所以返回的value值是 1,而文件“uploadfile”返回的是4。我們再看到上面的switch 可以知道執行this.configManager.getConfig 重新組裝了配置信息並將配置信息作為參數實例化Uploader ,並調用該實例 的 doExec()方法。

 1 public final class ActionMap {
 2     public static final Map<String, Integer> mapping = new HashMap<String, Integer>() {
 3         {
 4             this.put("config", Integer.valueOf(0));
 5             this.put("uploadimage", Integer.valueOf(1));
 6             this.put("uploadscrawl", Integer.valueOf(2));
 7             this.put("uploadvideo", Integer.valueOf(3));
 8             this.put("uploadfile", Integer.valueOf(4));
 9             this.put("catchimage", Integer.valueOf(5));
10             this.put("listfile", Integer.valueOf(6));
11             this.put("listimage", Integer.valueOf(7));
12         }
13     };
14     public static final int CONFIG = 0;
15     public static final int UPLOAD_IMAGE = 1;
16     public static final int UPLOAD_SCRAWL = 2;
17     public static final int UPLOAD_VIDEO = 3;
18     public static final int UPLOAD_FILE = 4;
19     public static final int CATCH_IMAGE = 5;
20     public static final int LIST_FILE = 6;
21     public static final int LIST_IMAGE = 7;
22 
23     public ActionMap() {
24     }
25 
26     public static int getType(String key) {
27         return ((Integer)mapping.get(key)).intValue();
28     }
29 }

4.我進入到 Uploader 類,上一步最後就是調用第10行的方法,因為配置里 不是base64 所以執行else里的內容,調用 BinaryUploader 的save方法

 1 public class Uploader {
 2     private HttpServletRequest request = null;
 3     private Map<String, Object> conf = null;
 4 
 5     public Uploader(HttpServletRequest request, Map<String, Object> conf) {
 6         this.request = request;
 7         this.conf = conf;
 8     }
 9 
10     public final State doExec() {
11         String filedName = (String)this.conf.get("fieldName");
12         State state = null;
13         if ("true".equals(this.conf.get("isBase64"))) {
14             state = Base64Uploader.save(this.request.getParameter(filedName), this.conf);
15         } else {
16             state = BinaryUploader.save(this.request, this.conf);
17         }
18 
19         return state;
20     }
21 }

 

5. 我們繼續進入到BinaryUploader 的save方法 ,我們看到下麵的代碼的第33行,會去設定 “physicalPath ” 的值,並作為參數 調用 方法: StorageManager.saveFileByInputStream 進行保存,而“physicalPath ” 值是由 配置信息 參數 config 獲取。所以我們需要通過修改配置 來 修改這個值就行了。

 

 1     public static final State save(HttpServletRequest request, Map<String, Object> conf) {
 2         FileItemStream fileStream = null;
 3         boolean isAjaxUpload = request.getHeader("X_Requested_With") != null;
 4         if (!ServletFileUpload.isMultipartContent(request)) {
 5             return new BaseState(false, 5);
 6         } else {
 7             ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
 8             if (isAjaxUpload) {
 9                 upload.setHeaderEncoding("UTF-8");
10             }
11 
12             try {
13                 for(FileItemIterator iterator = upload.getItemIterator(request); iterator.hasNext(); fileStream = null) {
14                     fileStream = iterator.next();
15                     if (!fileStream.isFormField()) {
16                         break;
17                     }
18                 }
19 
20                 if (fileStream == null) {
21                     return new BaseState(false, 7);
22                 } else {
23                     String savePath = (String)conf.get("savePath");
24                     String originFileName = fileStream.getName();
25                     String suffix = FileType.getSuffixByFilename(originFileName);
26                     originFileName = originFileName.substring(0, originFileName.length() - suffix.length());
27                     savePath = savePath + suffix;
28                     long maxSize = ((Long)conf.get("maxSize")).longValue();
29                     if (!validType(suffix, (String[])conf.get("allowFiles"))) {
30                         return new BaseState(false, 8);
31                     } else {
32                         savePath = PathFormat.parse(savePath, originFileName);
33                         String physicalPath = (String)conf.get("rootPath") + savePath;
34                         InputStream is = fileStream.openStream();
35                         State storageState = StorageManager.saveFileByInputStream(is, physicalPath, maxSize);
36                         is.close();
37                         if (storageState.isSuccess()) {
38                             storageState.putInfo("url", PathFormat.format(savePath));
39                             storageState.putInfo("type", suffix);
40                             storageState.putInfo("original", originFileName + suffix);
41                         }
42 
43                         return storageState;
44                     }
45                 }
46             } catch (FileUploadException var14) {
47                 return new BaseState(false, 6);
48             } catch (IOException var15) {
49                 return new BaseState(false, 4);
50             }
51         }
52     }

6.上面都是在分析代碼,下麵就開始修改了,我們在配置文件“ueditor/jsp/config.json”里添加 saveRootPath ,這就是存儲圖片或文件的絕對根路徑,修改 imageUrlPrefix 的值,這個鏈接是要指向 絕對根路徑,用於訪問圖片或文件,大家可以搭一個nginx伺服器,或者直接用Tomcat也可以,只要能訪問都行。

  "saveRootPath": "/data/", /* 文件和圖片上傳絕對根路徑*/
    /* 上傳圖片配置項 */
    "imageActionName": "uploadimage", /* 執行上傳圖片的action名稱 */
    "imageFieldName": "upfile", /* 提交的圖片表單名稱 */
    "imageMaxSize": 2048000, /* 上傳大小限制,單位B */
    "imageAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 上傳圖片格式顯示 */
    "imageCompressEnable": true, /* 是否壓縮圖片,預設是true */
    "imageCompressBorder": 1600, /* 圖片壓縮最長邊限制 */
    "imageInsertAlign": "none", /* 插入的圖片浮動方式 */
    "imageUrlPrefix": "http://xxx", /* 指向saveRootPath的url,用於訪問圖片或文件*/
  "imagePathFormat": "/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}",

 

7. 我們在 第 3 步 的invoke() 方法 中調用的  this.configManager.getConfig(actionCode); 方法里 組裝絕對根路徑。就是在返回conf之前添加 下麵代碼中的紅色內容。

1         conf.put("savePath", savePath);
2         conf.put("rootPath", this.rootPath);
3         conf.put("saveRootPath",this.jsonConfig.getString("saveRootPath"));
4         return conf;

8.  最後我們把 第5步 里的 save 方法里的 physicalPath 值修改一下 ,註釋原來的內容,新增下麵代碼的紅色內容。

1 //                      String physicalPath = (String)conf.get("rootPath") + savePath;
2                         String physicalPath = (String)conf.get("saveRootPath") + savePath;

這樣 我們就把 原來的相對路徑改成了我們想要的絕對路徑了,大家可以嘗試一下。

好了時間不早了,要休息了,大家如果有什麼更好的方法,可以在評論去留言,大家一起討論!如果有什麼不妥之處也請大家多多指教!

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Vue項目開發過程中,會因為很多不同的實際運用需求不斷地對webpack配置進行修改,在此之前,我們需要對webpack有一個基本的認識,瞭解它到底能為我們做些什麼 webpack是一個模塊打包的工具,它的作用是把互相依賴的模塊處理成靜態資源,如下圖所示。. webpack的作用: ● 把依賴樹按需 ...
  • 如果兩次Get請求的URL完全一樣,則IE瀏覽器會調用上次緩存的結果,不會發起新的Http請求。 解決辦法:在URL最後面加上時間戳。 jQuery全局設置禁止緩存 發送請求 運行效果 ...
  • JavaScript for 迴圈 迴圈可以將代碼塊執行指定的次數。 JavaScript 支持不同類型的迴圈: for - 迴圈代碼塊一定的次數 for/in - 迴圈遍歷對象的屬性 while - 當指定的條件為true,迴圈指定的代碼塊 do/while - 當指定的條件為true,迴圈指定的 ...
  • 列表推導式 你有一個list: bag = [1, 2, 3, 4, 5] 現在你想讓所有元素翻倍,讓它看起來是這個樣子: [2, 4, 6, 8, 10] 大多初學者,根據之前語言的經驗會大概這樣來做 bag = [1, 2, 3, 4, 5] for i in range(len(bag)): ...
  • 官網 http://www.fhadmin.org/D 集成安全許可權框架shiro Shiro 是一個用 Java 語言實現的框架,通過一個簡單易用的 API 提供身份驗證和授權,更安全,更可靠E 集成ehcache分散式緩存 是一個純Java的進程內緩存框架,具有快速、精幹等特點,廣泛使用的開源J ...
  • 1.搭建環境windows10+jdk1.8+eclipse4.8+maven 2.為了學習微服務架構學習搭建基礎項目 3.分為兩種搭建方式為maven項目和單獨建立springboot項目(eclipse需要安裝相關的插件) 第一種使用maven搭建 1)創建maven項目 file--new o ...
  • 上篇介紹了Util Angular Demo的目錄結構和運行機制,本文介紹Util封裝Angular的基本手法及背後的動機。 Angular應用由Ts和Html兩部分構成,本文介紹第一部分。 Angular Ts的封裝 Ts是Angular的代碼部分,用於編寫頁面邏輯。 依賴註入( Dependen ...
  • 配置中心使用ZooKeeper的持久節點的特性,將配置信息寫入到持久節點。客戶端啟動時,從ZooKeeper讀取配置信息,進而初始化內部資源,達到配置統一管理的目的。再結合ZooKeeper的Watch特性,配置信息變化實時推送到客戶端,即時生效,無需重啟客戶端,達到配置熱更新的效果。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...