前言
目前项目上正在做一个文件处理的东西,因为是单台服务器,带宽也有限,就将用户资源文件存储到空间上了;
正文
本文简单七牛云空间的使用,提供对应工具类,包含tonken生成、上传、删除、压缩图片等。
本文不含查询图片等操作,直接预上传前处理好实际URL地址并交回前端。
本文总结于项目使用,先说明几个关键参数:
AccessKey = Access私钥
SecretKey = Secret私钥
bucket = 对象存储空间名
key = 你上传的文件名
私钥自己账户申请开通。
token
七牛云空间上传图片前会有一个动作,要求前端携带一个token,这个token是由你的服务器端生成的,传参为指定图片名称、空间、2个私钥。
这里需要说明一下,前台后台key值要统一,不然校验不通过;
遇到的坑,按照API来说是让key值一致即可,请后台在返回前端的时候不要只返回token,请携带上key。
/**
* Description:简单token类型返回封装
* @param key 文件名
* @return String
* @author around
* @date 2017年8月14日上午9:57:29
*/
public static String getBaseToken(String bucket, String key) {
Auth auth = Auth.create(ACCESSKEY, SECRETKEY);
return auth.uploadToken(bucket, key);
}
/**
* Description:自定义token返回结果
* @param key 文件名
* @return
* @author around
* @date 2017年8月11日下午6:07:24
*/
public static String getCustomToken(String bucket, String key) {
Auth auth = Auth.create(ACCESSKEY, SECRETKEY);
StringMap putPolicy = new StringMap();
putPolicy.put("returnBody", "{\"key\":\"$(key)\",\"com\":\"$(x:com)\",\"hash\":\"$(etag)\",\"bucket\":\"$(bucket)\",\"fsize\":$(fsize)}");
long expireSeconds = 3600;
return auth.uploadToken(bucket, key, expireSeconds, putPolicy);
}
上传
前台直接以form表单形式上传,对了,根据后台生成token时,有的是定制了返回参数的魔法变量,那么返回时也会这样返回,给前端提供更多参数。
<form method="post" action="http://upload.qiniu.com/"
enctype="multipart/form-data">
<input name="key" type="hidden" value="<resource_key>">
<input name="x:<custom_name>" type="hidden" value="<custom_value>">
<input name="token" type="hidden" value="<upload_token>">
<input name="file" type="file" />
<input name="crc32" type="hidden" />
<input name="accept" type="hidden" />
</form>
魔法变量
如上面自定义token的例子,自定义请求返回结果:
putPolicy.put("returnBody", "{\"key\":\"$(key)\",\"com\":\"$(x:com)\",\"hash\":\"$(etag)\",\"bucket\":\"$(bucket)\",\"fsize\":$(fsize)}");
里面的com属性$(x:com)
就是自定义变量,定义方式就是$(x:com)
。
前台接收token,携带参数发起请求,如上面的form提交,绑定好参数后直接请求云空间,返回时将携带对应的参数值及自定义变量。
查询
本文没有查询,处理的方式是后台封装预处理成功的URL地址,随token返回时给前端,通过魔法变量在请求七牛时携带返回,拿到返回后随前端业务保存按钮提交至后台保存URL即可。
删除
提供单独删除和批量删除方法
/**
* Description:删除指定文件
* @param key 文件名
* @return boolean true:成功
* @author around
* @date 2017年8月11日下午6:21:18
*/
public static boolean remove(String bucket, String key) {
//构造一个带指定Zone对象的配置类
Configuration cfg = new Configuration(Zone.zone0());
Auth auth = Auth.create(ACCESSKEY, SECRETKEY);
BucketManager bucketManager = new BucketManager(auth, cfg);
try {
bucketManager.delete(bucket, key);
} catch (QiniuException ex) {
//如果遇到异常,说明删除失败
System.err.println(ex.code());
System.err.println(ex.response.toString());
return false;
}
return true;
}
/**
* Description:批量删除文件
* @param keyList 文件名数组
* @return boolean
* @author around
* @date 2017年8月14日上午9:56:03
*/
public static boolean remove(String bucket, String[] keyList) {
//构造一个带指定Zone对象的配置类
Configuration cfg = new Configuration(Zone.zone0());
//...其他参数参考类注释
Auth auth = Auth.create(ACCESSKEY, SECRETKEY);
BucketManager bucketManager = new BucketManager(auth, cfg);
try {
//单次批量请求的文件数量不得超过1000
//String[] keyList = new String[]{"qiniu.jpg","qiniu.mp4","qiniu.png",};
BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations();
batchOperations.addDeleteOp(bucket, keyList);
Response response = bucketManager.batch(batchOperations);
BatchStatus[] batchStatusList = response.jsonToObject(BatchStatus[].class);
for (int i = 0; i < keyList.length; i++) {
BatchStatus status = batchStatusList[i];
String key = keyList[i];
System.out.print(key + "\t");
if (status.code == 200) {
System.out.println("delete success");
} else {
System.out.println(status.data.error);
}
}
} catch (QiniuException ex) {
System.err.println(ex.response.toString());
return false;
}
return true;
}
图片瘦身
这个功能要说明一下,最开始看到这个功能,我还以为是调用这个接口图片上传的时候进行压缩了,图片空间这样就人性化了,结果发现我是想多了,毕竟人家是要赚钱的;
图片瘦身功能在如下内容里,不做详细介绍,自己创建即可,我这里只做如何使用瘦身的功能;
配置好瘦身规则后,会给你生成一个规则接口,当你的程序页面在加载图片空间的图片时,是通过路径下载的,例如路径是
http://xxx.bkt.clouddn.com/20170810171548_1046314da25a77e16218a00b823bb4da0450ab.jpg
那么在该路径上加入自己的瘦身规则:
http://xxx.bkt.clouddn.com/20170810171548_1046314da25a77e16218a00b823bb4da0450ab.jpg?imageView2/0/q/75|imageslim
这样就完成了图片在下载时候的瘦身处理,快速加载完成。
七牛的处理方式就是这样。
最后
说一下使用的感受:
1、使用它的优势就是它够快,能分担我们的压力,甚至可以分析上传用户所在的区域上传到不同的七牛大区存储区域,用户在访问下载的时候就直接从最近的服务器下载数据了;
2、服务器压力小了,我们不用花太多带宽在图片上了;
坑:
1、对象存储空间不提供文件夹自定义,只有自己以图片名称设置规则去分类图片;
2、多空间混合使用,没有提供类似的顶级包转类型,需要我们自己判断,这应该是个很普遍的问题;
我们的平台使用了2个空间,分别存储不同类别的数据,自己处理了包转进行分发生成不同的token和预处理URL,并在前端可直接动态调用对应的瘦身接口。
提供自己封装的七牛图片处理工具类
import com.qiniu.common.QiniuException;
import com.qiniu.common.Zone;
import com.qiniu.http.Response;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.model.BatchStatus;
import com.qiniu.util.Auth;
import com.qiniu.util.StringMap;
/**
* Description:七牛云空间工具类
* @author around
* @date 2017年8月10日下午2:15:19
*/
public class QiniuUtils {
/** Access 写自己的 */
private static final String ACCESSKEY = "";
/** Secret 写自己的 */
private static final String SECRETKEY = "";
/** 基础图片空间 */
public static final String CLOUD_BUCKET = "cloud";
/** 基础空间域名 */
public static final String CLOUD_URL = "xxxx.bkt.clouddn.com";
/** 产品空间 */
public static final String PRODUCT_BUCKET = "cloud-product";
/** 产品空间域名 */
public static final String PRODUCT_URL = "xxxx.bkt.clouddn.com";
/**
* Description:简单token类型返回封装
* @param key 文件名
* @return String
* @author around
* @date 2017年8月14日上午9:57:29
*/
public static String getBaseToken(String bucket, String key) {
Auth auth = Auth.create(ACCESSKEY, SECRETKEY);
return auth.uploadToken(bucket, key);
}
/**
* Description:自定义token返回结果
* @param key 文件名
* @return
* @author around
* @date 2017年8月11日下午6:07:24
*/
public static String getCustomToken(String bucket, String key) {
Auth auth = Auth.create(ACCESSKEY, SECRETKEY);
StringMap putPolicy = new StringMap();
putPolicy.put("returnBody", "{\"key\":\"$(key)\",\"com\":\"$(x:com)\",\"hash\":\"$(etag)\",\"bucket\":\"$(bucket)\",\"fsize\":$(fsize)}");
long expireSeconds = 3600;
return auth.uploadToken(bucket, key, expireSeconds, putPolicy);
}
/**
* Description:删除指定文件
* @param key 文件名
* @return boolean true:成功
* @author around
* @date 2017年8月11日下午6:21:18
*/
public static boolean remove(String bucket, String key) {
//构造一个带指定Zone对象的配置类
Configuration cfg = new Configuration(Zone.zone0());
Auth auth = Auth.create(ACCESSKEY, SECRETKEY);
BucketManager bucketManager = new BucketManager(auth, cfg);
try {
bucketManager.delete(bucket, key);
} catch (QiniuException ex) {
//如果遇到异常,说明删除失败
System.err.println(ex.code());
System.err.println(ex.response.toString());
return false;
}
return true;
}
/**
* Description:批量删除文件
* @param keyList 文件名数组
* @return boolean
* @author around
* @date 2017年8月14日上午9:56:03
*/
public static boolean remove(String bucket, String[] keyList) {
//构造一个带指定Zone对象的配置类
Configuration cfg = new Configuration(Zone.zone0());
//...其他参数参考类注释
Auth auth = Auth.create(ACCESSKEY, SECRETKEY);
BucketManager bucketManager = new BucketManager(auth, cfg);
try {
//单次批量请求的文件数量不得超过1000
//String[] keyList = new String[]{"qiniu.jpg","qiniu.mp4","qiniu.png",};
BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations();
batchOperations.addDeleteOp(bucket, keyList);
Response response = bucketManager.batch(batchOperations);
BatchStatus[] batchStatusList = response.jsonToObject(BatchStatus[].class);
for (int i = 0; i < keyList.length; i++) {
BatchStatus status = batchStatusList[i];
String key = keyList[i];
System.out.print(key + "\t");
if (status.code == 200) {
System.out.println("delete success");
} else {
System.out.println(status.data.error);
}
}
} catch (QiniuException ex) {
System.err.println(ex.response.toString());
return false;
}
return true;
}
public static void main(String[] args) {
System.out.println(getCustomToken("cloud","test.jpg"));
//remove("claim_guarantee.docx");
}
}