Commit 3d40fc81dd6099ed32a4743907d6c3a5032c0bff

Authored by YunaiV
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 22 */
23 23 @SneakyThrows
24 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 54 // 创建文件,通过 UUID 保证唯一
26 55 File file = File.createTempFile(IdUtil.simpleUUID(), null);
27 56 // 标记 JVM 退出时,自动删除
28 57 file.deleteOnExit();
29   - // 写入内容
30   - FileUtil.writeUtf8String(data, file);
31 58 return file;
32 59 }
33 60  
... ...
yudao-framework/yudao-spring-boot-starter-file/pom.xml
... ... @@ -51,6 +51,18 @@
51 51 <artifactId>jackson-core</artifactId>
52 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 67 <dependency>
56 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 1 package cn.iocoder.yudao.framework.file.core.client.impl;
2 2  
  3 +import cn.hutool.core.util.StrUtil;
3 4 import cn.iocoder.yudao.framework.file.core.client.FileClient;
4 5 import cn.iocoder.yudao.framework.file.core.client.FileClientConfig;
5 6 import lombok.extern.slf4j.Slf4j;
... ... @@ -55,4 +56,16 @@ public abstract class AbstractFileClient&lt;Config extends FileClientConfig&gt; implem
55 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 7 import software.amazon.awssdk.core.sync.RequestBody;
8 8 import software.amazon.awssdk.regions.Region;
9 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 12 import software.amazon.awssdk.services.s3.model.PutObjectRequest;
11 13  
12 14 import java.net.URI;
... ... @@ -14,7 +16,7 @@ import java.net.URI;
14 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 21 * S3 协议的客户端,采用亚马逊提供的 software.amazon.awssdk.s3 库
20 22 *
... ... @@ -84,12 +86,18 @@ public class S3FileClient extends AbstractFileClient&lt;S3FileClientConfig&gt; {
84 86  
85 87 @Override
86 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 95 @Override
91 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 76 byte[] content = ResourceUtil.readBytes("file/erweima.jpg");
77 77 String fullPath = client.upload(content, path);
78 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 57 return success(true);
58 58 }
59 59  
60   - @GetMapping("/get/{path}")
  60 + @GetMapping("/{configId}/get/{path}")
61 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 69 FileDO file = fileService.getFile(path);
65 70 if (file == null) {
66 71 log.warn("[getFile][path({}) 文件不存在]", path);
... ...