微信小程序使用七牛云存储
- 导读
- 开发前的准备
- 七牛云配置
- 微信小程序测试号配置
- java配置-spring-boot
- 正式开始
- java端代码
- 七牛云工具类编写
- 响应类编写
- 七牛云响应结果
- 获取token的控制器
- 小程序代码
- 七牛云工具类
- 工具类的调用
- 总结
- 查阅资料
- 七牛云
导读
最近在做一个微信小程序项目,项目中涉及到大量图片的存储,由于之前的项目用到了七牛云存储服务,所以也打算在此项目中选用七牛云作为资源站点使用。
七牛云的存储方式为:服务端转储,客户端直传,客户端token上传;
本文主要讲解客户端token上传
开发前的准备
七牛云配置
首先是创建七牛云账号,实名认证后,在控制台中开通存储服务。
首次使用七牛云服务的使用,会生成一对秘钥,后续需要使用此秘钥生成token。
新创建的存储空间会有一个月的免费域名使用,到期后需要使用自己的域名才能访问存储空间的内容,域名需要备案,备案时间为一到两周,如果是还未申请域名,可以提前准备。
这里使用七牛云免费提供的域名进行操作,自定义域名配置不做赘述。
微信小程序测试号配置
申请小程序测试号,配置服务器域名
java配置-spring-boot
application.yml配置
qiniu:ak: 七牛云AKsk: 七牛云SKdomain: 外链域名bucket: 空间名称
pom-七牛云SDK
<dependency><groupId>com.qiniu</groupId><artifactId>qiniu-java-sdk</artifactId><version>7.2.29</version>
</dependency>
正式开始
java端代码
七牛云工具类编写
/*** 工具类中一些常量可能会在别的地方用到,所以定义为静态*/
@Slf4j
@Component
public class QiniuUtil{public static String bucket;@Value("${qiniu.bucket}")public void setBucket(String bucket) {QiniuUtil.bucket = bucket;}public static String domain;@Value("${qiniu.domain}")public void setDomain(String domain) {QiniuUtil.domain = domain;}//构造一个带指定Zone对象的配置类public static Configuration configuration = new Configuration(Region.huanan());public static UploadManager uploadManager = new UploadManager(configuration);public static BucketManager bucketManager;public static Auth auth;@Autowiredpublic void setAuth(@Value("${qiniu.ak}")String accessKey,@Value("${qiniu.sk}") String secretKey){QiniuUtil.auth = Auth.create(accessKey, secretKey);QiniuUtil.bucketManager = new BucketManager(auth, configuration);}// 获取一个不会过期的,限定空间名称的tokenpublic static String getToken(){return auth.uploadToken(bucket);}
// 获取一个限定时间,限定空间,限定文件名称的tokenpublic static String getToken(String bucket,String key){return auth.uploadToken(bucket,key,1800,new StringMap());}
// 获取限定时间,限定空间,限定前缀的的tokenpublic static String getPrefixToken(String prefix){return getPrefixToken(bucket,prefix);}public static String getPrefixToken(String bucket,String prefix){StringMap putPolicy = new StringMap();
// 限定空间及前缀putPolicy.put("scope",bucket+":"+prefix);
// 是否限定前缀-1putPolicy.put("isPrefixalScope",1);
// 设置当前时间延后半小时过期putPolicy.put("deadline",System.currentTimeMillis()/1000+1800);return auth.uploadToken(bucket, prefix, 1800, putPolicy);}
}
响应类编写
@Data
public class HttpResult<T> implements Serializable{@ApiModelProperty("返回代码")private Integer code;@ApiModelProperty("消息")private String msg;@ApiModelProperty("返回数据")private T data;public HttpResult(){ }public HttpResult(Integer code, String msg) {this.code = code;this.msg = msg;}public HttpResult(Integer code, String msg, T data) {this.code = code;this.msg = msg;this.data = data;}public static<T> HttpResult success(){return new HttpResult<>(200,"操作成功");}// 成功,仅返回提示消息public static<T> HttpResult success(String msg){return new HttpResult<>(200,msg);}
// 成功,返回数据与消息public static<T> HttpResult success(String msg , T data){return new HttpResult<>(200,msg,data);}
// 成功,仅返回数据public static<T> HttpResult success(T data){return new HttpResult<>(200,"操作成功",data);}
}
七牛云响应结果
@Data
@Accessors(chain = true)
public class QiniuResult {private String uptoken;// 返回指定前缀private String prefixKey;public QiniuResult(String uptoken) {this.uptoken = uptoken;}public QiniuResult(String uptoken,String prefixKey) {this.uptoken = uptoken;this.prefixKey = prefixKey;}
}
获取token的控制器
因为多是批量上传,为了防止上传中断,导致无效图片占用空间,这里利用rabbit的消息过期机制,进行延时删除操作。
能完成延时功能的技术有很多,这里仅是为了练习rabbitMQ的使用。
@RestController
@RequestMapping("/util")
public class UtilController {@Autowiredprivate RedisUtil redisUtil;@Autowiredprivate RabbitUtil rabbitUtil;@GetMapping("/getUpToken")@ApiOperation("获取七牛云upToken")public HttpResult getQiniuToken(HttpServletRequest request,@ApiParam("详情图片数量")@RequestParam(name = "size", defaultValue = "0") Integer size,@ApiParam("图片类型") @RequestParam(name = "type") String type) {
// 未收到图片数量if (size == 0) throw new CommonBaseException(CommonBaseErrorCode.NO_FILE_TO_UPLOAD);
// 设置消息过期时间MessageProperties messageProperties = new MessageProperties();messageProperties.setExpiration(RabbitConstant.imgDelayTime.toString());// 生成商品图片前缀String uuId16 = request.getAttribute("userId")+"/"+OtherUtil.generateShortUuid();
// 创建消息并发送Message message = new Message((size + "-" + uuId16).getBytes(), messageProperties);rabbitUtil.sendMessage(RabbitConstant.delayExchange, RabbitConstant.delayTempKey, message);redisUtil.set(Constant.PRODUCT_IMG_KEY+uuId16,"1",RabbitConstant.imgDelayTime+300);
// 返回uptoken和商品前缀,token按类型做前缀分类return HttpResult.success(new QiniuResult(QiniuUtil.getPrefixToken(type+"/"+uuId16), uuId16));}
小程序代码
七牛云工具类
本工具类基于七牛云社区小程序SDK改造而来
// created by gpake
(function () {var config = {// 文件上传路径,根据七牛云所处地区设置,uploadURL: 'https://up-z2.qiniup.com',// 自身空间CDN加速域名,用作返回文件路径时,拼接展示domain: '',// 上传凭证upToken: '',// 上传凭证获取地址upTokenURL: '',// 上传凭证获取函数upTokenFunction: null}module.exports = {config: config,init: init,doUpload: doUpload,refreshUpToken: refreshUpToken,uploadURLFromRegionCode:uploadURLFromRegionCode}// 在整个程序生命周期中,只需要 init 一次即可// 如果需要变更参数,再调用 init 即可function init(options) {config = {uploadURL: '',domain: '',upToken: '',upTokenURL: '',upTokenFunction: null};updateConfigWithOptions(options);}// 利用自定义属性更新七牛云配置function updateConfigWithOptions(options) {if (options.uploadURL) {config.uploadURL = options.uploadURL;} else if(options.region){config.uploadURL=uploadURLFromRegionCode(options.region)}else{console.error('qiniu uploader need uploadURL');}if (options.upToken) {config.upToken = options.upToken;} else if (options.uptokenURL) {config.upTokenURL = options.uptokenURL;} else if (options.uptokenFunc) {config.upTokenFunction = options.uptokenFunc;}if (options.domain) {config.domain = options.domain;}}// 使用配置中,获取upToken的URL获取tokenfunction getUpToken(callback) {wx.request({url: config.upTokenURL,success: function (res) {var token = res.data.uptoken;config.upToken = token;if (callback) {callback();}},fail: function (error) {console.error(error);}})}// 刷新tokenfunction refreshUpToken(options) {config.upToken = '';if (options.upToken) {config.upToken = options.upToken;} else if (options.callback) {if (config.uptokenURL) {getUpToken(callback);} else if (config.upTokenFunction) {}} else if (config.upTokenFunction) {config.upToken = config.upTokenFunction(params);}if(!config.upToken || config.upToken===''){console.error('qiniu uploadToken is losed');}}// 执行上传操作,文件路径function doUpload(filePath, options) {//封装promisereturn new Promise((resolve, reject) => {// 过滤tokenif(!config.upToken || config.upToken===''){reject('qiniu uploadToken is losed')}//过滤文件名let fileName;if (options && options.key) {fileName = options.key;} else {fileName = filePath.split('//')[1];}// 封装token和文件名let formData = {'token': config.upToken,'key': fileName};// 使用微信上传API,上传到指定地域的域名wx.uploadFile({url: config.uploadURL,filePath: filePath,name: 'file',formData: formData,success: function (res) {// 如果状态码为200 则上传成功,解析参数后返回if(res.statusCode==200){let dataObject = JSON.parse(res.data);dataObject.imageURL = config.domain + dataObject.key;resolve(dataObject);}else{//不然则上传失败,抛出结果reject(res)}},fail: function (error) {reject(error)}})})}// 根据地域缩写获取指定地域上传域名function uploadURLFromRegionCode(code) {var uploadURL = null;switch (code) {case 'ECN'://华东地址uploadURL = "https://upload.qiniup.com";break;case 'NCN'://华北地址uploadURL = 'https://upload-z1.qiniup.com';break;case 'SCN'://华南地址uploadURL = 'https://upload-z2.qiniup.com';break;case 'NA'://北美地址uploadURL = 'https://upload-na0.qiniup.com';break;default:console.error('please make the region is with one of [ECN, SCN, NCN, NA]');}return uploadURL;}
})();
工具类的调用
const qiniuUploader = require("../../../utils/qiniuUploader");
function initQiniu(upToken) {var options = {upToken: upToken,uploadURL: 'https://up-z2.qiniup.com',domain:'http://static.***.***.***/'};qiniuUploader.init(options);
}
Page({
upload: async function(){// 设置类型未商品let type='product';//获取指定前缀的token,这里封装了个request工具类,做同步请求。let qiniuRes = await request.request("get","/util/getUpToken",{type:type,size:that.data.descImgs.length});// 拿到后台返回的keylet key=qiniuRes.data.prefixKey;// 拼接商品前缀let prefixKey= type+'/'+key;// 使用token初始化七牛云initQiniu(qiniuRes.data.uptoken);// 上传商品封面let cover=that.data.coverImg;let coverRes = await qiniuUploader.doUpload(cover,{key:prefixKey+"/cover"+cover.substr(cover.lastIndexOf("."))});// 遍历上传商品详情let descs = that.data.descImgs;// 这里使用for-i循环,因为forEach会使上传方法变异步,如果没有同步需求,可以使用forEach方法for(let i =0,len=descs.length;i<len;i++){let descRes = await qiniuUploader.doUpload(descs[i],{key:prefixKey+"/desc_"+i+descs[i].substr(descs[i].lastIndexOf("."))});}}
})
总结
这里只是简单的将整个七牛云token上传流程进行梳理,关键的只是配置问题,其余代码各位可以根据自身具体需求,修改其中逻辑。
查阅资料
七牛云
七牛云token配置属性.
七牛云微信小程序SDK文档-github.
七牛云各地域上传域名.
七牛云JAVA-SDK官方文档.