后端DEMO:https://github.com/coderliguoqing/UeditorSpringboot
前端DEMO:https://github.com/coderliguoqing/ueditor-web
預覽地址:https://coderliguoqing.github.io/ueditor-web/dist/#/ueditor
寫在最前面的話:鑒於近期很多的博友討論,說我按照文章的一步一步來,弄好之后,怎么會提示后端配置項http錯誤,文件上傳會提示上傳錯誤。這里提別申明一點,ueditor在前端配置好后,需要與后端部分配合進行,后端部分的項目代碼git地址:https://github.com/coderliguoqing/UeditorSpringboot,然后將配置ueditor.config.js 里的serverUrl的前綴改陳你自己的后端訪問的請求路徑地址,文件上傳的后端部分,只提供了demo,具體對接文件服務器的部分需要自己修改完成。
首先,談下這篇文章中的前后端所涉及到的技術框架內容。
雖然是后端的管理項目,但整體項目,是采用前后端分離的方式完成,這樣做的目的也是產品化的需求;
前端,vue+vuex+vue router+webpack+elementUI的方案完成框架的搭建,其中用到了superUI來作為后端登陸之后的主頁面框架,中間集成vue的大型單頁應用;
后端,springboot+spring+springmvc+spring serurity+mybatis+maven+redis+dubbo
+zookeeper的方式來構建項目框架和管理,提供給前端restful風格的接口。此處還提供app端、PC WEB端的接口。
UEditor之前一直有在項目中使用,作為國內開源的富文本編輯器,有百度的強大技術支持,整體來說是不錯的選擇,百度也提供了php、asp、.net、jsp的版本。原有的項目是采用整體式的開發方式,采用的是jsp的頁面開發技術,所以集成起來相對來說更加容易,只需要按照文檔的方式將前端集成進去,然后后端拿到源碼之后,針對文件上傳的類修改最終存儲的方法即可將文件等上傳到本身的服務器了。
然而,由於決定了做前后端分離的方式,必然就會有新的坑,特別是還選擇了新的技術vue.js+elementUI的這種方式。那么也只能放手一搏,不多啰嗦,介紹完,馬上開始正事。
1、下載UEditor官網最新的jsp版本的包,下載完成解壓之后得到一個ueditor1_4_3_3-utf8-jsp的文件夾,里面包含的內容如下:
除了jsp的文件夾之外,其余的文件和文件夾復制到前端項目中的static用於存放靜態文件的目錄下,結構如下:
這里特別說明jsp目錄下的資源為何不放進來,因為我們是vue搭建的項目,jsp頁面肯定是不會放在前端的項目中的,包括config.json也放在后端用於解析,這里后面會解釋這樣做的原因。
2、前端將文件放進來之后,暫時先這樣,咱們來整理后端的東西。這里將jsp目錄下的lib目中的ueditor.jar文件中的所有類全部拿出來(具體方式自己決定,反編譯工具或者拿到源碼都可以),放到后端項目中,然后在control層新建一個UeditorController.java的類,如下:
1 /** 2 * 用於處理關於ueditor插件相關的請求 3 * @author Guoqing 4 * 5 */ 6 @RestController 7 @CrossOrigin 8 @RequestMapping("/sys/ueditor") 9 public class UeditorController extends BaseController { 10 11 @RequestMapping(value = "/exec") 12 @ResponseBody 13 public String exec(HttpServletRequest request) throws UnsupportedEncodingException{ 14 request.setCharacterEncoding("utf-8"); 15 String rootPath = request.getRealPath("/"); 16 return new ActionEnter( request, rootPath).exec(); 17 } 18 }
該類主要處理,ueditor與后端服務器的交互,通過action=''不同的類型來處理,其中action=config為加載配置項,action=uploadImg 圖片上傳,在ActionEntor類中,你可以根據不同的請求類型來處理;
處理當action=config時的情況,保證前端的編輯器各項文件上傳功能,能夠正常使用。
然后jsp目錄下的config.json文件放到java/main/resources目錄下,修改ConfigManager.java類,如下:
注釋掉原有的讀取配置文件的方式,添加新的讀取路徑,這樣確保ueditor在初始化能夠正確的加載配置文件。此時,修改前端項目中ueditor.config.js中的serverUrl的值為:
// 服務器統一請求接口路徑
, serverUrl: "http://localhost:8080/sys/ueditor/exec"
而,針對ActionEnter.java類中,如下代碼后的文件上傳的處理,請大家針對自身的上傳方式和文件服務器選擇適合自己的方式:
switch ( actionCode ) { //讀取配置文件時的請求處理 case ActionMap.CONFIG: return this.configManager.getAllConfig().toString(); //上傳圖片、視頻、文件時的處理 case ActionMap.UPLOAD_IMAGE: case ActionMap.UPLOAD_SCRAWL: case ActionMap.UPLOAD_VIDEO: case ActionMap.UPLOAD_FILE: conf = this.configManager.getConfig( actionCode ); state = new Uploader( request, conf, baseFileService ).doExec(); break; //抓取遠程圖片時的處理方式,此處也可以關閉 //當從網頁上復制內容到編輯器中,如果圖片與該域名不同源,則會自動抓到本地的服務器保存 case ActionMap.CATCH_IMAGE: conf = configManager.getConfig( actionCode ); String[] list = this.request.getParameterValues( (String)conf.get( "fieldName" ) ); state = new ImageHunter( conf ).capture( list ); break; //上傳多文件時的文件在線管理 case ActionMap.LIST_IMAGE: case ActionMap.LIST_FILE: conf = configManager.getConfig( actionCode ); int start = this.getStartIndex(); state = new FileManager( conf ).listFile( start ); break; } return state.toJSONString();
接下來是前端的處理,介於大家的要求。作者將原本的demo進行了優化,將編輯器封裝成組件的方式,方便調用,代碼如下:
<template> <div> <script id="editor" type="text/plain" ></script> </div> </template> <script> import AppConfig from '@/config' import '../../../../../../static/ueditor/ueditor.config.js' import '../../../../../../static/ueditor/ueditor.all.js' import '../../../../../../static/ueditor/lang/zh-cn/zh-cn.js' export default { name: "UEditor", props: { id: { type: String }, config: { type: Object } }, data() { return { editor: null } }, mounted() { //初始化UE const _this = this; this.editor = UE.getEditor('editor',this.config); }, destoryed() { this.editor.destory(); }, methods:{ getUEContent: function(){ return this.editor.getContent(); } } } </script>
導出組件:
var UEditor = require('./src/ueditor.vue'); module.exports = { UEditor }
這里之所以是用一個模態框的方式來加載編輯器,是因為會存在編輯器工具欄浮動的問題,如果有問題,請根據如下的配置來處理即可;
頁面調用:
<template> <div id="app" class="hello"> <el-button size="primary" type="info" icon="plus" @click="openWindow">打開窗口</el-button> <el-dialog title="新增菜單" size="small" v-model="addFormVisible" :close-on-click-modal="false"> <div> <el-button size="primary" type="info" icon="plus" @click="getContent">獲取內容</el-button> <UEditor :config=config ref="ueditor"></UEditor> </div> </el-dialog> </div> </template> <script> import {UEditor} from './ueditor/index.js' export default{ name: 'hello', components: {UEditor}, data(){ return { config: { /*//可以在此處定義工具欄的內容 toolbars: [ ['fullscreen', 'source','|', 'undo', 'redo','|','bold', 'italic', 'underline', 'fontborder', 'strikethrough', '|','superscript','subscript','|', 'forecolor', 'backcolor','|', 'removeformat','|', 'insertorderedlist', 'insertunorderedlist', '|','selectall', 'cleardoc','fontfamily','fontsize','justifyleft','justifyright','justifycenter','justifyjustify','|', 'link','unlink'] ],*/ autoHeightEnabled: false, autoFloatEnabled: true, //是否工具欄可浮動 initialContent:'請輸入內容', //初始化編輯器的內容,也可以通過textarea/script給值,看官網例子 autoClearinitialContent:true, //是否自動清除編輯器初始內容,注意:如果focus屬性設置為true,這個也為真,那么編輯器一上來就會觸發導致初始化的內容看不到了 initialFrameWidth: null, initialFrameHeight: 450, BaseUrl: '', UEDITOR_HOME_URL: 'static/ueditor/' }, addFormVisible: false } }, methods: { openWindow: function(){ this.addFormVisible = true; }, //獲取文檔內容 getContent: function(){ let content = this.$refs.ueditor.getUEContent(); console.log(content); alert(content); } } } </script>
至此,大功告成,包括文件上傳下載等部分全部搞定,不過要聲明一點的是,當出現接口與頁面部署域名不同時,點擊選擇圖片上傳會出現iframe跨域的問題。
2017-09-08的更新,作者已經通過更改源碼的方式,處理了單圖選擇文件上傳存在跨域的問題,處理方式當然就是將原有的form.submit的表單上傳方式,更改為ajax的上傳方式;
ueditor.all.js 24503行的方法替換,源碼如下:
/** * 2017-09-07 改掉了ueditor源碼,將本身的單文件上傳的方法改為ajax上傳,主要目的是為了解決跨域的問題 * @author Guoqing */ domUtils.on(input, 'change', function() { if(!input.value) return; var loadingId = 'loading_' + (+new Date()).toString(36); var imageActionUrl = me.getActionUrl(me.getOpt('imageActionName')); var allowFiles = me.getOpt('imageAllowFiles'); me.focus(); me.execCommand('inserthtml', '<img class="loadingclass" id="' + loadingId + '" src="' + me.options.themePath + me.options.theme +'/images/spacer.gif" title="' + (me.getLang('simpleupload.loading') || '') + '" >'); /!* 判斷后端配置是否沒有加載成功 *!/ if (!me.getOpt('imageActionName')) { errorHandler(me.getLang('autoupload.errorLoadConfig')); return; } // 判斷文件格式是否錯誤 var filename = input.value, fileext = filename ? filename.substr(filename.lastIndexOf('.')):''; if (!fileext || (allowFiles && (allowFiles.join('') + '.').indexOf(fileext.toLowerCase() + '.') == -1)) { showErrorLoader(me.getLang('simpleupload.exceedTypeError')); return; } var params = utils.serializeParam(me.queryCommandValue('serverparam')) || ''; var action = utils.formatUrl(imageActionUrl + (imageActionUrl.indexOf('?') == -1 ? '?' : '&') + params); var formData = new FormData(); formData.append("upfile", form[0].files[0] ); $.ajax({ url: action, type: 'POST', cache: false, data: formData, processData: false, contentType: false, success: function (data) { data = JSON.parse(data); var link, loader, body = (iframe.contentDocument || iframe.contentWindow.document).body, result = body.innerText || body.textContent || ''; link = me.options.imageUrlPrefix + data.url; if(data.state == 'SUCCESS' && data.url) { loader = me.document.getElementById(loadingId); loader.setAttribute('src', link); loader.setAttribute('_src', link); loader.setAttribute('title', data.title || ''); loader.setAttribute('alt', data.original || ''); loader.removeAttribute('id'); domUtils.removeClasses(loader, 'loadingclass'); } else { showErrorLoader && showErrorLoader(data.state); } form.reset(); } }); function showErrorLoader(title){ if(loadingId) { var loader = me.document.getElementById(loadingId); loader && domUtils.remove(loader); me.fireEvent('showmessage', { 'id': loadingId, 'content': title, 'type': 'error', 'timeout': 4000 }); } } });
好了,如果以上對你有幫助的話,請順手點個贊,謝謝各位大蝦們啦!
效果圖如下:
/************************華麗麗的分割線*************************/
2017-11-29 響應大家的要求,前后端項目都提供了源碼的demo 請上github上查看,如還有問題,請多多交流
各位如果還有問題的,那么請入群吧: qq 581036486 入群密碼:88888888
https://github.com/coderliguoqing
歡迎圍觀、點贊!
我只是一個不想做程序員的好程序員。