diff --git a/fs-admin/src/main/resources/application-dev.yml b/fs-admin/src/main/resources/application-dev.yml index f976aebb4d8c8843823cb8fd68d3e694c65841e9..2045d343001a0501d8b34f6e18cf374c0cf7b1f6 100644 --- a/fs-admin/src/main/resources/application-dev.yml +++ b/fs-admin/src/main/resources/application-dev.yml @@ -27,7 +27,7 @@ spring: redis: host: 127.0.0.1 port: 6379 - password: insentek + password: 123456 database: 0 # 连接超时时间 timeout: 10s @@ -54,7 +54,7 @@ redisson: config: | singleServerConfig: address: "redis://127.0.0.1:6379" - password: "insentek" + password: "123456" database: 0 timeout: 3000 connectionPoolSize: 64 diff --git a/fs-admin/src/main/resources/application.yml b/fs-admin/src/main/resources/application.yml index 9471d68ad70d15b54633cdd5f7b76906996f53ac..1f3d5a0acdfb70a45fa073bdba06823368a508f8 100644 --- a/fs-admin/src/main/resources/application.yml +++ b/fs-admin/src/main/resources/application.yml @@ -121,7 +121,8 @@ security: - /apis/user/register - /apis/user/forget-password/code/** - /apis/user/forget-password - - /apis/share/items + - /apis/share/**/items + - /apis/share/verify/code - /apis/share/**/info --- #Sa-Token 配置 diff --git a/fs-framework/fs-redis/src/main/java/com/xddcodec/fs/framework/redis/RedisAutoConfigure.java b/fs-framework/fs-redis/src/main/java/com/xddcodec/fs/framework/redis/RedisAutoConfigure.java index abab4ab63a4a3648397169a127d0a489afe290ae..7c645cd8f96b576bd37c99a1b96f6302a16c57ad 100644 --- a/fs-framework/fs-redis/src/main/java/com/xddcodec/fs/framework/redis/RedisAutoConfigure.java +++ b/fs-framework/fs-redis/src/main/java/com/xddcodec/fs/framework/redis/RedisAutoConfigure.java @@ -1,8 +1,6 @@ package com.xddcodec.fs.framework.redis; -import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonTypeInfo; -import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; diff --git a/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/controller/FileShareController.java b/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/controller/FileShareController.java index fbf3a0195ed2fba07120e82d9794c17cea851c6f..bf35a2f81f0cfd1869516d826a9f73357ba457de 100644 --- a/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/controller/FileShareController.java +++ b/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/controller/FileShareController.java @@ -2,7 +2,6 @@ package com.xddcodec.fs.file.controller; import com.xddcodec.fs.file.domain.dto.CreateShareCmd; import com.xddcodec.fs.file.domain.dto.VerifyShareCodeCmd; -import com.xddcodec.fs.file.domain.qry.FileSharePageQry; import com.xddcodec.fs.file.domain.qry.FileShareQry; import com.xddcodec.fs.file.domain.vo.FileShareAccessRecordVO; import com.xddcodec.fs.file.domain.vo.FileShareThinVO; @@ -10,7 +9,6 @@ import com.xddcodec.fs.file.domain.vo.FileShareVO; import com.xddcodec.fs.file.domain.vo.FileVO; import com.xddcodec.fs.file.service.FileShareAccessRecordService; import com.xddcodec.fs.file.service.FileShareService; -import com.xddcodec.fs.framework.common.domain.PageResult; import com.xddcodec.fs.framework.common.domain.Result; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -34,10 +32,18 @@ public class FileShareController { @Autowired private FileShareAccessRecordService fileShareAccessRecordService; - @GetMapping("/pages") - @Operation(summary = "分页获取我的分享", description = "分页获取我的分享列表") - public PageResult getMyPages(FileSharePageQry qry) { - return fileShareService.getMyPages(qry); + @GetMapping("/list") + @Operation(summary = "获取我的分享", description = "获取我的分享列表") + public Result> getList(FileShareQry qry) { + List result = fileShareService.getList(qry); + return Result.ok(result); + } + + @GetMapping("/{shareId}") + @Operation(summary = "获取分享详细信息", description = "获取分享详细信息") + public Result getDetail(@PathVariable String shareId) { + FileShareVO result = fileShareService.getDetail(shareId); + return Result.ok(result); } @GetMapping("/{shareId}/access/records") @@ -54,10 +60,10 @@ public class FileShareController { return Result.ok(fileShareVO); } - @PutMapping("/{id}/cancel") + @DeleteMapping("/cancels") @Operation(summary = "取消分享", description = "取消分享") - public Result cancelShare(@PathVariable String id) { - fileShareService.cancelShare(id); + public Result cancelShares(@RequestBody List ids) { + fileShareService.cancelShares(ids); return Result.ok(); } @@ -75,8 +81,8 @@ public class FileShareController { } @Operation(summary = "获取分享页文件列表数据", description = "获取分享页文件列表数据") - @GetMapping("/items") - public Result> getShareFileItems(@Validated FileShareQry qry) { - return Result.ok(fileShareService.getShareFileItems(qry)); + @GetMapping("/{shareId}/items") + public Result> getShareFileItems(@PathVariable String shareId, @RequestParam(required = false) String parentId) { + return Result.ok(fileShareService.getShareFileItems(shareId, parentId)); } } diff --git a/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/domain/dto/CreateShareCmd.java b/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/domain/dto/CreateShareCmd.java index cd9137792cb7491d58a4760de7b1491b803b2a7e..1cdb78d1da9c68d81d8494a446d829dde27ac4c5 100644 --- a/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/domain/dto/CreateShareCmd.java +++ b/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/domain/dto/CreateShareCmd.java @@ -28,7 +28,7 @@ public class CreateShareCmd { private String shareName; /** - * 有效期类型:1-1天 2-7天 3-30天 4-自定义 null-永久 + * 有效期类型:1-7天 2-30天 3-自定义 4-永久 */ private Integer expireType; diff --git a/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/domain/qry/FileSharePageQry.java b/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/domain/qry/FileSharePageQry.java deleted file mode 100644 index 239abe6e143b10a43c3b68a6beaf9cd462b1ca6b..0000000000000000000000000000000000000000 --- a/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/domain/qry/FileSharePageQry.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.xddcodec.fs.file.domain.qry; - -import com.xddcodec.fs.framework.common.domain.PageQuery; -import lombok.Data; -import lombok.EqualsAndHashCode; - -@EqualsAndHashCode(callSuper = true) -@Data -public class FileSharePageQry extends PageQuery { - - private String keyword; -} diff --git a/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/domain/qry/FileShareQry.java b/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/domain/qry/FileShareQry.java index d21f69ed3cd380791ab9fb86666bcfeff859ddde..d2a2c529f27427fc697eac157d5a01d5539e4f1e 100644 --- a/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/domain/qry/FileShareQry.java +++ b/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/domain/qry/FileShareQry.java @@ -1,22 +1,12 @@ package com.xddcodec.fs.file.domain.qry; - -import jakarta.validation.constraints.NotBlank; +import com.xddcodec.fs.framework.common.domain.PageQuery; import lombok.Data; +import lombok.EqualsAndHashCode; -/** - * - * @author Yann - * @date 2025/11/19 15:50 - */ +@EqualsAndHashCode(callSuper = true) @Data -public class FileShareQry { +public class FileShareQry extends PageQuery { - /** 分享ID */ - @NotBlank(message = "分享ID不能为空") - private String shareId; - /** - * 文件父ID - */ - private String parentId; + private String keyword; } diff --git a/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/domain/vo/FileShareVO.java b/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/domain/vo/FileShareVO.java index 297aeff42908a6f7c9f1dc441ea5c4ce98f7eb88..3f3e8b31762c1b56be4890d2960a34dd5f5e78cb 100644 --- a/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/domain/vo/FileShareVO.java +++ b/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/domain/vo/FileShareVO.java @@ -26,11 +26,6 @@ public class FileShareVO implements Serializable { */ private String shareName; - /** - * 分享链接 - */ - private String shareUrl; - /** * 提取码 */ @@ -70,7 +65,7 @@ public class FileShareVO implements Serializable { /** * 文件数量 */ - private Integer fileCount; + private Long fileCount; /** * 创建时间 diff --git a/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/service/FileShareService.java b/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/service/FileShareService.java index d32fecb2937d1c2096a5d84a781098b704cd9233..c994084436f96cb1853c01ce19be7db3e2d21ee1 100644 --- a/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/service/FileShareService.java +++ b/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/service/FileShareService.java @@ -4,12 +4,10 @@ import com.mybatisflex.core.service.IService; import com.xddcodec.fs.file.domain.FileShare; import com.xddcodec.fs.file.domain.dto.CreateShareCmd; import com.xddcodec.fs.file.domain.dto.VerifyShareCodeCmd; -import com.xddcodec.fs.file.domain.qry.FileSharePageQry; import com.xddcodec.fs.file.domain.qry.FileShareQry; import com.xddcodec.fs.file.domain.vo.FileShareThinVO; import com.xddcodec.fs.file.domain.vo.FileShareVO; import com.xddcodec.fs.file.domain.vo.FileVO; -import com.xddcodec.fs.framework.common.domain.PageResult; import java.util.List; @@ -27,7 +25,15 @@ public interface FileShareService extends IService { * @param qry * @return */ - PageResult getMyPages(FileSharePageQry qry); + List getList(FileShareQry qry); + + /** + * 获取分享详情 + * + * @param shareId 分享ID + * @return + */ + FileShareVO getDetail(String shareId); /** * 创建分享 @@ -39,9 +45,9 @@ public interface FileShareService extends IService { /** * 取消分享 * - * @param shareId 分享ID + * @param ids 分享ID集合 */ - void cancelShare(String shareId); + void cancelShares(List ids); /** * 校验提取码 @@ -52,10 +58,18 @@ public interface FileShareService extends IService { /** * 获取文件分享页对象 + * * @param shareId 分享id * @return vo */ FileShareThinVO getFileShareThinVO(String shareId); - List getShareFileItems(FileShareQry qry); + /** + * 获取分享文件列表 + * + * @param shareId 分享id + * @param parentId 父目录id + * @return + */ + List getShareFileItems(String shareId, String parentId); } diff --git a/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/service/impl/FileShareAccessRecordServiceImpl.java b/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/service/impl/FileShareAccessRecordServiceImpl.java index 5a3701116d5388b7801c6825bc080bcfbeaf4040..6bf67f51bb0ca2da4566e21fedb10397b3d582d8 100644 --- a/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/service/impl/FileShareAccessRecordServiceImpl.java +++ b/fs-modules/fs-file/src/main/java/com/xddcodec/fs/file/service/impl/FileShareAccessRecordServiceImpl.java @@ -12,6 +12,7 @@ import io.github.linpeilie.Converter; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import java.time.LocalDateTime; import java.util.List; import static com.xddcodec.fs.file.domain.table.FileShareAccessRecordTableDef.FILE_SHARE_ACCESS_RECORD; @@ -40,6 +41,7 @@ public class FileShareAccessRecordServiceImpl extends ServiceImpl getMyPages(FileSharePageQry qry) { - Integer pageNumber = qry.getPage() == null ? 1 : qry.getPage(); - Integer pageSize = qry.getPageSize() == null ? 10 : qry.getPageSize(); - Page page = Page.of(pageNumber, pageSize); - + public List getList(FileShareQry qry) { String userId = StpUtil.getLoginIdAsString(); - QueryWrapper wrapper = new QueryWrapper(); wrapper.where(FILE_SHARE.USER_ID.eq(userId)); @@ -68,7 +65,6 @@ public class FileShareServiceImpl extends ServiceImpl fileShares = this.list(wrapper); + return converter.convert(fileShares, FileShareVO.class); + } + + @Override + public FileShareVO getDetail(String shareId) { + FileShare share = this.getById(shareId); + if (share == null) { + throw new BusinessException("该分享不存在"); + } + return buildShareVO(share); + } - page = this.page(page, wrapper); - long total = page.getTotalRow(); - List fileShares = page.getRecords(); - List fileShareVOS = converter.convert(fileShares, FileShareVO.class); - fileShareVOS.forEach(vo -> { - vo.setShareUrl(shareDomain + "/s/" + vo.getId()); - vo.setIsPermanent(vo.getExpireTime() == null); - }); - return PageResult.success(fileShareVOS, total); + /** + * 构建分享VO + */ + private FileShareVO buildShareVO(FileShare share) { + FileShareVO vo = converter.convert(share, FileShareVO.class); + // 是否永久有效 + vo.setIsPermanent(share.getExpireTime() == null); + // 查询有几个文件 + vo.setFileCount(fileShareItemService.countByShareId(share.getId())); + // 判断是否到期 + return vo; } @Override @@ -108,9 +118,9 @@ public class FileShareServiceImpl extends ServiceImpl now.plusDays(1); - case 2 -> now.plusDays(7); - case 3 -> now.plusDays(30); + case 1 -> now.plusDays(7); + case 2 -> now.plusDays(30); default -> now.plusDays(7); }; } @Override @Transactional(rollbackFor = Exception.class) - public void cancelShare(String shareId) { - String userId = StpUtil.getLoginIdAsString(); - - FileShare share = this.getById(shareId); - if (share == null) { - throw new BusinessException("该分享不存在"); - } - - if (!share.getUserId().equals(userId)) { - throw new BusinessException("无权取消此分享"); + public void cancelShares(List ids) { + for (String id : ids) { + FileShare share = this.getById(id); + if (share == null) { + continue; + } + if (share.getUserId().equals(StpUtil.getLoginIdAsString())) { + this.removeById(id); + fileShareItemService.removeByShareId(id); + } } - - this.removeById(share); - - fileShareItemService.removeByShareId(shareId); } @Override public boolean verifyShareCode(VerifyShareCodeCmd cmd) { - FileShare share = this.getById(cmd.getShareId()); + // 故意延迟200ms,增加暴力破解成本 + try { + Thread.sleep(200); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + FileShareVO share = this.getDetail(cmd.getShareId()); if (share == null) { throw new BusinessException("该分享不存在"); } @@ -194,7 +191,7 @@ public class FileShareServiceImpl extends ServiceImpl getShareFileItems(FileShareQry qry) { - FileShare fileShare = this.getById(qry.getShareId()); + public List getShareFileItems(String shareId, String parentId) { + FileShare fileShare = this.getById(shareId); if (fileShare == null) { throw new BusinessException("该分享不存在或已删除"); } - if (StringUtils.isNotEmpty(qry.getParentId())) { + if (StringUtils.isNotEmpty(parentId)) { // 若有父文件ID参数, 则需要查询子数据集 FileQry fileQry = new FileQry(); - fileQry.setParentId(qry.getParentId()); + fileQry.setParentId(parentId); return fileInfoService.getList(fileQry); } // 获取分享明细 - List shareFileIds = fileShareItemService.getShareFileIds(qry.getShareId()); + List shareFileIds = fileShareItemService.getShareFileIds(shareId); + + //记录访问日志 + recordShareAccessLog(shareId); + //访问计数 + 1 +// incrementViewCount(qry.getShareId()); + return fileInfoService.getByFileIds(shareFileIds); } + + /** + * 记录分享访问日志 + * + * @param shareId + */ + private void recordShareAccessLog(String shareId) { + String ip = IpUtils.getIpAddr(); + String address = Ip2RegionUtils.search(ip); + String browser = IpUtils.getBrowser(); + String os = IpUtils.getOs(); + CreateFileShareAccessRecordCmd cmd = new CreateFileShareAccessRecordCmd(); + cmd.setShareId(shareId); + cmd.setAccessIp(ip); + cmd.setAccessAddress(address); + cmd.setBrowser(browser); + cmd.setOs(os); + eventPublisher.publishEvent(new CreateFileShareAccessRecordEvent(this, cmd)); + } + + /** + * 原子递增访问次数 + */ +// private void incrementViewCount(String shareId) { +// String key = VIEW_COUNT_KEY + shareId; +// Long count = redisTemplate.opsForValue().increment(key); +// +// if (count == null) { +// return; +// } +// // 第一次访问时设置过期时间(与分享有效期一致,或者永不过期) +// if (count == 1) { +// // 选项1: 永不过期 +// // redisTemplate.persist(key); +// +// // 选项2: 与分享有效期同步(推荐) +// setExpireTimeByShareExpiry(shareId, key); +// } +// } }