From 5c2d35750c882a0751b3f3f267f422aab12817c2 Mon Sep 17 00:00:00 2001 From: Administrator Date: Sun, 27 Jul 2025 20:35:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=88=86=E4=BA=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../aipan/annotation/ShareCodeCheck.java | 14 + .../ycloud/aipan/aspect/ShareCodeAspect.java | 85 ++++ .../ycloud/aipan/config/AccountConfig.java | 4 + .../aipan/controller/ShareController.java | 119 ++++++ .../aipan/controller/req/ShareCancelReq.java | 14 + .../aipan/controller/req/ShareCheckReq.java | 11 + .../aipan/controller/req/ShareCreateReq.java | 42 ++ .../controller/req/ShareFileQueryReq.java | 13 + .../controller/req/ShareFileTransferReq.java | 24 ++ .../org/ycloud/aipan/dto/ShareAccountDTO.java | 15 + .../java/org/ycloud/aipan/dto/ShareDTO.java | 50 +++ .../org/ycloud/aipan/dto/ShareDetailDTO.java | 53 +++ .../org/ycloud/aipan/dto/ShareSimpleDTO.java | 51 +++ .../org/ycloud/aipan/enums/BizCodeEnum.java | 2 +- .../ycloud/aipan/enums/ShareDayTypeEnum.java | 39 ++ .../ycloud/aipan/enums/ShareStatusEnum.java | 22 + .../org/ycloud/aipan/enums/ShareTypeEnum.java | 18 + .../ycloud/aipan/mapper/ShareFileMapper.java | 4 +- .../java/org/ycloud/aipan/model/ShareDO.java | 3 + .../org/ycloud/aipan/model/ShareFileDO.java | 3 + .../org/ycloud/aipan/model/StorageDO.java | 2 + .../aipan/service/AccountFileService.java | 29 +- .../ycloud/aipan/service/ShareService.java | 29 ++ .../service/impl/AccountFileServiceImpl.java | 6 +- .../aipan/service/impl/ShareServiceImpl.java | 390 ++++++++++++++++++ .../java/org/ycloud/aipan/util/JwtUtil.java | 55 +++ src/main/resources/mapper/ShareFileMapper.xml | 6 + 27 files changed, 1098 insertions(+), 5 deletions(-) create mode 100644 src/main/java/org/ycloud/aipan/annotation/ShareCodeCheck.java create mode 100644 src/main/java/org/ycloud/aipan/aspect/ShareCodeAspect.java create mode 100644 src/main/java/org/ycloud/aipan/controller/ShareController.java create mode 100644 src/main/java/org/ycloud/aipan/controller/req/ShareCancelReq.java create mode 100644 src/main/java/org/ycloud/aipan/controller/req/ShareCheckReq.java create mode 100644 src/main/java/org/ycloud/aipan/controller/req/ShareCreateReq.java create mode 100644 src/main/java/org/ycloud/aipan/controller/req/ShareFileQueryReq.java create mode 100644 src/main/java/org/ycloud/aipan/controller/req/ShareFileTransferReq.java create mode 100644 src/main/java/org/ycloud/aipan/dto/ShareAccountDTO.java create mode 100644 src/main/java/org/ycloud/aipan/dto/ShareDTO.java create mode 100644 src/main/java/org/ycloud/aipan/dto/ShareDetailDTO.java create mode 100644 src/main/java/org/ycloud/aipan/dto/ShareSimpleDTO.java create mode 100644 src/main/java/org/ycloud/aipan/enums/ShareDayTypeEnum.java create mode 100644 src/main/java/org/ycloud/aipan/enums/ShareStatusEnum.java create mode 100644 src/main/java/org/ycloud/aipan/enums/ShareTypeEnum.java create mode 100644 src/main/java/org/ycloud/aipan/service/ShareService.java create mode 100644 src/main/java/org/ycloud/aipan/service/impl/ShareServiceImpl.java diff --git a/src/main/java/org/ycloud/aipan/annotation/ShareCodeCheck.java b/src/main/java/org/ycloud/aipan/annotation/ShareCodeCheck.java new file mode 100644 index 0000000..94ee05d --- /dev/null +++ b/src/main/java/org/ycloud/aipan/annotation/ShareCodeCheck.java @@ -0,0 +1,14 @@ +package org.ycloud.aipan.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Documented +@Retention(RUNTIME) +@Target({ElementType.METHOD}) +public @interface ShareCodeCheck { +} diff --git a/src/main/java/org/ycloud/aipan/aspect/ShareCodeAspect.java b/src/main/java/org/ycloud/aipan/aspect/ShareCodeAspect.java new file mode 100644 index 0000000..d5b3919 --- /dev/null +++ b/src/main/java/org/ycloud/aipan/aspect/ShareCodeAspect.java @@ -0,0 +1,85 @@ +package org.ycloud.aipan.aspect; + +import io.jsonwebtoken.Claims; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.ycloud.aipan.annotation.ShareCodeCheck; +import org.ycloud.aipan.enums.BizCodeEnum; +import org.ycloud.aipan.exception.BizException; +import org.ycloud.aipan.util.JsonData; +import org.ycloud.aipan.util.JwtUtil; + +@Aspect +@Component +@Slf4j +public class ShareCodeAspect { + + private static final ThreadLocal threadLocal = new ThreadLocal<>(); + + /** + * 设置当前线程共享shareID + * @param shareId + */ + public static void set(Long shareId){ + threadLocal.set(shareId); + } + + /** + * 获取当前线程绑定的shareID + * @return + */ + public static Long get(){ + return threadLocal.get(); + } + + + /** + * 定义 @Pointcut注解表达式, + * 方式一:@annotation:当执行的方法上拥有指定的注解时生效(我们采用这) + * 方式二:execution:一般用于指定方法的执行 + */ + @Pointcut("@annotation(shareCodeCheck)") + public void pointCutShareCodeCheck(ShareCodeCheck shareCodeCheck){ + + } + + + /** + * 环绕通知, 围绕着方法执行 + * @Around 可以用来在调用一个具体方法前和调用后来完成一些具体的任务。 + * 方式一:单用 @Around("execution(* net.xdclass.controller.*.*(..))")可以 + * 方式二:用@Pointcut和@Around联合注解也可以(我们采用这个) + */ + @Around("pointCutShareCodeCheck(shareCodeCheck)") + public Object around(ProceedingJoinPoint joinPoint, ShareCodeCheck shareCodeCheck) throws Throwable { + + HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.getRequestAttributes())).getRequest(); + + String shareToken = request.getHeader("share-token"); + if(StringUtils.isBlank(shareToken)){ + throw new BizException(BizCodeEnum.SHARE_CODE_ILLEGAL); + } + Claims claims = JwtUtil.checkShareJWT(shareToken); + if(claims == null){ + log.error("share-token 解析失败"); + return JsonData.buildResult(BizCodeEnum.SHARE_CODE_ILLEGAL); + } + Long shareId = Long.valueOf(claims.get(JwtUtil.CLAIM_SHARE_KEY)+""); + set(shareId); + log.info("环绕通知执行前"); + Object obj = joinPoint.proceed(); + log.info("环绕通知执行后"); + return obj; + + } + + +} \ No newline at end of file diff --git a/src/main/java/org/ycloud/aipan/config/AccountConfig.java b/src/main/java/org/ycloud/aipan/config/AccountConfig.java index 7393bc8..97e214c 100644 --- a/src/main/java/org/ycloud/aipan/config/AccountConfig.java +++ b/src/main/java/org/ycloud/aipan/config/AccountConfig.java @@ -22,4 +22,8 @@ public class AccountConfig { * 根文件夹的父ID */ public static final Long ROOT_PARENT_ID = 0L; + /** + * 网盘前端地址 + */ + public static final String PAN_FRONT_DOMAIN_SHARE_API = "127.0.0.1:9999/share/"; } \ No newline at end of file diff --git a/src/main/java/org/ycloud/aipan/controller/ShareController.java b/src/main/java/org/ycloud/aipan/controller/ShareController.java new file mode 100644 index 0000000..c84a71c --- /dev/null +++ b/src/main/java/org/ycloud/aipan/controller/ShareController.java @@ -0,0 +1,119 @@ +package org.ycloud.aipan.controller; + +import lombok.AllArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.ycloud.aipan.annotation.ShareCodeCheck; +import org.ycloud.aipan.aspect.ShareCodeAspect; +import org.ycloud.aipan.controller.req.*; +import org.ycloud.aipan.dto.AccountFileDTO; +import org.ycloud.aipan.dto.ShareDTO; +import org.ycloud.aipan.dto.ShareDetailDTO; +import org.ycloud.aipan.dto.ShareSimpleDTO; +import org.ycloud.aipan.enums.BizCodeEnum; +import org.ycloud.aipan.interceptor.LoginInterceptor; +import org.ycloud.aipan.service.ShareService; +import org.ycloud.aipan.util.JsonData; + +import java.util.List; + + +@RestController +@RequestMapping("/api/share/v1") +public class ShareController { + + @Autowired + private ShareService shareService; + + /** + * 获取我的个人分享列表接口 + */ + @GetMapping("list") + public JsonData list(){ + List list = shareService.listShare(); + return JsonData.buildSuccess(list); + } + + /** + * 创建分享链接 + */ + @PostMapping("create") + public JsonData create(@RequestBody ShareCreateReq req){ + req.setAccountId(LoginInterceptor.threadLocal.get().getId()); + ShareDTO shareDTO = shareService.createShare(req); + return JsonData.buildSuccess(shareDTO); + } + + + /** + * 取消分享 + */ + @PostMapping("cancel") + public JsonData cancel(@RequestBody ShareCancelReq req){ + req.setAccountId(LoginInterceptor.threadLocal.get().getId()); + shareService.cancelShare(req); + return JsonData.buildSuccess(); + } + + + /** + * 访问分享接口,返回基本的分享信息 + * 情况一:如果链接不需要校验码,则一并返回token + * 情况二:如果链接需要校验码,则返回校验码,调用对应接口校验码,再返回token + */ + @GetMapping("visit") + public JsonData visit(@RequestParam(value = "shareId") Long shareId){ + ShareSimpleDTO shareSimpleDTO = shareService.simpleDetail(shareId); + return JsonData.buildSuccess(shareSimpleDTO); + } + + + /** + * 校验分享码,返回临时token + */ + @PostMapping("check_share_code") + public JsonData checkShareCode(@RequestBody ShareCheckReq req){ + String shareToken = shareService.checkShareCode(req); + if(shareToken == null){ + return JsonData.buildResult(BizCodeEnum.SHARE_NOT_EXIST); + } + return JsonData.buildSuccess(shareToken); + } + + + /** + * 查看分享详情接口 + */ + @GetMapping("detail") + @ShareCodeCheck + public JsonData detail(){ + ShareDetailDTO shareDetailDTO = shareService.detail(ShareCodeAspect.get()); + return JsonData.buildSuccess(shareDetailDTO); + } + + + /** + * 查看某个分享文件夹下的文件列表 + */ + @PostMapping("list_share_file") + @ShareCodeCheck + public JsonData listShareFile(@RequestBody ShareFileQueryReq req){ + req.setShareId(ShareCodeAspect.get()); + List list = shareService.listShareFile(req); + return JsonData.buildSuccess(list); + } + + + /** + * 文件转存 + */ + @PostMapping("transfer") + @ShareCodeCheck + public JsonData transfer(@RequestBody ShareFileTransferReq req){ + req.setShareId(ShareCodeAspect.get()); + req.setAccountId(LoginInterceptor.threadLocal.get().getId()); + shareService.transferShareFile(req); + return JsonData.buildSuccess(); + } + +} \ No newline at end of file diff --git a/src/main/java/org/ycloud/aipan/controller/req/ShareCancelReq.java b/src/main/java/org/ycloud/aipan/controller/req/ShareCancelReq.java new file mode 100644 index 0000000..fb44763 --- /dev/null +++ b/src/main/java/org/ycloud/aipan/controller/req/ShareCancelReq.java @@ -0,0 +1,14 @@ +package org.ycloud.aipan.controller.req; + +import lombok.Data; + +import java.util.List; + + +@Data +public class ShareCancelReq { + + private List shareIds; + + private Long accountId; +} \ No newline at end of file diff --git a/src/main/java/org/ycloud/aipan/controller/req/ShareCheckReq.java b/src/main/java/org/ycloud/aipan/controller/req/ShareCheckReq.java new file mode 100644 index 0000000..156e4b5 --- /dev/null +++ b/src/main/java/org/ycloud/aipan/controller/req/ShareCheckReq.java @@ -0,0 +1,11 @@ +package org.ycloud.aipan.controller.req; + +import lombok.Data; + +@Data +public class ShareCheckReq { + + private Long shareId; + + private String shareCode; +} \ No newline at end of file diff --git a/src/main/java/org/ycloud/aipan/controller/req/ShareCreateReq.java b/src/main/java/org/ycloud/aipan/controller/req/ShareCreateReq.java new file mode 100644 index 0000000..5987a55 --- /dev/null +++ b/src/main/java/org/ycloud/aipan/controller/req/ShareCreateReq.java @@ -0,0 +1,42 @@ +package org.ycloud.aipan.controller.req; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ShareCreateReq { + + /** + * 分享名称 + */ + private String shareName; + + + /** + * 分享类型,是否需要提取码 + */ + private String shareType; + + /** + * 分享有效天数0永久,1-7天,2-30天 + */ + private Integer shareDayType; + + /** + * 文件id列表 + */ + private List fileIds; + + /** + * 分享人id + */ + private Long accountId; + +} \ No newline at end of file diff --git a/src/main/java/org/ycloud/aipan/controller/req/ShareFileQueryReq.java b/src/main/java/org/ycloud/aipan/controller/req/ShareFileQueryReq.java new file mode 100644 index 0000000..b656ad3 --- /dev/null +++ b/src/main/java/org/ycloud/aipan/controller/req/ShareFileQueryReq.java @@ -0,0 +1,13 @@ +package org.ycloud.aipan.controller.req; + +import lombok.Data; + +@Data +public class ShareFileQueryReq { + private Long shareId; + + /** + * 进入的目标文件夹ID + */ + private Long parentId; +} \ No newline at end of file diff --git a/src/main/java/org/ycloud/aipan/controller/req/ShareFileTransferReq.java b/src/main/java/org/ycloud/aipan/controller/req/ShareFileTransferReq.java new file mode 100644 index 0000000..f6dd886 --- /dev/null +++ b/src/main/java/org/ycloud/aipan/controller/req/ShareFileTransferReq.java @@ -0,0 +1,24 @@ +package org.ycloud.aipan.controller.req; + +import lombok.Data; + +import java.util.List; + + +@Data +public class ShareFileTransferReq { + + private Long shareId; + + private Long accountId; + + /** + * 目标文件夹ID + */ + private Long parentId; + + /** + * 转存的文件ID + */ + private List fileIds; +} \ No newline at end of file diff --git a/src/main/java/org/ycloud/aipan/dto/ShareAccountDTO.java b/src/main/java/org/ycloud/aipan/dto/ShareAccountDTO.java new file mode 100644 index 0000000..e521aac --- /dev/null +++ b/src/main/java/org/ycloud/aipan/dto/ShareAccountDTO.java @@ -0,0 +1,15 @@ +package org.ycloud.aipan.dto; + +import lombok.Data; + + +@Data +public class ShareAccountDTO { + + private Long id; + + private String username; + + private String avatarUrl; + +} \ No newline at end of file diff --git a/src/main/java/org/ycloud/aipan/dto/ShareDTO.java b/src/main/java/org/ycloud/aipan/dto/ShareDTO.java new file mode 100644 index 0000000..8f3a227 --- /dev/null +++ b/src/main/java/org/ycloud/aipan/dto/ShareDTO.java @@ -0,0 +1,50 @@ +package org.ycloud.aipan.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +import java.io.Serializable; +import java.util.Date; + +@Getter +@Setter +@Schema(name = "ShareDTO", description = "用户分享对象") +public class ShareDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "分享id") + private Long id; + + @Schema(description = "分享名称") + private String shareName; + + @Schema(description = "分享类型(no_code没有提取码 ,need_code有提取码)") + private String shareType; + + @Schema(description = "分享类型(0 永久有效;1: 7天有效;2: 30天有效)") + private Integer shareDayType; + + @Schema(description = "分享有效天数(永久有效为0)") + private Integer shareDay; + + @Schema(description = "分享结束时间") + private Date shareEndTime; + + @Schema(description = "分享链接地址") + private String shareUrl; + + @Schema(description = "分享提取码") + private String shareCode; + + @Schema(description = "分享状态 used正常, expired已失效, cancled取消") + private String shareStatus; + + @Schema(description = "分享创建人") + private Long accountId; + + @Schema(description = "创建时间") + private Date gmtCreate; + +} diff --git a/src/main/java/org/ycloud/aipan/dto/ShareDetailDTO.java b/src/main/java/org/ycloud/aipan/dto/ShareDetailDTO.java new file mode 100644 index 0000000..3cc67c5 --- /dev/null +++ b/src/main/java/org/ycloud/aipan/dto/ShareDetailDTO.java @@ -0,0 +1,53 @@ +package org.ycloud.aipan.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +@Getter +@Setter +@Schema(name = "ShareDetailDTO", description = "分享链接详情对象") +@Accessors(chain = true) +public class ShareDetailDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "分享id") + private Long id; + + @Schema(description = "分享名称") + private String shareName; + + @Schema(description = "分享类型(no_code没有提取码 ,need_code有提取码)") + private String shareType; + + @Schema(description = "分享类型(0 永久有效;1: 7天有效;2: 30天有效)") + private Integer shareDayType; + + @Schema(description = "分享有效天数(永久有效为0)") + private Integer shareDay; + + @Schema(description = "分享结束时间") + private Date shareEndTime; + + @Schema(description = "分享链接地址") + private String shareUrl; + + + /** + * 分享者信息 + */ + private ShareAccountDTO shareAccountDTO; + + + /** + * 分享的文件信息 + */ + private List fileDTOList; + +} diff --git a/src/main/java/org/ycloud/aipan/dto/ShareSimpleDTO.java b/src/main/java/org/ycloud/aipan/dto/ShareSimpleDTO.java new file mode 100644 index 0000000..378a354 --- /dev/null +++ b/src/main/java/org/ycloud/aipan/dto/ShareSimpleDTO.java @@ -0,0 +1,51 @@ +package org.ycloud.aipan.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; + +@Getter +@Setter +@Schema(name = "ShareSimpleDTO", description = "分享链接简单对象") +@Accessors(chain = true) +public class ShareSimpleDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "分享id") + private Long id; + + @Schema(description = "分享名称") + private String shareName; + + @Schema(description = "分享类型(no_code没有提取码 ,need_code有提取码)") + private String shareType; + + @Schema(description = "分享类型(0 永久有效;1: 7天有效;2: 30天有效)") + private Integer shareDayType; + + @Schema(description = "分享有效天数(永久有效为0)") + private Integer shareDay; + + @Schema(description = "分享结束时间") + private Date shareEndTime; + + @Schema(description = "分享链接地址") + private String shareUrl; + + + /** + * 分享者信息 + */ + private ShareAccountDTO shareAccountDTO; + + /** + * 分享令牌,不需要校验码的时候才会有这个 + */ + private String shareToken; + +} diff --git a/src/main/java/org/ycloud/aipan/enums/BizCodeEnum.java b/src/main/java/org/ycloud/aipan/enums/BizCodeEnum.java index 8b8a794..bd4136b 100644 --- a/src/main/java/org/ycloud/aipan/enums/BizCodeEnum.java +++ b/src/main/java/org/ycloud/aipan/enums/BizCodeEnum.java @@ -34,7 +34,7 @@ public enum BizCodeEnum { FILE_BATCH_UPDATE_ERROR(270101,"文件批量操作错误" ), FILE_DIR_NOT_EXIST(270102,"用户的上级目录不存在" ), FILE_DIR_ERROR(270103,"用户的上级目录错误" ), - + SHARE_CANCELED( 260406, "分享已取消"), ; private final int code; private final String message; diff --git a/src/main/java/org/ycloud/aipan/enums/ShareDayTypeEnum.java b/src/main/java/org/ycloud/aipan/enums/ShareDayTypeEnum.java new file mode 100644 index 0000000..629686b --- /dev/null +++ b/src/main/java/org/ycloud/aipan/enums/ShareDayTypeEnum.java @@ -0,0 +1,39 @@ +package org.ycloud.aipan.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 分享链接的日期类型 + */ +@Getter +@AllArgsConstructor +public enum ShareDayTypeEnum { + + PERMANENT(0,0), + + SEVEN_DAYS(1,7), + + THIRTY_DAYS(2,30); + + + private Integer dayType; + + private Integer days; + + + /** + * 根据类型获取对应的天数 + */ + public static Integer getDaysByType(Integer dayType){ + for (ShareDayTypeEnum value : ShareDayTypeEnum.values()) { + if(value.getDayType().equals(dayType)){ + return value.getDays(); + } + } + //默认是7天有效 + return SEVEN_DAYS.days; + } + + +} diff --git a/src/main/java/org/ycloud/aipan/enums/ShareStatusEnum.java b/src/main/java/org/ycloud/aipan/enums/ShareStatusEnum.java new file mode 100644 index 0000000..8640897 --- /dev/null +++ b/src/main/java/org/ycloud/aipan/enums/ShareStatusEnum.java @@ -0,0 +1,22 @@ +package org.ycloud.aipan.enums; + +/** + * 分享状态 + */ +public enum ShareStatusEnum { + + /** + * 已使用 + */ + USED, + + /** + * 已过期 + */ + EXPIRED, + + /** + * 已取消 + */ + CANCELED; +} diff --git a/src/main/java/org/ycloud/aipan/enums/ShareTypeEnum.java b/src/main/java/org/ycloud/aipan/enums/ShareTypeEnum.java new file mode 100644 index 0000000..6d09fea --- /dev/null +++ b/src/main/java/org/ycloud/aipan/enums/ShareTypeEnum.java @@ -0,0 +1,18 @@ +package org.ycloud.aipan.enums; + +import lombok.Getter; + +@Getter +public enum ShareTypeEnum { + + /** + * 无码 + */ + NO_CODE, + + /** + * 需要码 + */ + NEED_CODE; + +} diff --git a/src/main/java/org/ycloud/aipan/mapper/ShareFileMapper.java b/src/main/java/org/ycloud/aipan/mapper/ShareFileMapper.java index 499441d..7335be0 100644 --- a/src/main/java/org/ycloud/aipan/mapper/ShareFileMapper.java +++ b/src/main/java/org/ycloud/aipan/mapper/ShareFileMapper.java @@ -3,6 +3,8 @@ package org.ycloud.aipan.mapper; import org.ycloud.aipan.model.ShareFileDO; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import java.util.List; + /** *

* 文件分享表 Mapper 接口 @@ -12,5 +14,5 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; * @since 2025-02-12 */ public interface ShareFileMapper extends BaseMapper { - + void insertBatch(List shareFileDOS); } diff --git a/src/main/java/org/ycloud/aipan/model/ShareDO.java b/src/main/java/org/ycloud/aipan/model/ShareDO.java index 336d3c1..ebc005c 100644 --- a/src/main/java/org/ycloud/aipan/model/ShareDO.java +++ b/src/main/java/org/ycloud/aipan/model/ShareDO.java @@ -7,8 +7,10 @@ import com.baomidou.mybatisplus.annotation.TableName; import java.io.Serializable; import java.util.Date; import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; import lombok.Getter; import lombok.Setter; +import lombok.experimental.Accessors; /** *

@@ -22,6 +24,7 @@ import lombok.Setter; @Setter @TableName("share") @Schema(name = "ShareDO", description = "用户分享表") +@Builder public class ShareDO implements Serializable { private static final long serialVersionUID = 1L; diff --git a/src/main/java/org/ycloud/aipan/model/ShareFileDO.java b/src/main/java/org/ycloud/aipan/model/ShareFileDO.java index b0540d2..6b0b4bb 100644 --- a/src/main/java/org/ycloud/aipan/model/ShareFileDO.java +++ b/src/main/java/org/ycloud/aipan/model/ShareFileDO.java @@ -7,8 +7,10 @@ import com.baomidou.mybatisplus.annotation.TableName; import java.io.Serializable; import java.util.Date; import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; import lombok.Getter; import lombok.Setter; +import lombok.experimental.Accessors; /** *

@@ -22,6 +24,7 @@ import lombok.Setter; @Setter @TableName("share_file") @Schema(name = "ShareFileDO", description = "文件分享表") +@Builder public class ShareFileDO implements Serializable { private static final long serialVersionUID = 1L; diff --git a/src/main/java/org/ycloud/aipan/model/StorageDO.java b/src/main/java/org/ycloud/aipan/model/StorageDO.java index cc72f24..d42c132 100644 --- a/src/main/java/org/ycloud/aipan/model/StorageDO.java +++ b/src/main/java/org/ycloud/aipan/model/StorageDO.java @@ -9,6 +9,7 @@ import java.util.Date; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +import lombok.experimental.Accessors; /** *

@@ -22,6 +23,7 @@ import lombok.Setter; @Setter @TableName("storage") @Schema(name = "StorageDO", description = "存储信息表") +@Accessors(chain = true) public class StorageDO implements Serializable { private static final long serialVersionUID = 1L; diff --git a/src/main/java/org/ycloud/aipan/service/AccountFileService.java b/src/main/java/org/ycloud/aipan/service/AccountFileService.java index 9d6aedf..80c6803 100644 --- a/src/main/java/org/ycloud/aipan/service/AccountFileService.java +++ b/src/main/java/org/ycloud/aipan/service/AccountFileService.java @@ -4,6 +4,7 @@ package org.ycloud.aipan.service; import org.ycloud.aipan.controller.req.*; import org.ycloud.aipan.dto.AccountFileDTO; import org.ycloud.aipan.dto.FolderTreeNodeDTO; +import org.ycloud.aipan.model.AccountFileDO; import java.util.List; @@ -12,6 +13,7 @@ public interface AccountFileService { * 获取文件列表 */ List listFile(Long accountId, Long parentId); + /** * 创建文件夹 */ @@ -22,9 +24,10 @@ public interface AccountFileService { * 1、检查ID是否存在 * 2、新旧文件名称不能一样 * 3、同层文件名称不能一样 + * * @param req */ - void renameFile(FileUpdateReq req); + void renameFile(FileUpdateReq req); /** * 查询文件树接口 (非递归方式) @@ -73,6 +76,28 @@ public interface AccountFileService { */ Boolean secondUpload(FileSecondUploadReq req); - + /** + * 保存文件和账号文件的关系到数据库 + */ void saveFileAndAccountFile(FileUploadReq req, String storeFileObjectKey); + + /** + * 检查被移动的文件ID是否合法 + */ + List checkFileIdLegal(List fileIds, Long accountId); + + /** + * 包括递归处理,生成新的ID + */ + List findBatchCopyFileWithRecur(List accountFileDOList, Long targetParentId); + + /** + * 检查存储空间和更新存储空间 + */ + boolean checkAndUpdateCapacity(Long accountId, Long fileSize); + + /** + * 递归查找 + */ + void findAllAccountFileDOWithRecur(List allAccountFileDOList, List prepareAccountFileDOList, boolean onlyFolder); } diff --git a/src/main/java/org/ycloud/aipan/service/ShareService.java b/src/main/java/org/ycloud/aipan/service/ShareService.java new file mode 100644 index 0000000..6904b04 --- /dev/null +++ b/src/main/java/org/ycloud/aipan/service/ShareService.java @@ -0,0 +1,29 @@ +package org.ycloud.aipan.service; + + +import org.ycloud.aipan.controller.req.*; +import org.ycloud.aipan.dto.AccountFileDTO; +import org.ycloud.aipan.dto.ShareDTO; +import org.ycloud.aipan.dto.ShareDetailDTO; +import org.ycloud.aipan.dto.ShareSimpleDTO; + +import java.util.List; + +public interface ShareService { + + List listShare(); + + ShareDTO createShare(ShareCreateReq req); + + void cancelShare(ShareCancelReq req); + + ShareSimpleDTO simpleDetail(Long shareId); + + String checkShareCode(ShareCheckReq req); + + ShareDetailDTO detail(Long shareId); + + List listShareFile(ShareFileQueryReq req); + + void transferShareFile(ShareFileTransferReq req); +} diff --git a/src/main/java/org/ycloud/aipan/service/impl/AccountFileServiceImpl.java b/src/main/java/org/ycloud/aipan/service/impl/AccountFileServiceImpl.java index fa5e4bf..affdb4a 100644 --- a/src/main/java/org/ycloud/aipan/service/impl/AccountFileServiceImpl.java +++ b/src/main/java/org/ycloud/aipan/service/impl/AccountFileServiceImpl.java @@ -363,7 +363,8 @@ public class AccountFileServiceImpl implements AccountFileService { * @param accountId * @return */ - private List checkFileIdLegal(List fileIds, Long accountId) { + @Override + public List checkFileIdLegal(List fileIds, Long accountId) { List accountFileDOList = accountFileMapper .selectList(new QueryWrapper().in("id", fileIds).eq("account_id", accountId)); @@ -500,6 +501,7 @@ public class AccountFileServiceImpl implements AccountFileService { * @param prepareAccountFileDOList 待查询的文件和文件夹 * @param onlyFolder 控制是否只存储文件 */ + @Override public void findAllAccountFileDOWithRecur(List allAccountFileDOList, List prepareAccountFileDOList, boolean onlyFolder) { for (AccountFileDO accountFileDO : prepareAccountFileDOList) { @@ -523,6 +525,7 @@ public class AccountFileServiceImpl implements AccountFileService { * @param targetParentId * @return */ + @Override public List findBatchCopyFileWithRecur(List accountFileDOList, Long targetParentId) { List newAccountFileDOList = new ArrayList<>(); accountFileDOList.forEach(accountFileDO -> doCopyChildRecord(newAccountFileDOList, accountFileDO, targetParentId)); @@ -584,6 +587,7 @@ public class AccountFileServiceImpl implements AccountFileService { * @param fileSize * @return */ + @Override public boolean checkAndUpdateCapacity(Long accountId, Long fileSize) { StorageDO storageDO = storageMapper.selectOne(new QueryWrapper().eq("account_id", accountId)); Long totalSize = storageDO.getTotalSize(); diff --git a/src/main/java/org/ycloud/aipan/service/impl/ShareServiceImpl.java b/src/main/java/org/ycloud/aipan/service/impl/ShareServiceImpl.java new file mode 100644 index 0000000..78333fb --- /dev/null +++ b/src/main/java/org/ycloud/aipan/service/impl/ShareServiceImpl.java @@ -0,0 +1,390 @@ +package org.ycloud.aipan.service.impl; + +import cn.hutool.core.util.IdUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.extern.slf4j.Slf4j; +import org.ycloud.aipan.config.AccountConfig; +import org.ycloud.aipan.controller.req.*; +import org.ycloud.aipan.dto.*; +import org.ycloud.aipan.enums.BizCodeEnum; +import org.ycloud.aipan.enums.ShareDayTypeEnum; +import org.ycloud.aipan.enums.ShareStatusEnum; +import org.ycloud.aipan.enums.ShareTypeEnum; +import org.ycloud.aipan.exception.BizException; +import org.ycloud.aipan.interceptor.LoginInterceptor; +import org.ycloud.aipan.mapper.AccountFileMapper; +import org.ycloud.aipan.mapper.AccountMapper; +import org.ycloud.aipan.mapper.ShareFileMapper; +import org.ycloud.aipan.mapper.ShareMapper; +import org.ycloud.aipan.model.AccountDO; +import org.ycloud.aipan.model.AccountFileDO; +import org.ycloud.aipan.model.ShareDO; +import org.ycloud.aipan.model.ShareFileDO; +import org.ycloud.aipan.service.AccountFileService; +import org.ycloud.aipan.service.ShareService; +import org.ycloud.aipan.util.JwtUtil; +import org.ycloud.aipan.util.SpringBeanUtil; +import org.apache.commons.lang3.RandomStringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.*; +import java.util.stream.Collectors; + + +@Service +@Slf4j +public class ShareServiceImpl implements ShareService { + + @Autowired + private ShareMapper shareMapper; + + @Autowired + private ShareFileMapper shareFileMapper; + + @Autowired + private AccountFileService fileService; + + @Autowired + private AccountMapper accountMapper; + + @Autowired + private AccountFileMapper accountFileMapper; + + + @Override + public List listShare() { + AccountDTO accountDTO = LoginInterceptor.threadLocal.get(); + List shareDOList = shareMapper.selectList(new QueryWrapper().eq("account_id", accountDTO.getId()).orderByDesc("gmt_create")); + return SpringBeanUtil.copyProperties(shareDOList, ShareDTO.class); + } + + /** + * * 检查分享文件的权限 + * * 生成分享链接和持久化数据库 + * * 生成分享详情和持久化数据库 + * @param req + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public ShareDTO createShare(ShareCreateReq req) { + + //1、检查分享文件的权限 + List fileIds = req.getFileIds(); + fileService.checkFileIdLegal(fileIds, req.getAccountId()); + + //2、生成分享链接和持久化数据库 + Integer dayType = req.getShareDayType(); + Integer shareDays = ShareDayTypeEnum.getDaysByType(dayType); + Long shareId = IdUtil.getSnowflakeNextId(); + //生成分享链接 + String shareUrl = AccountConfig.PAN_FRONT_DOMAIN_SHARE_API + shareId; + log.info("shareUrl:{}",shareUrl); + ShareDO shareDO = ShareDO.builder() + .id(shareId) + .shareName(req.getShareName()) + .shareType(ShareTypeEnum.valueOf(req.getShareType()).name()) + .shareDayType(dayType) + .shareDay(shareDays) + .shareUrl(shareUrl) + .shareStatus(ShareStatusEnum.USED.name()) + .accountId(req.getAccountId()).build(); + + if(ShareDayTypeEnum.PERMANENT.getDayType().equals(dayType)){ + shareDO.setShareEndTime(Date.from(LocalDate.of(9999,12,31) + .atStartOfDay(ZoneId.systemDefault()).toInstant())); + }else { + shareDO.setShareEndTime(new Date(System.currentTimeMillis() + shareDays * 24 * 3600 * 1000L)); + } + if(ShareTypeEnum.NEED_CODE.name().equalsIgnoreCase(req.getShareType())){ + //生成提取码 6位 + String shareCode = RandomStringUtils.randomAlphabetic(6).toUpperCase(); + shareDO.setShareCode(shareCode); + } + shareMapper.insert(shareDO); + + //3、生成分享详情和持久化数据库 + List shareFileDOS = new ArrayList<>(); + fileIds.forEach(fileId -> { + ShareFileDO shareFileDO = ShareFileDO.builder() + .shareId(shareId) + .accountFileId(fileId) + .accountId(req.getAccountId()) + .build(); + shareFileDOS.add(shareFileDO); + }); + shareFileMapper.insertBatch(shareFileDOS); + return SpringBeanUtil.copyProperties(shareDO, ShareDTO.class); + } + + @Override + public void cancelShare(ShareCancelReq req) { + List shareDOList = shareMapper.selectList(new QueryWrapper().eq("account_id", req.getAccountId()).in("id", req.getShareIds())); + if(shareDOList.size() != req.getShareIds().size()){ + log.error("cancelShare,shareIds:{}",req.getShareIds()); + throw new BizException(BizCodeEnum.SHARE_CANCEL_ILLEGAL); + } + // 删除分享链接 + shareMapper.deleteBatchIds(req.getShareIds()); + //删除分享详情 + shareFileMapper.delete(new QueryWrapper().in("share_id", req.getShareIds())); + + } + + /** + * * 检查分享状态 + * * 查询分享记录实体 + * * 查询分享者信息 + * * 判断是否需要生成校验码,不需要的话可以直接生成分享token + * @param shareId + * @return + */ + @Override + public ShareSimpleDTO simpleDetail(Long shareId) { + // 检查分享状态 + ShareDO shareDO = checkShareStatus(shareId); + ShareSimpleDTO shareSimpleDTO = SpringBeanUtil.copyProperties(shareDO, ShareSimpleDTO.class); + //查询分享者信息 + ShareAccountDTO shareAccountDTO = getShareAccount(shareDO.getAccountId()); + shareSimpleDTO.setShareAccountDTO(shareAccountDTO); + //判断是否需要校验码 + if(ShareTypeEnum.NO_CODE.name().equalsIgnoreCase(shareDO.getShareType())){ + //直接生成分享token + String shareToken = JwtUtil.geneShareJWT(shareDO.getId()); + shareSimpleDTO.setShareToken(shareToken); + } + return shareSimpleDTO; + } + + @Override + public String checkShareCode(ShareCheckReq req) { + ShareDO shareDO = shareMapper.selectOne(new QueryWrapper().eq("id", req.getShareId()).eq("share_code", req.getShareCode()).eq("share_status", ShareStatusEnum.USED.name())); + if(shareDO != null){ + //判断是否过期 + if(shareDO.getShareEndTime().getTime() > System.currentTimeMillis()){ + //生成分享token + return JwtUtil.geneShareJWT(shareDO.getId()); + }else { + log.error("分享链接已失效:{}",req.getShareId()); + throw new BizException(BizCodeEnum.SHARE_EXPIRED); + } + } + return null; + } + + /** + * 分享详情接口 + * * 查询分享记录实体 + * * 检查分享状态 + * * 查询分享文件信息 + * * 查询分享者信息 + * * 构造分析详情对象返回 + * @param shareId + * @return + */ + @Override + public ShareDetailDTO detail(Long shareId) { + //查询分享记录实体 + ShareDO shareDO = checkShareStatus(shareId); + ShareDetailDTO shareDetailDTO = SpringBeanUtil.copyProperties(shareDO, ShareDetailDTO.class); + + //查询分享文件信息 + List accountFileDOList = getShareFileInfo(shareId); + List accountFileDTOList = SpringBeanUtil.copyProperties(accountFileDOList, AccountFileDTO.class); + shareDetailDTO.setFileDTOList(accountFileDTOList); + + //查询分享者信息 + ShareAccountDTO shareAccountDTO = getShareAccount(shareDO.getAccountId()); + shareDetailDTO.setShareAccountDTO(shareAccountDTO); + return shareDetailDTO; + } + + /** + * * 检查分享链接状态 + * * 查询分享ID是否在分享的文件列表中(需要获取分享文件列表的全部文件夹和子文件夹) + * * 分组后获取某个文件夹下面所有的子文件夹 + * * 根据父文件夹ID获取子文件夹列表 + * @param req + * @return + */ + @Override + public List listShareFile(ShareFileQueryReq req) { + //检查分享链接状态 + ShareDO shareDO = checkShareStatus(req.getShareId()); + + //查询分享ID是否在分享的文件列表中(需要获取分享文件列表的全部文件夹和子文件夹) + List accountFileDOList = checkShareFileIdOnStatus(shareDO.getId(), List.of(req.getParentId())); + + List accountFileDTOList = SpringBeanUtil.copyProperties(accountFileDOList, AccountFileDTO.class); + + //分组后获取某个文件夹下面所有的子文件夹 + Map> fileListMap = accountFileDTOList.stream() + .collect(Collectors.groupingBy(AccountFileDTO::getParentId)); + + //根据父文件夹ID获取子文件夹列表 + List childFileList = fileListMap.get(req.getParentId()); + + if(CollectionUtils.isEmpty(childFileList)){ + return List.of(); + } + + return childFileList; + } + + + /** + * * 分享链接是否状态准确 + * * 转存的文件是否是分享链接里面的文件 + * * 目标文件夹是否是当前用户的 + * * 获取转存的文件 + * * 保存需要转存的文件列表(递归子文件) + * * 同步更新所有文件的accountId为当前用户的id + * * 计算存储空间大小,检查是否足够 + * * 更新关联对象信息,存储文件映射关系 + * @param req + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void transferShareFile(ShareFileTransferReq req) { + + //分享链接是否状态准确 + checkShareStatus(req.getShareId()); + + //转存的文件是否是分享链接里面的文件 + checkInShareFiles(req.getFileIds(),req.getShareId()); + + //目标文件夹是否是当前用户的 + AccountFileDO currentAccountDO = accountFileMapper.selectOne(new QueryWrapper() + .eq("id", req.getParentId()).eq("account_id", req.getAccountId())); + if(currentAccountDO == null){ + log.error("目标文件夹不是当前用户的,{}",req); + throw new BizException(BizCodeEnum.FILE_NOT_EXISTS); + } + + //获取转存的文件 + List shareFileList = accountFileMapper.selectBatchIds(req.getFileIds()); + //保存需要转存的文件列表(递归子文件) + List batchTransferFileList = fileService.findBatchCopyFileWithRecur(shareFileList, req.getParentId()); + + //同步更新所有文件的accountId为当前用户的id + batchTransferFileList.forEach(file -> { + file.setAccountId(req.getAccountId()); + }); + + //计算存储空间大小,检查是否足够 + if(!fileService.checkAndUpdateCapacity(req.getAccountId(),batchTransferFileList.stream() + .map(accountFileDO -> accountFileDO.getFileSize() == null ? 0 : accountFileDO.getFileSize()) + .mapToLong(Long::valueOf).sum())){ + throw new BizException(BizCodeEnum.FILE_STORAGE_NOT_ENOUGH); + } + //更新关联对象信息,存储文件映射关系 + accountFileMapper.insertFileBatch(batchTransferFileList); + + + } + + private void checkInShareFiles(List fileIds, Long shareId) { + + //获取分享链接的文件 + List shareFileDOS = shareFileMapper.selectList(new QueryWrapper().eq("share_id", shareId)); + List shareFileIds = shareFileDOS.stream().map(ShareFileDO::getAccountFileId).toList(); + //找文件实体 + List shareAccountFileDOList = accountFileMapper.selectBatchIds(shareFileIds); + //递归找分享链接里面的所有子文件 + List allShareFiles = new ArrayList<>(); + fileService.findAllAccountFileDOWithRecur(allShareFiles, shareAccountFileDOList, false); + //提取全部文件的ID + List allShareFileIds = allShareFiles.stream().map(AccountFileDO::getId).toList(); + + //判断要转存的文件是否在里面 + for (Long fileId : fileIds) { + if(!allShareFileIds.contains(fileId)){ + log.error("文件不在分享链接里面,fileId:{}",fileId); + throw new BizException(BizCodeEnum.SHARE_FILE_ILLEGAL); + } + } + + } + + /** + * 返回分享的文件列表,包括子文件 + * @param shareId + * @param fileIdList + * @return + */ + private List checkShareFileIdOnStatus(Long shareId, List fileIdList) { + //需要获取分享文件列表的全部文件夹和子文件内容 + List shareFileInfoList = getShareFileInfo(shareId); + List allAccountFileDOList = new ArrayList<>(); + //获取全部文件,递归 + fileService.findAllAccountFileDOWithRecur(allAccountFileDOList, shareFileInfoList, false); + + if(CollectionUtils.isEmpty(allAccountFileDOList)){ + return List.of(); + } + + //把分享的对象文件的全部文件夹放到集合里面,判断目标文件集合是否都在里面 + Set allFileIdSet = allAccountFileDOList.stream().map(AccountFileDO::getId).collect(Collectors.toSet()); + if(!allFileIdSet.containsAll(fileIdList)){ + log.error("目标文件ID列表 不再 分享的文件列表中,{}",fileIdList); + throw new BizException(BizCodeEnum.SHARE_FILE_ILLEGAL); + } + return allAccountFileDOList; + } + + private List getShareFileInfo(Long shareId) { + + //找分享文件列表 + List shareFileDOS = shareFileMapper.selectList(new QueryWrapper().select("account_file_id") + .eq("share_id", shareId)); + List shareFileIdList = shareFileDOS.stream().map(ShareFileDO::getAccountFileId).toList(); + + //查找文件对象 + return accountFileMapper.selectBatchIds(shareFileIdList); + } + + /** + * 获取分享者信息 + * @param accountId + * @return + */ + private ShareAccountDTO getShareAccount(Long accountId) { + if(accountId != null){ + AccountDO accountDO = accountMapper.selectById(accountId); + if(accountDO != null){ + return SpringBeanUtil.copyProperties(accountDO, ShareAccountDTO.class); + } + } + return null; + } + + /** + * 检查分享状态 + * @param shareId + * @return + */ + private ShareDO checkShareStatus(Long shareId) { + ShareDO shareDO = shareMapper.selectById(shareId); + + if(shareDO == null){ + log.error("分享链接不存在:{}",shareId); + throw new BizException(BizCodeEnum.SHARE_NOT_EXIST); + } + //暂时未用,直接物理删除,可以调整 + if(ShareStatusEnum.CANCELED.name().equalsIgnoreCase(shareDO.getShareStatus())){ + log.error("分享链接已取消:{}",shareId); + throw new BizException(BizCodeEnum.SHARE_CANCELED); + } + //判断分享是否过期 + if(shareDO.getShareEndTime().before(new Date())){ + log.error("分享链接已过期:{}",shareId); + throw new BizException(BizCodeEnum.SHARE_EXPIRED); + } + return shareDO; + } +} \ No newline at end of file diff --git a/src/main/java/org/ycloud/aipan/util/JwtUtil.java b/src/main/java/org/ycloud/aipan/util/JwtUtil.java index 5e923e4..1b9f671 100644 --- a/src/main/java/org/ycloud/aipan/util/JwtUtil.java +++ b/src/main/java/org/ycloud/aipan/util/JwtUtil.java @@ -17,6 +17,14 @@ public class JwtUtil { // JWT的主题 private static final String LOGIN_SUBJECT = "YUAN"; + //分享主题 + private static final String SHARE_SUBJECT = "YUAN_SHARE"; + + //分享ID + public static final String CLAIM_SHARE_KEY = "SHARE_ID"; + + //分享token过期时间,1小时 + private static final long SHARE_TOKEN_EXPIRE = 1000 * 60 * 60; //注意这个密钥长度需要足够长, 推荐:JWT的密钥,从环境变量中获取 private final static String SECRET_KEY = "yuan.yuannet.netyuan.password.3421.sdfnet.com.efszyuaszgh"; @@ -118,4 +126,51 @@ public class JwtUtil { } return token; } + /** + * 创建分享的令牌 + */ + public static String geneShareJWT( Object claimValue) { + + // 创建 JWT token + String compact = Jwts.builder() + .subject(SHARE_SUBJECT) + .claim(CLAIM_SHARE_KEY, claimValue) + .issuedAt(new Date()) + .expiration(new Date(System.currentTimeMillis() + SHARE_TOKEN_EXPIRE)) + .signWith(KEY, ALGORITHM) // 直接使用KEY即可 + .compact(); + return compact; + } + + /** + * 创建分享的令牌 + */ + public static Claims checkShareJWT(String token) { + try { + log.debug("开始校验 Share JWT: {}", token); + // 校验 Token 是否为空 + if (token == null || token.trim().isEmpty()) { + log.error("Share Token 不能为空"); + return null; + } + token = token.trim(); + // 解析 JWT + Claims payload = Jwts.parser() + .verifyWith(KEY) //设置签名的密钥, 使用相同的 KEY + .build() + .parseSignedClaims(token).getPayload(); + + log.info("Share JWT 解密成功,Claims: {}", payload); + return payload; + } catch (IllegalArgumentException e) { + log.error("JWT 校验失败: {}", e.getMessage(), e); + } catch (io.jsonwebtoken.security.SignatureException e) { + log.error("JWT 签名验证失败: {}", e.getMessage(), e); + } catch (io.jsonwebtoken.ExpiredJwtException e) { + log.error("JWT 已过期: {}", e.getMessage(), e); + } catch (Exception e) { + log.error("JWT 解密失败: {}", e.getMessage(), e); + } + return null; + } } \ No newline at end of file diff --git a/src/main/resources/mapper/ShareFileMapper.xml b/src/main/resources/mapper/ShareFileMapper.xml index f76180f..ae31a32 100644 --- a/src/main/resources/mapper/ShareFileMapper.xml +++ b/src/main/resources/mapper/ShareFileMapper.xml @@ -16,5 +16,11 @@ id, share_id, account_file_id, account_id, gmt_create, gmt_modified + + insert into share_file (id,share_id, account_file_id, account_id) values + + (#{item.id},#{item.shareId},#{item.accountFileId},#{item.accountId}) + +