Commit 87670d18fdf8c96f5a61861b41381d8adf9cecc7

Authored by YunaiV
1 parent cdcecd0d

完成新 File 的功能

Showing 25 changed files with 258 additions and 186 deletions
yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/client/AbstractFileClient.java
1 package cn.iocoder.yudao.framework.file.core.client; 1 package cn.iocoder.yudao.framework.file.core.client;
2 2
3 import cn.hutool.core.util.StrUtil; 3 import cn.hutool.core.util.StrUtil;
4 -import cn.iocoder.yudao.framework.file.core.client.FileClient;  
5 -import cn.iocoder.yudao.framework.file.core.client.FileClientConfig;  
6 import lombok.extern.slf4j.Slf4j; 4 import lombok.extern.slf4j.Slf4j;
7 5
8 /** 6 /**
@@ -65,7 +63,7 @@ public abstract class AbstractFileClient<Config extends FileClientConfig> implem @@ -65,7 +63,7 @@ public abstract class AbstractFileClient<Config extends FileClientConfig> implem
65 * @return URL 访问地址 63 * @return URL 访问地址
66 */ 64 */
67 protected String formatFileUrl(String domain, String path) { 65 protected String formatFileUrl(String domain, String path) {
68 - return StrUtil.format("{}/system-api/{}/get/{}", domain, getId(), path); 66 + return StrUtil.format("{}/admin-api/infra/file/{}/get/{}", domain, getId(), path);
69 } 67 }
70 68
71 } 69 }
yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/client/db/DBFileClient.java
@@ -18,24 +18,31 @@ public class DBFileClient extends AbstractFileClient<DBFileClientConfig> { @@ -18,24 +18,31 @@ public class DBFileClient extends AbstractFileClient<DBFileClientConfig> {
18 18
19 @Override 19 @Override
20 protected void doInit() { 20 protected void doInit() {
21 - dao = SpringUtil.getBean(DBFileContentFrameworkDAO.class);  
22 } 21 }
23 22
24 @Override 23 @Override
25 public String upload(byte[] content, String path) { 24 public String upload(byte[] content, String path) {
26 - dao.insert(getId(), path, content); 25 + getDao().insert(getId(), path, content);
27 // 拼接返回路径 26 // 拼接返回路径
28 return super.formatFileUrl(config.getDomain(), path); 27 return super.formatFileUrl(config.getDomain(), path);
29 } 28 }
30 29
31 @Override 30 @Override
32 public void delete(String path) { 31 public void delete(String path) {
33 - dao.delete(getId(), path); 32 + getDao().delete(getId(), path);
34 } 33 }
35 34
36 @Override 35 @Override
37 public byte[] getContent(String path) { 36 public byte[] getContent(String path) {
38 - return dao.selectContent(getId(), path); 37 + return getDao().selectContent(getId(), path);
  38 + }
  39 +
  40 + private DBFileContentFrameworkDAO getDao() {
  41 + // 延迟获取,因为 SpringUtil 初始化太慢
  42 + if (dao == null) {
  43 + dao = SpringUtil.getBean(DBFileContentFrameworkDAO.class);
  44 + }
  45 + return dao;
39 } 46 }
40 47
41 } 48 }
yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/client/db/DBFileContentFrameworkDAO.java
@@ -7,10 +7,30 @@ package cn.iocoder.yudao.framework.file.core.client.db; @@ -7,10 +7,30 @@ package cn.iocoder.yudao.framework.file.core.client.db;
7 */ 7 */
8 public interface DBFileContentFrameworkDAO { 8 public interface DBFileContentFrameworkDAO {
9 9
  10 + /**
  11 + * 插入文件内容
  12 + *
  13 + * @param configId 配置编号
  14 + * @param path 路径
  15 + * @param content 内容
  16 + */
10 void insert(Long configId, String path, byte[] content); 17 void insert(Long configId, String path, byte[] content);
11 18
  19 + /**
  20 + * 删除文件内容
  21 + *
  22 + * @param configId 配置编号
  23 + * @param path 路径
  24 + */
12 void delete(Long configId, String path); 25 void delete(Long configId, String path);
13 26
  27 + /**
  28 + * 获得文件内容
  29 + *
  30 + * @param configId 配置编号
  31 + * @param path 路径
  32 + * @return 内容
  33 + */
14 byte[] selectContent(Long configId, String path); 34 byte[] selectContent(Long configId, String path);
15 35
16 } 36 }
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java
@@ -4,8 +4,8 @@ import cn.hutool.core.io.IoUtil; @@ -4,8 +4,8 @@ import cn.hutool.core.io.IoUtil;
4 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; 6 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
7 -import cn.iocoder.yudao.module.infra.controller.admin.file.vo.FilePageReqVO;  
8 -import cn.iocoder.yudao.module.infra.controller.admin.file.vo.FileRespVO; 7 +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO;
  8 +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FileRespVO;
9 import cn.iocoder.yudao.module.infra.convert.file.FileConvert; 9 import cn.iocoder.yudao.module.infra.convert.file.FileConvert;
10 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO; 10 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO;
11 import cn.iocoder.yudao.module.infra.service.file.FileService; 11 import cn.iocoder.yudao.module.infra.service.file.FileService;
@@ -50,9 +50,9 @@ public class FileController { @@ -50,9 +50,9 @@ public class FileController {
50 50
51 @DeleteMapping("/delete") 51 @DeleteMapping("/delete")
52 @ApiOperation("删除文件") 52 @ApiOperation("删除文件")
53 - @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = String.class) 53 + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
54 @PreAuthorize("@ss.hasPermission('infra:file:delete')") 54 @PreAuthorize("@ss.hasPermission('infra:file:delete')")
55 - public CommonResult<Boolean> deleteFile(@RequestParam("id") String id) { 55 + public CommonResult<Boolean> deleteFile(@RequestParam("id") Long id) {
56 fileService.deleteFile(id); 56 fileService.deleteFile(id);
57 return success(true); 57 return success(true);
58 } 58 }
@@ -60,19 +60,19 @@ public class FileController { @@ -60,19 +60,19 @@ public class FileController {
60 @GetMapping("/{configId}/get/{path}") 60 @GetMapping("/{configId}/get/{path}")
61 @ApiOperation("下载文件") 61 @ApiOperation("下载文件")
62 @ApiImplicitParams({ 62 @ApiImplicitParams({
63 - @ApiImplicitParam(name = "configId", value = "配置编号", required = true, dataTypeClass = String.class), 63 + @ApiImplicitParam(name = "configId", value = "配置编号", required = true, dataTypeClass = Long.class),
64 @ApiImplicitParam(name = "path", value = "文件路径", required = true, dataTypeClass = String.class) 64 @ApiImplicitParam(name = "path", value = "文件路径", required = true, dataTypeClass = String.class)
65 }) 65 })
66 - public void getFile(HttpServletResponse response,  
67 - @PathVariable("configId") String configId,  
68 - @PathVariable("path") String path) throws IOException {  
69 - FileDO file = fileService.getFile(path);  
70 - if (file == null) {  
71 - log.warn("[getFile][path({}) 文件不存在]", path); 66 + public void getFileContent(HttpServletResponse response,
  67 + @PathVariable("configId") Long configId,
  68 + @PathVariable("path") String path) throws IOException {
  69 + byte[] content = fileService.getFileContent(configId, path);
  70 + if (content == null) {
  71 + log.warn("[getFileContent][configId({}) path({}) 文件不存在]", configId, path);
72 response.setStatus(HttpStatus.NOT_FOUND.value()); 72 response.setStatus(HttpStatus.NOT_FOUND.value());
73 return; 73 return;
74 } 74 }
75 - ServletUtils.writeAttachment(response, path, file.getContent()); 75 + ServletUtils.writeAttachment(response, path, content);
76 } 76 }
77 77
78 @GetMapping("/page") 78 @GetMapping("/page")
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/FilePageReqVO.java renamed to yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FilePageReqVO.java
1 -package cn.iocoder.yudao.module.infra.controller.admin.file.vo; 1 +package cn.iocoder.yudao.module.infra.controller.admin.file.vo.file;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageParam; 3 import cn.iocoder.yudao.framework.common.pojo.PageParam;
4 import io.swagger.annotations.ApiModel; 4 import io.swagger.annotations.ApiModel;
@@ -19,7 +19,7 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @@ -19,7 +19,7 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
19 public class FilePageReqVO extends PageParam { 19 public class FilePageReqVO extends PageParam {
20 20
21 @ApiModelProperty(value = "文件路径", example = "yudao", notes = "模糊匹配") 21 @ApiModelProperty(value = "文件路径", example = "yudao", notes = "模糊匹配")
22 - private String id; 22 + private String path;
23 23
24 @ApiModelProperty(value = "文件类型", example = "jpg", notes = "模糊匹配") 24 @ApiModelProperty(value = "文件类型", example = "jpg", notes = "模糊匹配")
25 private String type; 25 private String type;
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/FileRespVO.java renamed to yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileRespVO.java
1 -package cn.iocoder.yudao.module.infra.controller.admin.file.vo; 1 +package cn.iocoder.yudao.module.infra.controller.admin.file.vo.file;
2 2
3 import io.swagger.annotations.ApiModel; 3 import io.swagger.annotations.ApiModel;
4 import io.swagger.annotations.ApiModelProperty; 4 import io.swagger.annotations.ApiModelProperty;
@@ -10,12 +10,21 @@ import java.util.Date; @@ -10,12 +10,21 @@ import java.util.Date;
10 @Data 10 @Data
11 public class FileRespVO { 11 public class FileRespVO {
12 12
  13 + @ApiModelProperty(value = "文件编号", required = true, example = "1024")
  14 + private Long id;
  15 +
13 @ApiModelProperty(value = "文件路径", required = true, example = "yudao.jpg") 16 @ApiModelProperty(value = "文件路径", required = true, example = "yudao.jpg")
14 - private String id; 17 + private String path;
  18 +
  19 + @ApiModelProperty(value = "文件 URL", required = true, example = "https://www.iocoder.cn/yudao.jpg")
  20 + private String url;
15 21
16 - @ApiModelProperty(value = "文件类型", required = true, example = "jpg") 22 + @ApiModelProperty(value = "文件类型", example = "jpg")
17 private String type; 23 private String type;
18 24
  25 + @ApiModelProperty(value = "文件大小", example = "2048", required = true)
  26 + private Integer size;
  27 +
19 @ApiModelProperty(value = "创建时间", required = true) 28 @ApiModelProperty(value = "创建时间", required = true)
20 private Date createTime; 29 private Date createTime;
21 30
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/convert/file/FileConvert.java
1 package cn.iocoder.yudao.module.infra.convert.file; 1 package cn.iocoder.yudao.module.infra.convert.file;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 -import cn.iocoder.yudao.module.infra.controller.admin.file.vo.FileRespVO; 4 +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FileRespVO;
5 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO; 5 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO;
6 import org.mapstruct.Mapper; 6 import org.mapstruct.Mapper;
7 import org.mapstruct.factory.Mappers; 7 import org.mapstruct.factory.Mappers;
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileDO.java
1 package cn.iocoder.yudao.module.infra.dal.dataobject.file; 1 package cn.iocoder.yudao.module.infra.dal.dataobject.file;
2 2
3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 -import com.baomidou.mybatisplus.annotation.IdType;  
5 import com.baomidou.mybatisplus.annotation.TableField; 4 import com.baomidou.mybatisplus.annotation.TableField;
6 -import com.baomidou.mybatisplus.annotation.TableId;  
7 import com.baomidou.mybatisplus.annotation.TableName; 5 import com.baomidou.mybatisplus.annotation.TableName;
8 import lombok.*; 6 import lombok.*;
9 7
@@ -27,8 +25,7 @@ public class FileDO extends BaseDO { @@ -27,8 +25,7 @@ public class FileDO extends BaseDO {
27 /** 25 /**
28 * 编号,数据库自增 26 * 编号,数据库自增
29 */ 27 */
30 - @TableId(type = IdType.INPUT)  
31 - private String id; 28 + private Long id;
32 /** 29 /**
33 * 配置编号 30 * 配置编号
34 * 31 *
@@ -40,6 +37,10 @@ public class FileDO extends BaseDO { @@ -40,6 +37,10 @@ public class FileDO extends BaseDO {
40 */ 37 */
41 private String path; 38 private String path;
42 /** 39 /**
  40 + * 访问地址
  41 + */
  42 + private String url;
  43 + /**
43 * 文件类型 44 * 文件类型
44 * 45 *
45 * 通过 {@link cn.hutool.core.io.FileTypeUtil#getType(InputStream)} 获取 46 * 通过 {@link cn.hutool.core.io.FileTypeUtil#getType(InputStream)} 获取
@@ -47,17 +48,8 @@ public class FileDO extends BaseDO { @@ -47,17 +48,8 @@ public class FileDO extends BaseDO {
47 @TableField(value = "`type`") 48 @TableField(value = "`type`")
48 private String type; 49 private String type;
49 /** 50 /**
50 - * 访问地址  
51 - */  
52 - private String url;  
53 - /**  
54 * 文件大小 51 * 文件大小
55 */ 52 */
56 private Integer size; 53 private Integer size;
57 - /**  
58 - * 文件内容  
59 - */  
60 - @Deprecated  
61 - private byte[] content;  
62 54
63 } 55 }
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileContentDAOImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.mysql.file;
  2 +
  3 +import cn.iocoder.yudao.framework.file.core.client.db.DBFileContentFrameworkDAO;
  4 +import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileContentDO;
  5 +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  6 +import org.springframework.stereotype.Repository;
  7 +
  8 +import javax.annotation.Resource;
  9 +
  10 +@Repository
  11 +public class FileContentDAOImpl implements DBFileContentFrameworkDAO {
  12 +
  13 + @Resource
  14 + private FileContentMapper fileContentMapper;
  15 +
  16 + @Override
  17 + public void insert(Long configId, String path, byte[] content) {
  18 + FileContentDO entity = new FileContentDO().setConfigId(configId)
  19 + .setPath(path).setContent(content);
  20 + fileContentMapper.insert(entity);
  21 + }
  22 +
  23 + @Override
  24 + public void delete(Long configId, String path) {
  25 + fileContentMapper.delete(buildQuery(configId, path));
  26 + }
  27 +
  28 + @Override
  29 + public byte[] selectContent(Long configId, String path) {
  30 + FileContentDO fileContentDO = fileContentMapper.selectOne(
  31 + buildQuery(configId, path).select(FileContentDO::getContent));
  32 + return fileContentDO != null ? fileContentDO.getContent() : null;
  33 + }
  34 +
  35 + private LambdaQueryWrapper<FileContentDO> buildQuery(Long configId, String path) {
  36 + return new LambdaQueryWrapper<FileContentDO>()
  37 + .eq(FileContentDO::getConfigId, configId)
  38 + .eq(FileContentDO::getPath, path);
  39 + }
  40 +
  41 +}
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileContentMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.mysql.file;
  2 +
  3 +import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileContentDO;
  4 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +
  7 +@Mapper
  8 +public interface FileContentMapper extends BaseMapper<FileContentDO> {
  9 +}
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileMapper.java
@@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.infra.dal.mysql.file; @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.infra.dal.mysql.file;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; 5 import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
6 -import cn.iocoder.yudao.module.infra.controller.admin.file.vo.FilePageReqVO; 6 +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO;
7 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO; 7 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO;
8 import org.apache.ibatis.annotations.Mapper; 8 import org.apache.ibatis.annotations.Mapper;
9 9
@@ -17,25 +17,10 @@ public interface FileMapper extends BaseMapperX&lt;FileDO&gt; { @@ -17,25 +17,10 @@ public interface FileMapper extends BaseMapperX&lt;FileDO&gt; {
17 17
18 default PageResult<FileDO> selectPage(FilePageReqVO reqVO) { 18 default PageResult<FileDO> selectPage(FilePageReqVO reqVO) {
19 return selectPage(reqVO, new QueryWrapperX<FileDO>() 19 return selectPage(reqVO, new QueryWrapperX<FileDO>()
20 - .likeIfPresent("id", reqVO.getId()) 20 + .likeIfPresent("path", reqVO.getPath())
21 .likeIfPresent("type", reqVO.getType()) 21 .likeIfPresent("type", reqVO.getType())
22 .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) 22 .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
23 .orderByDesc("create_time")); 23 .orderByDesc("create_time"));
24 } 24 }
25 25
26 - default Long selectCountById(String id) {  
27 - return selectCount(FileDO::getId, id);  
28 - }  
29 -  
30 - /**  
31 - * 基于 Path 获取文件  
32 - * 实际上,是基于 ID 查询  
33 - *  
34 - * @param path 路径  
35 - * @return 文件  
36 - */  
37 - default FileDO selectByPath(String path) {  
38 - return selectById(path);  
39 - }  
40 -  
41 } 26 }
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/framework/file/config/FileConfiguration.java deleted
1 -package cn.iocoder.yudao.module.infra.framework.file.config;  
2 -  
3 -import org.springframework.boot.context.properties.EnableConfigurationProperties;  
4 -import org.springframework.context.annotation.Configuration;  
5 -  
6 -/**  
7 - * 文件 配置类  
8 - */  
9 -@Configuration  
10 -@EnableConfigurationProperties(FileProperties.class)  
11 -public class FileConfiguration {  
12 -}  
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/framework/file/config/FileProperties.java deleted
1 -package cn.iocoder.yudao.module.infra.framework.file.config;  
2 -  
3 -import lombok.Data;  
4 -import org.springframework.boot.context.properties.ConfigurationProperties;  
5 -import org.springframework.validation.annotation.Validated;  
6 -  
7 -import javax.validation.constraints.NotNull;  
8 -  
9 -@ConfigurationProperties(prefix = "yudao.file")  
10 -@Validated  
11 -@Data  
12 -public class FileProperties {  
13 -  
14 - /**  
15 - * 对应 FileController 的 getFile 方法  
16 - */  
17 - @NotNull(message = "基础文件路径不能为空")  
18 - private String basePath;  
19 -  
20 - // TODO 七牛、等等  
21 -  
22 -}  
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/framework/file/package-info.java deleted
1 -/**  
2 - * 文件的存储,推荐使用七牛、阿里云、华为云、腾讯云等文件服务  
3 - *  
4 - * 在不采用云服务的情况下,我们有几种技术选型:  
5 - * 方案 1. 使用自建的文件服务,例如说 minIO、FastDFS 等等  
6 - * 方案 2. 使用服务器的文件系统存储  
7 - * 方案 3. 使用数据库进行存储  
8 - *  
9 - * 如果考虑额外在搭建服务,推荐方案 1。  
10 - * 对于方案 2 来说,如果要实现文件存储的高可用,需要多台服务器之间做实时同步,可以基于 rsync + inotify 来做  
11 - * 对于方案 3 的话,实现起来最简单,但是数据库本身不适合存储海量的文件  
12 - *  
13 - * 综合考虑,暂时使用方案 3 的方式,比较适合这样一个 all in one 的项目。  
14 - * 随着文件的量级大了之后,还是推荐采用云服务。  
15 - */  
16 -package cn.iocoder.yudao.module.infra.framework.file;  
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/framework/security/config/SecurityConfiguration.java
@@ -36,7 +36,7 @@ public class SecurityConfiguration { @@ -36,7 +36,7 @@ public class SecurityConfiguration {
36 registry.antMatchers(adminSeverContextPath).anonymous() 36 registry.antMatchers(adminSeverContextPath).anonymous()
37 .antMatchers(adminSeverContextPath + "/**").anonymous(); 37 .antMatchers(adminSeverContextPath + "/**").anonymous();
38 // 文件的获取接口,可匿名访问 38 // 文件的获取接口,可匿名访问
39 - registry.antMatchers(buildAdminApi("/infra/file/get/**"), buildAppApi("/infra/file/get/**")).anonymous(); 39 + registry.antMatchers(buildAdminApi("/infra/file/*/get/**"), buildAppApi("/infra/file/get/**")).permitAll();
40 } 40 }
41 41
42 }; 42 };
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigService.java
1 package cn.iocoder.yudao.module.infra.service.file; 1 package cn.iocoder.yudao.module.infra.service.file;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.file.core.client.FileClient;
4 import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigCreateReqVO; 5 import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigCreateReqVO;
5 import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO; 6 import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO;
6 import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigUpdateReqVO; 7 import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigUpdateReqVO;
@@ -83,4 +84,19 @@ public interface FileConfigService { @@ -83,4 +84,19 @@ public interface FileConfigService {
83 */ 84 */
84 String testFileConfig(Long id); 85 String testFileConfig(Long id);
85 86
  87 + /**
  88 + * 获得指定编号的文件客户端
  89 + *
  90 + * @param id 配置编号
  91 + * @return 文件客户端
  92 + */
  93 + FileClient getFileClient(Long id);
  94 +
  95 + /**
  96 + * 获得 Master 文件客户端
  97 + *
  98 + * @return 文件客户端
  99 + */
  100 + FileClient getMasterFileClient();
  101 +
86 } 102 }
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java
@@ -233,4 +233,9 @@ public class FileConfigServiceImpl implements FileConfigService { @@ -233,4 +233,9 @@ public class FileConfigServiceImpl implements FileConfigService {
233 return fileClientFactory.getFileClient(id).upload(content, IdUtil.fastSimpleUUID() + ".jpg"); 233 return fileClientFactory.getFileClient(id).upload(content, IdUtil.fastSimpleUUID() + ".jpg");
234 } 234 }
235 235
  236 + @Override
  237 + public FileClient getFileClient(Long id) {
  238 + return fileClientFactory.getFileClient(id);
  239 + }
  240 +
236 } 241 }
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java
1 package cn.iocoder.yudao.module.infra.service.file; 1 package cn.iocoder.yudao.module.infra.service.file;
2 2
3 -import cn.iocoder.yudao.module.infra.controller.admin.file.vo.FilePageReqVO; 3 +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO; 5 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO;
6 6
@@ -33,14 +33,15 @@ public interface FileService { @@ -33,14 +33,15 @@ public interface FileService {
33 * 33 *
34 * @param id 编号 34 * @param id 编号
35 */ 35 */
36 - void deleteFile(String id); 36 + void deleteFile(Long id);
37 37
38 /** 38 /**
39 - * 获得文件 39 + * 获得文件内容
40 * 40 *
  41 + * @param configId 配置编号
41 * @param path 文件路径 42 * @param path 文件路径
42 - * @return 文件 43 + * @return 文件内容
43 */ 44 */
44 - FileDO getFile(String path); 45 + byte[] getFileContent(Long configId, String path);
45 46
46 } 47 }
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java
1 package cn.iocoder.yudao.module.infra.service.file; 1 package cn.iocoder.yudao.module.infra.service.file;
2 2
3 import cn.hutool.core.io.FileTypeUtil; 3 import cn.hutool.core.io.FileTypeUtil;
  4 +import cn.hutool.core.lang.Assert;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 -import cn.iocoder.yudao.module.infra.controller.admin.file.vo.FilePageReqVO; 6 +import cn.iocoder.yudao.framework.file.core.client.FileClient;
  7 +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO;
6 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO; 8 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO;
7 import cn.iocoder.yudao.module.infra.dal.mysql.file.FileMapper; 9 import cn.iocoder.yudao.module.infra.dal.mysql.file.FileMapper;
8 -import cn.iocoder.yudao.module.infra.framework.file.config.FileProperties;  
9 import org.springframework.stereotype.Service; 10 import org.springframework.stereotype.Service;
10 11
11 import javax.annotation.Resource; 12 import javax.annotation.Resource;
12 import java.io.ByteArrayInputStream; 13 import java.io.ByteArrayInputStream;
13 14
14 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 15 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
15 -import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; 16 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_NOT_EXISTS;
16 17
17 /** 18 /**
18 * 文件 Service 实现类 19 * 文件 Service 实现类
@@ -23,10 +24,10 @@ import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; @@ -23,10 +24,10 @@ import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
23 public class FileServiceImpl implements FileService { 24 public class FileServiceImpl implements FileService {
24 25
25 @Resource 26 @Resource
26 - private FileMapper fileMapper; 27 + private FileConfigService fileConfigService;
27 28
28 @Resource 29 @Resource
29 - private FileProperties fileProperties; 30 + private FileMapper fileMapper;
30 31
31 @Override 32 @Override
32 public PageResult<FileDO> getFilePage(FilePageReqVO pageReqVO) { 33 public PageResult<FileDO> getFilePage(FilePageReqVO pageReqVO) {
@@ -35,36 +36,49 @@ public class FileServiceImpl implements FileService { @@ -35,36 +36,49 @@ public class FileServiceImpl implements FileService {
35 36
36 @Override 37 @Override
37 public String createFile(String path, byte[] content) { 38 public String createFile(String path, byte[] content) {
38 - if (fileMapper.selectCountById(path) > 0) {  
39 - throw exception(FILE_PATH_EXISTS);  
40 - } 39 + // 上传到文件存储器
  40 + FileClient client = fileConfigService.getMasterFileClient();
  41 + Assert.notNull(client, "客户端(master) 不能为空");
  42 + String url = client.upload(content, path);
  43 +
41 // 保存到数据库 44 // 保存到数据库
42 FileDO file = new FileDO(); 45 FileDO file = new FileDO();
43 - file.setId(path); 46 + file.setConfigId(client.getId());
  47 + file.setPath(path);
  48 + file.setUrl(url);
44 file.setType(FileTypeUtil.getType(new ByteArrayInputStream(content))); 49 file.setType(FileTypeUtil.getType(new ByteArrayInputStream(content)));
45 - file.setContent(content); 50 + file.setSize(content.length);
46 fileMapper.insert(file); 51 fileMapper.insert(file);
47 - // 拼接路径返回  
48 - return fileProperties.getBasePath() + path; 52 + return url;
49 } 53 }
50 54
51 @Override 55 @Override
52 - public void deleteFile(String id) { 56 + public void deleteFile(Long id) {
53 // 校验存在 57 // 校验存在
54 - this.validateFileExists(id);  
55 - // 更新 58 + FileDO file = this.validateFileExists(id);
  59 +
  60 + // 从文件存储器中删除
  61 + FileClient client = fileConfigService.getFileClient(file.getConfigId());
  62 + Assert.notNull(client, "客户端({}) 不能为空", file.getConfigId());
  63 + client.delete(file.getPath());
  64 +
  65 + // 删除记录
56 fileMapper.deleteById(id); 66 fileMapper.deleteById(id);
57 } 67 }
58 68
59 - private void validateFileExists(String id) {  
60 - if (fileMapper.selectById(id) == null) { 69 + private FileDO validateFileExists(Long id) {
  70 + FileDO fileDO = fileMapper.selectById(id);
  71 + if (fileDO == null) {
61 throw exception(FILE_NOT_EXISTS); 72 throw exception(FILE_NOT_EXISTS);
62 } 73 }
  74 + return fileDO;
63 } 75 }
64 76
65 @Override 77 @Override
66 - public FileDO getFile(String path) {  
67 - return fileMapper.selectByPath(path); 78 + public byte[] getFileContent(Long configId, String path) {
  79 + FileClient client = fileConfigService.getFileClient(configId);
  80 + Assert.notNull(client, "客户端({}) 不能为空", configId);
  81 + return client.getContent(path);
68 } 82 }
69 83
70 } 84 }
yudao-module-infra/yudao-module-infra-impl/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceTest.java
@@ -3,11 +3,11 @@ package cn.iocoder.yudao.module.infra.service.file; @@ -3,11 +3,11 @@ package cn.iocoder.yudao.module.infra.service.file;
3 import cn.hutool.core.io.resource.ResourceUtil; 3 import cn.hutool.core.io.resource.ResourceUtil;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; 5 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
  6 +import cn.iocoder.yudao.framework.file.core.client.FileClient;
6 import cn.iocoder.yudao.framework.test.core.util.AssertUtils; 7 import cn.iocoder.yudao.framework.test.core.util.AssertUtils;
7 -import cn.iocoder.yudao.module.infra.controller.admin.file.vo.FilePageReqVO; 8 +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO;
8 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO; 9 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO;
9 import cn.iocoder.yudao.module.infra.dal.mysql.file.FileMapper; 10 import cn.iocoder.yudao.module.infra.dal.mysql.file.FileMapper;
10 -import cn.iocoder.yudao.module.infra.framework.file.config.FileProperties;  
11 import cn.iocoder.yudao.module.infra.test.BaseDbUnitTest; 11 import cn.iocoder.yudao.module.infra.test.BaseDbUnitTest;
12 import org.junit.jupiter.api.Test; 12 import org.junit.jupiter.api.Test;
13 import org.springframework.boot.test.mock.mockito.MockBean; 13 import org.springframework.boot.test.mock.mockito.MockBean;
@@ -17,47 +17,46 @@ import javax.annotation.Resource; @@ -17,47 +17,46 @@ import javax.annotation.Resource;
17 17
18 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime; 18 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime;
19 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; 19 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
20 -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;  
21 -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; 20 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
22 import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; 21 import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
23 import static org.junit.jupiter.api.Assertions.*; 22 import static org.junit.jupiter.api.Assertions.*;
  23 +import static org.mockito.ArgumentMatchers.same;
  24 +import static org.mockito.Mockito.*;
24 25
25 -@Import({FileServiceImpl.class, FileProperties.class}) 26 +@Import({FileServiceImpl.class})
26 public class FileServiceTest extends BaseDbUnitTest { 27 public class FileServiceTest extends BaseDbUnitTest {
27 28
28 @Resource 29 @Resource
29 private FileService fileService; 30 private FileService fileService;
30 31
31 - @MockBean  
32 - private FileProperties fileProperties;  
33 -  
34 @Resource 32 @Resource
35 private FileMapper fileMapper; 33 private FileMapper fileMapper;
36 34
  35 + @MockBean
  36 + private FileConfigService fileConfigService;
  37 +
37 @Test 38 @Test
38 public void testGetFilePage() { 39 public void testGetFilePage() {
39 // mock 数据 40 // mock 数据
40 FileDO dbFile = randomPojo(FileDO.class, o -> { // 等会查询到 41 FileDO dbFile = randomPojo(FileDO.class, o -> { // 等会查询到
41 - o.setId("yunai"); 42 + o.setPath("yunai");
42 o.setType("jpg"); 43 o.setType("jpg");
43 o.setCreateTime(buildTime(2021, 1, 15)); 44 o.setCreateTime(buildTime(2021, 1, 15));
44 }); 45 });
45 fileMapper.insert(dbFile); 46 fileMapper.insert(dbFile);
46 - // 测试 id 不匹配  
47 - fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> o.setId("tudou"))); 47 + // 测试 path 不匹配
  48 + fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> o.setPath("tudou")));
48 // 测试 type 不匹配 49 // 测试 type 不匹配
49 fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> { 50 fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> {
50 - o.setId("yunai02");  
51 o.setType("png"); 51 o.setType("png");
52 })); 52 }));
53 // 测试 createTime 不匹配 53 // 测试 createTime 不匹配
54 fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> { 54 fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> {
55 - o.setId("yunai03");  
56 o.setCreateTime(buildTime(2020, 1, 15)); 55 o.setCreateTime(buildTime(2020, 1, 15));
57 })); 56 }));
58 // 准备参数 57 // 准备参数
59 FilePageReqVO reqVO = new FilePageReqVO(); 58 FilePageReqVO reqVO = new FilePageReqVO();
60 - reqVO.setId("yunai"); 59 + reqVO.setPath("yunai");
61 reqVO.setType("jp"); 60 reqVO.setType("jp");
62 reqVO.setBeginCreateTime(buildTime(2021, 1, 10)); 61 reqVO.setBeginCreateTime(buildTime(2021, 1, 10));
63 reqVO.setEndCreateTime(buildTime(2021, 1, 20)); 62 reqVO.setEndCreateTime(buildTime(2021, 1, 20));
@@ -67,7 +66,7 @@ public class FileServiceTest extends BaseDbUnitTest { @@ -67,7 +66,7 @@ public class FileServiceTest extends BaseDbUnitTest {
67 // 断言 66 // 断言
68 assertEquals(1, pageResult.getTotal()); 67 assertEquals(1, pageResult.getTotal());
69 assertEquals(1, pageResult.getList().size()); 68 assertEquals(1, pageResult.getList().size());
70 - AssertUtils.assertPojoEquals(dbFile, pageResult.getList().get(0), "content"); 69 + AssertUtils.assertPojoEquals(dbFile, pageResult.getList().get(0));
71 } 70 }
72 71
73 @Test 72 @Test
@@ -75,52 +74,68 @@ public class FileServiceTest extends BaseDbUnitTest { @@ -75,52 +74,68 @@ public class FileServiceTest extends BaseDbUnitTest {
75 // 准备参数 74 // 准备参数
76 String path = randomString(); 75 String path = randomString();
77 byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); 76 byte[] content = ResourceUtil.readBytes("file/erweima.jpg");
  77 + // mock Master 文件客户端
  78 + FileClient client = mock(FileClient.class);
  79 + when(fileConfigService.getMasterFileClient()).thenReturn(client);
  80 + String url = randomString();
  81 + when(client.upload(same(content), same(path))).thenReturn(url);
  82 + when(client.getId()).thenReturn(10L);
78 83
79 // 调用 84 // 调用
80 - String url = fileService.createFile(path, content); 85 + String result = fileService.createFile(path, content);
81 // 断言 86 // 断言
82 - assertEquals(fileProperties.getBasePath() + path, url); 87 + assertEquals(result, url);
83 // 校验数据 88 // 校验数据
84 - FileDO file = fileMapper.selectById(path);  
85 - assertEquals(path, file.getId()); 89 + FileDO file = fileMapper.selectOne(FileDO::getPath, path);
  90 + assertEquals(10L, file.getConfigId());
  91 + assertEquals(path, file.getPath());
  92 + assertEquals(url, file.getUrl());
86 assertEquals("jpg", file.getType()); 93 assertEquals("jpg", file.getType());
87 - assertArrayEquals(content, file.getContent());  
88 - }  
89 -  
90 - @Test  
91 - public void testCreateFile_exists() {  
92 - // mock 数据  
93 - FileDO dbFile = randomPojo(FileDO.class);  
94 - fileMapper.insert(dbFile);  
95 - // 准备参数  
96 - String path = dbFile.getId(); // 模拟已存在  
97 - byte[] content = ResourceUtil.readBytes("file/erweima.jpg");  
98 -  
99 - // 调用,并断言异常  
100 - assertServiceException(() -> fileService.createFile(path, content), FILE_PATH_EXISTS); 94 + assertEquals(content.length, file.getSize());
101 } 95 }
102 96
103 @Test 97 @Test
104 public void testDeleteFile_success() { 98 public void testDeleteFile_success() {
105 // mock 数据 99 // mock 数据
106 - FileDO dbFile = randomPojo(FileDO.class); 100 + FileDO dbFile = randomPojo(FileDO.class, o -> o.setConfigId(10L).setPath("tudou.jpg"));
107 fileMapper.insert(dbFile);// @Sql: 先插入出一条存在的数据 101 fileMapper.insert(dbFile);// @Sql: 先插入出一条存在的数据
  102 + // mock Master 文件客户端
  103 + FileClient client = mock(FileClient.class);
  104 + when(fileConfigService.getFileClient(eq(10L))).thenReturn(client);
108 // 准备参数 105 // 准备参数
109 - String id = dbFile.getId(); 106 + Long id = dbFile.getId();
110 107
111 // 调用 108 // 调用
112 fileService.deleteFile(id); 109 fileService.deleteFile(id);
113 // 校验数据不存在了 110 // 校验数据不存在了
114 assertNull(fileMapper.selectById(id)); 111 assertNull(fileMapper.selectById(id));
  112 + // 校验调用
  113 + verify(client).delete(eq("tudou.jpg"));
115 } 114 }
116 115
117 @Test 116 @Test
118 public void testDeleteFile_notExists() { 117 public void testDeleteFile_notExists() {
119 // 准备参数 118 // 准备参数
120 - String id = randomString(); 119 + Long id = randomLongId();
121 120
122 // 调用, 并断言异常 121 // 调用, 并断言异常
123 assertServiceException(() -> fileService.deleteFile(id), FILE_NOT_EXISTS); 122 assertServiceException(() -> fileService.deleteFile(id), FILE_NOT_EXISTS);
124 } 123 }
125 124
  125 + @Test
  126 + public void testGetFileContent() {
  127 + // 准备参数
  128 + Long configId = 10L;
  129 + String path = "tudou.jpg";
  130 + // mock 方法
  131 + FileClient client = mock(FileClient.class);
  132 + when(fileConfigService.getFileClient(eq(10L))).thenReturn(client);
  133 + byte[] content = new byte[]{};
  134 + when(client.getContent(eq("tudou.jpg"))).thenReturn(content);
  135 +
  136 + // 调用
  137 + byte[] result = fileService.getFileContent(configId, path);
  138 + // 断言
  139 + assertSame(result, content);
  140 + }
126 } 141 }
yudao-module-infra/yudao-module-infra-impl/src/test/resources/sql/create_tables.sql
@@ -32,9 +32,12 @@ CREATE TABLE IF NOT EXISTS &quot;infra_file_config&quot; ( @@ -32,9 +32,12 @@ CREATE TABLE IF NOT EXISTS &quot;infra_file_config&quot; (
32 ) COMMENT '文件配置表'; 32 ) COMMENT '文件配置表';
33 33
34 CREATE TABLE IF NOT EXISTS "infra_file" ( 34 CREATE TABLE IF NOT EXISTS "infra_file" (
35 - "id" varchar(188) NOT NULL, 35 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  36 + "config_id" bigint NOT NULL,
  37 + "path" varchar(512),
  38 + "url" varchar(1024),
36 "type" varchar(63) DEFAULT NULL, 39 "type" varchar(63) DEFAULT NULL,
37 - "content" blob NOT NULL, 40 + "size" bigint NOT NULL,
38 "creator" varchar(64) DEFAULT '', 41 "creator" varchar(64) DEFAULT '',
39 "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 42 "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
40 "updater" varchar(64) DEFAULT '', 43 "updater" varchar(64) DEFAULT '',
yudao-server/src/main/resources/application-dev.yaml
@@ -172,8 +172,6 @@ yudao: @@ -172,8 +172,6 @@ yudao:
172 session-timeout: 30m 172 session-timeout: 30m
173 mock-enable: true 173 mock-enable: true
174 mock-secret: test 174 mock-secret: test
175 - file:  
176 - base-path: http://api-dashboard.yudao.iocoder.cn${yudao.web.admin-api.prefix}/infra/file/get/  
177 xss: 175 xss:
178 enable: false 176 enable: false
179 exclude-urls: # 如下两个 url,仅仅是为了演示,去掉配置也没关系 177 exclude-urls: # 如下两个 url,仅仅是为了演示,去掉配置也没关系
yudao-server/src/main/resources/application-local.yaml
@@ -184,8 +184,6 @@ yudao: @@ -184,8 +184,6 @@ yudao:
184 session-timeout: 1d 184 session-timeout: 1d
185 mock-enable: true 185 mock-enable: true
186 mock-secret: test 186 mock-secret: test
187 - file:  
188 - base-path: http://127.0.0.1:${server.port}${yudao.web.admin-api.prefix}/infra/file/get/  
189 xss: 187 xss:
190 enable: false 188 enable: false
191 exclude-urls: # 如下两个 url,仅仅是为了演示,去掉配置也没关系 189 exclude-urls: # 如下两个 url,仅仅是为了演示,去掉配置也没关系
yudao-server/src/main/resources/application.yaml
@@ -92,7 +92,7 @@ yudao: @@ -92,7 +92,7 @@ yudao:
92 ignore-urls: 92 ignore-urls:
93 - /admin-api/system/tenant/get-id-by-name # 基于名字获取租户,不许带租户编号 93 - /admin-api/system/tenant/get-id-by-name # 基于名字获取租户,不许带租户编号
94 - /admin-api/system/captcha/get-image # 获取图片验证码,和租户无关 94 - /admin-api/system/captcha/get-image # 获取图片验证码,和租户无关
95 - - /admin-api/infra/file/get/* # 获取图片,和租户无关 95 + - /admin-api/infra/file/*/get/** # 获取图片,和租户无关
96 - /admin-api/system/sms/callback/* # 短信回调接口,无法带上租户编号 96 - /admin-api/system/sms/callback/* # 短信回调接口,无法带上租户编号
97 ignore-tables: 97 ignore-tables:
98 - system_tenant 98 - system_tenant
yudao-ui-admin/src/views/infra/file/index.vue
@@ -3,8 +3,8 @@ @@ -3,8 +3,8 @@
3 3
4 <!-- 搜索工作栏 --> 4 <!-- 搜索工作栏 -->
5 <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px"> 5 <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
6 - <el-form-item label="文件路径" prop="id">  
7 - <el-input v-model="queryParams.id" placeholder="请输入文件路径" clearable size="small" @keyup.enter.native="handleQuery"/> 6 + <el-form-item label="文件路径" prop="path">
  7 + <el-input v-model="queryParams.path" placeholder="请输入文件路径" clearable size="small" @keyup.enter.native="handleQuery"/>
8 </el-form-item> 8 </el-form-item>
9 <el-form-item label="文件类型" prop="type"> 9 <el-form-item label="文件类型" prop="type">
10 <el-select v-model="queryParams.type" placeholder="请选择文件类型" clearable size="small"> 10 <el-select v-model="queryParams.type" placeholder="请选择文件类型" clearable size="small">
@@ -31,21 +31,23 @@ @@ -31,21 +31,23 @@
31 31
32 <!-- 列表 --> 32 <!-- 列表 -->
33 <el-table v-loading="loading" :data="list"> 33 <el-table v-loading="loading" :data="list">
34 - <el-table-column label="文件路径" align="center" prop="id" width="300" /> 34 + <el-table-column label="文件名" align="center" prop="path" />
  35 + <el-table-column label="URL" align="center" prop="url" />
  36 + <el-table-column label="文件大小" align="center" prop="size" width="120" :formatter="sizeFormat" />
35 <el-table-column label="文件类型" align="center" prop="type" width="80" /> 37 <el-table-column label="文件类型" align="center" prop="type" width="80" />
36 - <el-table-column label="文件内容" align="center" prop="content">  
37 - <template slot-scope="scope">  
38 - <img v-if="scope.row.type === 'jpg' || scope.row.type === 'png' || scope.row.type === 'gif'"  
39 - width="200px" :src="getFileUrl + scope.row.id">  
40 - <i v-else>非图片,无法预览</i>  
41 - </template>  
42 - </el-table-column>  
43 - <el-table-column label="创建时间" align="center" prop="createTime" width="180"> 38 +<!-- <el-table-column label="文件内容" align="center" prop="content">-->
  39 +<!-- <template slot-scope="scope">-->
  40 +<!-- <img v-if="scope.row.type === 'jpg' || scope.row.type === 'png' || scope.row.type === 'gif'"-->
  41 +<!-- width="200px" :src="getFileUrl + scope.row.id">-->
  42 +<!-- <i v-else>非图片,无法预览</i>-->
  43 +<!-- </template>-->
  44 +<!-- </el-table-column>-->
  45 + <el-table-column label="上传时间" align="center" prop="createTime" width="180">
44 <template slot-scope="scope"> 46 <template slot-scope="scope">
45 <span>{{ parseTime(scope.row.createTime) }}</span> 47 <span>{{ parseTime(scope.row.createTime) }}</span>
46 </template> 48 </template>
47 </el-table-column> 49 </el-table-column>
48 - <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> 50 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="100">
49 <template slot-scope="scope"> 51 <template slot-scope="scope">
50 <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" 52 <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
51 v-hasPermi="['infra:file:delete']">删除</el-button> 53 v-hasPermi="['infra:file:delete']">删除</el-button>
@@ -102,7 +104,7 @@ export default { @@ -102,7 +104,7 @@ export default {
102 queryParams: { 104 queryParams: {
103 pageNo: 1, 105 pageNo: 1,
104 pageSize: 10, 106 pageSize: 10,
105 - id: null, 107 + path: null,
106 type: null, 108 type: null,
107 }, 109 },
108 // 用户导入参数 110 // 用户导入参数
@@ -193,6 +195,15 @@ export default { @@ -193,6 +195,15 @@ export default {
193 this.$modal.msgSuccess("删除成功"); 195 this.$modal.msgSuccess("删除成功");
194 }).catch(() => {}); 196 }).catch(() => {});
195 }, 197 },
  198 + // 用户昵称展示
  199 + sizeFormat(row, column) {
  200 + const unitArr = ["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"];
  201 + const srcSize = parseFloat(row.size);
  202 + const index = Math.floor(Math.log(srcSize) / Math.log(1024));
  203 + let size =srcSize/Math.pow(1024,index);
  204 + size = size.toFixed(2);//保留的小数位数
  205 + return size + ' ' + unitArr[index];
  206 + },
196 } 207 }
197 }; 208 };
198 </script> 209 </script>