发表于: 2017-07-09 14:53:02
3 1189
近日完成。
写存储的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也是要这要那。到现在,只有七牛的空间搞定了。请问师兄,需要企业才可以用的业务怎么开通啊?
明日计划:
下面可以写图片上传的前端了
评论