後端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目錄下的資源為何不放進來,因為我們是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
歡迎圍觀、點贊!
我隻是一個不想做程式員的好程式員。