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