七牛云上传图片
java项目中用到了七牛云上传图片,所以记录一下。是基于servlet的,相对的麻烦一点
在servlet中加入上传方法。
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //图片上传 if(!ServletFileUpload.isMultipartContent(req)){ System.out.println("请选择文件-1"); return; } Map<String, Object> resultMap = new HashMap<String, Object>(); if(StringUtils.isEqual("image",dir)){ FileUploadServiceImpl fileUploadServiceImpl = new FileUploadServiceImpl(); //文件上传到七牛云 Object resultObj = fileUploadServiceImpl.uploadFileToQn(req,resp,""); }else{ Logging.info("请选择上传图片,其他类型的文件暂不支持"); } }
上传方法:
public Object uploadFileToQn(HttpServletRequest request, HttpServletResponse response, String baseUrl){ long maxSize = 1000000; // 上传代码 FileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); upload.setHeaderEncoding("UTF-8"); List items; Object resultObj = null; try { items = upload.parseRequest(request); Iterator itr = items.iterator(); while (itr.hasNext()) { FileItem item = (FileItem) itr.next(); if (!item.isFormField()) { byte[] data = item.get(); //检查文件大小 String fileUrl = uploadQnBytes(data); //String fileUrl = "Fm88aB0hvslo6IGvrWCEKvJQ3FQg"; if(item.getSize() > maxSize){ System.out.println("上传文件大小超过限制。"); return null; } if (item.getSize() > 500 * 1024) { //文件大小大于200K fileUrl = Constant.DOMAIN_NAME + fileUrl + "?imageslim"; } else { fileUrl = Constant.DOMAIN_NAME + fileUrl; } resultObj = fileUrl; } } } catch (FileUploadException e1) { Logging.error("2-文件上传失败"); throw new IllegalStateException("2-文件上传失败"); } return resultObj; }
开始上传:
/** * 上传二进制到七牛 * @param byteArr * @return * @throws BusException * @throws ErrorException */ public String uploadQnBytes(byte[] byteArr) { if (null == byteArr) { Logging.error("1-文件流不存在"); throw new IllegalStateException("1-文件流不存在"); } //构造一个带指定Zone对象的配置类 Configuration cfg = new Configuration(Zone.zone0()); //...其他参数参考类注释 UploadManager uploadManager = new UploadManager(cfg); //...生成上传凭证,然后准备上传 String accessKey = Constant.ACCESS_KEY; String secretKey = Constant.SECRET_KEY; String bucket = Constant.BUCKET; //默认不指定key的情况下,以文件内容的hash值作为文件名 String key = null; Auth auth = Auth.create(accessKey, secretKey); String upToken = auth.uploadToken(bucket); try { Response response = uploadManager.put(byteArr, key, upToken); DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);//解析上传成功的结果 return putRet.key; } catch (QiniuException ex) { try { throw new IllegalStateException("2-response" + ex.response.bodyString()); } catch (QiniuException e) { throw new IllegalStateException("3-没有找到文件" + e.getMessage()); } } }
Auth类:
package com.xyt.common.util; import java.net.URI; import java.security.GeneralSecurityException; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import com.qiniu.util.Json; import com.qiniu.util.StringMap; import com.qiniu.util.StringUtils; import com.qiniu.util.UrlSafeBase64; public final class Auth { /** * 上传策略,参数规格详见 * <p/> * http://developer.qiniu.com/docs/v6/api/reference/security/put-policy.html */ private static final String[] policyFields = new String[]{ "callbackUrl", "callbackBody", "callbackHost", "callbackBodyType", "callbackFetchKey", "returnUrl", "returnBody", "endUser", "saveKey", "insertOnly", "detectMime", "mimeLimit", "fsizeLimit", "fsizeMin", "persistentOps", "persistentNotifyUrl", "persistentPipeline", "deleteAfterDays", }; private static final String[] deprecatedPolicyFields = new String[]{ "asyncOps", }; private final String accessKey; private final SecretKeySpec secretKey; private Auth(String accessKey, SecretKeySpec secretKeySpec) { this.accessKey = accessKey; this.secretKey = secretKeySpec; } public static Auth create(String accessKey, String secretKey) { if (StringUtils.isNullOrEmpty(accessKey) || StringUtils.isNullOrEmpty(secretKey)) { throw new IllegalArgumentException("empty key"); } byte[] sk = StringUtils.utf8Bytes(secretKey); SecretKeySpec secretKeySpec = new SecretKeySpec(sk, "HmacSHA1"); return new Auth(accessKey, secretKeySpec); } private static void copyPolicy(final StringMap policy, StringMap originPolicy, final boolean strict) { if (originPolicy == null) { return; } originPolicy.forEach(new StringMap.Consumer() { @Override public void accept(String key, Object value) { if (StringUtils.inStringArray(key, deprecatedPolicyFields)) { throw new IllegalArgumentException(key + " is deprecated!"); } if (!strict || StringUtils.inStringArray(key, policyFields)) { policy.put(key, value); } } }); } private Mac createMac() { Mac mac; try { mac = javax.crypto.Mac.getInstance("HmacSHA1"); mac.init(secretKey); } catch (GeneralSecurityException e) { e.printStackTrace(); throw new IllegalArgumentException(e); } return mac; } public String sign(byte[] data) { Mac mac = createMac(); String encodedSign = UrlSafeBase64.encodeToString(mac.doFinal(data)); return this.accessKey + ":" + encodedSign; } public String sign(String data) { return sign(StringUtils.utf8Bytes(data)); } public String signWithData(byte[] data) { String s = UrlSafeBase64.encodeToString(data); return sign(StringUtils.utf8Bytes(s)) + ":" + s; } public String signWithData(String data) { return signWithData(StringUtils.utf8Bytes(data)); } /** * 生成HTTP请求签名字符串 * * @param urlString * @param body * @param contentType * @return */ public String signRequest(String urlString, byte[] body, String contentType) { URI uri = URI.create(urlString); String path = uri.getRawPath(); String query = uri.getRawQuery(); Mac mac = createMac(); mac.update(StringUtils.utf8Bytes(path)); if (query != null && query.length() != 0) { mac.update((byte) ('?')); mac.update(StringUtils.utf8Bytes(query)); } mac.update((byte) '\n'); if (body != null && body.length > 0 && !StringUtils.isNullOrEmpty(contentType)) { if (contentType.equals(Client.FormMime) || contentType.equals(Client.JsonMime)) { mac.update(body); } } String digest = UrlSafeBase64.encodeToString(mac.doFinal()); return this.accessKey + ":" + digest; } /** * 验证回调签名是否正确 * * @param originAuthorization 待验证签名字符串,以 "QBox "作为起始字符 * @param url 回调地址 * @param body 回调请求体。原始请求体,不要解析后再封装成新的请求体--可能导致签名不一致。 * @param contentType 回调ContentType * @return */ public boolean isValidCallback(String originAuthorization, String url, byte[] body, String contentType) { String authorization = "QBox " + signRequest(url, body, contentType); return authorization.equals(originAuthorization); } /** * 下载签名 * * @param baseUrl 待签名文件url,如 http://img.domain.com/u/3.jpg 、 * http://img.domain.com/u/3.jpg?imageView2/1/w/120 * @return */ public String privateDownloadUrl(String baseUrl) { return privateDownloadUrl(baseUrl, 3600); } /** * 下载签名 * * @param baseUrl 待签名文件url,如 http://img.domain.com/u/3.jpg 、 * http://img.domain.com/u/3.jpg?imageView2/1/w/120 * @param expires 有效时长,单位秒。默认3600s * @return */ public String privateDownloadUrl(String baseUrl, long expires) { long deadline = System.currentTimeMillis() / 1000 + expires; return privateDownloadUrlWithDeadline(baseUrl, deadline); } String privateDownloadUrlWithDeadline(String baseUrl, long deadline) { StringBuilder b = new StringBuilder(); b.append(baseUrl); int pos = baseUrl.indexOf("?"); if (pos > 0) { b.append("&e="); } else { b.append("?e="); } b.append(deadline); String token = sign(StringUtils.utf8Bytes(b.toString())); b.append("&token="); b.append(token); return b.toString(); } /** * scope = bucket * 一般情况下可通过此方法获取token * * @param bucket 空间名 * @return 生成的上传token */ public String uploadToken(String bucket) { return uploadToken(bucket, null, 3600, null, true); } /** * scope = bucket:key * 同名文件覆盖操作、只能上传指定key的文件可以可通过此方法获取token * * @param bucket 空间名 * @param key key,可为 null * @return 生成的上传token */ public String uploadToken(String bucket, String key) { return uploadToken(bucket, key, 3600, null, true); } /** * 生成上传token * * @param bucket 空间名 * @param key key,可为 null * @param expires 有效时长,单位秒 * @param policy 上传策略的其它参数,如 new StringMap().put("endUser", "uid").putNotEmpty("returnBody", "")。 * scope通过 bucket、key间接设置,deadline 通过 expires 间接设置 * @return 生成的上传token */ public String uploadToken(String bucket, String key, long expires, StringMap policy) { return uploadToken(bucket, key, expires, policy, true); } /** * 生成上传token * * @param bucket 空间名 * @param key key,可为 null * @param expires 有效时长,单位秒。默认3600s * @param policy 上传策略的其它参数,如 new StringMap().put("endUser", "uid").putNotEmpty("returnBody", "")。 * scope通过 bucket、key间接设置,deadline 通过 expires 间接设置 * @param strict 是否去除非限定的策略字段,默认true * @return 生成的上传token */ public String uploadToken(String bucket, String key, long expires, StringMap policy, boolean strict) { long deadline = System.currentTimeMillis() / 1000 + expires; return uploadTokenWithDeadline(bucket, key, deadline, policy, strict); } public String uploadTokenWithDeadline(String bucket, String key, long deadline, StringMap policy, boolean strict) { String scope = bucket; if (key != null) { scope = bucket + ":" + key; } StringMap x = new StringMap(); copyPolicy(x, policy, strict); x.put("scope", scope); x.put("deadline", deadline); String s = Json.encode(x); return signWithData(StringUtils.utf8Bytes(s)); } public StringMap authorization(String url, byte[] body, String contentType) { String authorization = "QBox " + signRequest(url, body, contentType); return new StringMap().put("Authorization", authorization); } public StringMap authorization(String url) { return authorization(url, null, null); } }
就可以完成七牛云上传了。