又拍云和ueditor集成 javascript
图片上传选择又拍云的form api,这种方式图片上传就直接走又拍云服务器,不通过本身服务器。不过form api的sdk如今在又拍云官网只有php版,java版的有一个android的form sdk,没办法,只能本身搞了。 php
又拍云form api: html
要求: java
第一步:最简单的试炼 jquery
根据官网api实例,若是用form的话须要policy,signature,file这几个字段,action的路基为又拍云上传图片路径加bucket android
"http://v0.api.upyun.com/"+data["bucket"]
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <form id="upyun_form" action="dd" method="post" enctype="multipart/form-data"> <!-- 须要传递如下三个表单内容 --> <input id="upyun_policy" type="hidden" name="policy" value="pl"> <input id="upyun_signature" type="hidden" name="signature" value="si"> <input type="file" name="file"> <input type="submit" value="上传"> </form> <script type="text/javascript" src="/justforfun/lib/js/jquery.min.js"></script> <script type="text/javascript" > $(function(){ $.getJSON("/justforfun/upyun",function(data){ $("#upyun_form").attr("action","http://v0.api.upyun.com/"+data["bucket"]); $("#upyun_policy").val(data["policy"]); $("#upyun_signature").val(data["signature"]); }); }); </script> </body> </html>
为何要用ajax呢,由于文档中说了,policy和signature须要压缩加密,因此须要在后台搞一下。加密的话下载官网上Android的SDK,借用里面几个文件。就是下面标红的地方,由于我用的是spring MVC,搞json的时候用的是jackson这个包,不过sdk里面用的是json-lib,所以修改了下Util那个文件里面json的转换方式,别的地方没改。 web
ok,写一个上传的类。 ajax
参数说明: spring
callbackMethod 对应下面两个方法,一个是get同步回调,一个是post异步回调,测试中post不知到为何没搞成功,所用用return-url。 apache
callBackUrl回调的绝对路径:http://localhost:8080/XXX/upyun/callback
bucket没必要解释了,apiKey须要在又拍云设置,首先启用表单API功能,而后就可一得到密钥了。
方法解释:
getSignature是api里面规定的,直接调用Util的signature方法,并将生成的policy和apiKey用&连接搞进去。
UpYunUtils.signature(policy + "&" + API_KEY);
getSaveKey是保存图片时候的图片保存在bucket下的文件夹名字加文件名,api中有几种pattern,例如我使用的是32位随机字符串+后缀 "{random32}{.suffix}"
genarateUpyunEntity则是最主要的方法,返回一个UpyunEntity是为了能直接用spring MVC搞json方便来的。
package com.upyun; import java.io.File; import java.util.*; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * UEditor文件上传辅助类,上传至又拍云。 * */ public class UpYunUploader { private static Log logger = LogFactory.getLog(UpYunUploader.class); //回调的方法,见又拍云api private String callBackMethod; //回调时调用路径,注意使用绝对路径 private String callBackUrl; //又拍云的bucket private String bucket; //又拍云bucket中的apikey private String apiKey; public UpYunUploader(String callBackMethod, String callBackUrl, String bucket, String apiKey) { super(); this.callBackMethod = callBackMethod; this.callBackUrl = callBackUrl; this.bucket = bucket; this.apiKey = apiKey; } // TODO:save_flooder传值 public UpYunEntity genarateUpyunEntity(String saveFolder) throws UpYunException { String expiration = ((Long) (System.currentTimeMillis() / 1000 + 1000 * 5 * 10)) .toString(); // 过时时间,必须大于当前时间 String saveKey = getSaveKey(saveFolder, "{random32}{.suffix}"); HashMap<String, Object> params = new HashMap<String, Object>(); params.put(callBackMethod, callBackUrl); // TODO:DELETE logger.info("callBackUrl:" + callBackUrl); String policy = UpYunUtils.makePolicy(saveKey, expiration, bucket, params); String signature = getSignature(policy, apiKey); return new UpYunEntity(bucket, policy, signature); } public String getSaveKey(String saveFloder, String pattern) { return File.separator + saveFloder + File.separator + pattern; } public String getSignature(String policy, String API_KEY) { return UpYunUtils.signature(policy + "&" + API_KEY); } }
package com.upyun; import lombok.Data; public @Data class UpYunEntity { private String bucket; private String policy; private String signature; public UpYunEntity() { super(); } public UpYunEntity(String bucket, String policy, String signature) { super(); this.bucket = bucket; this.policy = policy; this.signature = signature; } }
controller
这个controller是在我修改完ueditor以后的版本,所以为了能方便指定保存的路径,加了一个upYunSaveFolder的参数,和以前html里面有点不太对应,凑合这看吧。逻辑就是这样一个逻辑。图片上传前,须要服务器生成一个policy和signature的加密字段,里面包含了apikey,保存路径,这次操做过时时间等等。
package com.upyun; import java.io.File; import java.util.List; import javax.annotation.Resource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.context.request.WebRequest; import com.upyun.UpYun.FolderItem; @Controller @RequestMapping("/upyun") public class UpYunController { private static Log logger = LogFactory.getLog(UpYunController.class); public static final String CALL_BACK = "/upyun/callback"; @Resource private UpYunUploader uploader; @Resource private UpYun upYun; @RequestMapping(method = RequestMethod.GET, params = { "upYunSaveFolder" }) public @ResponseBody UpYunEntity up(String upYunSaveFolder) throws UpYunException { return uploader.genarateUpyunEntity(upYunSaveFolder); } @RequestMapping("/callback") public @ResponseBody UeditorCallBackEntity callBack(UpYunCallBackEntity upyunImage, WebRequest request) { // TODO:delete logger.info(CALL_BACK + upyunImage); return new UeditorCallBackEntity(upyunImage); } @RequestMapping(value = "imageManager", params = { "upYunSaveFolder" }) public @ResponseBody String imageManager(String upYunSaveFolder) { List<FolderItem> list = upYun.readDir(upYunSaveFolder); StringBuffer buffer = new StringBuffer(); for (FolderItem fi : list) { buffer.append("/"); buffer.append(fi.name); buffer.append("ue_separate_ue"); } String imgStr = buffer.toString(); if (!imgStr.equals("")) { imgStr = imgStr.substring(0, imgStr.lastIndexOf("ue_separate_ue")) .replace(File.separator, "/").trim(); } // TODO:delete logger.info(imgStr); return imgStr; } }
第二部:ueditor好基友
要的是这个框框啊最后。
原来的修改功能不要了,图片上传ueditor用的是swfupload,为了和又拍云整合,须要改下面几个文件。(image那两个文件在dialogs/image下)
首先是config.js
在UEDITOR_CONFIG上面先存几个变量,注意visitPath和uploadPath的区别.
访问图片时是visitPath+/文件夹/图片.jpg
var upyunVisitPath = "http://practicephotos.b0.upaiyun.com/"; var upyunUploadPath = "http://v0.api.upyun.com/"; var BUCKET = "practicephotos"; // saveFolder上传到又拍云的文件夹,应根据同用户在session中或者什么地方传值, //注:saveFolder是为了upYunSaveFolder和imageManagerPath而存在的临时变量 var saveFolder = "uploadimagetest"; /** * 配置项主体。注意,此处全部涉及到路径的配置别遗漏URL变量。 * UEDITOR_CONFIG的配置均可以在js中动态修改 * editor.options.XXX = "" */ window.UEDITOR_CONFIG = { // 为编辑器实例添加一个路径,这个不能被注释 UEDITOR_HOME_URL : URL,
imageFieldName改成“file”,对应的image.html中也有修改,由于又拍云里面图片的字段必须是“file”。
// 图片上传地址:又拍云上传路径加bucket imageUrl : upyunUploadPath + BUCKET , //图片修正地址,后台会自动加上保存文件夹和图片路径/XXX/XXX.jpg //所以修正路径只加上又拍云的<strong>访问路径</strong>便可 imagePath : upyunVisitPath // 图片修正地址,引用了fixedImagePath,若有特殊需求,可自行配置 // 集成又拍云 须要修改这里和image.html里面的upfile , imageFieldName : "file" // 图片数据的key,若此处修改,须要在后台对应文件修改对应参数
注意在线管理里面修正路径与图片上传的不一样。
// 图片在线管理配置区 // , imageManagerUrl : projectName + "/upyun/imageManager" // 图片在线管理的处理地址 , //图片管理修正路径,与图片上传修正不一样,后台不会生成目录,所以须要本身加生 //<strong>访问路径</strong>和保存文件夹 imageManagerPath : upyunVisitPath + saveFolder // 图片修正地址,同imagePath ,ueditor.all.js,ctrl+f找图片修改,找到下面的地方,str,上线的时候本身压缩下js。
//TODO:若是还想要修改功能的话,下面注释的东西应该放回去 //移除了图片修改功能 // '+ //'<span onclick="$$._onImgEditButtonClick(\'' + dialogName + '\');" class="edui-clickable">' + editor.getLang("modify") + '</span> str = '<nobr>' + editor.getLang("property") + ': '+ '<span onclick=$$._onImgSetFloat("none") class="edui-clickable">' + editor.getLang("default") + '</span> ' + '<span onclick=$$._onImgSetFloat("left") class="edui-clickable">' + editor.getLang("justifyleft") + '</span> ' + '<span onclick=$$._onImgSetFloat("right") class="edui-clickable">' + editor.getLang("justifyright") + '</span> ' + '<span onclick=$$._onImgSetFloat("center") class="edui-clickable">' + editor.getLang("justifycenter") + '</span></nobr>';image.html
找到tabHeads,删掉不要的东西。
<div id="tabHeads" class="tabhead"> <span tabSrc="local" class="focus"><var id="lang_tab_local"></var></span> <span tabSrc="imgManager"><var id="lang_tab_imgManager"></var></span> </div>
<input id="upyun_policy" type="hidden" name="policy" /> <input id="upyun_signature" type="hidden" name="signature" />
在他原来的js上加一段ajax,注意imageFieldName改为file,与config.js里面对应。ajax传的data里面有一个upYunSaveFolder : editor.options.upYunSaveFolder,就是用这个变量来改变保存路径的,如何调用后面再说。
<script type="text/javascript"> $($.getJSON("/justforfun/upyun", data = { upYunSaveFolder : editor.options.upYunSaveFolder }, function(data) { $("#upyun_policy").val(data["policy"]); $("#upyun_signature").val(data["signature"]); })); //全局变量 var imageUrls = [], //用于保存从服务器返回的图片信息数组 selectedImageCount = 0; //当前已选择的但未上传的图片数量 editor.setOpt({ imageFieldName : "file", compressSide : 0, maxImageSideLength : 900 });
传递表单的附加参数,须要postParams中加值(在$G("upload").onclick那里)。首先在flashOptions中找到ext,注释掉这一行,不知道为何,只有注释掉这行以后才能传postParams里面的参数。
var postParams = { "dir" : baidu.g("savePath").value, "policy" : $("#upyun_policy").val(), "signature" : $("#upyun_signature").val() };image.js
在这里搜imageManagerUrl,找到这个ajax,填上data{upYunSaveFolder这一行}。
ajax.request(editor.options.imageManagerUrl, { timeout:100000, action:"get", data: { upYunSaveFolder: editor.options.upYunSaveFolder }, onsuccess:function (xhr) {前台调用,一、初始话的时候能够在getEditor的时候设置upYunSaveFolder,注意imageManagerPath必定要设置。二、在任何用到js的地方均可以修改editor.options.XXX属性,这里的话XXX就是upYunSaveFolder。
<script type="text/plain" id="editor" name="content" style="width: 680px;height:200px;"> ${(content)!""} </script>
<script type="text/javascript"> var uySaveFloder ="test"; var editor = UE.getEditor('editor',{wordCount:true,maximumWords:800,upYunSaveFolder:uySaveFloder,imageManagerPath:"http://practicephotos.b0.upaiyun.com/"+uySaveFloder}); //editor.options.imageManagerPath=""; </script>上传成功以后又拍云会返回又拍云的一些状态码,和ueditor里面的状态码并不对应。
首先是controller里面的回调方法,再贴一下。至于@Data注解和为何没写get set方法,请见lombok.
UeditorCallBackEntity状态码能够参照ueditor里面Upload.java和imageUp.jsp来搞。
UpYunCallBackEntity则根据又拍云文档里面回调的东西来作。注意文档中的那句话:加密的话即便是图片空间也不会返回图片宽高那些参数。
@RequestMapping("/callback") public @ResponseBody UeditorCallBackEntity callBack(UpYunCallBackEntity upyunImage, WebRequest request) { // TODO:delete logger.info(CALL_BACK + upyunImage); return new UeditorCallBackEntity(upyunImage); }
package com.upyun; import lombok.Data; /** * response.getWriter().print("{'original':'"+up.getOriginalName()+ * "','url':'"+up.getUrl()+ "','title':'"+up.getTitle()+ * "','state':'"+up.getState()+"'}"); * */ public @Data class UeditorCallBackEntity { private String original; private String url; private String title; private String state; public UeditorCallBackEntity(UpYunCallBackEntity upyunImage) { url = upyunImage.getUrl(); state = transUpYunCodeToUeState(upyunImage.getCode(), upyunImage.getMessage()); } private String transUpYunCodeToUeState(String code, String msg) { String defaultState = "未知错误"; if (code == null) { return defaultState; } if (code.equals("200")) { return "SUCCESS"; } return msg; } }
package com.upyun; import lombok.Data; /** * {"code":200, "message":"ok", "url":"\/test\/1382948348613.jpg", * "time":1382948355, "image_width":900, "image_height":506, "image_frames":1, * "image_type":"JPEG", "sign":"fab7c454ea8e54efdeacaf2557c25f6d"} * * */ public @Data class UpYunCallBackEntity { private String code; private String message; private String url; private String time; private String sign; }
在线管理
首先把又拍云的java sdk搞下来,把里面的UpYun放到工程里面。配置一个bean,把以前的upYunUploader一块儿贴在这。
在线管理,原来的imageManger.jsp里面是遍历上传图片的文件夹,而后会进行路径处理,重写这个方法。最初他会得到文件下的全部文件,而后字符串拼接成/XXX.jspue_separate_ue/XXX.jspue_separate_ue这种形式,还记得config.js里面的在线管理图片修正路径么?例如修正路径AAA,ueditor最终会把/XXX.jspue_separate_ue/XXX.jspue_separate_ue处理成AAA/XXX.jsp AAA/XXX.jspue_separate_ue这种样子。并且须要是个json。
controller处理方法
@RequestMapping(value = "imageManager", params = { "upYunSaveFolder" }) public @ResponseBody String imageManager(String upYunSaveFolder) { List<FolderItem> list = upYun.readDir(upYunSaveFolder); StringBuffer buffer = new StringBuffer(); for (FolderItem fi : list) { buffer.append("/"); buffer.append(fi.name); buffer.append("ue_separate_ue"); } String imgStr = buffer.toString(); if (!imgStr.equals("")) { imgStr = imgStr.substring(0, imgStr.lastIndexOf("ue_separate_ue")) .replace(File.separator, "/").trim(); } // TODO:delete logger.info(imgStr); return imgStr; }
至此,ueditor和又拍云整合就结束了。图片上传的配置主要在image.html里面。