后端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的类,如下:

 /**
* 用于处理关于ueditor插件相关的请求
* @author Guoqing
*
*/
@RestController
@CrossOrigin
@RequestMapping("/sys/ueditor")
public class UeditorController extends BaseController { @RequestMapping(value = "/exec")
@ResponseBody
public String exec(HttpServletRequest request) throws UnsupportedEncodingException{
request.setCharacterEncoding("utf-8");
String rootPath = request.getRealPath("/");
return new ActionEnter( request, rootPath).exec();
}
}

该类主要处理,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

欢迎围观、点赞!

我只是一个不想做程序员的好程序员。

vue.js+UEditor集成 [前后端分离项目]的更多相关文章

  1. vue+Ueditor集成 [前后端分离项目][图片、文件上传][富文本编辑]

    后端DEMO:https://github.com/coderliguoqing/UeditorSpringboot 前端DEMO:https://github.com/coderliguoqing/ ...

  2. .Net Core+Vue.js+ElementUI 实现前后端分离

    .Net Core+Vue.js+ElementUI 实现前后端分离 Tags: Vue 架构 前端采用:Vue.js.Element-UI.axios 后端采用:.Net Core Mvc 本项目是 ...

  3. nginx+vue+uwsgi+django的前后端分离项目部署

    Vue+Django前后端分离项目部署,nginx默认端口80,数据提交监听端口9000,反向代理(uwsgi配置)端口9999 1.下载项目文件(统一在/opt/luffyproject目录) (1 ...

  4. vue+uwsgi+nginx部署前后端分离项目

    前后端分离,vue前端提供静态页面,且可以向后台发起get,post等restful请求. django后台提供数据支撑,返回json数据,返回给vue,进行数据页面渲染 后端 创建虚拟环境 解决dj ...

  5. SpringBoot+Vue豆宝社区前后端分离项目手把手实战系列教程01---搭建前端工程

    豆宝社区项目实战教程简介 本项目实战教程配有免费视频教程,配套代码完全开源.手把手从零开始搭建一个目前应用最广泛的Springboot+Vue前后端分离多用户社区项目.本项目难度适中,为便于大家学习, ...

  6. SpringBoot+Vue豆宝社区前后端分离项目手把手实战系列教程02---创建后端工程

    本节代码开源地址 代码地址 项目运行截图 搭建后端工程 0.导入sql 在数据库导入 /* Navicat Premium Data Transfer Source Server : localhos ...

  7. linux --- 部署前后端分离项目

    vue + uwsgi +nginx 部署前后端分离项目 准备项目 1.将前端vue项目包和后端django项目包上传服务器,通过lrzsz,直接从windows拖进linux中 2.解压缩操作 前端 ...

  8. List多个字段标识过滤 IIS发布.net core mvc web站点 ASP.NET Core 实战:构建带有版本控制的 API 接口 ASP.NET Core 实战:使用 ASP.NET Core Web API 和 Vue.js 搭建前后端分离项目 Using AutoFac

    List多个字段标识过滤 class Program{  public static void Main(string[] args) { List<T> list = new List& ...

  9. Win10环境前后端分离项目基于Vue.js+Django+Python3实现微信(wechat)扫码支付流程(2021年最新攻略)

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_182 之前的一篇文章:mpvue1.0+python3.7+Django2.0.4实现微信小程序的支付功能,主要介绍了微信小程序内 ...

随机推荐

  1. Hibernate学习笔记二:Hibernate缓存策略详解

    一:为什么使用Hibernate缓存: Hibernate是一个持久层框架,经常访问物理数据库. 为了降低应用程序访问物理数据库的频次,从而提高应用程序的性能. 缓存内的数据是对物理数据源的复制,应用 ...

  2. MySql学习笔记(一) —— 数据的分组

    前面介绍的聚集函数只是用来计算行数,平均数,最大值,最小值而不用检索所有数据.通过count()函数,我们可以计算生产商1003提供的产品数目,但如果我要查询所有生产商提供的商品数,这就需要进行分组查 ...

  3. Java 多线程详解(四)------生产者和消费者

    Java 多线程详解(一)------概念的引入:http://www.cnblogs.com/ysocean/p/6882988.html Java 多线程详解(二)------如何创建进程和线程: ...

  4. MySQL索引和查询优化

    对于任何DBMS,索引都是进行优化的最主要的因素.对于少量的数据,没有合适的索引影响不是很大,但是,当随着数据量的增加,性能会急剧下降. 如果对多列进行索引(组合索引),列的顺序非常重要,MySQL仅 ...

  5. 微信小程序实战(商城)

    github地址(欢迎star):https://github.com/xiaobinwu/dj 版本:0.15.152900(暂未升级原因:升级后需要图片无法本地引用,必须使用image或是远程路径 ...

  6. nodeJS之二进制buffer对象

    前面的话 在ES6引入TypedArray之前,JavaScript语言没有读取或操作二进制数据流的机制.Buffer类被引入作为Nodejs的API的一部分,使其可以在TCP流和文件系统操作等场景中 ...

  7. PowerShell管道入门,看看你都会不(管道例子大全)

    PowerShell的一个重中之重的功能就是管道(pipeline),本文从浅入深,一步一步详解管道的使用方法和例子,来看看有没有你所不知道的吧,如果全知道,恭喜你已经很厉害啦--适用于所有Power ...

  8. Ch1. Intro to Programming

    1-1 Input three integers and output the average number. Keep three decimal places.  #include<stdi ...

  9. Python 基于TK 文本编辑器

    #coding=utf-8 import sys,os import tkFileDialog from Tkinter import * from tkFont import Font print ...

  10. 利用angular给节点添加样式

    <!DOCTYPE html> <html lang="en" ng-app="myapp"> <head> <met ...