mirror of
https://gitee.com/dromara/dax-pay.git
synced 2025-09-09 22:09:05 +00:00
ref 脚手架同步为最新版本
This commit is contained in:
41
bootx-platform/bootx-platform-starter/starter-file/pom.xml
Normal file
41
bootx-platform/bootx-platform-starter/starter-file/pom.xml
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform-starter</artifactId>
|
||||
<version>3.0.0.beta1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>starter-file</artifactId>
|
||||
<description>文件存储</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- web容器 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<!--文件存储-->
|
||||
<dependency>
|
||||
<groupId>org.dromara.x-file-storage</groupId>
|
||||
<artifactId>x-file-storage-spring</artifactId>
|
||||
<version>${x-file-storage.version}</version>
|
||||
</dependency>
|
||||
<!-- 数据库 -->
|
||||
<dependency>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>common-mybatis-plus</artifactId>
|
||||
<version>${bootx-platform.version}</version>
|
||||
</dependency>
|
||||
<!-- 认证 -->
|
||||
<dependency>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>starter-auth</artifactId>
|
||||
<version>${bootx-platform.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
@@ -0,0 +1,23 @@
|
||||
package cn.bootx.platform.starter.file;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.dromara.x.file.storage.spring.EnableFileStorage;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
/**
|
||||
* 文件管理
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2022/1/12
|
||||
*/
|
||||
@ComponentScan
|
||||
@ConfigurationPropertiesScan
|
||||
@EnableFileStorage
|
||||
@AutoConfiguration
|
||||
@MapperScan(annotationClass = Mapper.class)
|
||||
public class FileAutoConfiguration {
|
||||
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
package cn.bootx.platform.starter.file.code;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* 存储平台类型
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2022/1/14
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum FilePlatformTypeEnum {
|
||||
LOCAL("local"),
|
||||
FTP("ftp"),
|
||||
SFTP("sftp"),
|
||||
WEB_DAV("web_dav"),
|
||||
AMAZON("amazon"),
|
||||
MINIO("minio"),
|
||||
ALI("ali"),
|
||||
HUAWEI("huawei"),
|
||||
TENCENT("tencent"),
|
||||
BAIDU("baidu"),
|
||||
UPYUN("upyun"),
|
||||
QINIU("qiniu"),
|
||||
GOOGLE_CLOUD("google_cloud"),
|
||||
FAST_DFS("fast_dfs"),
|
||||
AZURE("azure");
|
||||
|
||||
private final String code;
|
||||
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
package cn.bootx.platform.starter.file.configuration;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* 文件上传配置
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2022/1/14
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@ConfigurationProperties(prefix = "bootx-platform.starter.file-upload")
|
||||
public class FileUploadProperties {
|
||||
|
||||
/**
|
||||
* 文件访问转发地址(当前后端服务地址或被代理后的地址), 流量会经过后端服务的转发
|
||||
*/
|
||||
private String forwardServerUrl = "http://127.0.0.1:9999";
|
||||
|
||||
/**
|
||||
* 处理为 / 结尾
|
||||
*/
|
||||
public String getForwardServerUrl() {
|
||||
return StrUtil.removeSuffix(forwardServerUrl, "/");
|
||||
}
|
||||
}
|
@@ -0,0 +1,90 @@
|
||||
package cn.bootx.platform.starter.file.controller;
|
||||
|
||||
import cn.bootx.platform.core.annotation.IgnoreAuth;
|
||||
import cn.bootx.platform.core.rest.Res;
|
||||
import cn.bootx.platform.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.core.rest.result.PageResult;
|
||||
import cn.bootx.platform.core.rest.result.Result;
|
||||
import cn.bootx.platform.starter.file.param.UploadFileQuery;
|
||||
import cn.bootx.platform.starter.file.result.UploadFileResult;
|
||||
import cn.bootx.platform.starter.file.service.FileUploadService;
|
||||
import com.fhs.core.trans.anno.TransMethodResult;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2022/1/12
|
||||
*/
|
||||
@Tag(name = "文件上传")
|
||||
@RestController
|
||||
@RequestMapping("/file")
|
||||
@RequiredArgsConstructor
|
||||
public class FIleUpLoadController {
|
||||
|
||||
private final FileUploadService uploadService;
|
||||
|
||||
@IgnoreAuth
|
||||
@TransMethodResult
|
||||
@Operation(summary = "分页")
|
||||
@GetMapping("/page")
|
||||
public Result<PageResult<UploadFileResult>> page(PageParam pageParam, UploadFileQuery param) {
|
||||
return Res.ok(uploadService.page(pageParam,param));
|
||||
}
|
||||
|
||||
@TransMethodResult
|
||||
@Operation(summary = "获取单条详情")
|
||||
@GetMapping("/findById")
|
||||
public Result<UploadFileResult> findById(Long id) {
|
||||
return Res.ok(uploadService.findById(id));
|
||||
}
|
||||
|
||||
@IgnoreAuth
|
||||
@Operation(summary = "根据URL获取单条详情")
|
||||
@GetMapping("/findByUrl")
|
||||
public Result<UploadFileResult> findById(String url) {
|
||||
return Res.ok(uploadService.findById(url));
|
||||
}
|
||||
|
||||
@Operation(summary = "删除")
|
||||
@PostMapping("/delete")
|
||||
public Result<Void> delete(Long id) {
|
||||
uploadService.delete(id);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@IgnoreAuth
|
||||
@Operation(summary = "上传")
|
||||
@PostMapping("/upload")
|
||||
public Result<UploadFileResult> local(@RequestPart MultipartFile file, String fileName) {
|
||||
return Res.ok(uploadService.upload(file, fileName));
|
||||
}
|
||||
|
||||
@IgnoreAuth
|
||||
@Operation(summary = "获取文件预览地址前缀(流量会经过后端)")
|
||||
@GetMapping("/forward/getFilePreviewUrlPrefix")
|
||||
public Result<String> getFilePreviewUrlPrefix() {
|
||||
return Res.ok(uploadService.getServerFilePreviewUrlPrefix());
|
||||
}
|
||||
|
||||
@IgnoreAuth
|
||||
@Operation(summary = "预览文件(流量会经过后端)")
|
||||
@GetMapping("/forward/preview/{id}")
|
||||
public void preview(@PathVariable Long id, HttpServletResponse response) {
|
||||
uploadService.preview(id, response);
|
||||
}
|
||||
|
||||
@IgnoreAuth
|
||||
@Operation(summary = "下载文件(流量会经过后端)")
|
||||
@GetMapping("/forward/download/{id}")
|
||||
public ResponseEntity<byte[]> download(@PathVariable Long id) {
|
||||
return uploadService.download(id);
|
||||
}
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
package cn.bootx.platform.starter.file.controller;
|
||||
|
||||
import cn.bootx.platform.core.annotation.IgnoreAuth;
|
||||
import cn.bootx.platform.core.annotation.RequestGroup;
|
||||
import cn.bootx.platform.core.annotation.RequestPath;
|
||||
import cn.bootx.platform.core.rest.Res;
|
||||
import cn.bootx.platform.core.rest.result.Result;
|
||||
import cn.bootx.platform.core.util.ValidationUtil;
|
||||
import cn.bootx.platform.starter.file.param.FilePlatformParam;
|
||||
import cn.bootx.platform.starter.file.result.FilePlatformResult;
|
||||
import cn.bootx.platform.starter.file.service.FilePlatformService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 文件存储平台
|
||||
* @author xxm
|
||||
* @since 2024/8/12
|
||||
*/
|
||||
@Validated
|
||||
@RequestGroup(groupCode = "file", groupName = "文件存储管理", moduleCode = "starter", moduleName = "starter模块")
|
||||
@Tag(name = "文件存储平台")
|
||||
@RestController
|
||||
@RequestMapping("/file/platform")
|
||||
@RequiredArgsConstructor
|
||||
public class FilePlatformController {
|
||||
private final FilePlatformService filePlatformService;
|
||||
|
||||
@IgnoreAuth
|
||||
@Operation(summary = "列表")
|
||||
@GetMapping("/findAll")
|
||||
public Result<List<FilePlatformResult>> findAll(){
|
||||
return Res.ok(filePlatformService.findAll());
|
||||
}
|
||||
|
||||
@Operation(summary = "详情")
|
||||
@GetMapping("/findById")
|
||||
public Result<FilePlatformResult> findById(Long id){
|
||||
return Res.ok(filePlatformService.findById(id));
|
||||
}
|
||||
|
||||
@RequestPath("更新文件存储平台地址")
|
||||
@Operation(summary = "更新文件存储平台地址")
|
||||
@PostMapping("/updateUrl")
|
||||
public Result<Void> update(@RequestBody FilePlatformParam filePlatform){
|
||||
ValidationUtil.validateParam(filePlatform);
|
||||
filePlatformService.updateUrl(filePlatform);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@RequestPath("设置默认存储平台地址")
|
||||
@Operation(summary = "设置默认存储平台地址")
|
||||
@PostMapping("/setDefault")
|
||||
public Result<Void> setDefault(@NotNull(message = "主键不可为空") Long id){
|
||||
filePlatformService.setDefault(id);
|
||||
return Res.ok();
|
||||
}
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
package cn.bootx.platform.starter.file.convert;
|
||||
|
||||
import cn.bootx.platform.starter.file.entity.UploadFileInfo;
|
||||
import cn.bootx.platform.starter.file.result.UploadFileResult;
|
||||
import org.dromara.x.file.storage.core.FileInfo;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* @author xxm
|
||||
* @since 2022/1/12
|
||||
*/
|
||||
@Mapper
|
||||
public interface FileConvert {
|
||||
|
||||
FileConvert CONVERT = Mappers.getMapper(FileConvert.class);
|
||||
|
||||
UploadFileResult convert(UploadFileInfo in);
|
||||
|
||||
UploadFileInfo convert(FileInfo in);
|
||||
|
||||
FileInfo toFileInfo(UploadFileInfo in);
|
||||
|
||||
UploadFileResult toDto(FileInfo in);
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
package cn.bootx.platform.starter.file.convert;
|
||||
|
||||
import cn.bootx.platform.starter.file.entity.FilePlatform;
|
||||
import cn.bootx.platform.starter.file.result.FilePlatformResult;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2024/8/12
|
||||
*/
|
||||
@Mapper
|
||||
public interface FilePlatformConvert {
|
||||
FilePlatformConvert CONVERT = Mappers.getMapper(FilePlatformConvert.class);
|
||||
|
||||
FilePlatformResult toResult(FilePlatform filePlatform);
|
||||
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
package cn.bootx.platform.starter.file.dao;
|
||||
|
||||
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
|
||||
import cn.bootx.platform.starter.file.entity.FilePlatform;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2024/8/12
|
||||
*/
|
||||
@Slf4j
|
||||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class FilePlatformManager extends BaseManager<FilePlatformMapper, FilePlatform> {
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
package cn.bootx.platform.starter.file.dao;
|
||||
|
||||
import cn.bootx.platform.starter.file.entity.FilePlatform;
|
||||
import com.github.yulichang.base.MPJBaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2024/8/12
|
||||
*/
|
||||
@Mapper
|
||||
public interface FilePlatformMapper extends MPJBaseMapper<FilePlatform> {
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
package cn.bootx.platform.starter.file.dao;
|
||||
|
||||
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.starter.file.entity.UploadFileInfo;
|
||||
import cn.bootx.platform.starter.file.param.UploadFileQuery;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author xxm
|
||||
* @since 2022/1/12
|
||||
*/
|
||||
@Slf4j
|
||||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class UploadFileManager extends BaseManager<UploadFileMapper, UploadFileInfo> {
|
||||
|
||||
|
||||
/**
|
||||
* 根据URL查询
|
||||
*/
|
||||
public Optional<UploadFileInfo> findByUrl(String url){
|
||||
return findByField(UploadFileInfo::getUrl, url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据URL删除
|
||||
*/
|
||||
public boolean deleteByUrl(String url){
|
||||
return deleteByField(UploadFileInfo::getUrl, url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页
|
||||
*/
|
||||
public Page<UploadFileInfo> page(PageParam pageParam, UploadFileQuery param) {
|
||||
Page<UploadFileInfo> mpPage = MpUtil.getMpPage(pageParam);
|
||||
return lambdaQuery()
|
||||
.like(StrUtil.isNotBlank(param.getOriginalFilename()), UploadFileInfo::getOriginalFilename, param.getOriginalFilename())
|
||||
.like(StrUtil.isNotBlank(param.getExt()), UploadFileInfo::getExt, param.getExt())
|
||||
.like(StrUtil.isNotBlank(param.getContentType()), UploadFileInfo::getContentType, param.getContentType())
|
||||
.ge(Objects.nonNull(param.getStartTime()), UploadFileInfo::getCreateTime, param.getStartTime())
|
||||
.le(Objects.nonNull(param.getEndTime()), UploadFileInfo::getCreateTime, param.getEndTime())
|
||||
.orderByDesc(UploadFileInfo::getId).page(mpPage);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
package cn.bootx.platform.starter.file.dao;
|
||||
|
||||
import cn.bootx.platform.starter.file.entity.UploadFileInfo;
|
||||
import com.github.yulichang.base.MPJBaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* @author xxm
|
||||
* @since 2022/1/12
|
||||
*/
|
||||
@Mapper
|
||||
public interface UploadFileMapper extends MPJBaseMapper<UploadFileInfo> {
|
||||
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
package cn.bootx.platform.starter.file.entity;
|
||||
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpRealDelEntity;
|
||||
import cn.bootx.platform.common.mybatisplus.function.ToResult;
|
||||
import cn.bootx.platform.starter.file.code.FilePlatformTypeEnum;
|
||||
import cn.bootx.platform.starter.file.convert.FilePlatformConvert;
|
||||
import cn.bootx.platform.starter.file.result.FilePlatformResult;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.annotation.FieldStrategy;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.experimental.FieldNameConstants;
|
||||
|
||||
/**
|
||||
* 文件存储平台
|
||||
* @author xxm
|
||||
* @since 2024/8/12
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@FieldNameConstants
|
||||
@Accessors(chain = true)
|
||||
@TableName("starter_file_platform")
|
||||
public class FilePlatform extends MpRealDelEntity implements ToResult<FilePlatformResult> {
|
||||
|
||||
/**
|
||||
* 接入类型
|
||||
* @see FilePlatformTypeEnum
|
||||
*/
|
||||
@TableField(updateStrategy = FieldStrategy.NEVER)
|
||||
private String type;
|
||||
|
||||
/** 名称 */
|
||||
@TableField(updateStrategy = FieldStrategy.NEVER)
|
||||
private String name;
|
||||
|
||||
/** 默认存储平台 */
|
||||
private boolean defaultPlatform;
|
||||
|
||||
/** 访问地址 */
|
||||
private String url;
|
||||
|
||||
public String getUrl() {
|
||||
return StrUtil.removeSuffix(url, "/");
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换
|
||||
*/
|
||||
@Override
|
||||
public FilePlatformResult toResult() {
|
||||
return FilePlatformConvert.CONVERT.toResult(this);
|
||||
}
|
||||
}
|
@@ -0,0 +1,127 @@
|
||||
package cn.bootx.platform.starter.file.entity;
|
||||
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpIdEntity;
|
||||
import cn.bootx.platform.common.mybatisplus.function.ToResult;
|
||||
import cn.bootx.platform.starter.file.convert.FileConvert;
|
||||
import cn.bootx.platform.starter.file.result.UploadFileResult;
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.dromara.x.file.storage.core.FileInfo;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 上传文件信息
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2022/1/12
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@TableName(value = "starter_file_upload_info", autoResultMap = true)
|
||||
public class UploadFileInfo extends MpIdEntity implements ToResult<UploadFileResult> {
|
||||
|
||||
/**
|
||||
* 文件访问地址
|
||||
*/
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 文件大小,单位字节
|
||||
*/
|
||||
private Long size;
|
||||
|
||||
/**
|
||||
* 文件名称
|
||||
*/
|
||||
private String filename;
|
||||
|
||||
/**
|
||||
* 原始文件名
|
||||
*/
|
||||
private String originalFilename;
|
||||
|
||||
/**
|
||||
* 基础存储路径
|
||||
*/
|
||||
private String basePath;
|
||||
|
||||
/**
|
||||
* 存储路径
|
||||
*/
|
||||
private String path;
|
||||
|
||||
/**
|
||||
* 文件扩展名
|
||||
*/
|
||||
private String ext;
|
||||
|
||||
/**
|
||||
* MIME 类型
|
||||
*/
|
||||
private String contentType;
|
||||
|
||||
/**
|
||||
* 存储平台
|
||||
*/
|
||||
private String platform;
|
||||
|
||||
/**
|
||||
* 缩略图访问路径
|
||||
*/
|
||||
private String thUrl;
|
||||
|
||||
/**
|
||||
* 缩略图名称
|
||||
*/
|
||||
private String thFilename;
|
||||
|
||||
/**
|
||||
* 缩略图大小,单位字节
|
||||
*/
|
||||
private Long thSize;
|
||||
|
||||
/**
|
||||
* 缩略图 MIME 类型
|
||||
*/
|
||||
private String thContentType;
|
||||
|
||||
/**
|
||||
* 文件所属对象id
|
||||
*/
|
||||
private String objectId;
|
||||
|
||||
/**
|
||||
* 文件所属对象类型,例如用户头像,评价图片
|
||||
*/
|
||||
private String objectType;
|
||||
|
||||
/** 创建时间 */
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Override
|
||||
public UploadFileResult toResult() {
|
||||
return FileConvert.CONVERT.convert(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化创建
|
||||
*/
|
||||
public static UploadFileInfo init(FileInfo fileInfo){
|
||||
return FileConvert.CONVERT.convert(fileInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为 x.file.storage 的文件信息对象
|
||||
*/
|
||||
public FileInfo toFileInfo(){
|
||||
return FileConvert.CONVERT.toFileInfo(this);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
package cn.bootx.platform.starter.file.handler;
|
||||
|
||||
import cn.bootx.platform.starter.file.dao.UploadFileManager;
|
||||
import cn.bootx.platform.starter.file.entity.UploadFileInfo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.x.file.storage.core.FileInfo;
|
||||
import org.dromara.x.file.storage.core.recorder.DefaultFileRecorder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* x.file.storage 文件上传信息储存
|
||||
* @author xxm
|
||||
* @since 2023/11/13
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class FileDetailRecordHandler extends DefaultFileRecorder {
|
||||
private final UploadFileManager uploadFileManager;
|
||||
|
||||
/**
|
||||
* 保存文件记录
|
||||
*/
|
||||
@Override
|
||||
public boolean save(FileInfo fileInfo) {
|
||||
UploadFileInfo uploadFileInfo = UploadFileInfo.init(fileInfo);
|
||||
uploadFileInfo.setCreateTime(LocalDateTime.now());
|
||||
uploadFileManager.save(uploadFileInfo);
|
||||
fileInfo.setId(String.valueOf(uploadFileInfo.getId()));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据URL获取文件记录
|
||||
*/
|
||||
@Override
|
||||
public FileInfo getByUrl(String url) {
|
||||
return uploadFileManager.findByUrl(url).map(UploadFileInfo::toFileInfo).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据URL删除
|
||||
*/
|
||||
@Override
|
||||
public boolean delete(String url) {
|
||||
return uploadFileManager.deleteByUrl(url);
|
||||
}
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
package cn.bootx.platform.starter.file.param;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 存储平台配置参数
|
||||
* @author xxm
|
||||
* @since 2024/8/12
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "存储平台配置参数")
|
||||
public class FilePlatformParam {
|
||||
|
||||
@NotNull(message = "主键不得为空")
|
||||
@Schema(description = "主键")
|
||||
private Long id;
|
||||
|
||||
@NotBlank(message = "平台地址不得为空")
|
||||
@Schema(description = "平台地址")
|
||||
private String url;
|
||||
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
package cn.bootx.platform.starter.file.param;
|
||||
|
||||
import cn.bootx.platform.common.mybatisplus.query.entity.SortParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 存储平台查询参数
|
||||
* @author xxm
|
||||
* @since 2024/8/12
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "存储平台查询参数")
|
||||
public class FilePlatformQuery extends SortParam {
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
package cn.bootx.platform.starter.file.param;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 上传文件查询参数
|
||||
* @author xxm
|
||||
* @since 2023/11/15
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "上传文件查询参数")
|
||||
public class UploadFileQuery {
|
||||
|
||||
/** 原始文件名 */
|
||||
@Schema(description = "原始文件名")
|
||||
private String originalFilename;
|
||||
|
||||
/** 开始时间 */
|
||||
@Schema(description = "开始时间")
|
||||
private LocalDateTime startTime;
|
||||
|
||||
/** 结束时间 */
|
||||
@Schema(description = "结束时间")
|
||||
private LocalDateTime endTime;
|
||||
|
||||
/** 文件扩展名 */
|
||||
@Schema(description = "文件扩展名")
|
||||
private String ext;
|
||||
|
||||
/** MIME 类型 */
|
||||
@Schema(description = "MIME 类型")
|
||||
private String contentType;
|
||||
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
package cn.bootx.platform.starter.file.result;
|
||||
|
||||
import cn.bootx.platform.core.result.BaseResult;
|
||||
import cn.bootx.platform.starter.file.code.FilePlatformTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 文件存储平台
|
||||
* @author xxm
|
||||
* @since 2024/8/12
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "文件存储平台")
|
||||
public class FilePlatformResult extends BaseResult {
|
||||
|
||||
/**
|
||||
* 平台类型
|
||||
* @see FilePlatformTypeEnum
|
||||
*/
|
||||
@Schema(description = "平台类型")
|
||||
private String type;
|
||||
|
||||
/** 名称 */
|
||||
@Schema(description = "名称")
|
||||
private String name;
|
||||
|
||||
/** 默认存储平台 */
|
||||
@Schema(description = "默认存储平台")
|
||||
private Boolean defaultPlatform;
|
||||
|
||||
/** 访问地址 */
|
||||
@Schema(description = "访问地址")
|
||||
private String url;
|
||||
}
|
@@ -0,0 +1,182 @@
|
||||
package cn.bootx.platform.starter.file.result;
|
||||
|
||||
import cn.bootx.platform.core.result.BaseResult;
|
||||
import cn.bootx.platform.starter.file.entity.FilePlatform;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import com.fhs.core.trans.anno.Trans;
|
||||
import com.fhs.core.trans.constant.TransType;
|
||||
import com.fhs.core.trans.vo.TransPojo;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.experimental.FieldNameConstants;
|
||||
import org.dromara.x.file.storage.core.FileInfo;
|
||||
import org.dromara.x.file.storage.core.constant.Constant;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 上传文件信息
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2022/1/12
|
||||
*/
|
||||
@FieldNameConstants
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "上传文件信息")
|
||||
public class UploadFileResult extends BaseResult implements TransPojo {
|
||||
|
||||
/**
|
||||
* 文件访问地址
|
||||
*/
|
||||
@Schema(description = "访问地址")
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 文件大小,单位字节
|
||||
*/
|
||||
@Schema(description = "文件大小")
|
||||
private Long size;
|
||||
|
||||
/**
|
||||
* 文件名称
|
||||
*/
|
||||
@Schema(description = "文件名称")
|
||||
private String filename;
|
||||
|
||||
/**
|
||||
* 原始文件名
|
||||
*/
|
||||
@Schema(description = "原始文件名")
|
||||
private String originalFilename;
|
||||
|
||||
/**
|
||||
* 基础存储路径
|
||||
*/
|
||||
@Schema(description = "基础存储路径")
|
||||
private String basePath;
|
||||
|
||||
/**
|
||||
* 存储路径
|
||||
*/
|
||||
@Schema(description = "存储路径")
|
||||
private String path;
|
||||
|
||||
/**
|
||||
* 文件扩展名
|
||||
*/
|
||||
@Schema(description = "扩展名")
|
||||
private String ext;
|
||||
|
||||
/**
|
||||
* MIME 类型
|
||||
*/
|
||||
@Schema(description = "MIME 类型")
|
||||
private String contentType;
|
||||
|
||||
/**
|
||||
* 存储平台
|
||||
*/
|
||||
@Trans(type = TransType.SIMPLE, target = FilePlatform.class, fields = FilePlatform.Fields.name, ref = Fields.platformName, uniqueField=FilePlatform.Fields.type)
|
||||
@Schema(description = "存储平台")
|
||||
private String platform;
|
||||
|
||||
/**
|
||||
* 存储平台
|
||||
*/
|
||||
private String platformName;
|
||||
|
||||
/**
|
||||
* 缩略图访问路径
|
||||
*/
|
||||
private String thUrl;
|
||||
|
||||
/**
|
||||
* 缩略图名称
|
||||
*/
|
||||
private String thFilename;
|
||||
|
||||
/**
|
||||
* 缩略图大小,单位字节
|
||||
*/
|
||||
private Long thSize;
|
||||
|
||||
/**
|
||||
* 缩略图 MIME 类型
|
||||
*/
|
||||
private String thContentType;
|
||||
|
||||
/**
|
||||
* 文件所属对象id
|
||||
*/
|
||||
private String objectId;
|
||||
|
||||
/**
|
||||
* 文件所属对象类型,例如用户头像,评价图片
|
||||
*/
|
||||
private String objectType;
|
||||
|
||||
/**
|
||||
* 文件元数据
|
||||
*/
|
||||
private Map<String, String> metadata;
|
||||
|
||||
/**
|
||||
* 文件用户元数据
|
||||
*/
|
||||
private Map<String, String> userMetadata;
|
||||
|
||||
/**
|
||||
* 缩略图元数据
|
||||
*/
|
||||
private Map<String, String> thMetadata;
|
||||
|
||||
/**
|
||||
* 缩略图用户元数据
|
||||
*/
|
||||
private Map<String, String> thUserMetadata;
|
||||
|
||||
/**
|
||||
* 附加属性字典
|
||||
*/
|
||||
private Dict attr;
|
||||
|
||||
/**
|
||||
* 文件的访问控制列表,一般情况下只有对象存储支持该功能,支持 String 或对应存储平台的 ACL 对象
|
||||
* <pre class="code">
|
||||
* //方式一,通过字符串设置通用的 ACL 详情:{@link Constant.ACL }
|
||||
* setFileAcl(ACL.PUBLIC_READ);
|
||||
* //方式二,针对指定存储平台设置更复杂的权限控制,以华为云 OBS 为例
|
||||
* AccessControlList acl = new AccessControlList();
|
||||
* Owner owner = new Owner();
|
||||
* owner.setId("ownerid");
|
||||
* acl.setOwner(owner);
|
||||
* // 保留Owner的完全控制权限(注:如果不设置该权限,该对象Owner自身将没有访问权限)
|
||||
* acl.grantPermission(new CanonicalGrantee("ownerid"), Permission.PERMISSION_FULL_CONTROL);
|
||||
* // 为指定用户设置完全控制权限
|
||||
* acl.grantPermission(new CanonicalGrantee("userid"), Permission.PERMISSION_FULL_CONTROL);
|
||||
* // 为所有用户设置读权限
|
||||
* acl.grantPermission(GroupGrantee.ALL_USERS, Permission.PERMISSION_READ);
|
||||
* setFileAcl(acl);
|
||||
* <pre/>
|
||||
*/
|
||||
private Object fileAcl;
|
||||
|
||||
/**
|
||||
* 缩略图的访问控制列表,一般情况下只有对象存储支持该功能
|
||||
* 详情见{@link FileInfo#setFileAcl}
|
||||
*/
|
||||
private Object thFileAcl;
|
||||
|
||||
/**
|
||||
* 文件大小
|
||||
*/
|
||||
public String getFileSize() {
|
||||
return FileUtil.readableFileSize(size);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,73 @@
|
||||
package cn.bootx.platform.starter.file.service;
|
||||
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpRealDelEntity;
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.core.exception.DataNotExistException;
|
||||
import cn.bootx.platform.starter.auth.util.SecurityUtil;
|
||||
import cn.bootx.platform.starter.file.dao.FilePlatformManager;
|
||||
import cn.bootx.platform.starter.file.entity.FilePlatform;
|
||||
import cn.bootx.platform.starter.file.param.FilePlatformParam;
|
||||
import cn.bootx.platform.starter.file.result.FilePlatformResult;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 存储平台
|
||||
* @author xxm
|
||||
* @since 2024/8/12
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class FilePlatformService {
|
||||
private final FilePlatformManager filePlatformManager;
|
||||
|
||||
|
||||
/**
|
||||
* 获取全部存储平台
|
||||
*/
|
||||
public List<FilePlatformResult> findAll(){
|
||||
return MpUtil.toListResult(filePlatformManager.findAll());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取存储平台
|
||||
*/
|
||||
public FilePlatformResult findById(Long id){
|
||||
return filePlatformManager.findById(id).map(FilePlatform::toResult).orElseThrow(() -> new DataNotExistException("存储平台不存在"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新
|
||||
*/
|
||||
public void updateUrl(FilePlatformParam filePlatform){
|
||||
FilePlatform platform = filePlatformManager.findById(filePlatform.getId())
|
||||
.orElseThrow(() -> new DataNotExistException("存储平台不存在"));
|
||||
platform.setUrl(filePlatform.getUrl());
|
||||
filePlatformManager.updateById(platform);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设为默认
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void setDefault(Long id){
|
||||
filePlatformManager.lambdaUpdate()
|
||||
.set(FilePlatform::isDefaultPlatform, false)
|
||||
.eq(FilePlatform::isDefaultPlatform, true)
|
||||
.set(FilePlatform::getLastModifiedTime, LocalDateTime.now())
|
||||
.set(MpRealDelEntity::getLastModifier, SecurityUtil.getUserIdOrDefaultId())
|
||||
.update();
|
||||
filePlatformManager.lambdaUpdate()
|
||||
.eq(FilePlatform::getId, id)
|
||||
.set(FilePlatform::getLastModifiedTime, LocalDateTime.now())
|
||||
.set(MpRealDelEntity::getLastModifier, SecurityUtil.getUserIdOrDefaultId())
|
||||
.set(FilePlatform::isDefaultPlatform, true)
|
||||
.update();
|
||||
}
|
||||
}
|
@@ -0,0 +1,153 @@
|
||||
package cn.bootx.platform.starter.file.service;
|
||||
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.core.exception.DataNotExistException;
|
||||
import cn.bootx.platform.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.core.rest.result.PageResult;
|
||||
import cn.bootx.platform.starter.file.configuration.FileUploadProperties;
|
||||
import cn.bootx.platform.starter.file.convert.FileConvert;
|
||||
import cn.bootx.platform.starter.file.dao.UploadFileManager;
|
||||
import cn.bootx.platform.starter.file.entity.UploadFileInfo;
|
||||
import cn.bootx.platform.starter.file.param.UploadFileQuery;
|
||||
import cn.bootx.platform.starter.file.result.UploadFileResult;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import jakarta.servlet.ServletOutputStream;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.x.file.storage.core.FileInfo;
|
||||
import org.dromara.x.file.storage.core.FileStorageService;
|
||||
import org.dromara.x.file.storage.core.upload.UploadPretreatment;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 文件上传管理类
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2022/1/14
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class FileUploadService {
|
||||
private final UploadFileManager uploadFileManager;
|
||||
private final FileStorageService fileStorageService;
|
||||
private final FileUploadProperties fileUploadProperties;
|
||||
|
||||
/**
|
||||
* 分页
|
||||
*/
|
||||
public PageResult<UploadFileResult> page(PageParam pageParam, UploadFileQuery param) {
|
||||
return MpUtil.toPageResult(uploadFileManager.page(pageParam,param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单条详情
|
||||
*/
|
||||
public UploadFileResult findById(Long id){
|
||||
return uploadFileManager.findById(id)
|
||||
.map(UploadFileInfo::toResult)
|
||||
.orElseThrow(DataNotExistException::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据URL获取单条详情
|
||||
*/
|
||||
public UploadFileResult findById(String url){
|
||||
return uploadFileManager.findByUrl(url)
|
||||
.map(UploadFileInfo::toResult)
|
||||
.orElseThrow(DataNotExistException::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件删除
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(Long id){
|
||||
UploadFileInfo uploadFileInfo = uploadFileManager.findById(id)
|
||||
.orElseThrow(DataNotExistException::new);
|
||||
fileStorageService.delete(FileConvert.CONVERT.toFileInfo(uploadFileInfo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
* @param file 文件
|
||||
* @param fileName 文件名称
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public UploadFileResult upload(MultipartFile file, String fileName) {
|
||||
UploadPretreatment uploadPretreatment = fileStorageService.of(file);
|
||||
if (StrUtil.isNotBlank(fileName)){
|
||||
uploadPretreatment.setOriginalFilename(fileName);
|
||||
}
|
||||
// 按年月日进行分目录
|
||||
uploadPretreatment.setPath(LocalDateTimeUtil.format(LocalDateTime.now(), "yyyy/MM/dd/"));
|
||||
|
||||
FileInfo upload = uploadPretreatment.upload();
|
||||
return FileConvert.CONVERT.toDto(upload);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件预览
|
||||
*/
|
||||
@SneakyThrows
|
||||
public void preview(Long id, HttpServletResponse response) {
|
||||
FileInfo info = fileStorageService.getFileInfoByUrl(String.valueOf(id));
|
||||
if (info == null){
|
||||
log.warn("文件不存在");
|
||||
return;
|
||||
}
|
||||
byte[] bytes = fileStorageService.download(info).bytes();
|
||||
var is = new ByteArrayInputStream(bytes);
|
||||
// 获取响应输出流
|
||||
ServletOutputStream os = response.getOutputStream();
|
||||
IoUtil.copy(is, os);
|
||||
response.addHeader(HttpHeaders.CONTENT_DISPOSITION, info.getContentType());
|
||||
IoUtil.close(is);
|
||||
IoUtil.close(os);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件下载
|
||||
*/
|
||||
@SneakyThrows
|
||||
public ResponseEntity<byte[]> download(Long id) {
|
||||
FileInfo fileInfo = fileStorageService.getFileInfoByUrl(String.valueOf(id));
|
||||
byte[] bytes = fileStorageService.download(fileInfo).bytes();
|
||||
// 设置header信息
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
|
||||
String fileName = fileInfo.getOriginalFilename();
|
||||
headers.setContentDispositionFormData("attachment", URLEncoder.encode(fileName, StandardCharsets.UTF_8));
|
||||
return new ResponseEntity<>(bytes,headers,HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件访问转发地址(当前后端服务地址或被代理后的地址), 流量会经过后端服务的转发
|
||||
*/
|
||||
public String getServerFilePreviewUrlPrefix() {
|
||||
return this.getForwardServerUrl() + "/file/preview/";
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件访问转发地址(当前后端服务地址或被代理后的地址), 流量会经过后端服务的转发
|
||||
*/
|
||||
private String getForwardServerUrl() {
|
||||
return fileUploadProperties.getForwardServerUrl();
|
||||
}
|
||||
}
|
@@ -0,0 +1 @@
|
||||
cn.bootx.platform.starter.file.FileAutoConfiguration
|
Reference in New Issue
Block a user