UEditor1.4.3.3整合Spring MVC和七牛
【前言】
项目中涉及将UEditor上传服务器整合进已有的基于Spring MVC的服务中,并且将上传到本地改为上传到七牛,看似简单的一个需求,实际做起来还是遇到了一些困难。在这里分享一下经验——
七牛官网的社区插件里有ueditor的插件

该插件是《ueditor上传图片到七牛云存储(form api,java)》的作品,也发布了git地址。从图上时间信息可知这是13年底的插件。
自从百度更新UEditor1.4.0之后,将分散的请求接口整合成一个ActionEnter入口,做了一个比较大的变动,原有的方式已经不适用了。
参考《Ueditor结合七牛云及百度云存储(JAVA版,ueditor-1.4.3)实现图片文件上传》的方法之后,解决了问题。
【UEditor分析】
该方法涉及到对UEditor源码的改动,所以首先要下载UEditor的源码。具体的二次开发细节和常见问题在UEditor开发文档中写的很清楚
大致说明一下编辑器涉及上传的几个文件:
ueditor.all.min.js是编辑器的汇总js,通过压缩ueditor.all.js得到,也是实际调用的js
在ueditor.all.js的// core/loadconfig.js中加载了UE.Editor.prototype.loadServerConfig,该结构是根据serverUrl请求config得到的。其实就是获取了服务器的config.json文件,所以该文件在服务器中的路径要格外注意。
config.json里配置了上传的地址等信息
imageUrlPrefix是图片上传的前缀,这里设置成七牛的上传地址。imagePathFormat是文件名,可以使用原有模版加入日期信息。imageManagerUrlPrefix是图片加载的前缀,上传成功后会从该地址读取图片插入到编辑器中。
ueditor.config.js是配置文件
值得注意的是var URL = window.UEDITOR_HOME_URL || getUEBasePath();和serverUrl: URL + "jsp/controller.jsp"这两句,一个指定了上传服务器的路径,一个指定了服务接口。
dialog目录管理编辑器中新开的窗口,包括文件上传窗口
internal.js是其入口
【开始】
【修改文件上传接口】
编辑器整合进spring框架,lib可以通过maven自行加载,这部分比较简单,略过不表。
将UEditor的源码加入spring

再新建一个controller,源码如下
@RestController
public class FileManagerController {
@RequestMapping(value = "controller")
public String controller(HttpServletRequest request,HttpServletResponse response) {
String rootPath = request.getServletContext().getRealPath("/");
return new ActionEnter( request, rootPath).exec();
}
}
Controller
这里做了一个名为controller的接口,调用ueditor的ActionEnter对象,注意因为ueditor的GET和POST方法都会通过ActionEnterd进行,只是action参数不同,所以该controller不要指定GET/POST方式
【修改文件上传方式】
这里因为将jsp调用改成了接口调用,所以文件传输的方法也要做相应修改,其实使用原来的jsp也是可以的
在com.baidu.ueditor.upload.Uploader找到doExec方法中对应的save方法,我这里没有启用Base64,所以走的是com.baidu.ueditor.upload.BinaryUploader的save方法。
做如下修改:
public class BinaryUploader {
public static final State save(HttpServletRequest request,
Map<String, Object> conf) {
boolean isAjaxUpload = request.getHeader( "X_Requested_With" ) != null;
if (!ServletFileUpload.isMultipartContent(request)) {
return new BaseState(false, AppInfo.NOT_MULTIPART_CONTENT);
}
ServletFileUpload upload = new ServletFileUpload(
new DiskFileItemFactory());
if ( isAjaxUpload ) {
upload.setHeaderEncoding( "UTF-8" );
}
try {
//创建一个通用的多部分解析器
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
//判断 request 是否有文件上传,即多部分请求
if(multipartResolver.isMultipart(request)){
//转换成多部分request
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest)request;
//取得request中的所有文件名
Iterator<String> iter = multiRequest.getFileNames();
while(iter.hasNext()){
//取得上传文件
MultipartFile file = multiRequest.getFile(iter.next());
if(file != null){
//取得当前上传文件的文件名称
String savePath = (String) conf.get("savePath");
String originFileName = file.getOriginalFilename();
System.out.println(originFileName);
String suffix = FileType.getSuffixByFilename(originFileName);
originFileName = originFileName.substring(0,
originFileName.length() - suffix.length());
savePath = savePath + suffix;
long maxSize = ((Long) conf.get("maxSize")).longValue();
if (!validType(suffix, (String[]) conf.get("allowFiles"))) {
return new BaseState(false, AppInfo.NOT_ALLOW_FILE_TYPE);
}
savePath = PathFormat.parse(savePath, originFileName);
String physicalPath = (String) conf.get("rootPath") + savePath;
System.out.println(physicalPath);
InputStream is = file.getInputStream();
State storageState = StorageManager.saveFileByInputStream(is,
physicalPath, maxSize);
is.close();
if (storageState.isSuccess()) {
storageState.putInfo("url", PathFormat.format(savePath));
storageState.putInfo("type", suffix);
storageState.putInfo("original", originFileName + suffix);
}
return storageState;
}
else{
return new BaseState(false, AppInfo.NOTFOUND_UPLOAD_DATA);
}
}
}
}
catch (IOException e) {
return new BaseState(false, AppInfo.PARSE_REQUEST_ERROR);
}
return new BaseState(false, AppInfo.IO_ERROR);
}
BinaryUploader
这样就可以使用servlet接口而不是jsp获取文件
【修改七牛上传】
再找到com.baidu.ueditor.upload.StorageManager的saveTmpFile方法,在这里改的主要原因是其他传输方式都会经过这一步,方便一步到位
源码如下:
private static State saveTmpFile(File tmpFile, String path) {
State state = null;
File targetFile = new File(path);
if (targetFile.canWrite()) {
return new BaseState(false, AppInfo.PERMISSION_DENIED);
}
String uploadto = QPropertiesUtil.get("jfinal.ueditor.upload_to");
System.out.println(uploadto);
boolean uploaderror = false;
if(QStringUtil.notEmpty(uploadto)){
String key = path.substring(path.lastIndexOf("/")+1);
if("qiniu".equals(uploadto)){
QQiNiuUtil.uploadFile(key, tmpFile.getAbsolutePath());//使用七牛上传
}else{
uploaderror = true;
}
}else{
uploaderror = true;
}
if(uploaderror){
try {
FileUtils.moveFile(tmpFile, targetFile);
} catch (IOException e) {
return new BaseState(false, AppInfo.IO_ERROR);
}
}
state = new BaseState(true);
state.putInfo( "size", targetFile.length() );
state.putInfo( "title", targetFile.getName() );
return state;
}
saveTmpFile
其中
if("qiniu".equals(uploadto)){
QQiNiuUtil.uploadFile(key, tmpFile.getAbsolutePath());
}else{
uploaderror = true;
}
就是使用七牛的核心方法了,QQiNiuUtil.uploadFile是uikoo9实现的方法,也可以改成自己的七牛上传方法
UploadManager uploadManager = new UploadManager();
Response res = uploadManager.put("上传的文件路径", "上传文件保存的文件名", Auth.create(accessKey, secretKey).uploadToken("上传空间名"));
【修改配置文件】
最后将var URL = window.UEDITOR_HOME_URL || getUEBasePath();
改成var URL = "http://www.xxxx.com/YYYY/" || getUEBasePath();
将serverUrl: URL + "jsp/controller.jsp"
改成serverUrl: URL + "controller"
至此就可以上传到七牛了。
【跨域问题】
【前后端分离的跨域问题】
如果要做到ueditor上传图片前后端分离,这里还要解决一个跨域的问题。假设包含编辑器的前端域名为web.ueditor.com,后端上传服务器的域名为server.ueditor.com,他们同属一个ueditor.com主域名。
首先在controller中使用@CrossOrigin(origins = “http://web.ueditor.com”)的CORS注解(Spring4)解决跨域问题,但这依然会在打开文件上传窗口时出现跨域问题。
问题出在internal.js的dialog = parent.$EDITORUI[window.frameElement.id.replace( /_iframe$/, '' )];
因为在修改serverUrl后,加载ueditor时用的已经是服务器的JS文件了,但parent还是客户端的,有兴趣的人可以在这里把parent打出来看看。所以虽然已经解决了客户端到服务器的跨域问题,但依然遇到了iframe的跨域问题,解决方法如下:
打开服务器的dialogs/internal.js,在错误语句前增加域信息
document.domain="ueditor.com";//加一句
dialog = parent.$EDITORUI[window.frameElement.id.replace( /_iframe$/, '' )];
使上传服务器属于ueditor.com域
再在调用这个编辑器的页面加入
<script>
document.domain = "ueditor.com";
</script>
使前端也属于ueditor.com域,就可以解决这个问题了
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
更好的跨域解决方法是使用nginx或apache的反向代理,都在一个域下了还跨什么呢^_^
UEditor1.4.3.3整合Spring MVC和七牛的更多相关文章
- Hibernate validator使用和自定义validator及整合Spring MVC
http://blog.csdn.net/lwphk/article/details/43983669 Hibernate validator使用 导入validation-api-xxx.jar 以 ...
- 【深度分析】:阿里,腾讯面试题 SpringBoot整合Spring MVC
Java学习总结 SpringBoot整合Spring MVC 1.SpringMVC概述 MVC(Model–view–controller)是软件工程中的一种软件架构模式,基于此模式把软件系统分为 ...
- spring 整合 spring mvc
需要进行 Spring 整合 SpringMVC 吗 ? 还是否需要再加入 Spring 的 IOC 容器 ? 是否需要再 web.xml 文件中配置启动 Spring IOC 容器的 Context ...
- MyBatis整合Spring MVC
前面几篇文章已经讲到了mybatis与spring 的集成.目前主流的Web MVC框架,除了Struts这个主力外,还有Spring MVC,主要是由于 Spring MVC 配置比较简单,使用起来 ...
- MyBatis整合Spring MVC(易百教程)
MyBatis是ibatis的升级版,作为hibernate的老对手,它是一个可以自定义SQL.存储过程和高级映射的持久层框架.与Hibernate 的主要区别就是 Mybatis 是半自动化的,而 ...
- Spring MVC(七篇)
(一)Spring MVC简介 (二)SpringMVC核心控制器 (三)Spring MVC Controller接口控制器详解(一) (三)Spring MVC Controller接口控制器详解 ...
- patchca整合Spring MVC生成超炫的验证码
转载:http://lavasoft.blog.51cto.com/62575/1406947 @Controller public class Login2Controller { priv ...
- spring mvc和web-flow的整合方案
发现了一份整合spring MVC 和webflow的很好的资料,日后翻译出来发布.先记着. http://docs.spring.io/spring-webflow/docs/2.3.x/refer ...
- spring mvc之启动过程源码分析
简介 这两个星期都在看spring mvc源码,看来看去还是还是很多细节没了解清楚,在这里把看明白的记录下,欢迎在评论中一起讨论. 一.铺垫 spring mvc是基于servlet的,在正式分析之前 ...
随机推荐
- 运行mvn install时跳过Test
1.1 方法一 <project> [...] <build> <plugins> <plugin> <groupId>org.apache ...
- chrome开发工具指南(六)
检查和编辑页面与样式 使用 Chrome DevTools 的 Elements 面板检查和实时编辑页面的 HTML 与 CSS. 在 Elements 面板中检查和实时编辑 DOM 树中的任何元素. ...
- 第1阶段——关于u-boot目标文件start.o中.globl 和.balignl理解(3)
汇编程序中以.开头的名称并不是指令的助记符,不会被翻译成机器指令,而是给汇编器一些特殊指示,称为伪操作. .globl _start 作用:声明一个_start全局符号(Symbol), 这个_sta ...
- unix下的文件和目录详解以及操作方法
前言:unix下一切东西都是文件,一共有7种不同的文件,前一篇博客已经讲解的很清楚了,不懂的可以看看这里.当然,博主知道有些朋友比忙,没时间看,那我就简单点讲讲这7中文件都有哪些吧. 文件类型包括在s ...
- 王者荣耀是怎样炼成的(一)《王者荣耀》用什么开发,游戏入门,unity3D介绍
在国内,如果你没有听说过<王者荣耀>,那你一定是古董级的人物了. <王者荣耀>(以下简称“农药”),专注于移动端(Android.IOS)的MOBA游戏.笔者看到这么火爆,就萌 ...
- Python中os和shutil模块实用方法集…
Python中os和shutil模块实用方法集锦 类型:转载 时间:2014-05-13 这篇文章主要介绍了Python中os和shutil模块实用方法集锦,需要的朋友可以参考下 复制代码代码如下: ...
- MPLS LDP随堂笔记1
LDP 的使用原因(对于不同协议来说) LDP的四大功能 发现邻居 hello 5s 15s 224.0.0.2 发现邻居关系 R1 UDP 646端口 R2 UDP 646端口 此时形成邻居 建立邻 ...
- go golang 笔试题 面试题 笔试 面试
go golang 笔试题 面试题 笔试 面试 发现go的笔试题目和面试题目还都是比较少的,于是乎就打算最近总结一下.虽然都不难,但是如果没有准备猛地遇到了还是挺容易踩坑的. 就是几个简单的笔试题目, ...
- 团队作业5——测试与发布(Alpha版本)
Deadline: 2017-5-7 22:00PM,以博客发表日期为准 评分基准: 按时交 - 有分,检查的项目包括后文的两个方面 测试报告 发布说明 晚交 - 0分 迟交一周以上 - 倒扣本次作业 ...
- 201521123083《Java程序设计》第11周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 上周这张图没理解完,继续 2. 书面作业 本次PTA作业题集多线程 1互斥访问与同步访问完成题集4-4(互斥访问) ...