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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM