发表于: 2017-07-09 14:53:02

3 1190


近日完成。

写存储的API,先学了一波Java IO 以及 NIO大概在代码里用到了三个功能

1. 读文件到byte[]

2. 写byte[]到文件

3. 读URL文件到byte[]


然后是搞文件存储。存储到本地,金山云,七牛云都用一样的API。基本思路是通过Buckets (就相当于是BucketUtils吧) 拿到一个Bucket的实例。不同Bucket可能用不同方法实现API。但是存储文件,都使用同样的API。


很多密码什么的都写在Buckets里面了。可以搞setter,可以改成读取properties文件加载这些,不过考虑如是小项目,也就是不超过10个云存储吧,手写好了。再加一层配置也是要手写配置文件而已。也可以通过setter在SpringContextConfig中配置。真到用时可以随便改。


然后就是Qiniu, Local这两个已经测试过了,金山这个写了没测试 (金山只对公司提供云存储,个人没法开,白存10元)。测试做了一下几个项目:

//Test cases
//    1. contains(String key)
//    2. upload a picture from local file
//    3. remove a picture
//    4. get a picture
//    5. upload a picture from url
//    6. upload a picture replacing a existing key



API:

public interface Bucket {
void add(String key, byte[] bytesData); //上传新文件
   void put(String key, byte[] bytesData); //上传新文件,若key已经存在则覆盖
   byte[] get(String key);                 //下载key对应文件
   void remove(String key);                //删除key以及对应文件
   boolean contains(String key);           //key属否存在
   String getObjectUrl(String key);        //返回可以访问key资源的URL
}


Utils类,方法都是static的,密码什么的写在了里面,可以改成写在properties里面,或者通过spring配置,感觉如果数量比较少,写类里面就好了。

public final class Buckets {
private Buckets(){}

//========= Enum ==============
   public enum BucketNames {
QINIU_PUBLIC_XIUZHEN1,
       JINSHAN_PUBLIC_XIUZHEN,
       LOCAL_SERVER_PUBLIC_XIUZHEN
   }

//========= Constants =========
   //七牛云参数
   private static final Zone QINIU_PUBLIC_XIUZHEN_ZONE = Zone.zone2();
   private static final String QINIU_PUBLIC_XIUZHEN_ACCESS_KEY = "你的key";
   private static final String QINIU_PUBLIC_XIUZHEN_SECRET_KEY = "你的秘密";
   private static final String QINIU_PUBLIC_XIUZHEN_BUCKET_NAME = "你的桶";
   private static final String QINIU_PUBLIC_XIUZHEN_URL = "你的地址";

   //金山云参数
   private static final String JINSHAN_PUBLIC_XIUZHEN_ACCESS_KEY_ID = "你的key";
   private static final String JINSHAN_PUBLIC_XIUZHEN_ACCESS_SECRET_KEY = "你的秘密";
   private static final String JINSHAN_PUBLIC_XIUZHEN_ENDPOINT_BEIJING = "ks3-cn-beijing.ksyun.com";
   private static final String JINSHAN_PUBLIC_XIUZHEN_ENDPOINT_SHANGHAI = "ks3-cn-shanghai.ksyun.com";
   private static final String JINSHAN_PUBLIC_XIUZHEN_ENDPOINT_HONGKONG = "ks3-cn-hk-1.ksyun.com";
   private static final String JINSHAN_PUBLIC_XIUZHEN_BUCKET_NAME = "你的桶";

   //========= Variables =========
   //七牛参数
   private static Zone qiniuPublicXiuzhenZone = QINIU_PUBLIC_XIUZHEN_ZONE;
   private static String qiniuPublicXiuzhenAccessKey = QINIU_PUBLIC_XIUZHEN_ACCESS_KEY;
   private static String qiniuPublicXiuzhenSecretKey = QINIU_PUBLIC_XIUZHEN_SECRET_KEY;
   private static String qiniuPublicXiuzhenBucketName = QINIU_PUBLIC_XIUZHEN_BUCKET_NAME;
   private static String qiniuPublicXiuzhenUrl = QINIU_PUBLIC_XIUZHEN_URL;

   //金山云参数
   private static String jinshanPublicXiuzhenEndpointBeijing = JINSHAN_PUBLIC_XIUZHEN_ENDPOINT_BEIJING;
   private static String jinshanPublicXiuzhenAccessKeyId = JINSHAN_PUBLIC_XIUZHEN_ACCESS_KEY_ID;
   private static String jinshanPublicXiuzhenAccessSecretKey = JINSHAN_PUBLIC_XIUZHEN_ACCESS_SECRET_KEY;
   private static String jinshanPublicXiuzhenBucketName = JINSHAN_PUBLIC_XIUZHEN_BUCKET_NAME;

   //LOCAL_SERVER_PUBLIC_XIUZHEN参数
   private static String localServerPublicPathPrefix = "";
   private static String localServerPublicUrlPrefix = "";
   //========= Setter Getters ====


   public static void setLocalServerPublicPathPrefix(String localServerPublicPathPrefix) {

      Buckets.localServerPublicPathPrefix = localServerPublicPathPrefix;

   }

   public static void setLocalServerPublicUrlPrefix(String localServerPublicUrlPrefix) {
      Buckets.localServerPublicUrlPrefix = localServerPublicUrlPrefix;
   }

//========= Methods ===========
   public static Bucket getBucket(BucketNames bucket){
Bucket result = null;
       switch (bucket) {
case QINIU_PUBLIC_XIUZHEN1:
result = new QiniuPublicBucket(qiniuPublicXiuzhenZone,
                       qiniuPublicXiuzhenAccessKey,
                       qiniuPublicXiuzhenSecretKey,
                       qiniuPublicXiuzhenBucketName,
                       qiniuPublicXiuzhenUrl);
               break;
           case JINSHAN_PUBLIC_XIUZHEN:
Ks3ClientConfig config = new Ks3ClientConfig();
               /**
                * 设置服务地址
                * 中国(北京)| ks3-cn-beijing.ksyun.com
                * 中国(上海)| ks3-cn-shanghai.ksyun.com
                * 中国(香港)| ks3-cn-hk-1.ksyun.com
                * 如果使用自定义域名,设置endpoint为自定义域名,同时设置domainMode为true
                */
               config.setEndpoint(jinshanPublicXiuzhenEndpointBeijing);   //此处以北京region为例
               /**
                *true:表示以自定义域名访问
                *false:表示以KS3的外网域名或内网域名访问,默认为false
                */
               config.setDomainMode(false);
               config.setProtocol(Ks3ClientConfig.PROTOCOL.http);
               /**
                *true表示以   endpoint/{bucket}/{key}的方式访问
                *false表示以  {bucket}.endpoint/{key}的方式访问
                */
               config.setPathStyleAccess(false);

               HttpClientConfig hconfig = new HttpClientConfig();
               //在HttpClientConfig中可以设置httpclient的相关属性,比如代理,超时,重试等。
               config.setHttpClientConfig(hconfig);
               Ks3 client = new Ks3Client(jinshanPublicXiuzhenAccessKeyId, jinshanPublicXiuzhenAccessSecretKey, config);
               /* 或者:client.setKs3config(config); */
               result = new JinshanPublicBucket(client, jinshanPublicXiuzhenBucketName);
               break;
           case LOCAL_SERVER_PUBLIC_XIUZHEN:
result = new LocalServerPublicBucket(localServerPublicPathPrefix, localServerPublicUrlPrefix);
           default:
result = new LocalServerPublicBucket(localServerPublicPathPrefix, localServerPublicUrlPrefix);
               break;
       }
return result;
   }
}


本地存储用的类:LocalServerPublicBucket。使用Buckets类生成实例之前先要用setter设置好存储位置,以及网络访问的URL。

package fileupload;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class LocalServerPublicBucket implements Bucket {

//========= Constants =========
   private static final String DEFAULT_PATH_PREFIX = "";
   private static final String DEFAULT_URL_PREFIX = "";

   //========= Variables =========
   private static String pathPrefix = DEFAULT_PATH_PREFIX;
   private static String urlPrefix = DEFAULT_URL_PREFIX;

   //========= Constructor =======
   protected LocalServerPublicBucket(String pathPrefix, String urlPrefix) {
this.pathPrefix = pathPrefix;
       this.urlPrefix = urlPrefix;
   }

//========= Setter Getters ====
   public static void setPathPrefix(String pathPrefix) {
LocalServerPublicBucket.pathPrefix = pathPrefix;
   }

public static void setUrlPrefix(String urlPrefix) {
LocalServerPublicBucket.urlPrefix = urlPrefix;
   }

//========= Methods ===========

   @Override
   public void add(String key, byte[] bytesData) {
try {
Files.write(getPath(key), bytesData);
       } catch (IOException e) {
e.printStackTrace();
       }
}

@Override
   public void put(String key, byte[] bytesData) {
add(key, bytesData);
   }

@Override
   public byte[] get(String key) {
byte[] result = null;
       try {
result = Files.readAllBytes(getPath(key));
       } catch (IOException e) {
e.printStackTrace();
       }
return result;
   }

@Override
   public void remove(String key) {
try {
Files.delete(getPath(key));
       } catch (IOException e) {
e.printStackTrace();
       }
}

@Override
   public boolean contains(String key) {
return Files.exists(getPath(key));
   }

@Override
   public String getObjectUrl(String key) {
return urlPrefix + key;
   }

private Path getPath(String key) {
System.out.println(pathPrefix + key);
       return Paths.get(pathPrefix+key);
   }
}


七牛的类

package fileupload;

import com.google.gson.Gson;
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.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.storage.model.FileInfo;
import com.qiniu.util.Auth;

import java.io.*;
import java.net.*;

public class QiniuPublicBucket implements Bucket {

//TODO: exception的logging以及清理干净不必要的printStackTrace

   //========= Variables =========
   private Zone zone = null;
   private String accessKey = null;
   private String secretKey = null;
   private String bucketName = null;
   private String bucketUrl = null;
   private Configuration cfg = null;

   //========= Constructors ====
   protected QiniuPublicBucket(Zone zone, String accessKey, String secretKey, String bucketName, String bucketUrl) {
this.zone = zone;
       this.accessKey = accessKey;
       this.secretKey = secretKey;
       this.bucketName = bucketName;
       this.bucketUrl = bucketUrl;
       this.cfg = new Configuration(zone);
   }

//========= Methods ===========
   @Override
   public void add(String key, byte[] bytesData) {
UploadManager uploadManager = null;
       Auth auth = null;
       String upToken = null;

       try {
uploadManager = new UploadManager(cfg);
           auth = Auth.create(accessKey, secretKey);
           upToken = auth.uploadToken(bucketName);
       } catch (Exception e) {
e.printStackTrace();
       }

try {
Response response = uploadManager.put(bytesData, key, upToken);
           //解析上传成功的结果
           DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
           System.out.println(putRet.key);
           System.out.println(putRet.hash);
       } catch (QiniuException ex) {
Response r = ex.response;
           System.err.println(r.toString());
           try {
System.err.println(r.bodyString());
           } catch (QiniuException ex2) {
//ignore
           }
}
}

@Override
   public void put(String key, byte[] bytesData) {
if (contains(key)) {
remove(key);
       }
add(key, bytesData);
   }

@Override
   public byte[] get(String key) {
String finalUrl = null;
       URL url = null;
       InputStream is = null;
       ByteArrayOutputStream baos = new ByteArrayOutputStream();
       byte[] byteBuffer = new byte[4096];
       BufferedInputStream bips = null;
       ByteArrayOutputStream baops = null;
       int n;

       finalUrl = getObjectUrl(key);

       try {
url = new URL(finalUrl);
           is = url.openStream();
       } catch (MalformedURLException e) {
e.printStackTrace();
       } catch (IOException e1) {
e1.printStackTrace();
       }

try {
while ((n = is.read(byteBuffer)) > 0) {
baos.write(byteBuffer, 0, n);
           }
} catch (IOException e1) {
e1.printStackTrace();
       }

return baos.toByteArray();
   }

@Override
   public void remove(String key) {
Auth auth = null;
       BucketManager bucketManager = null;
       try {
auth = Auth.create(accessKey, secretKey);
           bucketManager = new BucketManager(auth, cfg);
       } catch (Exception e) {
e.printStackTrace();
       }
try {
bucketManager.delete(bucketName, key);
       } catch (QiniuException ex) {
//如果遇到异常,说明删除失败
           System.err.println(ex.code());
           System.err.println(ex.response.toString());
       }
}

@Override
   public boolean contains(String key) {
Auth auth = null;
       BucketManager bucketManager = null;
       FileInfo info = null;
       try {
auth = Auth.create(accessKey, secretKey);
           bucketManager = new BucketManager(auth, cfg);
       } catch (Exception e) {
e.printStackTrace();
       }

try {
info = bucketManager.stat(bucketName, key);
       } catch (QiniuException e) {
e.printStackTrace();
       }

return info != null;
   }

@Override
   public String toString() {
return String.format("Qiniu (public download/private upload) bucket: %s", bucketName);
   }

@Override
   public String getObjectUrl(String key) {
if (key == null || key.length() == 0)
return null;

       String encodedKey = null;

       try {
encodedKey = URLEncoder.encode(key, "utf-8");
       } catch (UnsupportedEncodingException e) {
e.printStackTrace();
       }

return String.format("%s/%s", bucketUrl, encodedKey);
   }
}


金山的类(没有测试)

package fileupload;

import com.ksyun.ks3.dto.GetObjectResult;
import com.ksyun.ks3.dto.Ks3Object;
import com.ksyun.ks3.dto.ObjectMetadata;
import com.ksyun.ks3.dto.ResponseHeaderOverrides;
import com.ksyun.ks3.exception.serviceside.NotFoundException;
import com.ksyun.ks3.http.HttpClientConfig;
import com.ksyun.ks3.service.Ks3;
import com.ksyun.ks3.service.Ks3ClientConfig;
import com.ksyun.ks3.service.request.GetObjectRequest;
import com.ksyun.ks3.service.request.HeadObjectRequest;
import com.ksyun.ks3.service.request.PutObjectRequest;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class JinshanPublicBucket implements Bucket {
//TODO:Test all method, this class is not tested yet because do not have access to KS3. KS3 service is for business only.
   //========= Variables =========
   private Ks3 client = null;
   private String bucketName = null;

   //========= Constructor =======
   public JinshanPublicBucket(Ks3 client, String bucketName) {
this.client = client;
       this.bucketName = bucketName;
   }

//========= Setter Getters ====

   //========= Methods ===========
   @Override
   public boolean contains(String key) {
try {
HeadObjectRequest request = new HeadObjectRequest(bucketName, key);
           client.headObject(request);
           return true;
       } catch (NotFoundException e) {
return false;
       }
}


@Override
   public void add(String key, byte[] bytesData) {
ObjectMetadata meta = new ObjectMetadata();
       PutObjectRequest request = new PutObjectRequest(
bucketName,
               key,
               new ByteArrayInputStream(bytesData),
               meta);
       // 可以指定内容的长度,否则程序会把整个输入流缓存起来,可能导致jvm内存溢出
       meta.setContentLength(bytesData.length);
       client.putObject(request);
   }

@Override
   public void remove(String key) {
client.deleteObject(bucketName, key);
   }

@Override
   public void put(String key, byte[] bytesData) {
if (contains(key)) {
remove(key);
       }
add(key, bytesData);
   }

@Override
   public byte[] get(String key) {
GetObjectRequest request = new GetObjectRequest(bucketName, key);

       //重写返回的header
       ResponseHeaderOverrides overrides = new ResponseHeaderOverrides();
       overrides.setContentType("text/html");
       //.......
       request.setOverrides(overrides);
       //只接受数据的0-10字节。通过控制该项可以实现分块下载
       //request.setRange(0,10);
       GetObjectResult result = client.getObject(request);

       Ks3Object object = result.getObject();
       //获取object的元数据
       ObjectMetadata meta = object.getObjectMetadata();
       //当分块下载时获取文件的实际大小,而非当前小块的大小
       Long length = meta.getInstanceLength();
       //获取object的输入流
       InputStream is = object.getObjectContent();

       int n = 0;
       byte[] byteBuffer = new byte[4096];
       ByteArrayOutputStream baos = new ByteArrayOutputStream();

       try {
while ((n = is.read(byteBuffer)) > 0) {
baos.write(byteBuffer, 0, n);
           }
} catch (IOException e1) {
e1.printStackTrace();
       }

return baos.toByteArray();
   }

@Override
   public String getObjectUrl(String key) {
return null;
   }

@Override
   public String toString() {
return String.format("Jinshan (public download/private upload) bucket: %s", bucketName);
   }
}




今日掌握:

学了Java IO 以及NIO,感觉NIO比老的IO那一套用起来简单些。

看文档比较金山和七牛的对象存储,感觉金山的API似乎写的更好些,学起来更简单易懂。可惜金山存储业务没有开通,没法领悟。


今日遇到问题

任务7举步维艰啊。金山云的存储业务只针对企业,个人开不了。容联要发短信还要产品截图。SendCloud也是要这要那。到现在,只有七牛的空间搞定了。请问师兄,需要企业才可以用的业务怎么开通啊?


明日计划:

下面可以写图片上传的前端了


返回列表 返回列表
评论

    分享到