自定义对象存储
第一步
添加hzero文件存储核心组件依赖
<dependency>
<groupId>org.hzero.starter</groupId>
<artifactId>hzero-starter-file-core</artifactId>
</dependency>
添加需要添加自定义类型的SDK(此处以minio为例)
<!-- minio -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>${minio.version}</version>
</dependency>
第二步
定义对象存储实现类
- 此类继承
org.hzero.starter.file.service.AbstractFileService
文件服务抽象类,实现抽象方法
// 具体方法实现,参考minio文件存储组件
public class MinioFileServiceImpl extends AbstractFileService {
/**
* 对象存储客户端
*/
private MinioClient client;
/**
* 桶的权限控制参数
*/
private PolicyType policyType;
/**
* 初始化文件服务配置
*
* @param config 存储配置
* @return AbstractFileService
*/
@Override
public AbstractFileService init(StoreConfig config) {
this.config = config;
try {
// 初始化client
client = new MinioClient(config.getEndPoint(), config.getAccessKeyId(), config.getAccessKeySecret());
}catch (Exception e) {
// 异常处理
}
return this;
}
/**
* 上传本地文件(要用分片上传)
*
* @param file 文件信息
* @param filePath 文件地址
* @return 返回http地址
*/
@Override
public String upload(FileInfo file, String filePath) {
// 获取桶名
String realBucketName = getRealBucketName(file.getBucketName());
// 获取对象KEY
String fileKey = file.getFileKey();
try {
// 文件上传
client.putObject(xxxxx);
// 返回http地址
return getObjectPrefixUrl(realBucketName) + fileKey;
} catch (Exception e) {
// 异常处理
} finally {
// 关闭客户端
}
}
/**
* 文件上传
*
* @param file 文件信息
* @param inputStream 字节流
* @return 返回http地址
*/
@Override
public String upload(FileInfo file, InputStream inputStream) {
String realBucketName = getRealBucketName(file.getBucketName());
String fileKey = file.getFileKey();
try {
// 文件上传
client.putObject(xxxxx);
// 返回http地址
return getObjectPrefixUrl(realBucketName) + fileKey;
} catch (Exception e) {
// 异常处理
} finally {
// 关闭客户端
}
}
/**
* 文件复制
*
* @param file 原文件信息
* @param oldFileKey 原文件的fileKey
* @param oldBucketName 原文件的桶
* @return 新文件的地址
*/
@Override
public String copyFile(FileInfo file, String oldFileKey, String oldBucketName) {
String realBucketName = getRealBucketName(file.getBucketName());
String fileKey = file.getFileKey();
try {
// 文件复制
client.copyObject(getRealBucketName(oldBucketName), oldFileKey, realBucketName, fileKey);
// 返回新文件地址
return getObjectPrefixUrl(realBucketName) + fileKey;
} catch (Exception e) {
// 异常处理
} finally {
// 关闭客户端
}
}
/**
* 删除文件
*
* @param bucketName 桶
* @param url url
* @param fileKey 文件key
*/
@Override
public void deleteFile(String bucketName, String url, String fileKey) {
String realBucketName = getRealBucketName(bucketName);
if (StringUtils.isBlank(fileKey)) {
fileKey = getFileKey(realBucketName, url);
}
try {
// 删除附件文档
client.removeObject(realBucketName, fileKey);
} catch (Exception e) {
// 异常处理
} finally {
// 关闭客户端
}
}
/**
* 获取文件授权url
*
* @param servletRequest request
* @param bucketName 桶名
* @param url url
* @param fileName 文件名
* @param fileKey 文件key
* @param download 是否下载(是否将contentType设置为stream)
* @param expires 有效时长
* @return 下载地址
*/
@Override
public String getSignedUrl(HttpServletRequest servletRequest,
String bucketName,
String url,
String fileKey,
String fileName,
boolean download,
Long expires) {
String realBucketName = getRealBucketName(bucketName);
if (StringUtils.isBlank(fileKey)) {
fileKey = getFileKey(realBucketName, url);
}
String signedUrl;
// 路径有效期
Long expiresTime = expires == null ? fileConfig.getDefaultExpires() : expires;
try {
if (download) {
Map<String, String> reqParams = new HashMap<>(16);
reqParams.put("response-content-type", FileConstant.DEFAULT_MULTI_TYPE);
// 指定attachment,前端对文件做下载处理
reqParams.put("response-content-disposition", "attachment;filename=" + FilenameUtils.encodeFileName(servletRequest, fileName));
reqParams.put("response-cache-control", "must-revalidate, post-check=0, pre-check=0");
reqParams.put("response-expires", String.valueOf(System.currentTimeMillis() + 1000));
signedUrl = client.getPresignedObjectUrl(Method.GET, realBucketName, fileKey, expiresTime.intValue(), reqParams);
} else {
signedUrl = client.presignedGetObject(realBucketName, fileKey, expiresTime.intValue());
}
// 返回签名地址
return signedUrl;
} catch (Exception e) {
// 异常处理
} finally {
// 关闭客户端
}
}
/**
* 下载文件,获取文件流
*
* @param request HttpServletRequest
* @param response HttpServletResponse
* @param bucketName 桶
* @param url url
* @param fileKey 文件key
*/
@Override
public void download(HttpServletRequest request, HttpServletResponse response,
String bucketName, String url, String fileKey) {
String realBucketName = getRealBucketName(bucketName);
if (StringUtils.isBlank(fileKey)) {
// 获取文件实际的ObjectKey
fileKey = getFileKey(realBucketName, url);
}
try {
// 获取文件InputStream
InputStream is = client.getObject(realBucketName, fileKey);
byte[] data = IOUtils.toByteArray(is);
// 构建文件下载的response
buildResponse(response, data, FilenameUtils.encodeFileName(request, FilenameUtils.getFileName(StringUtils.isBlank(url) ? fileKey : url)));
} catch (Exception e) {
// 异常处理
} finally {
// 关闭客户端
}
}
/**
* 下载文件并解密
*
* @param request HttpServletRequest
* @param response HttpServletResponse
* @param bucketName 桶
* @param url url
* @param fileKey 文件key
* @param password 密钥
*/
@Override
public void decryptDownload(HttpServletRequest request, HttpServletResponse response,
String bucketName, String url, String fileKey, String password) {
String realBucketName = getRealBucketName(bucketName);
if (StringUtils.isBlank(fileKey)) {
// 获取文件实际的ObjectKey
fileKey = getFileKey(realBucketName, url);
}
try {
InputStream is = client.getObject(realBucketName, fileKey);
byte[] data = IOUtils.toByteArray(is);
if (StringUtils.isBlank(password)) {
data = AesUtils.decrypt(data);
} else {
data = AesUtils.decrypt(data, password);
}
// 构建文件下载的response
buildResponse(response, data, FilenameUtils.encodeFileName(request, FilenameUtils.getFileName(StringUtils.isBlank(url) ? fileKey : url)));
} catch (Exception e) {
// 异常处理
} finally {
// 关闭客户端
}
}
/**
* 获取对象前序URL
*
* @param bucketName 文件目录
* @return 文件URL
*/
@Override
public String getObjectPrefixUrl(String bucketName) {
return String.format("%s/%s/", config.getEndPoint(), bucketName);
}
}
第三步
定义文件存储创建类
-
此类实现
org.hzero.starter.file.service.StoreCreator
接口,实现接口方法。注意:值集HFLE.SERVER_PROVIDER中的不包含自定义需要的类型时,需要在值集中手动添加。
-
加上
@Component
注解注意:默认扫描路径
org.hzero.starter.file
,如果自定义的路径不同,则需要手动添加扫描路径。
@Component
public class MinioStoreCreator implements StoreCreator {
/**
* 获取文件存储类型,与值集HFLE.SERVER_PROVIDER对应即可
*
* @return 文件存储类型
*/
@Override
public Integer storeType() {
// 返回值对应 值集HFLE.SERVER_PROVIDER中的值
return 3;
}
/**
* 获取文件处理类
*
* @return 文件处理类实例化对象
*/
@Override
public AbstractFileService getFileService() {
// new 文件服务实现类
return new MinioFileServiceImpl();
}
}
前端配置处理
HFLE.SERVER_PROVIDER
值集新增类型后,会有默认的配置页面,定制化开发参考前端开发指引