Commit 3d40fc81dd6099ed32a4743907d6c3a5032c0bff
1 parent
ed53ca3d
完善 yudao-spring-boot-starter-file 组件,支持 S3 对接云存储、local、ftp、sftp 等协议
Showing
15 changed files
with
512 additions
and
8 deletions
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/io/FileUtils.java
| @@ -22,12 +22,39 @@ public class FileUtils { | @@ -22,12 +22,39 @@ public class FileUtils { | ||
| 22 | */ | 22 | */ |
| 23 | @SneakyThrows | 23 | @SneakyThrows |
| 24 | public static File createTempFile(String data) { | 24 | public static File createTempFile(String data) { |
| 25 | + File file = createTempFile(); | ||
| 26 | + // 写入内容 | ||
| 27 | + FileUtil.writeUtf8String(data, file); | ||
| 28 | + return file; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + /** | ||
| 32 | + * 创建临时文件 | ||
| 33 | + * 该文件会在 JVM 退出时,进行删除 | ||
| 34 | + * | ||
| 35 | + * @param data 文件内容 | ||
| 36 | + * @return 文件 | ||
| 37 | + */ | ||
| 38 | + @SneakyThrows | ||
| 39 | + public static File createTempFile(byte[] data) { | ||
| 40 | + File file = createTempFile(); | ||
| 41 | + // 写入内容 | ||
| 42 | + FileUtil.writeBytes(data, file); | ||
| 43 | + return file; | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * 创建临时文件,无内容 | ||
| 48 | + * 该文件会在 JVM 退出时,进行删除 | ||
| 49 | + * | ||
| 50 | + * @return 文件 | ||
| 51 | + */ | ||
| 52 | + @SneakyThrows | ||
| 53 | + public static File createTempFile() { | ||
| 25 | // 创建文件,通过 UUID 保证唯一 | 54 | // 创建文件,通过 UUID 保证唯一 |
| 26 | File file = File.createTempFile(IdUtil.simpleUUID(), null); | 55 | File file = File.createTempFile(IdUtil.simpleUUID(), null); |
| 27 | // 标记 JVM 退出时,自动删除 | 56 | // 标记 JVM 退出时,自动删除 |
| 28 | file.deleteOnExit(); | 57 | file.deleteOnExit(); |
| 29 | - // 写入内容 | ||
| 30 | - FileUtil.writeUtf8String(data, file); | ||
| 31 | return file; | 58 | return file; |
| 32 | } | 59 | } |
| 33 | 60 |
yudao-framework/yudao-spring-boot-starter-file/pom.xml
| @@ -51,6 +51,18 @@ | @@ -51,6 +51,18 @@ | ||
| 51 | <artifactId>jackson-core</artifactId> | 51 | <artifactId>jackson-core</artifactId> |
| 52 | </dependency> | 52 | </dependency> |
| 53 | 53 | ||
| 54 | + <dependency> | ||
| 55 | + <groupId>commons-net</groupId> | ||
| 56 | + <artifactId>commons-net</artifactId> <!-- 解决 ftp 连接 --> | ||
| 57 | + <version>3.8.0</version> | ||
| 58 | + </dependency> | ||
| 59 | + <dependency> | ||
| 60 | + <groupId>com.jcraft</groupId> | ||
| 61 | + <artifactId>jsch</artifactId> <!-- 解决 sftp 连接 --> | ||
| 62 | + <version>0.1.55</version> | ||
| 63 | + </dependency> | ||
| 64 | + | ||
| 65 | + | ||
| 54 | <!-- 三方云服务相关 --> | 66 | <!-- 三方云服务相关 --> |
| 55 | <dependency> | 67 | <dependency> |
| 56 | <groupId>software.amazon.awssdk</groupId> | 68 | <groupId>software.amazon.awssdk</groupId> |
yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/client/impl/AbstractFileClient.java
| 1 | package cn.iocoder.yudao.framework.file.core.client.impl; | 1 | package cn.iocoder.yudao.framework.file.core.client.impl; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.util.StrUtil; | ||
| 3 | import cn.iocoder.yudao.framework.file.core.client.FileClient; | 4 | import cn.iocoder.yudao.framework.file.core.client.FileClient; |
| 4 | import cn.iocoder.yudao.framework.file.core.client.FileClientConfig; | 5 | import cn.iocoder.yudao.framework.file.core.client.FileClientConfig; |
| 5 | import lombok.extern.slf4j.Slf4j; | 6 | import lombok.extern.slf4j.Slf4j; |
| @@ -55,4 +56,16 @@ public abstract class AbstractFileClient<Config extends FileClientConfig> implem | @@ -55,4 +56,16 @@ public abstract class AbstractFileClient<Config extends FileClientConfig> implem | ||
| 55 | return id; | 56 | return id; |
| 56 | } | 57 | } |
| 57 | 58 | ||
| 59 | + /** | ||
| 60 | + * 格式化文件的 URL 访问地址 | ||
| 61 | + * 使用场景:local、ftp、db,通过 FileController 的 getFile 来获取文件内容 | ||
| 62 | + * | ||
| 63 | + * @param domain 自定义域名 | ||
| 64 | + * @param path 文件路径 | ||
| 65 | + * @return URL 访问地址 | ||
| 66 | + */ | ||
| 67 | + protected String formatFileUrl(String domain, String path) { | ||
| 68 | + return StrUtil.format("{}/system-api/{}/get/{}", domain, getId(), path); | ||
| 69 | + } | ||
| 70 | + | ||
| 58 | } | 71 | } |
yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/client/impl/ftp/FtpFileClient.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.file.core.client.impl.ftp; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.io.FileUtil; | ||
| 4 | +import cn.hutool.core.util.CharsetUtil; | ||
| 5 | +import cn.hutool.core.util.StrUtil; | ||
| 6 | +import cn.hutool.extra.ftp.Ftp; | ||
| 7 | +import cn.hutool.extra.ftp.FtpException; | ||
| 8 | +import cn.hutool.extra.ftp.FtpMode; | ||
| 9 | +import cn.iocoder.yudao.framework.file.core.client.impl.AbstractFileClient; | ||
| 10 | + | ||
| 11 | +import java.io.ByteArrayInputStream; | ||
| 12 | +import java.io.ByteArrayOutputStream; | ||
| 13 | +import java.io.File; | ||
| 14 | + | ||
| 15 | +/** | ||
| 16 | + * Ftp 文件客户端 | ||
| 17 | + * | ||
| 18 | + * @author 芋道源码 | ||
| 19 | + */ | ||
| 20 | +public class FtpFileClient extends AbstractFileClient<FtpFileClientConfig> { | ||
| 21 | + | ||
| 22 | + private Ftp ftp; | ||
| 23 | + | ||
| 24 | + public FtpFileClient(Long id, FtpFileClientConfig config) { | ||
| 25 | + super(id, config); | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + @Override | ||
| 29 | + protected void doInit() { | ||
| 30 | + // 补全风格。例如说 Linux 是 /,Windows 是 \ | ||
| 31 | + if (!config.getBasePath().endsWith(File.separator)) { | ||
| 32 | + config.setBasePath(config.getBasePath() + File.separator); | ||
| 33 | + } | ||
| 34 | + // 初始化 Ftp 对象 | ||
| 35 | + this.ftp = new Ftp(config.getHost(), config.getPort(), config.getUsername(), config.getPassword(), | ||
| 36 | + CharsetUtil.CHARSET_UTF_8, null, null, FtpMode.valueOf(config.getMode())); | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + @Override | ||
| 40 | + public String upload(byte[] content, String path) { | ||
| 41 | + // 执行写入 | ||
| 42 | + String filePath = getFilePath(path); | ||
| 43 | + String fileName = FileUtil.getName(filePath); | ||
| 44 | + String dir = StrUtil.removeSuffix(filePath, fileName); | ||
| 45 | + boolean success = ftp.upload(dir, fileName, new ByteArrayInputStream(content)); | ||
| 46 | + if (!success) { | ||
| 47 | + throw new FtpException(StrUtil.format("上海文件到目标目录 ({}) 失败", filePath)); | ||
| 48 | + } | ||
| 49 | + // 拼接返回路径 | ||
| 50 | + return super.formatFileUrl(config.getDomain(), path); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + @Override | ||
| 54 | + public void delete(String path) { | ||
| 55 | + String filePath = getFilePath(path); | ||
| 56 | + ftp.delFile(filePath); | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + @Override | ||
| 60 | + public byte[] getContent(String path) { | ||
| 61 | + String filePath = getFilePath(path); | ||
| 62 | + String fileName = FileUtil.getName(filePath); | ||
| 63 | + String dir = StrUtil.removeSuffix(path, fileName); | ||
| 64 | + ByteArrayOutputStream out = new ByteArrayOutputStream(); | ||
| 65 | + ftp.download(dir, fileName, out); | ||
| 66 | + return out.toByteArray(); | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + private String getFilePath(String path) { | ||
| 70 | + return config.getBasePath() + path; | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | +} |
yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/client/impl/ftp/FtpFileClientConfig.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.file.core.client.impl.ftp; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.file.core.client.FileClientConfig; | ||
| 4 | +import lombok.Data; | ||
| 5 | +import org.hibernate.validator.constraints.URL; | ||
| 6 | + | ||
| 7 | +import javax.validation.constraints.NotEmpty; | ||
| 8 | +import javax.validation.constraints.NotNull; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * Ftp 文件客户端的配置类 | ||
| 12 | + * | ||
| 13 | + * @author 芋道源码 | ||
| 14 | + */ | ||
| 15 | +@Data | ||
| 16 | +public class FtpFileClientConfig implements FileClientConfig { | ||
| 17 | + | ||
| 18 | + /** | ||
| 19 | + * 基础路径 | ||
| 20 | + */ | ||
| 21 | + @NotEmpty(message = "基础路径不能为空") | ||
| 22 | + private String basePath; | ||
| 23 | + | ||
| 24 | + /** | ||
| 25 | + * 自定义域名 | ||
| 26 | + */ | ||
| 27 | + @NotEmpty(message = "domain 不能为空") | ||
| 28 | + @URL(message = "domain 必须是 URL 格式") | ||
| 29 | + private String domain; | ||
| 30 | + | ||
| 31 | + /** | ||
| 32 | + * 主机地址 | ||
| 33 | + */ | ||
| 34 | + @NotEmpty(message = "host 不能为空") | ||
| 35 | + private String host; | ||
| 36 | + /** | ||
| 37 | + * 主机端口 | ||
| 38 | + */ | ||
| 39 | + @NotNull(message = "port 不能为空") | ||
| 40 | + private Integer port; | ||
| 41 | + /** | ||
| 42 | + * 用户名 | ||
| 43 | + */ | ||
| 44 | + @NotEmpty(message = "用户名不能为空") | ||
| 45 | + private String username; | ||
| 46 | + /** | ||
| 47 | + * 密码 | ||
| 48 | + */ | ||
| 49 | + @NotEmpty(message = "密码不能为空") | ||
| 50 | + private String password; | ||
| 51 | + /** | ||
| 52 | + * 连接模式 | ||
| 53 | + * | ||
| 54 | + * 使用 {@link cn.hutool.extra.ftp.FtpMode} 对应的字符串 | ||
| 55 | + */ | ||
| 56 | + @NotEmpty(message = "连接模式不能为空") | ||
| 57 | + private String mode; | ||
| 58 | + | ||
| 59 | +} |
yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/client/impl/local/LocalFileClient.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.file.core.client.impl.local; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.io.FileUtil; | ||
| 4 | +import cn.iocoder.yudao.framework.file.core.client.impl.AbstractFileClient; | ||
| 5 | + | ||
| 6 | +import java.io.File; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * 本地文件客户端 | ||
| 10 | + * | ||
| 11 | + * @author 芋道源码 | ||
| 12 | + */ | ||
| 13 | +public class LocalFileClient extends AbstractFileClient<LocalFileClientConfig> { | ||
| 14 | + | ||
| 15 | + public LocalFileClient(Long id, LocalFileClientConfig config) { | ||
| 16 | + super(id, config); | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + @Override | ||
| 20 | + protected void doInit() { | ||
| 21 | + // 补全风格。例如说 Linux 是 /,Windows 是 \ | ||
| 22 | + if (!config.getBasePath().endsWith(File.separator)) { | ||
| 23 | + config.setBasePath(config.getBasePath() + File.separator); | ||
| 24 | + } | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + @Override | ||
| 28 | + public String upload(byte[] content, String path) { | ||
| 29 | + // 执行写入 | ||
| 30 | + String filePath = getFilePath(path); | ||
| 31 | + FileUtil.writeBytes(content, filePath); | ||
| 32 | + // 拼接返回路径 | ||
| 33 | + return super.formatFileUrl(config.getDomain(), path); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + @Override | ||
| 37 | + public void delete(String path) { | ||
| 38 | + String filePath = getFilePath(path); | ||
| 39 | + FileUtil.del(filePath); | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + @Override | ||
| 43 | + public byte[] getContent(String path) { | ||
| 44 | + String filePath = getFilePath(path); | ||
| 45 | + return FileUtil.readBytes(filePath); | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + private String getFilePath(String path) { | ||
| 49 | + return config.getBasePath() + path; | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | +} |
yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/client/impl/local/LocalFileClientConfig.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.file.core.client.impl.local; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.file.core.client.FileClientConfig; | ||
| 4 | +import lombok.Data; | ||
| 5 | +import org.hibernate.validator.constraints.URL; | ||
| 6 | + | ||
| 7 | +import javax.validation.constraints.NotEmpty; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * 本地文件客户端的配置类 | ||
| 11 | + * | ||
| 12 | + * @author 芋道源码 | ||
| 13 | + */ | ||
| 14 | +@Data | ||
| 15 | +public class LocalFileClientConfig implements FileClientConfig { | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * 基础路径 | ||
| 19 | + */ | ||
| 20 | + @NotEmpty(message = "基础路径不能为空") | ||
| 21 | + private String basePath; | ||
| 22 | + | ||
| 23 | + /** | ||
| 24 | + * 自定义域名 | ||
| 25 | + */ | ||
| 26 | + @NotEmpty(message = "domain 不能为空") | ||
| 27 | + @URL(message = "domain 必须是 URL 格式") | ||
| 28 | + private String domain; | ||
| 29 | + | ||
| 30 | +} |
yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/client/impl/s3/S3FileClient.java
| @@ -7,6 +7,8 @@ import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; | @@ -7,6 +7,8 @@ import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; | ||
| 7 | import software.amazon.awssdk.core.sync.RequestBody; | 7 | import software.amazon.awssdk.core.sync.RequestBody; |
| 8 | import software.amazon.awssdk.regions.Region; | 8 | import software.amazon.awssdk.regions.Region; |
| 9 | import software.amazon.awssdk.services.s3.S3Client; | 9 | import software.amazon.awssdk.services.s3.S3Client; |
| 10 | +import software.amazon.awssdk.services.s3.model.DeleteObjectRequest; | ||
| 11 | +import software.amazon.awssdk.services.s3.model.GetObjectRequest; | ||
| 10 | import software.amazon.awssdk.services.s3.model.PutObjectRequest; | 12 | import software.amazon.awssdk.services.s3.model.PutObjectRequest; |
| 11 | 13 | ||
| 12 | import java.net.URI; | 14 | import java.net.URI; |
| @@ -14,7 +16,7 @@ import java.net.URI; | @@ -14,7 +16,7 @@ import java.net.URI; | ||
| 14 | import static cn.iocoder.yudao.framework.file.core.client.impl.s3.S3FileClientConfig.ENDPOINT_QINIU; | 16 | import static cn.iocoder.yudao.framework.file.core.client.impl.s3.S3FileClientConfig.ENDPOINT_QINIU; |
| 15 | 17 | ||
| 16 | /** | 18 | /** |
| 17 | - * 基于 S3 协议,实现 MinIO、阿里云、腾讯云、七牛云、华为云等云服务 | 19 | + * 基于 S3 协议的文件客户端,实现 MinIO、阿里云、腾讯云、七牛云、华为云等云服务 |
| 18 | * | 20 | * |
| 19 | * S3 协议的客户端,采用亚马逊提供的 software.amazon.awssdk.s3 库 | 21 | * S3 协议的客户端,采用亚马逊提供的 software.amazon.awssdk.s3 库 |
| 20 | * | 22 | * |
| @@ -84,12 +86,18 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> { | @@ -84,12 +86,18 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> { | ||
| 84 | 86 | ||
| 85 | @Override | 87 | @Override |
| 86 | public void delete(String path) { | 88 | public void delete(String path) { |
| 87 | - | 89 | + DeleteObjectRequest.Builder request = DeleteObjectRequest.builder() |
| 90 | + .bucket(config.getBucket()) // bucket 必须传递 | ||
| 91 | + .key(path); // 相对路径作为 key | ||
| 92 | + client.deleteObject(request.build()); | ||
| 88 | } | 93 | } |
| 89 | 94 | ||
| 90 | @Override | 95 | @Override |
| 91 | public byte[] getContent(String path) { | 96 | public byte[] getContent(String path) { |
| 92 | - return new byte[0]; | 97 | + GetObjectRequest.Builder request = GetObjectRequest.builder() |
| 98 | + .bucket(config.getBucket()) // bucket 必须传递 | ||
| 99 | + .key(path); // 相对路径作为 key | ||
| 100 | + return client.getObjectAsBytes(request.build()).asByteArray(); | ||
| 93 | } | 101 | } |
| 94 | 102 | ||
| 95 | } | 103 | } |
yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/client/impl/sftp/SftpFileClient.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.file.core.client.impl.sftp; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.io.FileUtil; | ||
| 4 | +import cn.hutool.extra.ssh.Sftp; | ||
| 5 | +import cn.iocoder.yudao.framework.common.util.io.FileUtils; | ||
| 6 | +import cn.iocoder.yudao.framework.file.core.client.impl.AbstractFileClient; | ||
| 7 | + | ||
| 8 | +import java.io.File; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * Sftp 文件客户端 | ||
| 12 | + * | ||
| 13 | + * @author 芋道源码 | ||
| 14 | + */ | ||
| 15 | +public class SftpFileClient extends AbstractFileClient<SftpFileClientConfig> { | ||
| 16 | + | ||
| 17 | + private Sftp sftp; | ||
| 18 | + | ||
| 19 | + public SftpFileClient(Long id, SftpFileClientConfig config) { | ||
| 20 | + super(id, config); | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + @Override | ||
| 24 | + protected void doInit() { | ||
| 25 | + // 补全风格。例如说 Linux 是 /,Windows 是 \ | ||
| 26 | + if (!config.getBasePath().endsWith(File.separator)) { | ||
| 27 | + config.setBasePath(config.getBasePath() + File.separator); | ||
| 28 | + } | ||
| 29 | + // 初始化 Ftp 对象 | ||
| 30 | + this.sftp = new Sftp(config.getHost(), config.getPort(), config.getUsername(), config.getPassword()); | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + @Override | ||
| 34 | + public String upload(byte[] content, String path) { | ||
| 35 | + // 执行写入 | ||
| 36 | + String filePath = getFilePath(path); | ||
| 37 | + File file = FileUtils.createTempFile(content); | ||
| 38 | + sftp.upload(filePath, file); | ||
| 39 | + // 拼接返回路径 | ||
| 40 | + return super.formatFileUrl(config.getDomain(), path); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + @Override | ||
| 44 | + public void delete(String path) { | ||
| 45 | + String filePath = getFilePath(path); | ||
| 46 | + sftp.delFile(filePath); | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + @Override | ||
| 50 | + public byte[] getContent(String path) { | ||
| 51 | + String filePath = getFilePath(path); | ||
| 52 | + File destFile = FileUtils.createTempFile(); | ||
| 53 | + sftp.download(filePath, destFile); | ||
| 54 | + return FileUtil.readBytes(destFile); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + private String getFilePath(String path) { | ||
| 58 | + return config.getBasePath() + path; | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | +} |
yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/client/impl/sftp/SftpFileClientConfig.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.file.core.client.impl.sftp; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.file.core.client.FileClientConfig; | ||
| 4 | +import lombok.Data; | ||
| 5 | +import org.hibernate.validator.constraints.URL; | ||
| 6 | + | ||
| 7 | +import javax.validation.constraints.NotEmpty; | ||
| 8 | +import javax.validation.constraints.NotNull; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * Sftp 文件客户端的配置类 | ||
| 12 | + * | ||
| 13 | + * @author 芋道源码 | ||
| 14 | + */ | ||
| 15 | +@Data | ||
| 16 | +public class SftpFileClientConfig implements FileClientConfig { | ||
| 17 | + | ||
| 18 | + /** | ||
| 19 | + * 基础路径 | ||
| 20 | + */ | ||
| 21 | + @NotEmpty(message = "基础路径不能为空") | ||
| 22 | + private String basePath; | ||
| 23 | + | ||
| 24 | + /** | ||
| 25 | + * 自定义域名 | ||
| 26 | + */ | ||
| 27 | + @NotEmpty(message = "domain 不能为空") | ||
| 28 | + @URL(message = "domain 必须是 URL 格式") | ||
| 29 | + private String domain; | ||
| 30 | + | ||
| 31 | + /** | ||
| 32 | + * 主机地址 | ||
| 33 | + */ | ||
| 34 | + @NotEmpty(message = "host 不能为空") | ||
| 35 | + private String host; | ||
| 36 | + /** | ||
| 37 | + * 主机端口 | ||
| 38 | + */ | ||
| 39 | + @NotNull(message = "port 不能为空") | ||
| 40 | + private Integer port; | ||
| 41 | + /** | ||
| 42 | + * 用户名 | ||
| 43 | + */ | ||
| 44 | + @NotEmpty(message = "用户名不能为空") | ||
| 45 | + private String username; | ||
| 46 | + /** | ||
| 47 | + * 密码 | ||
| 48 | + */ | ||
| 49 | + @NotEmpty(message = "密码不能为空") | ||
| 50 | + private String password; | ||
| 51 | + | ||
| 52 | +} |
yudao-framework/yudao-spring-boot-starter-file/src/test/java/cn/iocoder/yudao/framework/file/core/client/ftp/FtpFileClientTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.file.core.client.ftp; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.io.resource.ResourceUtil; | ||
| 4 | +import cn.hutool.core.util.IdUtil; | ||
| 5 | +import cn.hutool.extra.ftp.FtpMode; | ||
| 6 | +import cn.iocoder.yudao.framework.file.core.client.impl.ftp.FtpFileClient; | ||
| 7 | +import cn.iocoder.yudao.framework.file.core.client.impl.ftp.FtpFileClientConfig; | ||
| 8 | +import org.junit.jupiter.api.Test; | ||
| 9 | + | ||
| 10 | +public class FtpFileClientTest { | ||
| 11 | + | ||
| 12 | + @Test | ||
| 13 | + public void test() { | ||
| 14 | + // 创建客户端 | ||
| 15 | + FtpFileClientConfig config = new FtpFileClientConfig(); | ||
| 16 | + config.setDomain("http://127.0.0.1:48080"); | ||
| 17 | + config.setBasePath("/home/ftp"); | ||
| 18 | + config.setHost("kanchai.club"); | ||
| 19 | + config.setPort(221); | ||
| 20 | + config.setUsername(""); | ||
| 21 | + config.setPassword(""); | ||
| 22 | + config.setMode(FtpMode.Passive.name()); | ||
| 23 | + FtpFileClient client = new FtpFileClient(0L, config); | ||
| 24 | + client.init(); | ||
| 25 | + // 上传文件 | ||
| 26 | + String path = IdUtil.fastSimpleUUID() + ".jpg"; | ||
| 27 | + byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); | ||
| 28 | + String fullPath = client.upload(content, path); | ||
| 29 | + System.out.println("访问地址:" + fullPath); | ||
| 30 | + if (false) { | ||
| 31 | + byte[] bytes = client.getContent(path); | ||
| 32 | + System.out.println("文件内容:" + bytes); | ||
| 33 | + } | ||
| 34 | + if (false) { | ||
| 35 | + client.delete(path); | ||
| 36 | + } | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | +} |
yudao-framework/yudao-spring-boot-starter-file/src/test/java/cn/iocoder/yudao/framework/file/core/client/local/LocalFileClientTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.file.core.client.local; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.io.resource.ResourceUtil; | ||
| 4 | +import cn.hutool.core.util.IdUtil; | ||
| 5 | +import cn.iocoder.yudao.framework.file.core.client.impl.local.LocalFileClient; | ||
| 6 | +import cn.iocoder.yudao.framework.file.core.client.impl.local.LocalFileClientConfig; | ||
| 7 | +import org.junit.jupiter.api.Test; | ||
| 8 | + | ||
| 9 | +public class LocalFileClientTest { | ||
| 10 | + | ||
| 11 | + @Test | ||
| 12 | + public void test() { | ||
| 13 | + // 创建客户端 | ||
| 14 | + LocalFileClientConfig config = new LocalFileClientConfig(); | ||
| 15 | + config.setDomain("http://127.0.0.1:48080"); | ||
| 16 | + config.setBasePath("/Users/yunai/file_test"); | ||
| 17 | + LocalFileClient client = new LocalFileClient(0L, config); | ||
| 18 | + client.init(); | ||
| 19 | + // 上传文件 | ||
| 20 | + String path = IdUtil.fastSimpleUUID() + ".jpg"; | ||
| 21 | + byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); | ||
| 22 | + String fullPath = client.upload(content, path); | ||
| 23 | + System.out.println("访问地址:" + fullPath); | ||
| 24 | + client.delete(path); | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | +} |
yudao-framework/yudao-spring-boot-starter-file/src/test/java/cn/iocoder/yudao/framework/file/core/client/s3/S3FileClientTest.java
| @@ -76,6 +76,15 @@ public class S3FileClientTest { | @@ -76,6 +76,15 @@ public class S3FileClientTest { | ||
| 76 | byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); | 76 | byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); |
| 77 | String fullPath = client.upload(content, path); | 77 | String fullPath = client.upload(content, path); |
| 78 | System.out.println("访问地址:" + fullPath); | 78 | System.out.println("访问地址:" + fullPath); |
| 79 | + // 读取文件 | ||
| 80 | + if (false) { | ||
| 81 | + byte[] bytes = client.getContent(path); | ||
| 82 | + System.out.println("文件内容:" + bytes); | ||
| 83 | + } | ||
| 84 | + // 删除文件 | ||
| 85 | + if (false) { | ||
| 86 | + client.delete(path); | ||
| 87 | + } | ||
| 79 | } | 88 | } |
| 80 | 89 | ||
| 81 | } | 90 | } |
yudao-framework/yudao-spring-boot-starter-file/src/test/java/cn/iocoder/yudao/framework/file/core/client/sftp/SftpFileClientTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.file.core.client.sftp; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.io.resource.ResourceUtil; | ||
| 4 | +import cn.hutool.core.util.IdUtil; | ||
| 5 | +import cn.iocoder.yudao.framework.file.core.client.impl.sftp.SftpFileClient; | ||
| 6 | +import cn.iocoder.yudao.framework.file.core.client.impl.sftp.SftpFileClientConfig; | ||
| 7 | +import org.junit.jupiter.api.Test; | ||
| 8 | + | ||
| 9 | +public class SftpFileClientTest { | ||
| 10 | + | ||
| 11 | + @Test | ||
| 12 | + public void test() { | ||
| 13 | + // 创建客户端 | ||
| 14 | + SftpFileClientConfig config = new SftpFileClientConfig(); | ||
| 15 | + config.setDomain("http://127.0.0.1:48080"); | ||
| 16 | + config.setBasePath("/home/ftp"); | ||
| 17 | + config.setHost("kanchai.club"); | ||
| 18 | + config.setPort(222); | ||
| 19 | + config.setUsername(""); | ||
| 20 | + config.setPassword(""); | ||
| 21 | + SftpFileClient client = new SftpFileClient(0L, config); | ||
| 22 | + client.init(); | ||
| 23 | + // 上传文件 | ||
| 24 | + String path = IdUtil.fastSimpleUUID() + ".jpg"; | ||
| 25 | + byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); | ||
| 26 | + String fullPath = client.upload(content, path); | ||
| 27 | + System.out.println("访问地址:" + fullPath); | ||
| 28 | + if (false) { | ||
| 29 | + byte[] bytes = client.getContent(path); | ||
| 30 | + System.out.println("文件内容:" + bytes); | ||
| 31 | + } | ||
| 32 | + if (false) { | ||
| 33 | + client.delete(path); | ||
| 34 | + } | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | +} |
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java
| @@ -57,10 +57,15 @@ public class FileController { | @@ -57,10 +57,15 @@ public class FileController { | ||
| 57 | return success(true); | 57 | return success(true); |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | - @GetMapping("/get/{path}") | 60 | + @GetMapping("/{configId}/get/{path}") |
| 61 | @ApiOperation("下载文件") | 61 | @ApiOperation("下载文件") |
| 62 | - @ApiImplicitParam(name = "path", value = "文件附件", required = true, dataTypeClass = MultipartFile.class) | ||
| 63 | - public void getFile(HttpServletResponse response, @PathVariable("path") String path) throws IOException { | 62 | + @ApiImplicitParams({ |
| 63 | + @ApiImplicitParam(name = "configId", value = "配置编号", required = true, dataTypeClass = String.class), | ||
| 64 | + @ApiImplicitParam(name = "path", value = "文件路径", required = true, dataTypeClass = String.class) | ||
| 65 | + }) | ||
| 66 | + public void getFile(HttpServletResponse response, | ||
| 67 | + @PathVariable("configId") String configId, | ||
| 68 | + @PathVariable("path") String path) throws IOException { | ||
| 64 | FileDO file = fileService.getFile(path); | 69 | FileDO file = fileService.getFile(path); |
| 65 | if (file == null) { | 70 | if (file == null) { |
| 66 | log.warn("[getFile][path({}) 文件不存在]", path); | 71 | log.warn("[getFile][path({}) 文件不存在]", path); |