• 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的反向代理,都在一个域下了还跨什么呢^_^

  • 相关阅读:
    Dynamic proxy (good-原创)
    思维导图
    Android学习之 WebView使用小结
    shell语法简单介绍
    php反射类 ReflectionClass
    老鸟的Python新手教程
    腾讯云安装openvz,高速搭建測试环境
    NYOJ-1058 部分和问题
    NGUI ScrollView动态加入和删除对象。
    几种常见模式识别算法整理和总结
  • 原文地址:https://www.cnblogs.com/Orange42/p/5992452.html
Copyright © 2020-2023  润新知