diff --git a/continew-admin-common/pom.xml b/continew-admin-common/pom.xml
index e59e3dc9..7ef23564 100644
--- a/continew-admin-common/pom.xml
+++ b/continew-admin-common/pom.xml
@@ -82,6 +82,12 @@
sms4j-spring-boot-starter
+
+
+ org.dromara.x-file-storage
+ x-file-storage-spring
+
+
org.freemarker
diff --git a/continew-admin-common/src/main/java/top/charles7c/continew/admin/common/config/mybatis/MyBatisPlusMetaObjectHandler.java b/continew-admin-common/src/main/java/top/charles7c/continew/admin/common/config/mybatis/MyBatisPlusMetaObjectHandler.java
index 1f81caa3..255bc574 100644
--- a/continew-admin-common/src/main/java/top/charles7c/continew/admin/common/config/mybatis/MyBatisPlusMetaObjectHandler.java
+++ b/continew-admin-common/src/main/java/top/charles7c/continew/admin/common/config/mybatis/MyBatisPlusMetaObjectHandler.java
@@ -61,11 +61,11 @@ public class MyBatisPlusMetaObjectHandler implements MetaObjectHandler {
Long createUser = LoginHelper.getUserId();
LocalDateTime createTime = LocalDateTime.now();
if (metaObject.getOriginalObject() instanceof BaseDO baseDO) {
- // 继承了 BaseDO 的类,填充创建信息
+ // 继承了 BaseDO 的类,填充创建信息字段
baseDO.setCreateUser(ObjectUtil.defaultIfNull(baseDO.getCreateUser(), createUser));
baseDO.setCreateTime(ObjectUtil.defaultIfNull(baseDO.getCreateTime(), createTime));
} else {
- // 未继承 BaseDO 的类,如存在创建信息则进行填充
+ // 未继承 BaseDO 的类,如存在创建信息字段则进行填充
this.fillFieldValue(metaObject, CREATE_USER, createUser, false);
this.fillFieldValue(metaObject, CREATE_TIME, createTime, false);
}
@@ -94,7 +94,7 @@ public class MyBatisPlusMetaObjectHandler implements MetaObjectHandler {
baseDO.setUpdateUser(updateUser);
baseDO.setUpdateTime(updateTime);
} else {
- // 未继承 BaseDO 的类,根据类中拥有的修改信息进行填充,不存在修改信息不进行填充
+ // 未继承 BaseDO 的类,根据类中拥有的修改信息字段进行填充,不存在修改信息字段不进行填充
this.fillFieldValue(metaObject, UPDATE_USER, updateUser, true);
this.fillFieldValue(metaObject, UPDATE_TIME, updateTime, true);
}
diff --git a/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/config/FileRecorderImpl.java b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/config/FileRecorderImpl.java
new file mode 100644
index 00000000..fddcbca1
--- /dev/null
+++ b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/config/FileRecorderImpl.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.charles7c.continew.admin.system.config;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import org.dromara.x.file.storage.core.FileInfo;
+import org.dromara.x.file.storage.core.recorder.FileRecorder;
+import org.springframework.stereotype.Component;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.EscapeUtil;
+
+import top.charles7c.continew.admin.common.util.helper.LoginHelper;
+import top.charles7c.continew.admin.system.enums.FileTypeEnum;
+import top.charles7c.continew.admin.system.mapper.FileMapper;
+import top.charles7c.continew.admin.system.mapper.StorageMapper;
+import top.charles7c.continew.admin.system.model.entity.FileDO;
+import top.charles7c.continew.admin.system.model.entity.StorageDO;
+
+/**
+ * 文件记录实现类
+ *
+ * @author Charles7c
+ * @since 2023/12/24 22:31
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class FileRecorderImpl implements FileRecorder {
+
+ private final FileMapper fileMapper;
+ private final StorageMapper storageMapper;
+
+ @Override
+ public boolean save(FileInfo fileInfo) {
+ FileDO file = new FileDO();
+ file.setName(EscapeUtil.unescape(fileInfo.getOriginalFilename()));
+ file.setSize(fileInfo.getSize());
+ file.setUrl(fileInfo.getUrl());
+ file.setExtension(fileInfo.getExt());
+ file.setType(FileTypeEnum.getByExtension(file.getExtension()));
+ StorageDO storage = storageMapper.lambdaQuery().eq(StorageDO::getCode, fileInfo.getPlatform()).one();
+ file.setStorageId(storage.getId());
+ file.setCreateTime(DateUtil.toLocalDateTime(fileInfo.getCreateTime()));
+ file.setUpdateUser(LoginHelper.getUserId());
+ file.setUpdateTime(file.getCreateTime());
+ fileMapper.insert(file);
+ return true;
+ }
+
+ @Override
+ public FileInfo getByUrl(String url) {
+ FileDO file = fileMapper.lambdaQuery().eq(FileDO::getUrl, url).one();
+ FileInfo fileInfo = new FileInfo();
+ fileInfo.setOriginalFilename(file.getName());
+ fileInfo.setSize(file.getSize());
+ fileInfo.setUrl(file.getUrl());
+ fileInfo.setExt(file.getExtension());
+ return fileInfo;
+ }
+
+ @Override
+ public boolean delete(String url) {
+ return fileMapper.lambdaUpdate().eq(FileDO::getUrl, url).remove();
+ }
+}
\ No newline at end of file
diff --git a/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/enums/FileTypeEnum.java b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/enums/FileTypeEnum.java
index 384e4475..d6e88161 100644
--- a/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/enums/FileTypeEnum.java
+++ b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/enums/FileTypeEnum.java
@@ -16,12 +16,15 @@
package top.charles7c.continew.admin.system.enums;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
+import cn.hutool.core.util.StrUtil;
+
import top.charles7c.continew.starter.data.mybatis.plus.base.IBaseEnum;
/**
@@ -62,4 +65,17 @@ public enum FileTypeEnum implements IBaseEnum {
private final Integer value;
private final String description;
private final List extensions;
+
+ /**
+ * 根据扩展名查询
+ *
+ * @param extension
+ * 扩展名
+ * @return 文件类型
+ */
+ public static FileTypeEnum getByExtension(String extension) {
+ return Arrays.stream(FileTypeEnum.values())
+ .filter(t -> t.getExtensions().contains(StrUtil.emptyIfNull(extension).toLowerCase())).findFirst()
+ .orElse(FileTypeEnum.UNKNOWN);
+ }
}
diff --git a/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/mapper/StorageMapper.java b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/mapper/StorageMapper.java
new file mode 100644
index 00000000..cee45005
--- /dev/null
+++ b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/mapper/StorageMapper.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.charles7c.continew.admin.system.mapper;
+
+import top.charles7c.continew.admin.system.model.entity.StorageDO;
+import top.charles7c.continew.starter.data.mybatis.plus.base.BaseMapper;
+
+/**
+ * 存储库 Mapper
+ *
+ * @author Charles7c
+ * @since 2023/12/26 22:09
+ */
+public interface StorageMapper extends BaseMapper {}
\ No newline at end of file
diff --git a/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/model/entity/FileDO.java b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/model/entity/FileDO.java
index f3d497ce..dadc1250 100644
--- a/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/model/entity/FileDO.java
+++ b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/model/entity/FileDO.java
@@ -20,7 +20,7 @@ import java.io.Serial;
import lombok.Data;
-import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.*;
import top.charles7c.continew.admin.system.enums.FileTypeEnum;
import top.charles7c.continew.starter.extension.crud.base.BaseDO;
@@ -38,6 +38,9 @@ public class FileDO extends BaseDO {
@Serial
private static final long serialVersionUID = 1L;
+ @TableId(type = IdType.ASSIGN_ID)
+ private Long id;
+
/**
* 名称
*/
@@ -58,18 +61,13 @@ public class FileDO extends BaseDO {
*/
private String extension;
- /**
- * MIME类型
- */
- private String mimeType;
-
/**
* 类型
*/
private FileTypeEnum type;
/**
- * 存储库ID
+ * 存储库 ID
*/
private Long storageId;
}
\ No newline at end of file
diff --git a/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/model/entity/StorageDO.java b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/model/entity/StorageDO.java
new file mode 100644
index 00000000..0d95d239
--- /dev/null
+++ b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/model/entity/StorageDO.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.charles7c.continew.admin.system.model.entity;
+
+import java.io.Serial;
+
+import lombok.Data;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+
+import top.charles7c.continew.starter.extension.crud.base.BaseDO;
+
+/**
+ * 存储库实体
+ *
+ * @author Charles7c
+ * @since 2023/12/26 22:09
+ */
+@Data
+@TableName("sys_storage")
+public class StorageDO extends BaseDO {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 名称
+ */
+ private String name;
+
+ /**
+ * 编码
+ */
+ private String code;
+
+ /**
+ * Access Key
+ */
+ private String accessKey;
+
+ /**
+ * Secret Key
+ */
+ private String secretKey;
+
+ /**
+ * Endpoint
+ */
+ private String endpoint;
+
+ /**
+ * 桶名称
+ */
+ private String bucketName;
+
+ /**
+ * 自定义域名
+ */
+ private String domain;
+
+ /**
+ * 描述
+ */
+ private String description;
+
+ /**
+ * 是否为默认存储
+ */
+ private Boolean isDefault;
+
+ /**
+ * 排序
+ */
+ private Integer sort;
+
+ /**
+ * 状态
+ */
+ private Integer status;
+}
\ No newline at end of file
diff --git a/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/model/query/StorageQuery.java b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/model/query/StorageQuery.java
new file mode 100644
index 00000000..71fb8865
--- /dev/null
+++ b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/model/query/StorageQuery.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.charles7c.continew.admin.system.model.query;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+import lombok.Data;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import top.charles7c.continew.starter.data.mybatis.plus.query.Query;
+import top.charles7c.continew.starter.data.mybatis.plus.query.QueryType;
+
+/**
+ * 存储库查询条件
+ *
+ * @author Charles7c
+ * @since 2023/12/26 22:09
+ */
+@Data
+@Schema(description = "存储库查询条件")
+public class StorageQuery implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 名称
+ */
+ @Schema(description = "名称")
+ @Query(type = QueryType.INNER_LIKE)
+ private String name;
+
+ /**
+ * 状态
+ */
+ @Schema(description = "状态")
+ @Query(type = QueryType.EQUAL)
+ private Integer status;
+}
\ No newline at end of file
diff --git a/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/model/req/StorageReq.java b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/model/req/StorageReq.java
new file mode 100644
index 00000000..9b819787
--- /dev/null
+++ b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/model/req/StorageReq.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.charles7c.continew.admin.system.model.req;
+
+import java.io.Serial;
+
+import jakarta.validation.constraints.*;
+
+import lombok.Data;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import top.charles7c.continew.admin.common.enums.DisEnableStatusEnum;
+import top.charles7c.continew.starter.extension.crud.base.BaseReq;
+
+/**
+ * 创建或修改存储库信息
+ *
+ * @author Charles7c
+ * @since 2023/12/26 22:09
+ */
+@Data
+@Schema(description = "创建或修改存储库信息")
+public class StorageReq extends BaseReq {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 名称
+ */
+ @Schema(description = "名称")
+ @NotBlank(message = "名称不能为空")
+ private String name;
+
+ /**
+ * 编码
+ */
+ @Schema(description = "编码")
+ @NotBlank(message = "编码不能为空")
+ private String code;
+
+ /**
+ * Access Key
+ */
+ @Schema(description = "Access Key")
+ private String accessKey;
+
+ /**
+ * Secret Key
+ */
+ @Schema(description = "Secret Key")
+ private String secretKey;
+
+ /**
+ * Endpoint
+ */
+ @Schema(description = "Endpoint")
+ private String endpoint;
+
+ /**
+ * 桶名称
+ */
+ @Schema(description = "桶名称")
+ private String bucketName;
+
+ /**
+ * 自定义域名
+ */
+ @Schema(description = "自定义域名")
+ private String domain;
+
+ /**
+ * 描述
+ */
+ @Schema(description = "描述")
+ private String description;
+
+ /**
+ * 是否为默认存储
+ */
+ @Schema(description = "是否为默认存储")
+ @NotNull(message = "是否为默认存储不能为空")
+ private Boolean isDefault;
+
+ /**
+ * 排序
+ */
+ @Schema(description = "排序")
+ private Integer sort;
+
+ /**
+ * 状态
+ */
+ @Schema(description = "状态(1:启用;2:禁用)", type = "Integer", allowableValues = {"1", "2"}, example = "1")
+ private DisEnableStatusEnum status;
+}
\ No newline at end of file
diff --git a/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/model/resp/StorageDetailResp.java b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/model/resp/StorageDetailResp.java
new file mode 100644
index 00000000..e5b21d5d
--- /dev/null
+++ b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/model/resp/StorageDetailResp.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.charles7c.continew.admin.system.model.resp;
+
+import java.io.Serial;
+
+import lombok.Data;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+
+import top.charles7c.continew.starter.extension.crud.base.BaseDetailResp;
+
+/**
+ * 存储库详情信息
+ *
+ * @author Charles7c
+ * @since 2023/12/26 22:09
+ */
+@Data
+@ExcelIgnoreUnannotated
+@Schema(description = "存储库详情信息")
+public class StorageDetailResp extends BaseDetailResp {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 名称
+ */
+ @Schema(description = "名称")
+ @ExcelProperty(value = "名称")
+ private String name;
+
+ /**
+ * 编码
+ */
+ @Schema(description = "编码")
+ @ExcelProperty(value = "编码")
+ private String code;
+
+ /**
+ * Access Key
+ */
+ @Schema(description = "Access Key")
+ @ExcelProperty(value = "Access Key")
+ private String accessKey;
+
+ /**
+ * Secret Key
+ */
+ @Schema(description = "Secret Key")
+ @ExcelProperty(value = "Secret Key")
+ private String secretKey;
+
+ /**
+ * Endpoint
+ */
+ @Schema(description = "Endpoint")
+ @ExcelProperty(value = "Endpoint")
+ private String endpoint;
+
+ /**
+ * 桶名称
+ */
+ @Schema(description = "桶名称")
+ @ExcelProperty(value = "桶名称")
+ private String bucketName;
+
+ /**
+ * 自定义域名
+ */
+ @Schema(description = "自定义域名")
+ @ExcelProperty(value = "自定义域名")
+ private String domain;
+
+ /**
+ * 描述
+ */
+ @Schema(description = "描述")
+ @ExcelProperty(value = "描述")
+ private String description;
+
+ /**
+ * 是否为默认存储
+ */
+ @Schema(description = "是否为默认存储")
+ @ExcelProperty(value = "是否为默认存储")
+ private Boolean isDefault;
+
+ /**
+ * 排序
+ */
+ @Schema(description = "排序")
+ @ExcelProperty(value = "排序")
+ private Integer sort;
+
+ /**
+ * 状态
+ */
+ @Schema(description = "状态")
+ @ExcelProperty(value = "状态")
+ private Integer status;
+}
\ No newline at end of file
diff --git a/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/model/resp/StorageResp.java b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/model/resp/StorageResp.java
new file mode 100644
index 00000000..97cfc30b
--- /dev/null
+++ b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/model/resp/StorageResp.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.charles7c.continew.admin.system.model.resp;
+
+import java.io.Serial;
+
+import lombok.Data;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import top.charles7c.continew.starter.extension.crud.base.BaseResp;
+
+/**
+ * 存储库信息
+ *
+ * @author Charles7c
+ * @since 2023/12/26 22:09
+ */
+@Data
+@Schema(description = "存储库信息")
+public class StorageResp extends BaseResp {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 名称
+ */
+ @Schema(description = "名称")
+ private String name;
+
+ /**
+ * 编码
+ */
+ @Schema(description = "编码")
+ private String code;
+
+ /**
+ * Access Key
+ */
+ @Schema(description = "Access Key")
+ private String accessKey;
+
+ /**
+ * Secret Key
+ */
+ @Schema(description = "Secret Key")
+ private String secretKey;
+
+ /**
+ * Endpoint
+ */
+ @Schema(description = "Endpoint")
+ private String endpoint;
+
+ /**
+ * 桶名称
+ */
+ @Schema(description = "桶名称")
+ private String bucketName;
+
+ /**
+ * 自定义域名
+ */
+ @Schema(description = "自定义域名")
+ private String domain;
+
+ /**
+ * 描述
+ */
+ @Schema(description = "描述")
+ private String description;
+
+ /**
+ * 是否为默认存储
+ */
+ @Schema(description = "是否为默认存储")
+ private Boolean isDefault;
+
+ /**
+ * 排序
+ */
+ @Schema(description = "排序")
+ private Integer sort;
+
+ /**
+ * 状态
+ */
+ @Schema(description = "状态")
+ private Integer status;
+}
\ No newline at end of file
diff --git a/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/service/FileService.java b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/service/FileService.java
index 7df68656..3bbe45c9 100644
--- a/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/service/FileService.java
+++ b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/service/FileService.java
@@ -16,6 +16,10 @@
package top.charles7c.continew.admin.system.service;
+import java.util.List;
+
+import org.springframework.web.multipart.MultipartFile;
+
import top.charles7c.continew.admin.system.model.query.FileQuery;
import top.charles7c.continew.admin.system.model.req.FileReq;
import top.charles7c.continew.admin.system.model.resp.FileDetailResp;
@@ -28,4 +32,24 @@ import top.charles7c.continew.starter.extension.crud.base.BaseService;
* @author Charles7c
* @since 2023/12/23 10:38
*/
-public interface FileService extends BaseService {}
\ No newline at end of file
+public interface FileService extends BaseService {
+
+ /**
+ * 上传
+ *
+ * @param file
+ * 文件信息
+ * @param storageCode
+ * 存储库编码
+ */
+ void upload(MultipartFile file, String storageCode);
+
+ /**
+ * 根据存储库 ID 列表查询
+ *
+ * @param storageIds
+ * 存储库 ID 列表
+ * @return 文件数量
+ */
+ Long countByStorageIds(List storageIds);
+}
\ No newline at end of file
diff --git a/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/service/StorageService.java b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/service/StorageService.java
new file mode 100644
index 00000000..ab0cdbf7
--- /dev/null
+++ b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/service/StorageService.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.charles7c.continew.admin.system.service;
+
+import top.charles7c.continew.admin.system.model.entity.StorageDO;
+import top.charles7c.continew.admin.system.model.query.StorageQuery;
+import top.charles7c.continew.admin.system.model.req.StorageReq;
+import top.charles7c.continew.admin.system.model.resp.StorageDetailResp;
+import top.charles7c.continew.admin.system.model.resp.StorageResp;
+import top.charles7c.continew.starter.extension.crud.base.BaseService;
+
+/**
+ * 存储库业务接口
+ *
+ * @author Charles7c
+ * @since 2023/12/26 22:09
+ */
+public interface StorageService extends BaseService {
+
+ /**
+ * 查询默认存储库
+ *
+ * @return 存储库信息
+ */
+ StorageDO getDefaultStorage();
+
+ /**
+ * 根据编码查询
+ *
+ * @param code
+ * 编码
+ * @return 存储库信息
+ */
+ StorageDO getByCode(String code);
+}
\ No newline at end of file
diff --git a/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/service/impl/FileServiceImpl.java b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/service/impl/FileServiceImpl.java
index 7bc9f411..79f646c4 100644
--- a/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/service/impl/FileServiceImpl.java
+++ b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/service/impl/FileServiceImpl.java
@@ -16,17 +16,29 @@
package top.charles7c.continew.admin.system.service.impl;
-import lombok.RequiredArgsConstructor;
+import java.util.List;
+import jakarta.annotation.Resource;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import org.dromara.x.file.storage.core.*;
import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import cn.hutool.core.util.StrUtil;
import top.charles7c.continew.admin.system.mapper.FileMapper;
import top.charles7c.continew.admin.system.model.entity.FileDO;
+import top.charles7c.continew.admin.system.model.entity.StorageDO;
import top.charles7c.continew.admin.system.model.query.FileQuery;
import top.charles7c.continew.admin.system.model.req.FileReq;
import top.charles7c.continew.admin.system.model.resp.FileDetailResp;
import top.charles7c.continew.admin.system.model.resp.FileResp;
import top.charles7c.continew.admin.system.service.FileService;
+import top.charles7c.continew.admin.system.service.StorageService;
+import top.charles7c.continew.starter.core.util.validate.CheckUtils;
import top.charles7c.continew.starter.extension.crud.base.BaseServiceImpl;
/**
@@ -35,7 +47,45 @@ import top.charles7c.continew.starter.extension.crud.base.BaseServiceImpl;
* @author Charles7c
* @since 2023/12/23 10:38
*/
+@Slf4j
@Service
@RequiredArgsConstructor
public class FileServiceImpl extends BaseServiceImpl
- implements FileService {}
\ No newline at end of file
+ implements FileService {
+
+ @Resource
+ private StorageService storageService;
+ private final FileStorageService fileStorageService;
+
+ @Override
+ public void upload(MultipartFile file, String storageCode) {
+ if (StrUtil.isBlank(storageCode)) {
+ StorageDO storage = storageService.getDefaultStorage();
+ CheckUtils.throwIfNull(storage, "请先指定默认存储库");
+ storageCode = storage.getCode();
+ }
+ UploadPretreatment uploadPretreatment = fileStorageService.of(file).setPlatform(storageCode);
+ uploadPretreatment.setProgressMonitor(new ProgressListener() {
+ @Override
+ public void start() {
+ log.info("开始上传");
+ }
+
+ @Override
+ public void progress(long progressSize, long allSize) {
+ log.info("已上传 [{}],总大小 [{}]", progressSize, allSize);
+ }
+
+ @Override
+ public void finish() {
+ log.info("上传结束");
+ }
+ });
+ uploadPretreatment.upload();
+ }
+
+ @Override
+ public Long countByStorageIds(List storageIds) {
+ return baseMapper.lambdaQuery().in(FileDO::getStorageId, storageIds).count();
+ }
+}
\ No newline at end of file
diff --git a/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/service/impl/StorageServiceImpl.java b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/service/impl/StorageServiceImpl.java
new file mode 100644
index 00000000..d0cc55b2
--- /dev/null
+++ b/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/service/impl/StorageServiceImpl.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.charles7c.continew.admin.system.service.impl;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import jakarta.annotation.Resource;
+import jakarta.servlet.ServletContext;
+
+import lombok.RequiredArgsConstructor;
+
+import org.dromara.x.file.storage.core.FileStorageProperties;
+import org.dromara.x.file.storage.core.FileStorageService;
+import org.dromara.x.file.storage.core.FileStorageServiceBuilder;
+import org.dromara.x.file.storage.core.platform.FileStorage;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Service;
+import org.springframework.web.accept.ContentNegotiationManager;
+import org.springframework.web.servlet.HandlerMapping;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
+import org.springframework.web.util.UrlPathHelper;
+
+import cn.hutool.core.util.ReflectUtil;
+import cn.hutool.core.util.StrUtil;
+
+import top.charles7c.continew.admin.common.enums.DisEnableStatusEnum;
+import top.charles7c.continew.admin.system.mapper.StorageMapper;
+import top.charles7c.continew.admin.system.model.entity.StorageDO;
+import top.charles7c.continew.admin.system.model.query.StorageQuery;
+import top.charles7c.continew.admin.system.model.req.StorageReq;
+import top.charles7c.continew.admin.system.model.resp.StorageDetailResp;
+import top.charles7c.continew.admin.system.model.resp.StorageResp;
+import top.charles7c.continew.admin.system.service.FileService;
+import top.charles7c.continew.admin.system.service.StorageService;
+import top.charles7c.continew.starter.core.util.validate.CheckUtils;
+import top.charles7c.continew.starter.extension.crud.base.BaseServiceImpl;
+
+/**
+ * 存储库业务实现
+ *
+ * @author Charles7c
+ * @since 2023/12/26 22:09
+ */
+@Service
+@RequiredArgsConstructor
+public class StorageServiceImpl
+ extends BaseServiceImpl
+ implements StorageService {
+
+ private final ApplicationContext applicationContext;
+ private final FileStorageService fileStorageService;
+ @Resource
+ private final FileService fileService;
+
+ @Override
+ public Long add(StorageReq req) {
+ String code = req.getCode();
+ CheckUtils.throwIf(this.isCodeExists(code, null), "新增失败,[{}] 已存在", code);
+ req.setStatus(DisEnableStatusEnum.ENABLE);
+ this.loadFileStorage(req);
+ return super.add(req);
+ }
+
+ @Override
+ public void update(StorageReq req, Long id) {
+ String code = req.getCode();
+ CheckUtils.throwIf(this.isCodeExists(code, id), "修改失败,[{}] 已存在", code);
+ StorageDO oldStorage = super.getById(id);
+ CheckUtils.throwIf(
+ Boolean.TRUE.equals(oldStorage.getIsDefault()) && DisEnableStatusEnum.DISABLE.equals(req.getStatus()),
+ "[{}] 是默认存储库,不允许禁用", oldStorage.getName());
+ this.loadFileStorage(req);
+ super.update(req, id);
+ }
+
+ @Override
+ public void delete(List ids) {
+ CheckUtils.throwIf(fileService.countByStorageIds(ids) > 0, "所选存储库存在文件关联,请删除文件后重试");
+ List storageList = baseMapper.lambdaQuery().in(StorageDO::getId, ids).list();
+ storageList.forEach(s -> this.removeFileStorage(s.getCode()));
+ super.delete(ids);
+ }
+
+ @Override
+ public StorageDO getDefaultStorage() {
+ return baseMapper.lambdaQuery().eq(StorageDO::getIsDefault, true).one();
+ }
+
+ @Override
+ public StorageDO getByCode(String code) {
+ return baseMapper.lambdaQuery().eq(StorageDO::getCode, code).one();
+ }
+
+ /**
+ * 加载存储配置
+ *
+ * @param req
+ * 存储配置信息
+ */
+ private void loadFileStorage(StorageReq req) {
+ CopyOnWriteArrayList fileStorageList = fileStorageService.getFileStorageList();
+ FileStorageProperties.LocalPlusConfig localPlusConfig = new FileStorageProperties.LocalPlusConfig();
+ localPlusConfig.setPlatform(req.getCode());
+ localPlusConfig.setStoragePath(req.getBucketName());
+ localPlusConfig.setDomain(req.getDomain());
+ fileStorageList
+ .addAll(FileStorageServiceBuilder.buildLocalPlusFileStorage(Collections.singletonList(localPlusConfig)));
+ }
+
+ /**
+ * 移除存储配置
+ *
+ * @param code
+ * 存储配置编码
+ */
+ private void removeFileStorage(String code) {
+ CopyOnWriteArrayList fileStorageList = fileStorageService.getFileStorageList();
+ FileStorage fileStorage = fileStorageService.getFileStorage(code);
+ fileStorageList.remove(fileStorage);
+ fileStorage.close();
+ }
+
+ /**
+ * 编码是否存在
+ *
+ * @param code
+ * 编码
+ * @param id
+ * ID
+ * @return 是否存在
+ */
+ private boolean isCodeExists(String code, Long id) {
+ return baseMapper.lambdaQuery().eq(StorageDO::getCode, code).ne(null != id, StorageDO::getId, id).exists();
+ }
+
+ /**
+ * 注册静态资源映射
+ *
+ * @param registerMapping
+ * 静态资源映射列表
+ */
+ private void registerResource(Map registerMapping) {
+ final UrlPathHelper urlPathHelper = applicationContext.getBean("mvcUrlPathHelper", UrlPathHelper.class);
+ final ContentNegotiationManager contentNegotiationManager =
+ applicationContext.getBean("mvcContentNegotiationManager", ContentNegotiationManager.class);
+ final ServletContext servletContext = applicationContext.getBean(ServletContext.class);
+ final HandlerMapping resourceHandlerMapping =
+ applicationContext.getBean("resourceHandlerMapping", HandlerMapping.class);
+ // 已经注册的静态资源映射
+ final Map handlerMap =
+ (Map)ReflectUtil.getFieldValue(resourceHandlerMapping, "handlerMap");
+ final ResourceHandlerRegistry resourceHandlerRegistry =
+ new ResourceHandlerRegistry(applicationContext, servletContext, contentNegotiationManager, urlPathHelper);
+ // 重新注册静态资源映射
+ for (Map.Entry entry : registerMapping.entrySet()) {
+ String pathPattern = StrUtil.appendIfMissing(entry.getKey(), "/**");
+ String resourceLocations = StrUtil.appendIfMissing(entry.getValue(), "/");
+ // 移除之前注册过的
+ handlerMap.remove(pathPattern);
+ // 重新注册
+ resourceHandlerRegistry.addResourceHandler(pathPattern).addResourceLocations("file:" + resourceLocations);
+ }
+ final Map additionalUrlMap =
+ ReflectUtil.invoke(resourceHandlerRegistry, "getHandlerMapping").getUrlMap();
+ ReflectUtil.invoke(resourceHandlerMapping, "registerHandlers", additionalUrlMap);
+ }
+}
\ No newline at end of file
diff --git a/continew-admin-webapi/src/main/java/top/charles7c/continew/admin/ContiNewAdminApplication.java b/continew-admin-webapi/src/main/java/top/charles7c/continew/admin/ContiNewAdminApplication.java
index 00889ea2..ab1ed1bb 100644
--- a/continew-admin-webapi/src/main/java/top/charles7c/continew/admin/ContiNewAdminApplication.java
+++ b/continew-admin-webapi/src/main/java/top/charles7c/continew/admin/ContiNewAdminApplication.java
@@ -23,6 +23,7 @@ import lombok.extern.slf4j.Slf4j;
import io.swagger.v3.oas.annotations.Hidden;
+import org.dromara.x.file.storage.spring.EnableFileStorage;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
@@ -44,6 +45,7 @@ import top.charles7c.continew.starter.core.autoconfigure.project.ProjectProperti
* @since 2022/12/8 23:15
*/
@Slf4j
+@EnableFileStorage
@RestController
@SpringBootApplication
@RequiredArgsConstructor
diff --git a/continew-admin-webapi/src/main/java/top/charles7c/continew/admin/webapi/system/StorageController.java b/continew-admin-webapi/src/main/java/top/charles7c/continew/admin/webapi/system/StorageController.java
new file mode 100644
index 00000000..86cfdb9f
--- /dev/null
+++ b/continew-admin-webapi/src/main/java/top/charles7c/continew/admin/webapi/system/StorageController.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.charles7c.continew.admin.webapi.system;
+
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+import org.springframework.web.bind.annotation.*;
+
+import top.charles7c.continew.admin.system.model.query.StorageQuery;
+import top.charles7c.continew.admin.system.model.req.StorageReq;
+import top.charles7c.continew.admin.system.model.resp.StorageDetailResp;
+import top.charles7c.continew.admin.system.model.resp.StorageResp;
+import top.charles7c.continew.admin.system.service.StorageService;
+import top.charles7c.continew.starter.extension.crud.annotation.CrudRequestMapping;
+import top.charles7c.continew.starter.extension.crud.base.BaseController;
+
+/**
+ * 存储库管理 API
+ *
+ * @author Charles7c
+ * @since 2023/12/26 22:09
+ */
+@Tag(name = "存储库管理 API")
+@RestController
+@CrudRequestMapping("/system/storage")
+public class StorageController
+ extends BaseController {}
\ No newline at end of file
diff --git a/continew-admin-webapi/src/main/resources/db/changelog/v2.2.0/continew-admin_table.sql b/continew-admin-webapi/src/main/resources/db/changelog/v2.2.0/continew-admin_table.sql
index f6b62ada..efd4c0b7 100644
--- a/continew-admin-webapi/src/main/resources/db/changelog/v2.2.0/continew-admin_table.sql
+++ b/continew-admin-webapi/src/main/resources/db/changelog/v2.2.0/continew-admin_table.sql
@@ -12,8 +12,8 @@ CREATE TABLE IF NOT EXISTS `sys_file` (
`storage_id` bigint(20) NOT NULL COMMENT '存储库ID',
`create_user` bigint(20) NOT NULL COMMENT '创建人',
`create_time` datetime NOT NULL COMMENT '创建时间',
- `update_user` bigint(20) DEFAULT NULL COMMENT '修改人',
- `update_time` datetime DEFAULT NULL COMMENT '修改时间',
+ `update_user` bigint(20) NOT NULL COMMENT '修改人',
+ `update_time` datetime NOT NULL COMMENT '修改时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_type`(`type`) USING BTREE,
INDEX `idx_create_user`(`create_user`) USING BTREE,