springboot配置多种存储方式

1

目   标

实现阿里云oss,ftp和本地文件存储的功能,通过配置方式选择启用不同的功能

2

接   口

在接口里添加上传,删除,下载以及远程访问方法

public interface FileClient {    /**     * 上传文件     *     * @param inputStream 文件流     * @param path        相对路径     * @return 完整路径,即 HTTP 访问地址     */    String upload(InputStream inputStream, String path);
    /**     * 删除文件     *     * @param path 相对路径     */    void delete(String path);
    /**     * 获得文件的内容     *     * @param path 相对路径     * @return 文件的内容     */    byte[] getContent(String path);
    /**     * 获得文件的签名地址     *     * @param path 相对路径     * @return 文件的内容     */    String getSignedUrl(String path);
    ClinetTypeEnum getClientType();
}​​​​​

public enum ClinetTypeEnum {
    //ftp    FTP("ftp"),    //oss    OSS("oss"),    //local    LOCAL("local");
    private final String type;
    ClinetTypeEnum(String type) {        this.type = type;    }
    public String getType() {        return type;    }}
public interface FileClientConfig {
}

3

ftp实现

在file.ftp.enable的情况下生成FtpFileConfig,在生成FtpFileConfig的情况下生成FtpFileClient

通过配置是否启用ftp,可选择性的生成FtpFileClient

ftp库由hutool依赖提供

getSignedUrl方法可通过实际情况自定义

@Component@ConditionalOnBean(value = FtpFileConfig.class)@Log4j2public class FtpFileClient implements FileClient {
    private final FtpFileConfig ftpFileConfig;    private final Ftp ftp;
    @Autowired    public FtpFileClient(FtpFileConfig ftpFileConfig) {        this.ftpFileConfig = ftpFileConfig;        ftp = new Ftp(ftpFileConfig.getIp(), ftpFileConfig.getPort(), ftpFileConfig.getUsername(), ftpFileConfig.getPassword());        ftp.setMode(FtpMode.Passive);    }
    @Override    public String upload(InputStream inputStream, String path) {        String filePath = getFilePath(path);        String fileName = FileUtil.getName(filePath);        String dir = StrUtil.removeSuffix(filePath, fileName);        ftp.reconnectIfTimeout();        boolean success = ftp.upload(dir, fileName, inputStream);        if (!success) {            throw new FtpException(StrUtil.format("上传文件到目标目录 ({}) 失败", filePath));        }        return null;    }
    @Override    public void delete(String path) {        String filePath = getFilePath(path);        ftp.reconnectIfTimeout();        ftp.delFile(filePath);    }
    @Override    public byte[] getContent(String path) {        String filePath = getFilePath(path);        String fileName = FileUtil.getName(filePath);        String dir = StrUtil.removeSuffix(filePath, fileName);        ByteArrayOutputStream out = new ByteArrayOutputStream();        ftp.reconnectIfTimeout();        ftp.download(dir, fileName, out);        return out.toByteArray();    }
    @Override    public String getSignedUrl(String path) {        return null;    }
    private String getFilePath(String path) {        return ftpFileConfig.getBasePath() + path;    }
    @Override    public ClinetTypeEnum getClientType() {        return ClinetTypeEnum.FTP;    }}
@Data@Component@ConditionalOnProperty(value = "file.ftp.enable", havingValue = "true")public class FtpFileConfig implements FileClientConfig {    @Value("${file.ftp.ip}")    private String ip;    @Value("${file.ftp.port}")    private int port;    @Value("${file.ftp.username}")    private String username;    @Value("${file.ftp.password}")    private String password;    @Value("${file.ftp.basePath}")    private String basePath;}

4

阿里云oss实现

在file.oss.enable的情况下生成OssFileConfig,在生成FtpFileConfig的情况下生成OssFileClient

通过配置是否启用oss,可选择性的生成OssFileClient

oss库由阿里云sdk提供

@Component@ConditionalOnBean(value = OssFileConfig.class)@Log4j2@Datapublic class OssFileClient implements FileClient {

    private final OssFileConfig ossFileConfig;
    private final OSSClient inClient;
    private final OSSClient outClient;
    @Autowired    public OssFileClient(OssFileConfig ossFileConfig) {        this.ossFileConfig = ossFileConfig;        this.inClient = new OSSClient(ossFileConfig.getInEndpoint(), ossFileConfig.getAccessKeyId(), ossFileConfig.getAccessKeySecret());        this.outClient = new OSSClient(ossFileConfig.getEndpoint(), ossFileConfig.getAccessKeyId(), ossFileConfig.getAccessKeySecret());    }

    @Override    public String upload(InputStream inputStream, String path) {        OSSClient client = getInClient();        String bucket = ossFileConfig.getBucket();        client.putObject(bucket, path, inputStream);        //使用内网地址上传,返回地址改为外网地址        String url = ossFileConfig.getHttpBase() + path;        log.info("[{}] OSS上传成功,返回签名URL: {}", Thread.currentThread().getName(), url);        return url;    }
    @Override    public void delete(String path) {        OSSClient client = getInClient();        client.deleteObject(ossFileConfig.getBucket(), path);    }
    @Override    public byte[] getContent(String path) {        OSSClient ossClient = getInClient();        OSSObject ossObject = ossClient.getObject(ossFileConfig.getBucket(), path);        return IoUtil.readBytes(ossObject.getObjectContent());    }
    @Override    public String getSignedUrl(String path) {        Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000L);        String bucket = ossFileConfig.getBucket();        if (path.startsWith(ossFileConfig.getHttpBase())) {            path = path.replace(ossFileConfig.getHttpBase(), "");        }        URL url = getOutClient().generatePresignedUrl(bucket, path, expiration);        return url.toString();    }
    @Override    public ClinetTypeEnum getClientType() {        return ClinetTypeEnum.OSS;    }}

​​​​​​​

@Data@Component@ConditionalOnProperty(value = "file.oss.enable", havingValue = "true")public class OssFileConfig implements FileClientConfig {
    @Value("${file.oss.bucket}")    private String bucket;
    @Value("${file.oss.accessKeyId}")    private String accessKeyId;
    @Value("${file.oss.accessKeySecret}")    private String accessKeySecret;
    @Value("${file.oss.endpoint}")    private String endpoint;
    @Value("${file.oss.httpBase}")    private String httpBase;
    @Value("${file.oss.inEndpoint}")    private String inEndpoint;
    @Value("${file.oss.inHttpBase}")    private String inHttpBase;
}

5

本地存储实现

在file.local.enable的情况下生成LocalFileConfig,在生成LocalFileConfig的情况下生成LocalFileClient

通过配置是否启用local,可选择性的生成LocalFileClient

文件将会保存在服务器本地

getSignedUrl方法可通过实际情况自定义,如果不需要签名,也可以直接使用nginx代理地址

@Component@ConditionalOnBean(value = LocalFileConfig.class)@Log4j2public class LocalFileClient implements FileClient {
    private final LocalFileConfig localFileConfig;
    @Autowired    public LocalFileClient(LocalFileConfig localFileConfig) {        this.localFileConfig = localFileConfig;    }
    @Override    public String upload(InputStream inputStream, String path) {        String filePath = getFilePath(path);        FileUtil.writeFromStream(inputStream, filePath);        return null;    }
    @Override    public void delete(String path) {        String filePath = getFilePath(path);        FileUtil.del(filePath);    }
    @Override    public byte[] getContent(String path) {        String filePath = getFilePath(path);        return FileUtil.readBytes(filePath);    }
    @Override    public String getSignedUrl(String path) {        return null;    }
    private String getFilePath(String path) {        return localFileConfig.getBasePath() + path;    }
    @Override    public ClinetTypeEnum getClientType() {        return ClinetTypeEnum.LOCAL;    }}
@Data@Component@ConditionalOnProperty(value = "file.local.enable", havingValue = "true")public class LocalFileConfig implements FileClientConfig {    @Value("${file.local.basePath}")    private String basePath;}

6

使  用

在配置文件里配置不同存储方式的配置和是否启用

​​​​​​​

file:  local:    enable: true    basePath: /temp/  oss:    enable: true    bucket: 1    accessKeyId: 1    accessKeySecret: 1    endpoint: http://oss-cn-hangzhou.aliyuncs.com    httpBase: http://1.oss-cn-hangzhou.aliyuncs.com/    inEndpoint: http://oss-cn-hangzhou-internal.aliyuncs.com    inHttpBase: http://1.oss-cn-hangzhou-internal.aliyuncs.com/  ftp:    enable: true    ip: 192.168.1.1    port: 7763    username: 1    password: 2    basePath: /file

在代码里注入FileClient后即可调用不同的功能

​​​​​​​

@Autowiredprivate List<FileClient> fileClients;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值