完成 yudao-spring-boot-starter-file 组件,支持 S3 对接云存储、local、ftp、sftp、db 等协议

pull/2/head
YunaiV 2022-03-14 23:07:37 +08:00
parent 3d40fc81dd
commit 05d4aae65d
26 changed files with 271 additions and 33 deletions

View File

@ -11,6 +11,7 @@ import org.springframework.context.annotation.Configuration;
*
* @author
*/
@Configuration
@EnableConfigurationProperties(PayProperties.class)
public class YudaoPayAutoConfiguration {

View File

@ -27,11 +27,11 @@ public class PayClientFactoryImpl implements PayClientFactory {
* Map
* key
*/
private final ConcurrentMap<Long, AbstractPayClient<?>> channelIdClients = new ConcurrentHashMap<>();
private final ConcurrentMap<Long, AbstractPayClient<?>> clients = new ConcurrentHashMap<>();
@Override
public PayClient getPayClient(Long channelId) {
AbstractPayClient<?> client = channelIdClients.get(channelId);
AbstractPayClient<?> client = clients.get(channelId);
if (client == null) {
log.error("[getPayClient][渠道编号({}) 找不到客户端]", channelId);
}
@ -42,11 +42,11 @@ public class PayClientFactoryImpl implements PayClientFactory {
@SuppressWarnings("unchecked")
public <Config extends PayClientConfig> void createOrUpdatePayClient(Long channelId, String channelCode,
Config config) {
AbstractPayClient<Config> client = (AbstractPayClient<Config>) channelIdClients.get(channelId);
AbstractPayClient<Config> client = (AbstractPayClient<Config>) clients.get(channelId);
if (client == null) {
client = this.createPayClient(channelId, channelCode, config);
client.init();
channelIdClients.put(client.getId(), client);
clients.put(client.getId(), client);
} else {
client.refresh(config);
}
@ -69,7 +69,7 @@ public class PayClientFactoryImpl implements PayClientFactory {
case ALIPAY_PC: return (AbstractPayClient<Config>) new AlipayQrPayClient(channelId, (AlipayPayClientConfig) config);
}
// 创建失败,错误日志 + 抛出异常
log.error("[createSmsClient][配置({}) 找不到合适的客户端实现]", config);
log.error("[createPayClient][配置({}) 找不到合适的客户端实现]", config);
throw new IllegalArgumentException(String.format("配置(%s) 找不到合适的客户端实现", config));
}

View File

@ -56,5 +56,4 @@ public enum PayChannelEnum {
return ArrayUtil.firstMatch(o -> o.getCode().equals(code), values());
}
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.framework.file.config;
import cn.iocoder.yudao.framework.file.core.client.FileClientFactory;
import cn.iocoder.yudao.framework.file.core.client.FileClientFactoryImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
*
*
* @author
*/
@Configuration
public class YudaoFileAutoConfiguration {
@Bean
public FileClientFactory fileClientFactory() {
return new FileClientFactoryImpl();
}
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.framework.file.core.client.impl;
package cn.iocoder.yudao.framework.file.core.client;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.file.core.client.FileClient;

View File

@ -0,0 +1,22 @@
package cn.iocoder.yudao.framework.file.core.client;
public interface FileClientFactory {
/**
*
*
* @param channelId
* @return
*/
FileClient getFileClient(Long channelId);
/**
*
*
* @param configId
* @param storage {@link cn.iocoder.yudao.framework.file.core.enums.FileStorageEnum}
* @param config
*/
<Config extends FileClientConfig> void createOrUpdateFileClient(Long configId, Integer storage, Config config);
}

View File

@ -0,0 +1,69 @@
package cn.iocoder.yudao.framework.file.core.client;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ReflectUtil;
import cn.iocoder.yudao.framework.file.core.enums.FileStorageEnum;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
*
*
* @author
*/
@Slf4j
public class FileClientFactoryImpl implements FileClientFactory {
/**
* Map
* key
*/
private final ConcurrentMap<Long, AbstractFileClient<?>> clients = new ConcurrentHashMap<>();
@Override
public FileClient getFileClient(Long channelId) {
AbstractFileClient<?> client = clients.get(channelId);
if (client == null) {
log.error("[getFileClient][配置编号({}) 找不到客户端]", channelId);
}
return client;
}
@Override
@SuppressWarnings("unchecked")
public <Config extends FileClientConfig> void createOrUpdateFileClient(Long configId, Integer storage, Config config) {
AbstractFileClient<Config> client = (AbstractFileClient<Config>) clients.get(configId);
if (client == null) {
client = this.createFileClient(configId, storage, config);
client.init();
clients.put(client.getId(), client);
} else {
client.refresh(config);
}
}
@SuppressWarnings("unchecked")
private <Config extends FileClientConfig> AbstractFileClient<Config> createFileClient(
Long configId, Integer storage, Config config) {
FileStorageEnum storageEnum = FileStorageEnum.getByStorage(storage);
Assert.notNull(storageEnum, String.format("文件配置(%s) 为空", storageEnum));
// 创建客户端
// switch (storageEnum) {
// case WX_PUB: return (AbstractFileClient<Config>) new WXPubFileClient(channelId, (WXFileClientConfig) config);
// case WX_LITE: return (AbstractFileClient<Config>) new WXPubFileClient(channelId, (WXFileClientConfig) config);
// case WX_APP: return (AbstractFileClient<Config>) new WXPubFileClient(channelId, (WXFileClientConfig) config);
// case ALIPAY_WAP: return (AbstractFileClient<Config>) new AlipayWapFileClient(channelId, (AlipayFileClientConfig) config);
// case ALIPAY_QR: return (AbstractFileClient<Config>) new AlipayQrFileClient(channelId, (AlipayFileClientConfig) config);
// case ALIPAY_APP: return (AbstractFileClient<Config>) new AlipayQrFileClient(channelId, (AlipayFileClientConfig) config);
// case ALIPAY_PC: return (AbstractFileClient<Config>) new AlipayQrFileClient(channelId, (AlipayFileClientConfig) config);
// }
return (AbstractFileClient<Config>) ReflectUtil.newInstance(storageEnum.getClientClass(), configId, config);
// storageEnum.getClientClass().newInstance()
// // 创建失败,错误日志 + 抛出异常
// log.error("[createSmsClient][配置({}) 找不到合适的客户端实现]", config);
// throw new IllegalArgumentException(String.format("配置(%s) 找不到合适的客户端实现", config));
}
}

View File

@ -0,0 +1,41 @@
package cn.iocoder.yudao.framework.file.core.client.db;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.file.core.client.AbstractFileClient;
/**
* DB
*
* @author
*/
public class DBFileClient extends AbstractFileClient<DBFileClientConfig> {
private DBFileContentFrameworkDAO dao;
public DBFileClient(Long id, DBFileClientConfig config) {
super(id, config);
}
@Override
protected void doInit() {
dao = SpringUtil.getBean(DBFileContentFrameworkDAO.class);
}
@Override
public String upload(byte[] content, String path) {
dao.insert(getId(), path, content);
// 拼接返回路径
return super.formatFileUrl(config.getDomain(), path);
}
@Override
public void delete(String path) {
dao.delete(getId(), path);
}
@Override
public byte[] getContent(String path) {
return dao.selectContent(getId(), path);
}
}

View File

@ -0,0 +1,24 @@
package cn.iocoder.yudao.framework.file.core.client.db;
import cn.iocoder.yudao.framework.file.core.client.FileClientConfig;
import lombok.Data;
import org.hibernate.validator.constraints.URL;
import javax.validation.constraints.NotEmpty;
/**
* DB
*
* @author
*/
@Data
public class DBFileClientConfig implements FileClientConfig {
/**
*
*/
@NotEmpty(message = "domain 不能为空")
@URL(message = "domain 必须是 URL 格式")
private String domain;
}

View File

@ -0,0 +1,16 @@
package cn.iocoder.yudao.framework.file.core.client.db;
/**
* Framework DAO
*
* @author
*/
public interface DBFileContentFrameworkDAO {
void insert(Long configId, String path, byte[] content);
void delete(Long configId, String path);
byte[] selectContent(Long configId, String path);
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.framework.file.core.client.impl.ftp;
package cn.iocoder.yudao.framework.file.core.client.ftp;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.CharsetUtil;
@ -6,7 +6,7 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.ftp.Ftp;
import cn.hutool.extra.ftp.FtpException;
import cn.hutool.extra.ftp.FtpMode;
import cn.iocoder.yudao.framework.file.core.client.impl.AbstractFileClient;
import cn.iocoder.yudao.framework.file.core.client.AbstractFileClient;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.framework.file.core.client.impl.ftp;
package cn.iocoder.yudao.framework.file.core.client.ftp;
import cn.iocoder.yudao.framework.file.core.client.FileClientConfig;
import lombok.Data;

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.framework.file.core.client.impl.local;
package cn.iocoder.yudao.framework.file.core.client.local;
import cn.hutool.core.io.FileUtil;
import cn.iocoder.yudao.framework.file.core.client.impl.AbstractFileClient;
import cn.iocoder.yudao.framework.file.core.client.AbstractFileClient;
import java.io.File;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.framework.file.core.client.impl.local;
package cn.iocoder.yudao.framework.file.core.client.local;
import cn.iocoder.yudao.framework.file.core.client.FileClientConfig;
import lombok.Data;

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.framework.file.core.client.impl.s3;
package cn.iocoder.yudao.framework.file.core.client.s3;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.file.core.client.impl.AbstractFileClient;
import cn.iocoder.yudao.framework.file.core.client.AbstractFileClient;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.core.sync.RequestBody;
@ -13,7 +13,7 @@ import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import java.net.URI;
import static cn.iocoder.yudao.framework.file.core.client.impl.s3.S3FileClientConfig.ENDPOINT_QINIU;
import static cn.iocoder.yudao.framework.file.core.client.s3.S3FileClientConfig.ENDPOINT_QINIU;
/**
* S3 MinIO

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.framework.file.core.client.impl.s3;
package cn.iocoder.yudao.framework.file.core.client.s3;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.file.core.client.FileClientConfig;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.framework.file.core.client.impl.s3;
package cn.iocoder.yudao.framework.file.core.client.s3;
import software.amazon.awssdk.core.interceptor.Context;
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;

View File

@ -1,9 +1,9 @@
package cn.iocoder.yudao.framework.file.core.client.impl.sftp;
package cn.iocoder.yudao.framework.file.core.client.sftp;
import cn.hutool.core.io.FileUtil;
import cn.hutool.extra.ssh.Sftp;
import cn.iocoder.yudao.framework.common.util.io.FileUtils;
import cn.iocoder.yudao.framework.file.core.client.impl.AbstractFileClient;
import cn.iocoder.yudao.framework.file.core.client.AbstractFileClient;
import java.io.File;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.framework.file.core.client.impl.sftp;
package cn.iocoder.yudao.framework.file.core.client.sftp;
import cn.iocoder.yudao.framework.file.core.client.FileClientConfig;
import lombok.Data;

View File

@ -0,0 +1,55 @@
package cn.iocoder.yudao.framework.file.core.enums;
import cn.hutool.core.util.ArrayUtil;
import cn.iocoder.yudao.framework.file.core.client.FileClient;
import cn.iocoder.yudao.framework.file.core.client.FileClientConfig;
import cn.iocoder.yudao.framework.file.core.client.db.DBFileClient;
import cn.iocoder.yudao.framework.file.core.client.db.DBFileClientConfig;
import cn.iocoder.yudao.framework.file.core.client.ftp.FtpFileClient;
import cn.iocoder.yudao.framework.file.core.client.ftp.FtpFileClientConfig;
import cn.iocoder.yudao.framework.file.core.client.local.LocalFileClient;
import cn.iocoder.yudao.framework.file.core.client.local.LocalFileClientConfig;
import cn.iocoder.yudao.framework.file.core.client.s3.S3FileClient;
import cn.iocoder.yudao.framework.file.core.client.s3.S3FileClientConfig;
import cn.iocoder.yudao.framework.file.core.client.sftp.SftpFileClient;
import cn.iocoder.yudao.framework.file.core.client.sftp.SftpFileClientConfig;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
*
*
* @author
*/
@AllArgsConstructor
@Getter
public enum FileStorageEnum {
DB(1, DBFileClientConfig.class, DBFileClient.class),
LOCAL(10, LocalFileClientConfig.class, LocalFileClient.class),
FTP(11, FtpFileClientConfig.class, FtpFileClient.class),
SFTP(12, SftpFileClientConfig.class, SftpFileClient.class),
S3(20, S3FileClientConfig.class, S3FileClient.class),
;
/**
*
*/
private final Integer storage;
/**
*
*/
private final Class<? extends FileClientConfig> configClass;
/**
*
*/
private final Class<? extends FileClient> clientClass;
public static FileStorageEnum getByStorage(Integer storage) {
return ArrayUtil.firstMatch(o -> o.getStorage().equals(storage), values());
}
}

View File

@ -0,0 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.iocoder.yudao.framework.file.config.YudaoFileAutoConfiguration

View File

@ -3,8 +3,6 @@ package cn.iocoder.yudao.framework.file.core.client.ftp;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.extra.ftp.FtpMode;
import cn.iocoder.yudao.framework.file.core.client.impl.ftp.FtpFileClient;
import cn.iocoder.yudao.framework.file.core.client.impl.ftp.FtpFileClientConfig;
import org.junit.jupiter.api.Test;
public class FtpFileClientTest {

View File

@ -2,8 +2,6 @@ package cn.iocoder.yudao.framework.file.core.client.local;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.IdUtil;
import cn.iocoder.yudao.framework.file.core.client.impl.local.LocalFileClient;
import cn.iocoder.yudao.framework.file.core.client.impl.local.LocalFileClientConfig;
import org.junit.jupiter.api.Test;
public class LocalFileClientTest {

View File

@ -1,4 +0,0 @@
/**
* package Git
*/
package cn.iocoder.yudao.framework.file.core.client;

View File

@ -4,8 +4,6 @@ import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
import cn.iocoder.yudao.framework.file.core.client.impl.s3.S3FileClient;
import cn.iocoder.yudao.framework.file.core.client.impl.s3.S3FileClientConfig;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

View File

@ -2,8 +2,6 @@ package cn.iocoder.yudao.framework.file.core.client.sftp;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.IdUtil;
import cn.iocoder.yudao.framework.file.core.client.impl.sftp.SftpFileClient;
import cn.iocoder.yudao.framework.file.core.client.impl.sftp.SftpFileClientConfig;
import org.junit.jupiter.api.Test;
public class SftpFileClientTest {