新增文件可下载标识、加密短信验证支持等

This commit is contained in:
yangchaojin
2026-01-28 18:57:50 +08:00
parent 1d79da5914
commit 1fa8296385
11 changed files with 247 additions and 14 deletions

View File

@@ -340,7 +340,8 @@ CREATE TABLE infra_file (
updater varchar(64) DEFAULT '' NULL, updater varchar(64) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL, deleted bit DEFAULT '0' NOT NULL,
DOWNLOAD_COUNT INT DEFAULT 0 NOT NULL DOWNLOAD_COUNT INT DEFAULT 0 NOT NULL,
DOWNLOADABLE SMALLINT DEFAULT 1 NOT NULL
); );
COMMENT ON COLUMN infra_file.id IS '文件编号'; COMMENT ON COLUMN infra_file.id IS '文件编号';
@@ -358,6 +359,7 @@ COMMENT ON COLUMN infra_file.updater IS '更新者';
COMMENT ON COLUMN infra_file.update_time IS '更新时间'; COMMENT ON COLUMN infra_file.update_time IS '更新时间';
COMMENT ON COLUMN infra_file.deleted IS '是否删除'; COMMENT ON COLUMN infra_file.deleted IS '是否删除';
COMMENT ON COLUMN INFRA_FILE.DOWNLOAD_COUNT IS '下载次数'; COMMENT ON COLUMN INFRA_FILE.DOWNLOAD_COUNT IS '下载次数';
COMMENT ON COLUMN INFRA_FILE.DOWNLOADABLE IS '是否可下载1是0否';
COMMENT ON TABLE infra_file IS '文件表'; COMMENT ON TABLE infra_file IS '文件表';
CREATE INDEX idx_infra_file_hash ON infra_file(hash); CREATE INDEX idx_infra_file_hash ON infra_file(hash);

View File

@@ -0,0 +1,9 @@
package com.zt.plat.framework.common.enums;
/**
* 验证码发送方式
*/
public enum VerifyCodeSendType {
SMS, // 短信验证码
E_OFFICE // e办消息推送
}

View File

@@ -22,4 +22,6 @@ public class FileCreateReqDTO {
@NotEmpty(message = "文件内容不能为空") @NotEmpty(message = "文件内容不能为空")
private byte[] content; private byte[] content;
@Schema(description = "是否可下载true是false否", example = "true")
private Boolean downloadable;
} }

View File

@@ -37,4 +37,7 @@ public class FileRespDTO {
@Schema(description = "文件下载次数") @Schema(description = "文件下载次数")
private Integer downloadCount; private Integer downloadCount;
@Schema(description = "是否可下载true是false否")
private Boolean downloadable;
} }

View File

@@ -23,8 +23,8 @@ import java.util.Date;
@Accessors(chain = true) @Accessors(chain = true)
public class FileRespVO { public class FileRespVO {
public String getUrl() { public String getUrl() {
// 加密附件不返回 url // 不可下载 或 加密附件不返回 url
if (Boolean.TRUE.equals(this.isEncrypted)) { if (Boolean.FALSE.equals(this.downloadable) || Boolean.TRUE.equals(this.isEncrypted)) {
return null; return null;
} }
// 如果 url 已经是临时下载地址(如预签名 URL直接返回 // 如果 url 已经是临时下载地址(如预签名 URL直接返回
@@ -62,8 +62,8 @@ public class FileRespVO {
private String previewUrl; private String previewUrl;
public String getPreviewUrl() { public String getPreviewUrl() {
// 加密附件不返回 previewUrl // 不可下载不返回 previewUrl
if (Boolean.TRUE.equals(this.isEncrypted)) { if (Boolean.FALSE.equals(this.downloadable) ) {
return null; return null;
} }
// 仅当 url 不为空时生成 // 仅当 url 不为空时生成
@@ -75,7 +75,15 @@ public class FileRespVO {
if (onlinePreview == null || onlinePreview.isEmpty()) { if (onlinePreview == null || onlinePreview.isEmpty()) {
return null; return null;
} }
String presignedUrl = this.getUrl(); // 添加加密文件预览逻辑
String presignedUrl = null;
if (Boolean.TRUE.equals(this.isEncrypted)) {
if (url != null && (url.startsWith("http://") || url.startsWith("https://"))) {
presignedUrl = url;
}
}else{
presignedUrl = this.getUrl();
}
if (presignedUrl == null || presignedUrl.isEmpty()) { if (presignedUrl == null || presignedUrl.isEmpty()) {
return null; return null;
} }
@@ -102,4 +110,6 @@ public class FileRespVO {
@Schema(description = "下载次数") @Schema(description = "下载次数")
private Integer downloadCount; private Integer downloadCount;
@Schema(description = "是否可下载true是false否")
private Boolean downloadable;
} }

View File

@@ -70,6 +70,11 @@ public class FileDO extends BaseDO {
*/ */
private Integer downloadCount; private Integer downloadCount;
/**
* 是否可下载true是false否
*/
private Boolean downloadable;
/** /**
* 是否加密 * 是否加密
* <p> * <p>

View File

@@ -6,4 +6,7 @@ package com.zt.plat.module.infra.dal.redis;
public class RedisKeyConstants { public class RedisKeyConstants {
public static final String FILE_VERIFICATION_CODE = "infra:file:verification_code:%d:%d"; public static final String FILE_VERIFICATION_CODE = "infra:file:verification_code:%d:%d";
public static final String FILE_VERIFICATION_CODE_USER_SET = "infra:file:verification_code:user:%d"; public static final String FILE_VERIFICATION_CODE_USER_SET = "infra:file:verification_code:user:%d";
// 加密文件预览token
public static final String FILE_PREVIEW_TOKEN = "infra:file:preview-token:%s";
} }

View File

@@ -2,11 +2,12 @@ package com.zt.plat.module.infra.framework.rpc.config;
import com.zt.plat.module.system.api.permission.PermissionApi; import com.zt.plat.module.system.api.permission.PermissionApi;
import com.zt.plat.module.system.api.permission.RoleApi; import com.zt.plat.module.system.api.permission.RoleApi;
import com.zt.plat.module.system.api.sms.SmsSendApi;
import com.zt.plat.module.system.api.user.AdminUserApi; import com.zt.plat.module.system.api.user.AdminUserApi;
import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@Configuration(value = "infraRpcConfiguration", proxyBeanMethods = false) @Configuration(value = "infraRpcConfiguration", proxyBeanMethods = false)
@EnableFeignClients(clients = {PermissionApi.class, RoleApi.class, AdminUserApi.class}) @EnableFeignClients(clients = {PermissionApi.class, RoleApi.class, AdminUserApi.class, SmsSendApi.class })
public class RpcConfiguration { public class RpcConfiguration {
} }

View File

@@ -1,5 +1,6 @@
package com.zt.plat.module.infra.service.file; package com.zt.plat.module.infra.service.file;
import com.zt.plat.framework.common.enums.VerifyCodeSendType;
import com.zt.plat.framework.common.pojo.PageResult; import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.module.infra.controller.admin.file.vo.file.FileCreateReqVO; import com.zt.plat.module.infra.controller.admin.file.vo.file.FileCreateReqVO;
import com.zt.plat.module.infra.controller.admin.file.vo.file.FilePageReqVO; import com.zt.plat.module.infra.controller.admin.file.vo.file.FilePageReqVO;
@@ -10,6 +11,8 @@ import com.zt.plat.module.infra.dal.dataobject.file.FileDO;
import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotEmpty;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import java.io.OutputStream;
/** /**
* 文件 Service 接口 * 文件 Service 接口
* *
@@ -72,6 +75,14 @@ public interface FileService {
*/ */
String generateFileVerificationCode(Long fileId, Long userId); String generateFileVerificationCode(Long fileId, Long userId);
/**
* 发送验证码
* @param code 验证码
* @param verifyCodeSendType 发送类型
*/
void sendVerifyCode(String code, VerifyCodeSendType verifyCodeSendType);
/** /**
* 校验验证码并返回解密后的文件内容 * 校验验证码并返回解密后的文件内容
*/ */
@@ -125,4 +136,25 @@ public interface FileService {
* @param fileId * @param fileId
*/ */
void incDownloadCount(Long fileId); void incDownloadCount(Long fileId);
/**
* 临时生成文件预览token
* @param fileId 文件ID
* @param userId 用户ID
* @return 临时token
*/
String generatePreviewToken(Long fileId, Long userId);
/**
* 验证文件预览token
* @param fileId 文件ID
* @param token 用户ID
* @return 临时token
*/
boolean verifyPreviewToken(Long fileId, String token);
/**
* 校验预览 token 后,将文件内容解密并写入输出流(用于预览)
*/
void writeDecryptedToStream(Long fileId, OutputStream outputStream) throws Exception;
} }

Some files were not shown because too many files have changed in this diff Show More