diff --git a/README.md b/README.md index 47a394c..34b7663 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,7 @@

- - ZFile - -

+ +![zfile](https://cdn.jun6.net/uPic/2022/09/04/zfile-header.png) + 基于 Java 的在线网盘程序,支持对接 S3、OneDrive、SharePoint、又拍云、本地存储、FTP、SFTP 等存储源,支持在线浏览图片、播放音视频,文本文件、Office、obj(3d)等文件类型。

license diff --git a/src/main/java/im/zhaojun/zfile/ZfileApplication.java b/src/main/java/im/zhaojun/zfile/ZfileApplication.java index 0f3cacf..40e7cac 100644 --- a/src/main/java/im/zhaojun/zfile/ZfileApplication.java +++ b/src/main/java/im/zhaojun/zfile/ZfileApplication.java @@ -6,16 +6,18 @@ import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.EnableAspectJAutoProxy; + +/** + * @author zhaojun + */ @SpringBootApplication @EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true) -@ServletComponentScan(basePackages = "im.zhaojun.zfile.*.filter") +@ServletComponentScan(basePackages = {"im.zhaojun.zfile.core.filter", "im.zhaojun.zfile.module.storage.filter"}) @ComponentScan(basePackages = "im.zhaojun.zfile.*") public class ZfileApplication { - public static void main(String[] args) { SpringApplication.run(ZfileApplication.class, args); } - } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/controller/CacheController.java b/src/main/java/im/zhaojun/zfile/admin/controller/CacheController.java deleted file mode 100644 index a26311b..0000000 --- a/src/main/java/im/zhaojun/zfile/admin/controller/CacheController.java +++ /dev/null @@ -1,108 +0,0 @@ -package im.zhaojun.zfile.admin.controller; - -import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; -import com.github.xiaoymin.knife4j.annotations.ApiSort; -import im.zhaojun.zfile.home.model.dto.CacheInfoDTO; -import im.zhaojun.zfile.admin.service.StorageSourceService; -import im.zhaojun.zfile.common.util.AjaxJson; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import javax.annotation.Resource; - -/** - * 存储源缓存维护接口 - * - * @author zhaojun - */ -@RestController -@Api(tags = "存储源模块-缓存") -@ApiSort(5) -@RequestMapping("/admin/cache") -public class CacheController { - - @Resource - private StorageSourceService storageSourceService; - - @ApiOperationSupport(order = 1) - @ApiOperation(value = "启用存储源缓存", notes = "开启缓存后,N 秒内重复请求相同文件夹,不会重复调用 API。" + - "参数 N 在配置文件中设置 {zfile.cache.timeout},默认为 1800 秒。") - @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true) - @PostMapping("/{storageId}/enable") - public AjaxJson enableCache(@PathVariable("storageId") Integer storageId) { - storageSourceService.updateCacheStatus(storageId, true); - return AjaxJson.getSuccess(); - } - - - @ApiOperationSupport(order = 2) - @ApiOperation(value = "禁用存储源缓存") - @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true) - @PostMapping("/{storageId}/disable") - public AjaxJson disableCache(@PathVariable("storageId") Integer storageId) { - storageSourceService.updateCacheStatus(storageId, false); - return AjaxJson.getSuccess(); - } - - - @ApiOperationSupport(order = 3) - @ApiOperation(value = "查看存储源缓存", notes = "可查看存储源缓存的所有目录路径") - @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true) - @GetMapping("/{storageId}/info") - public AjaxJson cacheInfo(@PathVariable("storageId") Integer storageId) { - CacheInfoDTO cacheInfo = storageSourceService.findCacheInfo(storageId); - return AjaxJson.getSuccessData(cacheInfo); - } - - - @ApiOperationSupport(order = 4) - @ApiOperation(value = "刷新存储源缓存", notes = "刷新存储源缓存路径,系统会重新预热此路径的内容") - @ApiImplicitParams({ - @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true), - @ApiImplicitParam(paramType = "body", name = "key", value = "缓存 key", required = true) - }) - @PostMapping("/{storageId}/refresh") - public AjaxJson refreshCache(@PathVariable("storageId") Integer storageId, String key) throws Exception { - storageSourceService.refreshCache(storageId, key); - return AjaxJson.getSuccess(); - } - - - @ApiOperationSupport(order = 5) - @ApiOperation(value = "开启缓存自动刷新", notes = "开启后每隔 N 秒检测到期的缓存, 对于过期缓存尝试调用 API, 重新写入缓存." + - "参数 N 在配置文件中设置 {zfile.cache.auto-refresh-interval},默认为 5 秒。") - @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true) - @PostMapping("/{storageId}/auto-refresh/start") - public AjaxJson enableAutoRefresh(@PathVariable("storageId") Integer storageId) { - storageSourceService.startAutoCacheRefresh(storageId); - return AjaxJson.getSuccess(); - } - - - @ApiOperationSupport(order = 5) - @ApiOperation(value = "关闭缓存自动刷新") - @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true) - @PostMapping("/{storageId}/auto-refresh/stop") - public AjaxJson disableAutoRefresh(@PathVariable("storageId") Integer storageId) { - storageSourceService.stopAutoCacheRefresh(storageId); - return AjaxJson.getSuccess(); - } - - - @ApiOperationSupport(order = 6) - @ApiOperation(value = "清空缓存") - @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true) - @PostMapping("/{storageId}/clear") - public AjaxJson clearCache(@PathVariable("storageId") Integer storageId) { - storageSourceService.clearCache(storageId); - return AjaxJson.getSuccess(); - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/controller/link/DownloadLogManagerController.java b/src/main/java/im/zhaojun/zfile/admin/controller/link/DownloadLogManagerController.java deleted file mode 100644 index 7b068a0..0000000 --- a/src/main/java/im/zhaojun/zfile/admin/controller/link/DownloadLogManagerController.java +++ /dev/null @@ -1,150 +0,0 @@ -package im.zhaojun.zfile.admin.controller.link; - -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.OrderItem; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; -import com.github.xiaoymin.knife4j.annotations.ApiSort; -import im.zhaojun.zfile.admin.convert.DownloadLogConvert; -import im.zhaojun.zfile.admin.model.entity.DownloadLog; -import im.zhaojun.zfile.admin.model.entity.StorageSource; -import im.zhaojun.zfile.admin.model.request.link.BatchDeleteRequest; -import im.zhaojun.zfile.admin.model.request.link.QueryDownloadLogRequest; -import im.zhaojun.zfile.admin.model.result.link.DownloadLogResult; -import im.zhaojun.zfile.admin.service.DownloadLogService; -import im.zhaojun.zfile.admin.service.StorageSourceService; -import im.zhaojun.zfile.common.util.AjaxJson; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import javax.annotation.Resource; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Stream; - -/** - * 直链下载日志接口 - * - * @author zhaojun - */ -@Api(tags = "直链日志管理") -@ApiSort(7) -@Controller -@RequestMapping("/admin/download/log") -public class DownloadLogManagerController { - - @Resource - private StorageSourceService storageSourceService; - - @Resource - private DownloadLogConvert downloadLogConvert; - - @Resource - private DownloadLogService downloadLogService; - - @ApiOperationSupport(order = 1) - @GetMapping("/list") - @ApiOperation(value = "直链下载日志") - @ResponseBody - @ApiImplicitParams({ - @ApiImplicitParam(paramType = "query", name = "key", value = "直链 key"), - @ApiImplicitParam(paramType = "query", name = "page", value = "分页页数"), - @ApiImplicitParam(paramType = "query", name = "limit", value = "每页条数"), - @ApiImplicitParam(paramType = "query", name = "orderBy", defaultValue = "createDate", value = "排序字段"), - @ApiImplicitParam(paramType = "query", name = "orderDirection", defaultValue = "desc", value = "排序顺序") - }) - public AjaxJson list(QueryDownloadLogRequest queryDownloadLogRequest, - @RequestParam(required = false, defaultValue = "create_time") String orderBy, - @RequestParam(required = false, defaultValue = "desc") String orderDirection) { - Page pages = Page.of(queryDownloadLogRequest.getPage(), queryDownloadLogRequest.getLimit()); - boolean asc = Objects.equals(orderDirection, "asc"); - pages.addOrder(new OrderItem(orderBy, asc)); - - DownloadLog downloadLog = new DownloadLog(); - QueryWrapper queryWrapper = new QueryWrapper<>(downloadLog); - - if (StrUtil.isNotEmpty(queryDownloadLogRequest.getStorageKey())) { - queryWrapper.eq("storage_key", queryDownloadLogRequest.getStorageKey()); - } - if (StrUtil.isNotEmpty(queryDownloadLogRequest.getPath())) { - queryWrapper.like("path", queryDownloadLogRequest.getPath()); - } - if (StrUtil.isNotEmpty(queryDownloadLogRequest.getShortKey())) { - queryWrapper.like("short_key", queryDownloadLogRequest.getShortKey()); - } - if (StrUtil.isNotEmpty(queryDownloadLogRequest.getIp())) { - queryWrapper.like("ip", queryDownloadLogRequest.getIp()); - } - if (StrUtil.isNotEmpty(queryDownloadLogRequest.getReferer())) { - queryWrapper.like("referer", queryDownloadLogRequest.getReferer()); - } - if (StrUtil.isNotEmpty(queryDownloadLogRequest.getUserAgent())) { - queryWrapper.like("user_agent", queryDownloadLogRequest.getUserAgent()); - } - if (ObjectUtil.isNotEmpty(queryDownloadLogRequest.getDateFrom())) { - queryWrapper.ge("create_time", queryDownloadLogRequest.getDateFrom()); - } - if (ObjectUtil.isNotEmpty(queryDownloadLogRequest.getDateTo())) { - queryWrapper.le("create_time", queryDownloadLogRequest.getDateFrom()); - } - Page selectResult = downloadLogService.page(pages, queryWrapper); - - long total = selectResult.getTotal(); - List records = selectResult.getRecords(); - - Map cache = new HashMap<>(); - - Stream shortLinkResultList = records.stream().map(model -> { - String storageKey = model.getStorageKey(); - StorageSource storageSource; - if (cache.containsKey(storageKey)) { - storageSource = cache.get(storageKey); - } else { - storageSource = storageSourceService.findByStorageKey(storageKey); - cache.put(storageKey, storageSource); - } - return downloadLogConvert.entityToResultList(model, storageSource); - }); - return AjaxJson.getPageData(total, shortLinkResultList); - } - - - @ApiOperationSupport(order = 2) - @DeleteMapping("/delete/{id}") - @ApiOperation(value = "删除直链") - @ApiImplicitParam(paramType = "path", name = "id", value = "直链 id", required = true) - @ResponseBody - public AjaxJson deleteById(@PathVariable Integer id) { - downloadLogService.removeById(id); - return AjaxJson.getSuccess(); - } - - - @ApiOperationSupport(order = 3) - @PostMapping("/delete/batch") - @ResponseBody - @ApiImplicitParam(paramType = "query", name = "ids", value = "直链 id", required = true) - @ApiOperation(value = "批量删除直链") - public AjaxJson batchDelete(@RequestBody BatchDeleteRequest batchDeleteRequest) { - List ids = batchDeleteRequest.getIds(); - downloadLogService.removeBatchByIds(ids); - return AjaxJson.getSuccess(); - } - - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/controller/link/ShortLinkManagerController.java b/src/main/java/im/zhaojun/zfile/admin/controller/link/ShortLinkManagerController.java deleted file mode 100644 index 563d9d1..0000000 --- a/src/main/java/im/zhaojun/zfile/admin/controller/link/ShortLinkManagerController.java +++ /dev/null @@ -1,143 +0,0 @@ -package im.zhaojun.zfile.admin.controller.link; - -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.OrderItem; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; -import com.github.xiaoymin.knife4j.annotations.ApiSort; -import im.zhaojun.zfile.admin.convert.ShortLinkConvert; -import im.zhaojun.zfile.admin.model.entity.ShortLink; -import im.zhaojun.zfile.admin.model.entity.StorageSource; -import im.zhaojun.zfile.admin.model.request.link.BatchDeleteRequest; -import im.zhaojun.zfile.admin.model.result.link.ShortLinkResult; -import im.zhaojun.zfile.admin.service.ShortLinkService; -import im.zhaojun.zfile.admin.service.StorageSourceService; -import im.zhaojun.zfile.common.util.AjaxJson; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import javax.annotation.Resource; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Stream; - -/** - * 直链管理接口 - * - * @author zhaojun - */ -@Api(tags = "直链管理") -@ApiSort(7) -@Controller -@RequestMapping("/admin") -public class ShortLinkManagerController { - - @Resource - private ShortLinkService shortLinkService; - - @Resource - private StorageSourceService storageSourceService; - - @Resource - private ShortLinkConvert shortLinkConvert; - - @ApiOperationSupport(order = 1) - @GetMapping("/link/list") - @ApiOperation(value = "搜索短链") - @ResponseBody - @ApiImplicitParams({ - @ApiImplicitParam(paramType = "query", name = "key", value = "短链 key"), - @ApiImplicitParam(paramType = "query", name = "storageId", value = "存储源 ID"), - @ApiImplicitParam(paramType = "query", name = "url", value = "短链 url"), - @ApiImplicitParam(paramType = "query", name = "dateFrom", value = "短链创建时间从"), - @ApiImplicitParam(paramType = "query", name = "dateTo", value = "短链创建时间至"), - @ApiImplicitParam(paramType = "query", name = "page", value = "分页页数"), - @ApiImplicitParam(paramType = "query", name = "limit", value = "每页条数"), - @ApiImplicitParam(paramType = "query", name = "orderBy", defaultValue = "createDate", value = "排序字段"), - @ApiImplicitParam(paramType = "query", name = "orderDirection", defaultValue = "desc", value = "排序顺序") - }) - public AjaxJson list(String key, String storageId, - String url, - String dateFrom, - String dateTo, - Integer page, - Integer limit, - @RequestParam(required = false, defaultValue = "create_date") String orderBy, - @RequestParam(required = false, defaultValue = "desc") String orderDirection) { - Page pages = Page.of(page, limit); - boolean asc = Objects.equals(orderDirection, "asc"); - pages.addOrder(new OrderItem(orderBy, asc)); - QueryWrapper queryWrapper = new QueryWrapper<>(new ShortLink()); - if (StrUtil.isNotEmpty(storageId)) { - queryWrapper.eq("storage_id", storageId); - } - if (StrUtil.isNotEmpty(key)) { - queryWrapper.like("short_key", key); - } - if (StrUtil.isNotEmpty(url)) { - queryWrapper.like("url", url); - } - if (StrUtil.isNotEmpty(dateFrom)) { - queryWrapper.ge("create_date", dateFrom); - } - if (StrUtil.isNotEmpty(dateTo)) { - queryWrapper.le("create_date", dateTo); - } - Page selectResult = shortLinkService.page(pages, queryWrapper); - - long total = selectResult.getTotal(); - List records = selectResult.getRecords(); - - Map cache = new HashMap<>(); - - Stream shortLinkResultList = records.stream().map(shortLink -> { - Integer shortLinkStorageId = shortLink.getStorageId(); - StorageSource storageSource; - if (cache.containsKey(shortLinkStorageId)) { - storageSource = cache.get(shortLinkStorageId); - } else { - storageSource = storageSourceService.findById(shortLinkStorageId); - cache.put(shortLinkStorageId, storageSource); - } - return shortLinkConvert.entityToResultList(shortLink, storageSource); - }); - return AjaxJson.getPageData(total, shortLinkResultList); - } - - - @ApiOperationSupport(order = 2) - @DeleteMapping("/link/delete/{id}") - @ApiOperation(value = "删除短链") - @ApiImplicitParam(paramType = "path", name = "id", value = "短链 id", required = true) - @ResponseBody - public AjaxJson deleteById(@PathVariable Integer id) { - shortLinkService.removeById(id); - return AjaxJson.getSuccess(); - } - - - @ApiOperationSupport(order = 3) - @PostMapping("/link/delete/batch") - @ResponseBody - @ApiImplicitParam(paramType = "query", name = "ids", value = "短链 id", required = true) - @ApiOperation(value = "批量删除短链") - public AjaxJson batchDelete(@RequestBody BatchDeleteRequest batchDeleteRequest) { - shortLinkService.removeBatchByIds(batchDeleteRequest.getIds()); - return AjaxJson.getSuccess(); - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/controller/login/LoginController.java b/src/main/java/im/zhaojun/zfile/admin/controller/login/LoginController.java deleted file mode 100644 index 8cc56e1..0000000 --- a/src/main/java/im/zhaojun/zfile/admin/controller/login/LoginController.java +++ /dev/null @@ -1 +0,0 @@ -package im.zhaojun.zfile.admin.controller.login; import cn.dev33.satoken.stp.SaTokenInfo; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.crypto.SecureUtil; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiSort; import com.github.xiaoymin.knife4j.annotations.DynamicParameter; import com.github.xiaoymin.knife4j.annotations.DynamicResponseParameters; import dev.samstevens.totp.exceptions.QrGenerationException; import im.zhaojun.zfile.admin.model.enums.LoginVerifyModeEnum; import im.zhaojun.zfile.admin.model.request.login.VerifyLogin2FARequest; import im.zhaojun.zfile.admin.model.result.login.Login2FAResult; import im.zhaojun.zfile.admin.model.result.login.LoginVerifyImgResult; import im.zhaojun.zfile.admin.service.SystemConfigService; import im.zhaojun.zfile.admin.service.login.ImgVerifyCodeService; import im.zhaojun.zfile.admin.service.login.TwoFAVerifyService; import im.zhaojun.zfile.common.util.AjaxJson; import im.zhaojun.zfile.home.model.dto.SystemConfigDTO; import im.zhaojun.zfile.home.model.request.UserLoginRequest; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import javax.validation.Valid; import java.util.Objects; /** * 登陆注销相关接口 * * @author zhaojun */ @Api(tags = "登录模块") @ApiSort(1) @RestController @RequestMapping("/admin") public class LoginController { @Resource private SystemConfigService systemConfigService; @Resource private ImgVerifyCodeService imgVerifyCodeService; @Resource private TwoFAVerifyService twoFAVerifyService; @ApiOperationSupport(order = 1, ignoreParameters = {"zfile-token"}) @ApiOperation(value = "登录") @DynamicResponseParameters(properties = { @DynamicParameter(name = "data", value = "登录成功后返回 token 值,后续请求需要在 header 或 cookie 中添加名为 zfile-token 的令牌", example = "629932e1-5103-4c33-85c0-dc89df108ef7", required = true), @DynamicParameter(name = "code", value = "状态码,0 为正常,其他值表示登录失败,异常情况下见响应消息", dataTypeClass = Integer.class, example = "0"), @DynamicParameter(name = "msg", value = "响应消息", example = "ok"), }) @PostMapping("/login") public AjaxJson doLogin(@Valid @RequestBody UserLoginRequest userLoginRequest) { SystemConfigDTO systemConfig = systemConfigService.getSystemConfig(); String verifyCode = userLoginRequest.getVerifyCode(); String verifyCodeUUID = userLoginRequest.getVerifyCodeUUID(); LoginVerifyModeEnum loginVerifyMode = systemConfig.getLoginVerifyMode(); String loginVerifySecret = systemConfig.getLoginVerifySecret(); if (Objects.equals(loginVerifyMode, LoginVerifyModeEnum.TWO_FACTOR_AUTHENTICATION_MODE)) { twoFAVerifyService.checkCode(loginVerifySecret, verifyCode); } else if (Objects.equals(loginVerifyMode, LoginVerifyModeEnum.IMG_VERIFY_MODE)) { imgVerifyCodeService.checkCaptcha(verifyCodeUUID, verifyCode); } if (Objects.equals(systemConfig.getUsername(), userLoginRequest.getUsername()) && Objects.equals(systemConfig.getPassword(), SecureUtil.md5(userLoginRequest.getPassword()))) { StpUtil.login("admin"); SaTokenInfo tokenInfo = StpUtil.getTokenInfo(); return AjaxJson.getSuccess("登录成功", tokenInfo.getTokenValue()); } return AjaxJson.getError("登录失败, 账号或密码错误"); } @ApiOperationSupport(order = 2) @ApiOperation(value = "注销") @PostMapping("/logout") public AjaxJson logout() { StpUtil.logout(); return AjaxJson.getSuccess("注销成功"); } @ApiOperationSupport(order = 3) @ApiOperation(value = "生成 2FA") @GetMapping("/2fa/setup") public AjaxJson setupDevice() throws QrGenerationException { Login2FAResult login2FAResult = twoFAVerifyService.setupDevice(); return AjaxJson.getSuccessData(login2FAResult); } @ApiOperationSupport(order = 4) @ApiOperation(value = "2FA 验证并绑定") @PostMapping("/2fa/verify") public AjaxJson deviceVerify(@Valid @RequestBody VerifyLogin2FARequest verifyLogin2FARequest) { twoFAVerifyService.deviceVerify(verifyLogin2FARequest); return AjaxJson.getSuccess(); } @ApiOperationSupport(order = 5) @ApiOperation(value = "获取登陆验证方式") @GetMapping("/login/verify-mode") public AjaxJson loginVerifyMode() { SystemConfigDTO systemConfig = systemConfigService.getSystemConfig(); return AjaxJson.getSuccessData(systemConfig.getLoginVerifyMode()); } @ApiOperationSupport(order = 6) @ApiOperation(value = "获取图形验证码") @GetMapping("/login/captcha") public AjaxJson captcha() { LoginVerifyImgResult loginVerifyImgResult = imgVerifyCodeService.generatorCaptcha(); return AjaxJson.getSuccessData(loginVerifyImgResult); } @ApiOperationSupport(order = 7) @ApiOperation(value = "检测是否已登录") @GetMapping("/login/check") public AjaxJson checkLogin() { return AjaxJson.getSuccessData(StpUtil.isLogin()); } } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/exception/ForbidFileOperationException.java b/src/main/java/im/zhaojun/zfile/admin/exception/ForbidFileOperationException.java deleted file mode 100644 index 0190858..0000000 --- a/src/main/java/im/zhaojun/zfile/admin/exception/ForbidFileOperationException.java +++ /dev/null @@ -1,22 +0,0 @@ -package im.zhaojun.zfile.admin.exception; - -import lombok.Getter; - -/** - * 禁止的文件操作异常 - * - * @author zhaojun - */ -@Getter -public class ForbidFileOperationException extends RuntimeException { - - private final Integer storageId; - - private final String action; - - public ForbidFileOperationException(Integer storageId, String action) { - this.storageId = storageId; - this.action = action; - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/mapper/DownloadLogMapper.java b/src/main/java/im/zhaojun/zfile/admin/mapper/DownloadLogMapper.java deleted file mode 100644 index b8083a8..0000000 --- a/src/main/java/im/zhaojun/zfile/admin/mapper/DownloadLogMapper.java +++ /dev/null @@ -1,15 +0,0 @@ -package im.zhaojun.zfile.admin.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import im.zhaojun.zfile.admin.model.entity.DownloadLog; -import org.apache.ibatis.annotations.Mapper; - -/** - * 下载日志 Mapper 接口 - * - * @author zhaojun - */ -@Mapper -public interface DownloadLogMapper extends BaseMapper { - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/model/dto/StorageSourceCacheKey.java b/src/main/java/im/zhaojun/zfile/admin/model/dto/StorageSourceCacheKey.java deleted file mode 100644 index 8f28c93..0000000 --- a/src/main/java/im/zhaojun/zfile/admin/model/dto/StorageSourceCacheKey.java +++ /dev/null @@ -1,21 +0,0 @@ -package im.zhaojun.zfile.admin.model.dto; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -/** - * 缓存对象,用户表示那个存储源的那个文件夹. - * - * @author zhaojun - */ -@Data -@AllArgsConstructor -@NoArgsConstructor -public class StorageSourceCacheKey { - - private Integer storageId; - - private String key; - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/model/param/IStorageParam.java b/src/main/java/im/zhaojun/zfile/admin/model/param/IStorageParam.java deleted file mode 100644 index 9fc2786..0000000 --- a/src/main/java/im/zhaojun/zfile/admin/model/param/IStorageParam.java +++ /dev/null @@ -1,5 +0,0 @@ -package im.zhaojun.zfile.admin.model.param; - - -public interface IStorageParam { -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/model/verify/VerifyResult.java b/src/main/java/im/zhaojun/zfile/admin/model/verify/VerifyResult.java deleted file mode 100644 index c64a215..0000000 --- a/src/main/java/im/zhaojun/zfile/admin/model/verify/VerifyResult.java +++ /dev/null @@ -1,56 +0,0 @@ -package im.zhaojun.zfile.admin.model.verify; - -import lombok.Data; - -/** - * 用于表示校验结果的类 - * - * @author zhaojun - */ -@Data -public class VerifyResult { - - /** - * 是否成功 - */ - private boolean passed; - - /** - * 消息 - */ - private String msg; - - /** - * 代码 - */ - private Integer code; - - /** - * 表达式 - */ - private String pattern; - - public static VerifyResult success() { - VerifyResult verifyResult = new VerifyResult(); - verifyResult.setPassed(true); - return verifyResult; - } - - - public static VerifyResult success(String pattern) { - VerifyResult verifyResult = new VerifyResult(); - verifyResult.setPassed(true); - verifyResult.setPattern(pattern); - return verifyResult; - } - - - public static VerifyResult fail(String msg, Integer code) { - VerifyResult verifyResult = new VerifyResult(); - verifyResult.setPassed(false); - verifyResult.setMsg(msg); - verifyResult.setCode(code); - return verifyResult; - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/service/DownloadLogService.java b/src/main/java/im/zhaojun/zfile/admin/service/DownloadLogService.java deleted file mode 100644 index da33f1b..0000000 --- a/src/main/java/im/zhaojun/zfile/admin/service/DownloadLogService.java +++ /dev/null @@ -1,17 +0,0 @@ -package im.zhaojun.zfile.admin.service; - -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import im.zhaojun.zfile.admin.mapper.DownloadLogMapper; -import im.zhaojun.zfile.admin.model.entity.DownloadLog; -import org.springframework.stereotype.Service; - -/** - * 下载日志 Service - * - * @author zhaojun - */ -@Service -public class DownloadLogService extends ServiceImpl { - - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/service/FilterConfigService.java b/src/main/java/im/zhaojun/zfile/admin/service/FilterConfigService.java deleted file mode 100644 index cfeeb18..0000000 --- a/src/main/java/im/zhaojun/zfile/admin/service/FilterConfigService.java +++ /dev/null @@ -1,219 +0,0 @@ -package im.zhaojun.zfile.admin.service; - -import cn.hutool.core.io.FileUtil; -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import im.zhaojun.zfile.admin.mapper.FilterConfigMapper; -import im.zhaojun.zfile.admin.model.entity.FilterConfig; -import im.zhaojun.zfile.common.exception.FileAccessException; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.annotation.Resource; -import java.nio.file.FileSystems; -import java.nio.file.PathMatcher; -import java.nio.file.Paths; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * 存储源过滤器 Service - * - * @author zhaojun - */ -@Slf4j -@Service -public class FilterConfigService extends ServiceImpl { - - @Resource - private FilterConfigMapper filterConfigMapper; - - - /** - * 存储源 ID -> 过滤器列表(全部)缓存. - */ - private final Map> baseCache = new HashMap<>(); - - /** - * 存储源 ID -> 过滤器列表(禁止访问)缓存. - */ - private final Map> inaccessibleCache = new HashMap<>(); - - /** - * 存储源 ID -> 过滤器列表(禁止下载)缓存. - */ - private final Map> disableDownloadCache = new HashMap<>(); - - - /** - * 根据存储源 ID 获取存储源配置列表 - * - * @param storageId - * 存储源 ID - * - * @return 存储源过滤器配置列表 - */ - public List findByStorageId(Integer storageId){ - if (baseCache.get(storageId) != null) { - return baseCache.get(storageId); - } else { - List dbResult = filterConfigMapper.findByStorageId(storageId); - baseCache.put(storageId, dbResult); - return dbResult; - } - } - - - /** - * 批量保存存储源过滤器配置, 会先删除之前的所有配置(在事务中运行) - * - * @param storageId - * 存储源 ID - * - * @param filterConfigList - * 存储源过滤器配置列表 - */ - @Transactional(rollbackFor = Exception.class) - public void batchSave(Integer storageId, List filterConfigList) { - filterConfigMapper.deleteByStorageId(storageId); - super.saveBatch(filterConfigList); - baseCache.put(storageId, filterConfigList); - } - - - /** - * 判断访问的路径是否是不允许访问的 - * - * @param storageId - * 存储源 ID - * - * @param path - * 请求路径 - * - * @throws FileAccessException 如果没权限访问此目录, 则抛出异常 - * - */ - public void checkPathPermission(Integer storageId, String path) { - List filterConfigList = findByStorageIdAndInaccessible(storageId); - if (testPattern(filterConfigList, path)) { - throw new FileAccessException("您没有权限访问该路径"); - } - - } - - - /** - * 获取所有类型为禁止访问的过滤规则 - * - * @param storageId - * 存储 ID - * - * @return 禁止访问的过滤规则列表 - */ - public List findByStorageIdAndInaccessible(Integer storageId){ - if (inaccessibleCache.get(storageId) != null) { - return inaccessibleCache.get(storageId); - } else { - List dbResult = filterConfigMapper.findByStorageIdAndInaccessible(storageId); - inaccessibleCache.put(storageId, dbResult); - return dbResult; - } - } - - - /** - * 获取所有类型为禁止下载的过滤规则 - * - * @param storageId - * 存储 ID - * - * @return 禁止下载的过滤规则列表 - */ - public List findByStorageIdAndDisableDownload(Integer storageId){ - if (disableDownloadCache.get(storageId) != null) { - return disableDownloadCache.get(storageId); - } else { - List dbResult = filterConfigMapper.findByStorageIdAndDisableDownload(storageId); - disableDownloadCache.put(storageId, dbResult); - return dbResult; - } - } - - - /** - * 指定存储源下的文件名称, 根据过滤表达式判断是否会显示, 如果符合任意一条表达式, 表示隐藏则返回 true, 反之表示不隐藏则返回 false. - * - * @param storageId - * 存储源 ID - * - * @param fileName - * 文件名 - * - * @return 是否是隐藏文件夹 - */ - public boolean filterResultIsHidden(Integer storageId, String fileName) { - List filterConfigList = findByStorageId(storageId); - return testPattern(filterConfigList, fileName); - } - - - /** - * 指定存储源下的文件名称, 根据过滤表达式判断文件名和所在路径是否禁止下载, 如果符合任意一条表达式, 则返回 true, 反之则返回 false. - * - * @param storageId - * 存储源 ID - * - * @param fileName - * 文件名 - * - * @return 是否显示 - */ - public boolean filterResultIsDisableDownload(Integer storageId, String fileName) { - List filterConfigList = findByStorageIdAndDisableDownload(storageId); - String filePath = FileUtil.getParent(fileName, 1); - if (StrUtil.isEmpty(filePath)) { - return testPattern(filterConfigList, fileName); - } else { - return testPattern(filterConfigList, fileName) || testPattern(filterConfigList, filePath); - } - } - - - /** - * 根据规则表达式和测试字符串进行匹配,如测试字符串和其中一个规则匹配上,则返回 true,反之返回 false。 - * - * @param patternList - * 规则列表 - * - * @param test - * - * 测试字符串 - * - * @return 是否显示 - */ - private boolean testPattern(List patternList, String test) { - for (FilterConfig filterConfig : patternList) { - String expression = filterConfig.getExpression(); - - if (StrUtil.isEmpty(expression)) { - return false; - } - - try { - PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:" + expression); - boolean match = pathMatcher.matches(Paths.get(test)); - if (match) { - return true; - } - log.debug("regex: {}, name {}, contains: {}", expression, test, match); - } catch (Exception e) { - log.debug("regex: {}, name {}, parse error, skip expression", expression, test); - } - } - - return false; - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/service/PasswordConfigService.java b/src/main/java/im/zhaojun/zfile/admin/service/PasswordConfigService.java deleted file mode 100644 index b6a0d52..0000000 --- a/src/main/java/im/zhaojun/zfile/admin/service/PasswordConfigService.java +++ /dev/null @@ -1,159 +0,0 @@ -package im.zhaojun.zfile.admin.service; - -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import im.zhaojun.zfile.admin.mapper.PasswordConfigMapper; -import im.zhaojun.zfile.admin.model.entity.PasswordConfig; -import im.zhaojun.zfile.admin.model.verify.VerifyResult; -import im.zhaojun.zfile.common.util.AjaxJson; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.annotation.Resource; -import java.nio.file.FileSystems; -import java.nio.file.PathMatcher; -import java.nio.file.Paths; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -/** - * 存储源密码配置 Service - * - * @author zhaojun - */ -@Service -@Slf4j -public class PasswordConfigService extends ServiceImpl { - - @Resource - private PasswordConfigMapper passwordConfigMapper; - - - /** - * 存储源 ID -> 密码规则列表(全部)缓存. - */ - private final Map> baseCache = new HashMap<>(); - - - /** - * 根据存储源 ID 查询密码规则列表 - * - * @param storageId - * 存储源 ID - * - * @return 密码规则列表 - */ - public List findByStorageId(Integer storageId) { - if (baseCache.get(storageId) != null) { - return baseCache.get(storageId); - } else { - List dbResult = passwordConfigMapper.findByStorageId(storageId); - baseCache.put(storageId, dbResult); - return dbResult; - } - } - - - /** - * 批量保存指定存储源 ID 的密码规则列表 - * - * @param storageId - * 存储源 ID - * - * @param passwordConfigList - * 存储源类别 - */ - @Transactional(rollbackFor = Exception.class) - public void batchSave(Integer storageId, List passwordConfigList) { - passwordConfigMapper.deleteByStorageId(storageId); - super.saveBatch(passwordConfigList); - baseCache.put(storageId, passwordConfigList); - } - - - /** - * 校验密码 - * - * @param storageId - * 存储源 ID - * - * @param path - * 请求路径 - * - * @param inputPassword - * 用户输入的密码 - * - * @return 是否校验通过 - */ - public VerifyResult verifyPassword(Integer storageId, String path, String inputPassword) { - List passwordConfigList = findByStorageId(storageId); - - for (PasswordConfig passwordConfig : passwordConfigList) { - String expression = passwordConfig.getExpression(); - if (StrUtil.isEmpty(expression)) { - continue; - } - - try { - PathMatcher pathMatcher = FileSystems.getDefault() - .getPathMatcher("glob:" + expression); - // 判断当前请求路径是否和规则路径表达式匹配 - boolean match = pathMatcher.matches(Paths.get(path)); - // 如果匹配且输入了密码则校验 - if (match) { - if (StrUtil.isEmpty(inputPassword)) { - return VerifyResult.fail("此文件夹需要密码.", AjaxJson.REQUIRED_PASSWORD); - } - - String expectedPassword = passwordConfig.getPassword(); - if (matchPassword(expectedPassword, inputPassword)) { - log.debug("匹配文件夹密码 path: {}, expression: {}, 用户输入: {}, 匹配成功", path, expression, inputPassword); - return VerifyResult.success(expression); - } - log.debug("匹配文件夹密码 path: {}, expression: {}, 用户输入: {}, 不匹配.", path, expression, inputPassword); - return VerifyResult.fail("此文件夹密码错误.", AjaxJson.INVALID_PASSWORD); - } - } catch (Exception e) { - log.warn("匹配文件夹密码 path: {}, expression: {}, 用户输入: {}, 解析错误, 跳过此规则.", - path, expression, inputPassword, e); - } - } - - log.debug("校验文件夹密码 path: {}, 没有匹配的表达式, 不进行密码校验.", path); - return VerifyResult.success(); - } - - - /** - * 校验两个密码是否相同, 忽略空白字符 - * - * @param expectedPasswordContent - * 预期密码 - * - * @param password - * 实际输入密码 - * - * @return 是否匹配 - */ - private boolean matchPassword(String expectedPasswordContent, String password) { - if (Objects.equals(expectedPasswordContent, password)) { - return true; - } - - if (expectedPasswordContent == null) { - return false; - } - - if (password == null) { - return false; - } - - expectedPasswordContent = expectedPasswordContent.replace("\n", "").trim(); - password = password.replace("\n", "").trim(); - return Objects.equals(expectedPasswordContent, password); - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/service/ReadmeConfigService.java b/src/main/java/im/zhaojun/zfile/admin/service/ReadmeConfigService.java deleted file mode 100644 index 1196134..0000000 --- a/src/main/java/im/zhaojun/zfile/admin/service/ReadmeConfigService.java +++ /dev/null @@ -1,114 +0,0 @@ -package im.zhaojun.zfile.admin.service; - -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import im.zhaojun.zfile.admin.mapper.ReadmeConfigMapper; -import im.zhaojun.zfile.admin.model.entity.ReadmeConfig; -import im.zhaojun.zfile.common.constant.ZFileConstant; -import im.zhaojun.zfile.common.util.StringUtils; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.annotation.Resource; -import java.nio.file.FileSystems; -import java.nio.file.PathMatcher; -import java.nio.file.Paths; -import java.util.List; - -/** - * 存储源 readme 配置 Service - * - * @author zhaojun - */ -@Slf4j -@Service -public class ReadmeConfigService extends ServiceImpl { - - @Resource - private ReadmeConfigMapper readmeConfigMapper; - - - /** - * 根据存储源 ID 查询文档配置 - * - * @param storageId - * 存储源ID - * - * @return 存储源文档配置列表 - */ - public List findByStorageId(Integer storageId){ - return readmeConfigMapper.findByStorageId(storageId); - } - - - /** - * 批量保存存储源 readme 配置, 会先删除之前的所有配置(在事务中运行) - * - * @param storageId - * 存储源 ID - * - * @param filterConfigList - * 存储源 readme 配置列表 - */ - @Transactional(rollbackFor = Exception.class) - public void batchSave(Integer storageId, List filterConfigList) { - readmeConfigMapper.deleteByStorageId(storageId); - super.saveBatch(filterConfigList); - } - - - - /** - * 根据存储源指定路径下的 readme 配置 - * - * @param storageId - * 存储源ID - * - * @param path - * 文件夹路径 - * - * @return 存储源 readme 配置列表 - */ - public ReadmeConfig findReadmeByPath(Integer storageId, String path) { - List readmeConfigList = readmeConfigMapper.findByStorageId(storageId); - return getReadmeByTestPattern(readmeConfigList, path); - } - - - /** - * 根据规则表达式和测试字符串进行匹配,如测试字符串和其中一个规则匹配上,则返回 true,反之返回 false。 - * - * @param patternList - * 规则列表 - * - * @param test - * 测试字符串 - * - * @return 是否显示 - */ - private ReadmeConfig getReadmeByTestPattern(List patternList, String test) { - test = StringUtils.concat(test, ZFileConstant.PATH_SEPARATOR); - - for (ReadmeConfig filterConfig : patternList) { - String expression = filterConfig.getExpression(); - if (StrUtil.isEmpty(expression)) { - continue; - } - - try { - PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:" + expression); - boolean match = pathMatcher.matches(Paths.get(test)); - if (match) { - return filterConfig; - } - log.debug("regex: {}, name {}, contains: {}", expression, test, match); - } catch (Exception e) { - log.debug("regex: {}, name {}, parse error, skip expression", expression, test); - } - } - - return null; - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/service/StorageSourceConfigService.java b/src/main/java/im/zhaojun/zfile/admin/service/StorageSourceConfigService.java deleted file mode 100644 index 497bc44..0000000 --- a/src/main/java/im/zhaojun/zfile/admin/service/StorageSourceConfigService.java +++ /dev/null @@ -1,119 +0,0 @@ -package im.zhaojun.zfile.admin.service; - -import cn.hutool.core.collection.CollUtil; -import com.baomidou.mybatisplus.extension.service.IService; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import im.zhaojun.zfile.admin.mapper.StorageSourceConfigMapper; -import im.zhaojun.zfile.admin.model.entity.StorageSourceConfig; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.annotation.Resource; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * 存储源拓展配置 Service - * - * @author zhaojun - */ -@Service -@Slf4j -public class StorageSourceConfigService extends ServiceImpl implements IService { - - @Resource - private StorageSourceConfigMapper storageSourceConfigMapper; - - /** - * 存储源 ID -> 存储源参数列表对象缓存 - */ - private final Map> sourceConfigConfigMapCache = new HashMap<>(); - - /** - * 根据存储源 ID 查询存储源拓展配置, 并按照存储源 id 排序 - * - * @param storageId - * 存储源 ID - * - * @return 存储源拓展配置列表 - */ - public List selectStorageConfigByStorageId(Integer storageId) { - if (sourceConfigConfigMapCache.containsKey(storageId)) { - return sourceConfigConfigMapCache.get(storageId); - } else { - List dbResult = storageSourceConfigMapper.findByStorageIdOrderById(storageId); - sourceConfigConfigMapCache.put(storageId, dbResult); - return dbResult; - } - } - - - /** - * 获取指定存储源的指定参数名称 - * - * @param storageId - * 存储源 id - * - * @param name - * 参数名 - * - * @return 参数信息 - */ - public StorageSourceConfig findByStorageIdAndName(Integer storageId, String name) { - return storageSourceConfigMapper.findByStorageIdAndName(storageId, name); - } - - - /** - * 批量更新存储源设置 - * - * @param storageSourceConfigList - * 存储源设置列表 - */ - @Transactional(rollbackFor = Exception.class) - public void updateStorageConfig(List storageSourceConfigList) { - super.updateBatchById(storageSourceConfigList); - if (CollUtil.isNotEmpty(storageSourceConfigList)) { - StorageSourceConfig first = CollUtil.getFirst(storageSourceConfigList); - Integer storageId = first.getStorageId(); - sourceConfigConfigMapCache.remove(storageId); - } - } - - - /** - * 根据存储源 id 删除所有设置 - * - * @param id - * 存储源 ID - */ - @Transactional(rollbackFor = Exception.class) - public void deleteByStorageId(Integer id) { - storageSourceConfigMapper.deleteByStorageId(id); - sourceConfigConfigMapCache.remove(id); - } - - - /** - * 批量保存 - * - * @param entityList - * 实体对象集合 - * - * @return 是否保存成功 - */ - @Override - public boolean saveBatch(Collection entityList) { - if (CollUtil.isNotEmpty(entityList)) { - StorageSourceConfig storageSourceConfig = CollUtil.getFirst(entityList); - Integer storageId = storageSourceConfig.getStorageId(); - sourceConfigConfigMapCache.put(storageId, new ArrayList<>(entityList)); - } - return saveBatch(entityList, DEFAULT_BATCH_SIZE); - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/service/StorageSourceService.java b/src/main/java/im/zhaojun/zfile/admin/service/StorageSourceService.java deleted file mode 100644 index f8ba017..0000000 --- a/src/main/java/im/zhaojun/zfile/admin/service/StorageSourceService.java +++ /dev/null @@ -1,503 +0,0 @@ -package im.zhaojun.zfile.admin.service; - -import cn.hutool.core.convert.Convert; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.ReflectUtil; -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.extension.service.IService; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import im.zhaojun.zfile.admin.annotation.model.StorageSourceParamDef; -import im.zhaojun.zfile.admin.mapper.StorageSourceMapper; -import im.zhaojun.zfile.admin.model.entity.StorageSource; -import im.zhaojun.zfile.admin.model.entity.StorageSourceConfig; -import im.zhaojun.zfile.admin.model.param.IStorageParam; -import im.zhaojun.zfile.admin.model.request.SaveStorageSourceRequest; -import im.zhaojun.zfile.common.cache.ZFileCache; -import im.zhaojun.zfile.common.context.StorageSourceContext; -import im.zhaojun.zfile.common.exception.InitializeStorageSourceException; -import im.zhaojun.zfile.common.exception.InvalidStorageSourceException; -import im.zhaojun.zfile.home.model.dto.CacheInfoDTO; -import im.zhaojun.zfile.home.model.dto.StorageSourceAllParam; -import im.zhaojun.zfile.home.model.dto.StorageSourceDTO; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; -import im.zhaojun.zfile.home.model.request.UpdateStorageSortRequest; -import im.zhaojun.zfile.home.service.base.AbstractBaseFileService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.BeanUtils; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.annotation.Resource; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -/** - * 存储源基本信息 Service - * - * @author zhaojun - */ -@Slf4j -@Service -public class StorageSourceService extends ServiceImpl implements IService { - - @Resource - private StorageSourceMapper storageSourceMapper; - - @Resource - private StorageSourceConfigService storageSourceConfigService; - - @Resource - private StorageSourceContext storageSourceContext; - - @Resource - private ZFileCache zFileCache; - - public static final Class STORAGE_SOURCE_ALL_PARAM_CLASS = StorageSourceAllParam.class; - - - /** - * 存储源 ID -> 存储源对象缓存 - */ - private final Map storageIdMapCache = new HashMap<>(); - - - /** - * 存储源 KEY -> 存储源对象缓存 - */ - private final Map storageKeyMapCache = new HashMap<>(); - - - /** - * 获取所有存储源列表 - * - * @return 存储源列表 - */ - public List findAllOrderByOrderNum() { - return storageSourceMapper.findAllOrderByOrderNum(); - } - - - /** - * 获取所有已启用的存储源列表,按照存储源的排序号排序 - * - * @return 已启用的存储源列表 - */ - public List findListByEnableOrderByOrderNum() { - return storageSourceMapper.findListByEnableOrderByOrderNum(); - } - - - /** - * 获取指定存储源设置 - * - * @param id - * 存储源 ID - * - * @return 存储源设置 - */ - public StorageSource findById(Integer id) { - if (storageIdMapCache.get(id) != null) { - return storageIdMapCache.get(id); - } else { - StorageSource dbResult = storageSourceMapper.selectById(id); - storageIdMapCache.put(id, dbResult); - return dbResult; - } - } - - - /** - * 获取指定存储源 DTO 对象, 此对象包含详细的参数设置. - * - * @param id - * 存储源 ID - * - * @return 存储源 DTO - */ - public StorageSourceDTO findStorageSourceDTOById(Integer id) { - StorageSource storageSource = findById(id); - Boolean defaultSwitchToImgMode = storageSource.getDefaultSwitchToImgMode(); - if (defaultSwitchToImgMode == null) { - storageSource.setDefaultSwitchToImgMode(false); - } - - StorageSourceDTO storageSourceDTO = new StorageSourceDTO(); - BeanUtils.copyProperties(storageSource, storageSourceDTO); - - List storageSourceConfigList = storageSourceConfigService.selectStorageConfigByStorageId(storageSource.getId()); - - StorageSourceAllParam storageSourceAllParam = new StorageSourceAllParam(); - for (StorageSourceConfig storageSourceConfig : storageSourceConfigList) { - String name = storageSourceConfig.getName(); - String value = storageSourceConfig.getValue(); - - Field declaredField; - try { - declaredField = STORAGE_SOURCE_ALL_PARAM_CLASS.getDeclaredField(name); - declaredField.setAccessible(true); - - Class paramFieldType = declaredField.getType(); - Object convertToValue = Convert.convert(paramFieldType, value); - declaredField.set(storageSourceAllParam, convertToValue); - } catch (NoSuchFieldException | IllegalAccessException e) { - log.error("通过反射, 将字段 {} 注入 StorageSourceDTO 时出现异常:", name, e); - } - } - - storageSourceDTO.setStorageSourceAllParam(storageSourceAllParam); - return storageSourceDTO; - } - - - /** - * 根据 id 获取指定存储源的类型. - * - * @param id - * 存储源 ID - * - * @return 存储源对应的类型. - */ - public StorageTypeEnum findStorageTypeById(Integer id) { - return findById(id).getType(); - } - - - /** - * 保存存储源基本信息及其对应的参数设置 - * - * @param saveStorageSourceRequest - * 存储源 DTO 对象 - */ - @Transactional(rollbackFor = Exception.class) - public void saveStorageSource(SaveStorageSourceRequest saveStorageSourceRequest) { - - // 判断是新增还是修改 - boolean updateFlag = saveStorageSourceRequest.getId() != null; - - // 保存基本信息 - StorageSource storageSource = new StorageSource(); - StorageTypeEnum storageType = saveStorageSourceRequest.getType(); - BeanUtils.copyProperties(saveStorageSourceRequest, storageSource); - - if (storageSource.getId() == null) { - Integer nextId = selectNextId(); - storageSource.setId(nextId); - } - - - // 获取通过 id 缓存的对象 - StorageSource cacheStorageSource = storageIdMapCache.get(storageSource.getId()); - // 如果缓存的对象和当前的对象 key 不同, 则说明修改了 key, 需要移除 key 缓存, 并重新写入. - if (ObjectUtil.isNotEmpty(cacheStorageSource) && - !StrUtil.equals(cacheStorageSource.getKey(), storageSource.getKey())) { - storageKeyMapCache.remove(cacheStorageSource.getKey()); - } - - super.saveOrUpdate(storageSource); - - if (StrUtil.isEmpty(storageSource.getKey()) && !StrUtil.equals(storageSource.getId().toString(), storageSource.getKey())) { - storageSource.setKey(Convert.toStr(storageSource.getId())); - baseMapper.updateById(storageSource); - } - storageKeyMapCache.put(storageSource.getKey(), storageSource); - - StorageSourceAllParam storageSourceAllParam = saveStorageSourceRequest.getStorageSourceAllParam(); - - // 获取该存储源类型需要的参数列表 - List storageSourceParamList = StorageSourceContext.getStorageSourceParamListByType(storageType); - - List storageSourceConfigList = new ArrayList<>(); - storageSourceConfigService.deleteByStorageId(saveStorageSourceRequest.getId()); - - for (StorageSourceParamDef storageSourceParam : storageSourceParamList) { - String paramKey = storageSourceParam.getKey(); - String paramName = storageSourceParam.getName(); - - StorageSourceConfig storageSourceConfig = new StorageSourceConfig(); - storageSourceConfigList.add(storageSourceConfig); - - Object fieldValue = ReflectUtil.getFieldValue(storageSourceAllParam, paramKey); - String fieldStrValue = Convert.toStr(fieldValue); - - boolean paramRequired = storageSourceParam.isRequired(); - String paramDefaultValue = storageSourceParam.getDefaultValue(); - - // 如果是必填的, 并且值为空, 则抛出异常 - if (paramRequired && StrUtil.isEmpty(fieldStrValue)) { - throw new InitializeStorageSourceException("存储源参数配置错误: [" + paramName + "] 不能为空"); - } - - // 如果默认值不为空, 且输入值为空, 则使用默认值 - if (StrUtil.isNotEmpty(paramDefaultValue) && StrUtil.isEmpty(fieldStrValue)) { - fieldStrValue = paramDefaultValue; - } - - storageSourceConfig.setTitle(paramName); - storageSourceConfig.setName(paramKey); - storageSourceConfig.setValue(fieldStrValue); - storageSourceConfig.setType(storageType); - storageSourceConfig.setStorageId(storageSource.getId()); - } - storageSourceConfigService.saveBatch(storageSourceConfigList); - - storageSourceContext.init(storageSource.getId()); - - AbstractBaseFileService driveService = storageSourceContext.get(storageSource.getId()); - if (driveService.getIsUnInitialized()) { - throw new InitializeStorageSourceException("初始化异常, 请检查配置是否正确."); - } - - if (storageSource.getAutoRefreshCache()) { - startAutoCacheRefresh(storageSource.getId()); - } else if (updateFlag) { - stopAutoCacheRefresh(storageSource.getId()); - } - - } - - - /** - * 查询存储源最大的 ID - * - * @return 存储源最大 ID - */ - public synchronized Integer selectNextId() { - Integer maxId = storageSourceMapper.selectMaxId(); - if (maxId == null) { - return 1; - } else { - return maxId + 1; - } - } - - - - /** - * 删除指定存储源设置, 会级联删除其参数设置 - * - * @param id - * 存储源 ID - */ - @Transactional(rollbackFor = Exception.class) - public void deleteById(Integer id) { - if (log.isDebugEnabled()) { - log.debug("尝试删除存储源, storageId: {}", id); - } - StorageSource storageSource = findById(id); - storageSourceMapper.deleteById(id); - storageSourceConfigService.deleteByStorageId(id); - if (storageSource.getEnableCache()) { - zFileCache.stopAutoCacheRefresh(id); - zFileCache.clear(id); - } - String key = storageSource.getKey(); - storageIdMapCache.remove(id); - storageKeyMapCache.remove(key); - storageSourceContext.destroy(id); - if (log.isDebugEnabled()) { - log.debug("尝试删除存储源成功, 已清理相关数据, storageId: {}", id); - } - } - - - /** - * 更新指定存储源的缓存启用状态 - * - * @param storageId - * 存储源 ID - * - * @param cacheEnable - * 是否启用缓存 - */ - public void updateCacheStatus(Integer storageId, Boolean cacheEnable) { - StorageSource storageSource = findById(storageId); - if (storageSource != null) { - storageSource.setEnableCache(cacheEnable); - super.saveOrUpdate(storageSource); - storageIdMapCache.put(storageId, storageSource); - } - } - - - /** - * 获取指定存储源的缓存信息 - * - * @param storageId - * 存储源 ID - * - * @return 缓存信息 - */ - public CacheInfoDTO findCacheInfo(Integer storageId) { - long hitCount = zFileCache.getHitCount(storageId); - long missCount = zFileCache.getMissCount(storageId); - Set keys = zFileCache.keySet(storageId); - int cacheCount = keys.size(); - return new CacheInfoDTO(cacheCount, hitCount, missCount, keys); - } - - - /** - * 刷新指定 key 的缓存: - * 1. 清空此 key 的缓存. - * 2. 重新调用方法写入缓存. - * - * @param storageId - * 存储源 ID - * - * @param key - * 缓存 key (文件夹名称) - */ - public void refreshCache(Integer storageId, String key) throws Exception { - if (log.isDebugEnabled()) { - log.debug("手动刷新缓存 storageId: {}, key: {}", storageId, key); - } - zFileCache.remove(storageId, key); - AbstractBaseFileService baseFileService = storageSourceContext.get(storageId); - baseFileService.fileList(key); - } - - - /** - * 开启缓存自动刷新 - * - * @param storageId - * 存储源 ID - */ - public void startAutoCacheRefresh(Integer storageId) { - StorageSource storageSource = findById(storageId); - storageSource.setAutoRefreshCache(true); - super.saveOrUpdate(storageSource); - storageIdMapCache.put(storageId, storageSource); - zFileCache.startAutoCacheRefresh(storageId); - } - - - /** - * 停止缓存自动刷新 - * - * @param storageId - * 存储源 ID - */ - public void stopAutoCacheRefresh(Integer storageId) { - StorageSource storageSource = findById(storageId); - storageSource.setAutoRefreshCache(false); - super.saveOrUpdate(storageSource); - storageIdMapCache.put(storageId, storageSource); - zFileCache.stopAutoCacheRefresh(storageId); - } - - - /** - * 清理缓存 - * - * @param storageId - * 存储源 ID - */ - public void clearCache(Integer storageId) { - zFileCache.clear(storageId); - } - - - /** - * 交换存储源排序 - * - * @param updateStorageSortRequestList - * 更新排序的存储源 id 及排序值列表 - */ - @Transactional(rollbackFor = Exception.class) - public void updateStorageSort(List updateStorageSortRequestList) { - for (int i = 0; i < updateStorageSortRequestList.size(); i++) { - UpdateStorageSortRequest item = updateStorageSortRequestList.get(i); - if (!Objects.equals(i, item.getOrderNum())) { - storageSourceMapper.updateSetOrderNumById(i, item.getId()); - storageIdMapCache.clear(); - } - } - } - - - /** - * 根据存储源 key 获取存储源 - * - * @param storageKey - * 存储源 key - * - * @throws InvalidStorageSourceException 存储源不存在时, 抛出异常. - * - * @return 存储源信息 - */ - public StorageSource findByStorageKey(String storageKey) { - if (storageKeyMapCache.containsKey(storageKey)) { - return storageKeyMapCache.get(storageKey); - } else { - StorageSource storageSource = storageSourceMapper.findByStorageKey(storageKey); - if (storageSource != null) { - storageKeyMapCache.put(storageKey, storageSource); - } - return storageSource; - } - - - } - - - /** - * 判断存储源 key 是否已存在 (不读取缓存) - * - * @param storageKey - * 存储源 key - * - * @return 是否已存在 - */ - public boolean existByStorageKey(String storageKey) { - return storageSourceMapper.findIdByStorageKey(storageKey) != null; - } - - - /** - * 根据存储源 id 获取存储源 key - * - * @param id - * 存储源 id - * - * @return 存储源 key - */ - public String findKeyById(Integer id){ - return findById(id).getKey(); - } - - - /** - * 根据存储源 key 获取存储源 - * - * @param storageKey - * 存储源 key - * - * @return 存储源信息 - */ - public Integer findIdByKey(String storageKey) { - StorageSource storageSource = findByStorageKey(storageKey); - if (storageSource == null) { - return null; - } else { - return storageSource.getId(); - } - } - - - @Override - public boolean updateById(StorageSource entity) { - if (entity != null) { - Integer id = entity.getId(); - storageIdMapCache.put(id, entity); - storageKeyMapCache.put(entity.getKey(), entity); - } - return super.updateById(entity); - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/cache/MyTimedCache.java b/src/main/java/im/zhaojun/zfile/common/cache/MyTimedCache.java deleted file mode 100644 index 95b3ba0..0000000 --- a/src/main/java/im/zhaojun/zfile/common/cache/MyTimedCache.java +++ /dev/null @@ -1,61 +0,0 @@ -package im.zhaojun.zfile.common.cache; - -import cn.hutool.cache.impl.TimedCache; -import cn.hutool.extra.spring.SpringUtil; -import im.zhaojun.zfile.common.context.StorageSourceContext; -import im.zhaojun.zfile.admin.model.dto.StorageSourceCacheKey; -import im.zhaojun.zfile.home.service.base.AbstractBaseFileService; -import lombok.extern.slf4j.Slf4j; - -/** - * 自定义缓存类, 实现缓存超时后自动刷新 - * - * @author zhaojun - */ -@Slf4j -public class MyTimedCache extends TimedCache { - - private StorageSourceContext storageSourceContext; - - public MyTimedCache(long timeout) { - super(timeout); - } - - - /** - * 当缓存超时后自动刷新 - * - * @param key - * 缓存 key - * - * @param cachedObject - * 缓存值 - */ - @Override - protected void onRemove(K key, V cachedObject) { - if (storageSourceContext == null) { - storageSourceContext = SpringUtil.getBean(StorageSourceContext.class); - } - - StorageSourceCacheKey cacheKey = (StorageSourceCacheKey) key; - AbstractBaseFileService baseFileService = storageSourceContext.get(cacheKey.getStorageId()); - - if (log.isDebugEnabled()) { - log.debug("尝试刷新缓存: {}", cacheKey); - } - - if (baseFileService == null) { - log.error("尝试刷新缓存: {}, 时出现异常, 存储源已不存在", cacheKey); - return; - } - - try { - baseFileService.fileList(cacheKey.getKey()); - } catch (Exception e) { - log.error("尝试刷新缓存 {} 失败", cacheKey); - e.printStackTrace(); - } - - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/cache/ZFileCache.java b/src/main/java/im/zhaojun/zfile/common/cache/ZFileCache.java deleted file mode 100644 index 35e10c2..0000000 --- a/src/main/java/im/zhaojun/zfile/common/cache/ZFileCache.java +++ /dev/null @@ -1,257 +0,0 @@ -package im.zhaojun.zfile.common.cache; - -import cn.hutool.cache.impl.CacheObj; -import im.zhaojun.zfile.admin.model.dto.StorageSourceCacheKey; -import im.zhaojun.zfile.admin.model.entity.StorageSource; -import im.zhaojun.zfile.admin.service.StorageSourceService; -import im.zhaojun.zfile.common.context.StorageSourceContext; -import im.zhaojun.zfile.home.model.dto.SystemConfigDTO; -import im.zhaojun.zfile.home.model.result.FileItemResult; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -import javax.annotation.Resource; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - * ZFile 缓存工具类 - * - * @author zhaojun - */ -@Service("zFileCache") -@Slf4j -public class ZFileCache { - - @Resource - private StorageSourceService storageSourceService; - - @Resource - private StorageSourceContext storageSourceContext; - - /** - * 缓存过期时间 - */ - @Value("${zfile.cache.timeout}") - private long timeout; - - /** - * 缓存自动刷新间隔 - */ - @Value("${zfile.cache.auto-refresh.interval}") - private long autoRefreshInterval; - - /** - * 文件/文件对象缓存. - * - * ConcurrentMap>> - * ConcurrentMap> - * - * storageId: 存储源 ID - * key: 文件夹路径 - * value: 文件夹中内容 - */ - private final ConcurrentMap>> storageSourcesCache = new ConcurrentHashMap<>(); - - /** - * 系统设置缓存 - */ - private SystemConfigDTO systemConfigCache; - - - /** - * 写入缓存 - * - * @param storageId - * 存储源 ID - * - * @param key - * 文件夹路径 - * - * @param value - * 文件夹中列表 - */ - public synchronized void put(Integer storageId, String key, List value) { - getCacheByStorageId(storageId).put(new StorageSourceCacheKey(storageId, key), value); - } - - - /** - * 获取指定存储源, 某个文件夹的名称 - * - * @param storageId - * 存储源 ID - * - * @param key - * 文件夹路径 - * - * @return 存储源中文件夹的内容 - */ - public List get(Integer storageId, String key) { - return getCacheByStorageId(storageId).get(new StorageSourceCacheKey(storageId, key), false); - } - - - /** - * 清空指定存储源的缓存. - * - * @param storageId - * 存储源 ID - */ - public void clear(Integer storageId) { - if (log.isDebugEnabled()) { - log.debug("清空存储源所有缓存, storageId: {}", storageId); - } - getCacheByStorageId(storageId).clear(); - } - - - - /** - * 获取所有缓存 key (文件夹名称) - * - * @return 所有缓存 key - */ - public Set keySet(Integer storageId) { - Iterator>> cacheObjIterator = getCacheByStorageId(storageId).cacheObjIterator(); - Set keys = new HashSet<>(); - while (cacheObjIterator.hasNext()) { - keys.add(cacheObjIterator.next().getKey().getKey()); - } - return keys; - } - - - /** - * 从缓存中删除指定存储源的某个路径的缓存 - * - * @param storageId - * 存储源 ID - * - * @param key - * 文件夹路径 - */ - public void remove(Integer storageId, String key) { - getCacheByStorageId(storageId).remove(new StorageSourceCacheKey(storageId, key)); - } - - - /** - * 更新缓存中的系统设置 - * - * @param systemConfigCache - * 系统设置 - */ - public void updateConfig(SystemConfigDTO systemConfigCache) { - this.systemConfigCache = systemConfigCache; - } - - - /** - * 从缓存中获取系统设置 - * - * @return 系统设置 - */ - public SystemConfigDTO getConfig() { - return this.systemConfigCache; - } - - - /** - * 清空系统设置缓存 - */ - public void removeConfig() { - this.systemConfigCache = null; - } - - - /** - * 获取指定存储源对应的缓存 - * - * @param storageId - * 存储源 ID - * - * @return 存储源对应的缓存 - */ - private synchronized MyTimedCache> getCacheByStorageId(Integer storageId) { - MyTimedCache> driveCache = storageSourcesCache.get(storageId); - if (driveCache == null) { - driveCache = new MyTimedCache<>(timeout * 1000); - storageSourcesCache.put(storageId, driveCache); - startAutoCacheRefresh(storageId); - } - return driveCache; - } - - - /** - * 获取指定存储源的缓存命中数 - * - * @param storageId - * 存储源 ID - * - * @return 缓存命中数 - */ - public long getHitCount(Integer storageId) { - return getCacheByStorageId(storageId).getHitCount(); - } - - - /** - * 获取指定存储源的缓存未命中数 - * - * @param storageId - * 存储源 ID - * - * @return 缓存未命中数 - */ - public long getMissCount(Integer storageId) { - return getCacheByStorageId(storageId).getMissCount(); - } - - - /** - * 开启缓存自动刷新 - * - * @param storageId - * 存储源 ID - */ - public void startAutoCacheRefresh(Integer storageId) { - if (log.isDebugEnabled()) { - log.debug("开启缓存自动刷新 storageId: {}", storageId); - } - StorageSource storageSource = storageSourceService.findById(storageId); - Boolean autoRefreshCache = storageSource.getAutoRefreshCache(); - if (autoRefreshCache != null && autoRefreshCache) { - MyTimedCache> driveCache = storageSourcesCache.get(storageId); - if (driveCache == null) { - driveCache = new MyTimedCache<>(timeout * 1000); - storageSourcesCache.put(storageId, driveCache); - } - driveCache.schedulePrune(autoRefreshInterval * 1000); - } - } - - - /** - * 停止缓存自动刷新 - * - * @param storageId - * 存储源 ID - */ - public void stopAutoCacheRefresh(Integer storageId) { - if (log.isDebugEnabled()) { - log.debug("停止缓存自动刷新 storageId: {}", storageId); - } - MyTimedCache> driveCache = storageSourcesCache.get(storageId); - if (driveCache != null) { - driveCache.cancelPruneSchedule(); - } - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/config/FlywayDbInitializer.java b/src/main/java/im/zhaojun/zfile/common/config/FlywayDbInitializer.java deleted file mode 100644 index 75a106e..0000000 --- a/src/main/java/im/zhaojun/zfile/common/config/FlywayDbInitializer.java +++ /dev/null @@ -1 +0,0 @@ -package im.zhaojun.zfile.common.config; import cn.hutool.core.util.StrUtil; import org.flywaydb.core.Flyway; import org.springframework.context.annotation.Configuration; import javax.annotation.PostConstruct; import javax.annotation.Resource; import javax.sql.DataSource; import java.sql.SQLException; import java.util.Locale; /** * 数据库初始化 * * @author zhaojun */ @Configuration public class FlywayDbInitializer { public static final String[] SUPPORT_DB_TYPE = new String[]{"mysql", "sqlite"}; @Resource private DataSource dataSource; /** * 启动时根据当前数据库类型执行数据库初始化 */ @PostConstruct public void migrateFlyway() { try { String databaseProductName = dataSource.getConnection().getMetaData().getDatabaseProductName(); String dbType = databaseProductName.toLowerCase(Locale.ROOT); // 检查当前数据库类型是否支持 if (!StrUtil.equalsAnyIgnoreCase(dbType, SUPPORT_DB_TYPE)) { throw new RuntimeException("不支持的数据库类型 [" + dbType + "]"); } Flyway load = Flyway.configure().dataSource(dataSource).outOfOrder(true).locations("db/migration-" + dbType).load(); load.migrate(); } catch (SQLException e) { e.printStackTrace(); } } } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/config/Knife4jConfiguration.java b/src/main/java/im/zhaojun/zfile/common/config/Knife4jConfiguration.java deleted file mode 100644 index 1997c4d..0000000 --- a/src/main/java/im/zhaojun/zfile/common/config/Knife4jConfiguration.java +++ /dev/null @@ -1 +0,0 @@ -package im.zhaojun.zfile.common.config; import com.github.xiaoymin.knife4j.spring.extension.OpenApiExtensionResolver; import io.swagger.models.auth.In; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.builders.RequestParameterBuilder; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.Contact; import springfox.documentation.service.RequestParameter; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; import java.util.ArrayList; import java.util.List; /** * @author zhaojun */ @Configuration @EnableSwagger2 public class Knife4jConfiguration { private final OpenApiExtensionResolver openApiExtensionResolver; @Autowired public Knife4jConfiguration(OpenApiExtensionResolver openApiExtensionResolver) { this.openApiExtensionResolver = openApiExtensionResolver; } /** * onedrive api docket * * @return docket */ @Bean(value = "onedriveApi") public Docket onedriveApi() { String groupName = "OneDrive 相关"; return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("im.zhaojun.zfile.common.controller.onedrive")) .paths(PathSelectors.regex("/onedrive/.*|/sharepoint/.*")) .build() .groupName(groupName) .extensions(openApiExtensionResolver.buildExtensions(groupName)); } /** * admin api docket * * @return docket */ @Bean(value = "adminApi") public Docket adminApi() { String groupName = "管理员功能"; return new Docket(DocumentationType.SWAGGER_2) .globalRequestParameters(generateRequestParameters()) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("im.zhaojun.zfile.controller.admin")) .paths(PathSelectors.ant("/admin/**")) .build() .groupName(groupName) .extensions(openApiExtensionResolver.buildExtensions(groupName)); } /** * home api docket * * @return docket */ @Bean(value = "homeApi") public Docket homeApi() { String groupName = "用户功能"; return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("im.zhaojun.zfile.controller.home")) .paths(PathSelectors.any()) .build() .groupName(groupName) .extensions(openApiExtensionResolver.buildExtensions(groupName)); } /** * install api info * * @return api info */ @Bean(value = "installApi") public Docket installApi() { String groupName = "初始化功能"; return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("im.zhaojun.zfile.home.install")) .paths(PathSelectors.any()) .build() .groupName(groupName) .extensions(openApiExtensionResolver.buildExtensions(groupName)); } /** * 获取通用的全局参数 * * @return 全局参数列表 */ private List generateRequestParameters(){ RequestParameterBuilder token = new RequestParameterBuilder(); List parameters = new ArrayList<>(); token.name("zfile-token").description("token").in(In.HEADER.toValue()).required(true).build(); parameters.add(token.build()); return parameters; } /** * api 基本信息描述 * * @return ApiInfo */ private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("ZFILE 文档") .description("# 这是 ZFILE Restful 接口文档展示页面") .termsOfServiceUrl("https://www.zfile.vip") .contact(new Contact("zhaojun", "https://zfile.vip", "admin@zfile.vip")) .version("1.0") .build(); } } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/config/MybatisEnumTypeHandler.java b/src/main/java/im/zhaojun/zfile/common/config/MybatisEnumTypeHandler.java deleted file mode 100644 index 7547a5b..0000000 --- a/src/main/java/im/zhaojun/zfile/common/config/MybatisEnumTypeHandler.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c) 2011-2022, baomidou (jobob@qq.com). - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package im.zhaojun.zfile.common.config; - -import com.baomidou.mybatisplus.annotation.EnumValue; -import com.baomidou.mybatisplus.annotation.IEnum; -import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; -import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils; -import com.baomidou.mybatisplus.core.toolkit.ReflectionKit; -import com.baomidou.mybatisplus.core.toolkit.StringUtils; -import org.apache.ibatis.reflection.DefaultReflectorFactory; -import org.apache.ibatis.reflection.MetaClass; -import org.apache.ibatis.reflection.ReflectorFactory; -import org.apache.ibatis.reflection.invoker.Invoker; -import org.apache.ibatis.type.BaseTypeHandler; -import org.apache.ibatis.type.JdbcType; - -import java.lang.reflect.Field; -import java.math.BigDecimal; -import java.sql.CallableStatement; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Arrays; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; - -/** - * 自定义枚举属性转换器 - * - * @author hubin - * @since 2017-10-11 - */ -public class MybatisEnumTypeHandler> extends BaseTypeHandler { - - private static final Map TABLE_METHOD_OF_ENUM_TYPES = new ConcurrentHashMap<>(); - private static final ReflectorFactory REFLECTOR_FACTORY = new DefaultReflectorFactory(); - private final Class enumClassType; - private final Class propertyType; - private final Invoker getInvoker; - - public MybatisEnumTypeHandler(Class enumClassType) { - if (enumClassType == null) { - throw new IllegalArgumentException("Type argument cannot be null"); - } - this.enumClassType = enumClassType; - MetaClass metaClass = MetaClass.forClass(enumClassType, REFLECTOR_FACTORY); - String name = "value"; - if (!IEnum.class.isAssignableFrom(enumClassType)) { - name = findEnumValueFieldName(this.enumClassType).orElseThrow(() -> new IllegalArgumentException(String.format("Could not find @EnumValue in Class: %s.", this.enumClassType.getName()))); - } - this.propertyType = ReflectionKit.resolvePrimitiveIfNecessary(metaClass.getGetterType(name)); - this.getInvoker = metaClass.getGetInvoker(name); - } - - /** - * 查找标记标记EnumValue字段 - * - * @param clazz class - * @return EnumValue字段 - * @since 3.3.1 - */ - public static Optional findEnumValueFieldName(Class clazz) { - if (clazz != null && clazz.isEnum()) { - String className = clazz.getName(); - return Optional.ofNullable(CollectionUtils.computeIfAbsent(TABLE_METHOD_OF_ENUM_TYPES, className, key -> { - Optional fieldOptional = findEnumValueAnnotationField(clazz); - return fieldOptional.map(Field::getName).orElse(null); - })); - } - return Optional.empty(); - } - - private static Optional findEnumValueAnnotationField(Class clazz) { - return Arrays.stream(clazz.getDeclaredFields()).filter(field -> field.isAnnotationPresent(EnumValue.class)).findFirst(); - } - - /** - * 判断是否为MP枚举处理 - * - * @param clazz class - * @return 是否为MP枚举处理 - * @since 3.3.1 - */ - public static boolean isMpEnums(Class clazz) { - return clazz != null && clazz.isEnum() && (IEnum.class.isAssignableFrom(clazz) || findEnumValueFieldName(clazz).isPresent()); - } - - @SuppressWarnings("Duplicates") - @Override - public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) - throws SQLException { - if (jdbcType == null) { - ps.setObject(i, this.getValue(parameter)); - } else { - // see r3589 - ps.setObject(i, this.getValue(parameter), jdbcType.TYPE_CODE); - } - } - - @Override - public E getNullableResult(ResultSet rs, String columnName) throws SQLException { - Object value = rs.getObject(columnName); - if (null == value && rs.wasNull()) { - return null; - } - return this.valueOf(value); - } - - @Override - public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException { - Object value = rs.getObject(columnIndex, this.propertyType); - if (null == value && rs.wasNull()) { - return null; - } - return this.valueOf(value); - } - - @Override - public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { - Object value = cs.getObject(columnIndex, this.propertyType); - if (null == value && cs.wasNull()) { - return null; - } - return this.valueOf(value); - } - - private E valueOf(Object value) { - E[] es = this.enumClassType.getEnumConstants(); - return Arrays.stream(es).filter((e) -> equalsValue(value, getValue(e))).findAny().orElse(null); - } - - /** - * 值比较 - * - * @param sourceValue 数据库字段值 - * @param targetValue 当前枚举属性值 - * @return 是否匹配 - * @since 3.3.0 - */ - protected boolean equalsValue(Object sourceValue, Object targetValue) { - String sValue = StringUtils.toStringTrim(sourceValue); - String tValue = StringUtils.toStringTrim(targetValue); - if (sourceValue instanceof Number && targetValue instanceof Number - && new BigDecimal(sValue).compareTo(new BigDecimal(tValue)) == 0) { - return true; - } - return Objects.equals(sValue, tValue); - } - - private Object getValue(Object object) { - try { - return this.getInvoker.invoke(object, new Object[0]); - } catch (ReflectiveOperationException e) { - throw ExceptionUtils.mpe(e); - } - } -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/config/SaTokenConfigure.java b/src/main/java/im/zhaojun/zfile/common/config/SaTokenConfigure.java deleted file mode 100644 index 2d61aeb..0000000 --- a/src/main/java/im/zhaojun/zfile/common/config/SaTokenConfigure.java +++ /dev/null @@ -1 +0,0 @@ -package im.zhaojun.zfile.common.config; import cn.dev33.satoken.interceptor.SaRouteInterceptor; import cn.dev33.satoken.router.SaRouter; import cn.dev33.satoken.stp.StpUtil; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * SaToken 权限配置, 配置管理员才能访问管理员功能. * * @author zhaojun */ @Configuration public class SaTokenConfigure implements WebMvcConfigurer { /** * 注册权限校验拦截器, 拦截所有 /admin/** 请求, 但登陆相关的接口不需要认证. * @param registry * 拦截器注册器 */ @Override public void addInterceptors(InterceptorRegistry registry) { // 注册路由拦截器,自定义验证规则 registry.addInterceptor(new SaRouteInterceptor((req, res, handler) -> { // 根据路由划分模块,不同模块不同鉴权 SaRouter.match("/admin/**", StpUtil::checkLogin); // 忽略所有登陆相关接口 })).addPathPatterns("/**").excludePathPatterns("/admin/login", "/admin/login/**", "/admin"); } } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/exception/DisableProxyDownloadException.java b/src/main/java/im/zhaojun/zfile/common/exception/DisableProxyDownloadException.java deleted file mode 100644 index b537702..0000000 --- a/src/main/java/im/zhaojun/zfile/common/exception/DisableProxyDownloadException.java +++ /dev/null @@ -1,10 +0,0 @@ -package im.zhaojun.zfile.common.exception; - -/** - * 禁止服务器代理下载异常 - * - * @author zhaojun - */ -public class DisableProxyDownloadException extends RuntimeException { - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/exception/FileAccessException.java b/src/main/java/im/zhaojun/zfile/common/exception/FileAccessException.java deleted file mode 100644 index 928fa23..0000000 --- a/src/main/java/im/zhaojun/zfile/common/exception/FileAccessException.java +++ /dev/null @@ -1,31 +0,0 @@ -package im.zhaojun.zfile.common.exception; - -/** - * 文件权限异常 - * - * @author zhaojun - */ -public class FileAccessException extends RuntimeException { - - private static final long serialVersionUID = 1L; - - public FileAccessException() { - } - - public FileAccessException(String message) { - super(message); - } - - public FileAccessException(String message, Throwable cause) { - super(message, cause); - } - - public FileAccessException(Throwable cause) { - super(cause); - } - - public FileAccessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/exception/FileUploadException.java b/src/main/java/im/zhaojun/zfile/common/exception/FileUploadException.java deleted file mode 100644 index 5323598..0000000 --- a/src/main/java/im/zhaojun/zfile/common/exception/FileUploadException.java +++ /dev/null @@ -1,27 +0,0 @@ -package im.zhaojun.zfile.common.exception; - -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; -import lombok.Getter; - -/** - * 文件上传异常 - * - * @author zhaojun - */ -@Getter -public class FileUploadException extends RuntimeException { - - private final StorageTypeEnum storageTypeEnum; - - private final Integer storageId; - - private final String path; - - public FileUploadException(StorageTypeEnum storageTypeEnum, Integer storageId, String path, Throwable cause) { - super(cause); - this.storageTypeEnum = storageTypeEnum; - this.path = path; - this.storageId = storageId; - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/exception/GlobalException.java b/src/main/java/im/zhaojun/zfile/common/exception/GlobalException.java deleted file mode 100644 index 1cb5f1c..0000000 --- a/src/main/java/im/zhaojun/zfile/common/exception/GlobalException.java +++ /dev/null @@ -1 +0,0 @@ -package im.zhaojun.zfile.common.exception; import cn.dev33.satoken.exception.NotLoginException; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import im.zhaojun.zfile.admin.exception.ForbidFileOperationException; import im.zhaojun.zfile.admin.exception.StorageSourceAutoConfigCorsException; import im.zhaojun.zfile.admin.service.SystemConfigService; import im.zhaojun.zfile.common.exception.file.operator.GetFileInfoException; import im.zhaojun.zfile.common.exception.file.operator.ProxyDownloadFileException; import im.zhaojun.zfile.common.util.AjaxJson; import im.zhaojun.zfile.common.util.RequestHolder; import im.zhaojun.zfile.common.util.StringUtils; import lombok.extern.slf4j.Slf4j; import org.apache.catalina.connector.ClientAbortException; import org.springframework.http.HttpStatus; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.validation.BindException; import org.springframework.validation.BindingResult; import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.HashMap; import java.util.Map; /** * 全局异常处理 * * @author zhaojun */ @ControllerAdvice @Slf4j public class GlobalException { @Resource private SystemConfigService systemConfigService; @ExceptionHandler({IllegalDownloadLinkException.class}) @ResponseBody @ResponseStatus(HttpStatus.FORBIDDEN) public AjaxJson getFileInfoException(IllegalDownloadLinkException e) { return AjaxJson.getError(e.getMessage()); } @ExceptionHandler({GetFileInfoException.class}) @ResponseBody @ResponseStatus(HttpStatus.BAD_REQUEST) public AjaxJson getFileInfoException(GetFileInfoException e) { log.error("获取文件信息异常 {}. 存储源 ID: {}, 文件路径: {}", e.getMessage(), e.getStorageId(), e.getPathAndName()); return AjaxJson.getError("获取文件信息异常, 请联系管理员"); } @ExceptionHandler({ProxyDownloadFileException.class}) @ResponseBody @ResponseStatus(HttpStatus.BAD_REQUEST) public AjaxJson proxyDownloadFileException(ProxyDownloadFileException e) { log.error("代理下载文件异常 {}. 存储源 ID: {}, 下载路径: {}", e.getMessage(), e.getStorageId(), e.getPathAndName()); return AjaxJson.getError("下载文件异常, 请联系管理员!"); } @ExceptionHandler({LoginVerifyException.class}) @ResponseBody @ResponseStatus(HttpStatus.FORBIDDEN) public AjaxJson loginVerifyException(LoginVerifyException e) { return AjaxJson.getError(e.getMessage()); } @ExceptionHandler({StorageSourceNotSupportProxyUploadException.class}) @ResponseBody @ResponseStatus(HttpStatus.BAD_REQUEST) public AjaxJson storageSourceNotSupportProxyUploadException(StorageSourceNotSupportProxyUploadException e) { return AjaxJson.getError("非法操作, 当前存储源不支持此方式上传."); } @ExceptionHandler({DisableProxyDownloadException.class}) @ResponseBody @ResponseStatus(HttpStatus.BAD_REQUEST) public AjaxJson disableProxyDownloadException(DisableProxyDownloadException e) { return AjaxJson.getError("非法操作, 当前文件不支持此类下载方式."); } @ExceptionHandler({UnsupportedOperationException.class}) @ResponseBody @ResponseStatus(HttpStatus.BAD_REQUEST) public AjaxJson handleFileUploadException(UnsupportedOperationException e) { return AjaxJson.getError(e.getMessage()); } @ExceptionHandler({FileUploadException.class}) @ResponseBody @ResponseStatus(HttpStatus.UNAUTHORIZED) public AjaxJson handleFileUploadException(FileUploadException e) { if (log.isDebugEnabled()) { log.debug("上传文件失败: 存储类型: {}, 存储源 id: {}, 存储源路径: {}", e.getStorageTypeEnum(), e.getStorageId(), e.getPath(), e); } return AjaxJson.getError("上传失败"); } @ExceptionHandler({FileAccessException.class}) @ResponseBody @ResponseStatus(HttpStatus.UNAUTHORIZED) public AjaxJson handleFileAccessException(FileAccessException e) { return AjaxJson.getError(e.getMessage()); } @ExceptionHandler({HttpMessageNotReadableException.class}) @ResponseBody @ResponseStatus(HttpStatus.BAD_REQUEST) public AjaxJson handlerHttpMessageNotReadableException(HttpMessageNotReadableException e) { return AjaxJson.getBadRequestError("请求参数不合法"); } @ExceptionHandler({NotEnabledStorageSourceException.class}) @ResponseStatus(HttpStatus.FORBIDDEN) @ResponseBody public AjaxJson notEnabledDrive() { return AjaxJson.getError("存储源已关闭"); } @ExceptionHandler({NotExistFileException.class}) @ResponseBody public AjaxJson notExistFile() { return AjaxJson.getError("文件不存在"); } /** * 捕获 ClientAbortException 异常, 不做任何处理, 防止出现大量堆栈日志输出, 此异常不影响功能. */ @ExceptionHandler({HttpMediaTypeNotAcceptableException.class, ClientAbortException.class}) @ResponseBody @ResponseStatus public void clientAbortException() { // if (log.isDebugEnabled()) { // log.debug("出现了断开异常:", ex); // } } @ExceptionHandler(value = {MethodArgumentNotValidException.class, BindException.class}) @ResponseBody public AjaxJson handleValidException(Exception e) { BindingResult bindingResult = null; if (e instanceof MethodArgumentNotValidException) { bindingResult = ((MethodArgumentNotValidException) e).getBindingResult(); } else if (e instanceof BindException) { bindingResult = ((BindException) e).getBindingResult(); } Map errorMap = new HashMap<>(16); bindingResult.getFieldErrors().forEach((fieldError) -> errorMap.put(fieldError.getField(), fieldError.getDefaultMessage()) ); return new AjaxJson(400, "非法参数 !", errorMap); } /** * 密码校验异常 */ @ExceptionHandler({PasswordVerifyException.class}) @ResponseBody @ResponseStatus public AjaxJson passwordVerifyException(PasswordVerifyException ex) { return AjaxJson.get(ex.getCode(), ex.getMessage()); } /** * 无效的存储源异常 */ @ExceptionHandler({InvalidStorageSourceException.class}) @ResponseBody @ResponseStatus(HttpStatus.BAD_REQUEST) public AjaxJson invalidDriveException() { return AjaxJson.getBadRequestError("此存储源不存在或初始化失败, 请检查后台参数配置"); } /** * 文件预览异常 */ @ExceptionHandler({PreviewException.class}) @ResponseBody @ResponseStatus public AjaxJson previewException(PreviewException ex) { return AjaxJson.getError(ex.getMessage()); } /** * 初始化异常 */ @ExceptionHandler({InitializeStorageSourceException.class}) @ResponseBody @ResponseStatus public AjaxJson initializeException(InitializeStorageSourceException ex) { return AjaxJson.getError(ex.getMessage()); } /** * 初始化时自动设置 cors 异常 */ @ExceptionHandler({StorageSourceAutoConfigCorsException.class}) @ResponseBody @ResponseStatus public AjaxJson autoConfigCorsException(StorageSourceAutoConfigCorsException ex) { log.error("跨域配置失败, 存储源初始化信息 {}, 异常信息: ", JSON.toJSON(ex.getIStorageParam()), ex); return AjaxJson.getError(ex.getMessage()); } /** * 无权限时,进行文件操作异常. */ @ExceptionHandler({ForbidFileOperationException.class}) @ResponseBody @ResponseStatus public AjaxJson autoConfigCorsException(ForbidFileOperationException ex) { log.error("存储源 {} 拦截非法的文件操作 {}", ex.getStorageId(), ex.getAction()); return AjaxJson.getError("非法操作"); } @ExceptionHandler @ResponseBody @ResponseStatus public AjaxJson extraExceptionHandler(Exception e) { log.error(e.getMessage(), e); if (e.getClass() == Exception.class) { return AjaxJson.getError("系统异常, 请联系管理员"); } else { return AjaxJson.getError(e.getMessage()); } } /** * 登录异常拦截器 */ @ExceptionHandler(NotLoginException.class) @ResponseStatus(HttpStatus.UNAUTHORIZED) @ResponseBody public AjaxJson handlerNotLoginException(NotLoginException e) { HttpServletRequest request = RequestHolder.getRequest(); String axiosRequest = request.getHeader("axios-request"); if (StrUtil.isNotEmpty(axiosRequest)){ return AjaxJson.getNotLogin(); } try { String domain = systemConfigService.getRealFrontDomain(); String loginUrl = StringUtils.removeDuplicateSlashes(domain + "/login"); RequestHolder.getResponse().sendRedirect(loginUrl); } catch (IOException ex) { throw new RuntimeException(ex); } return null; } } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/exception/IllegalDownloadLinkException.java b/src/main/java/im/zhaojun/zfile/common/exception/IllegalDownloadLinkException.java deleted file mode 100644 index 6a8d1ee..0000000 --- a/src/main/java/im/zhaojun/zfile/common/exception/IllegalDownloadLinkException.java +++ /dev/null @@ -1,21 +0,0 @@ -package im.zhaojun.zfile.common.exception; - -/** - * 非法使用下载链接异常. - * - * @author zhaojun - */ -public class IllegalDownloadLinkException extends RuntimeException { - - public IllegalDownloadLinkException() { - super(); - } - - public IllegalDownloadLinkException(String message) { - super(message); - } - - public IllegalDownloadLinkException(String message, Throwable cause) { - super(message, cause); - } -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/exception/InitializeStorageSourceException.java b/src/main/java/im/zhaojun/zfile/common/exception/InitializeStorageSourceException.java deleted file mode 100644 index 1724821..0000000 --- a/src/main/java/im/zhaojun/zfile/common/exception/InitializeStorageSourceException.java +++ /dev/null @@ -1,30 +0,0 @@ -package im.zhaojun.zfile.common.exception; - -/** - * 存储源初始化异常 - * - * @author zhaojun - */ -public class InitializeStorageSourceException extends RuntimeException { - - private static final long serialVersionUID = -1920550904063819880L; - - public InitializeStorageSourceException() { - } - - public InitializeStorageSourceException(String message) { - super(message); - } - - public InitializeStorageSourceException(String message, Throwable cause) { - super(message, cause); - } - - public InitializeStorageSourceException(Throwable cause) { - super(cause); - } - - public InitializeStorageSourceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/exception/InstallSystemException.java b/src/main/java/im/zhaojun/zfile/common/exception/InstallSystemException.java deleted file mode 100644 index 239fc1a..0000000 --- a/src/main/java/im/zhaojun/zfile/common/exception/InstallSystemException.java +++ /dev/null @@ -1,30 +0,0 @@ -package im.zhaojun.zfile.common.exception; - -/** - * 系统初始化异常 - * - * @author zhaojun - */ -public class InstallSystemException extends RuntimeException { - - public InstallSystemException() { - super(); - } - - public InstallSystemException(String message) { - super(message); - } - - public InstallSystemException(String message, Throwable cause) { - super(message, cause); - } - - public InstallSystemException(Throwable cause) { - super(cause); - } - - protected InstallSystemException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/exception/InvalidShortLinkException.java b/src/main/java/im/zhaojun/zfile/common/exception/InvalidShortLinkException.java deleted file mode 100644 index bf1e4d6..0000000 --- a/src/main/java/im/zhaojun/zfile/common/exception/InvalidShortLinkException.java +++ /dev/null @@ -1,29 +0,0 @@ -package im.zhaojun.zfile.common.exception; - -/** - * 无效的直链异常 - * - * @author zhaojun - */ -public class InvalidShortLinkException extends RuntimeException { - - public InvalidShortLinkException() { - } - - public InvalidShortLinkException(String message) { - super(message); - } - - public InvalidShortLinkException(String message, Throwable cause) { - super(message, cause); - } - - public InvalidShortLinkException(Throwable cause) { - super(cause); - } - - public InvalidShortLinkException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/exception/InvalidStorageSourceException.java b/src/main/java/im/zhaojun/zfile/common/exception/InvalidStorageSourceException.java deleted file mode 100644 index e4c4c5b..0000000 --- a/src/main/java/im/zhaojun/zfile/common/exception/InvalidStorageSourceException.java +++ /dev/null @@ -1,29 +0,0 @@ -package im.zhaojun.zfile.common.exception; - -/** - * 无效的存储源异常 - * - * @author zhaojun - */ -public class InvalidStorageSourceException extends RuntimeException { - - public InvalidStorageSourceException() { - } - - public InvalidStorageSourceException(String message) { - super(message); - } - - public InvalidStorageSourceException(String message, Throwable cause) { - super(message, cause); - } - - public InvalidStorageSourceException(Throwable cause) { - super(cause); - } - - public InvalidStorageSourceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/exception/NotAllowedDownloadException.java b/src/main/java/im/zhaojun/zfile/common/exception/NotAllowedDownloadException.java deleted file mode 100644 index 0489b31..0000000 --- a/src/main/java/im/zhaojun/zfile/common/exception/NotAllowedDownloadException.java +++ /dev/null @@ -1,29 +0,0 @@ -package im.zhaojun.zfile.common.exception; - -/** - * 文件不允许下载异常 - * - * @author zhaojun - */ -public class NotAllowedDownloadException extends RuntimeException { - - public NotAllowedDownloadException() { - } - - public NotAllowedDownloadException(String message) { - super(message); - } - - public NotAllowedDownloadException(String message, Throwable cause) { - super(message, cause); - } - - public NotAllowedDownloadException(Throwable cause) { - super(cause); - } - - public NotAllowedDownloadException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/exception/NotEnabledStorageSourceException.java b/src/main/java/im/zhaojun/zfile/common/exception/NotEnabledStorageSourceException.java deleted file mode 100644 index 515c852..0000000 --- a/src/main/java/im/zhaojun/zfile/common/exception/NotEnabledStorageSourceException.java +++ /dev/null @@ -1,29 +0,0 @@ -package im.zhaojun.zfile.common.exception; - -/** - * 未启用的存储源异常 - * - * @author zhaojun - */ -public class NotEnabledStorageSourceException extends RuntimeException { - - public NotEnabledStorageSourceException() { - } - - public NotEnabledStorageSourceException(String message) { - super(message); - } - - public NotEnabledStorageSourceException(String message, Throwable cause) { - super(message, cause); - } - - public NotEnabledStorageSourceException(Throwable cause) { - super(cause); - } - - public NotEnabledStorageSourceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/exception/NotExistFileException.java b/src/main/java/im/zhaojun/zfile/common/exception/NotExistFileException.java deleted file mode 100644 index 24d114c..0000000 --- a/src/main/java/im/zhaojun/zfile/common/exception/NotExistFileException.java +++ /dev/null @@ -1,30 +0,0 @@ -package im.zhaojun.zfile.common.exception; - -/** - * 不存在的文件异常 - * - * @author zhaojun - */ -public class NotExistFileException extends RuntimeException { - - public NotExistFileException() { - super(); - } - - public NotExistFileException(String message) { - super(message); - } - - public NotExistFileException(String message, Throwable cause) { - super(message, cause); - } - - public NotExistFileException(Throwable cause) { - super(cause); - } - - protected NotExistFileException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/exception/PreviewException.java b/src/main/java/im/zhaojun/zfile/common/exception/PreviewException.java deleted file mode 100644 index dc567ac..0000000 --- a/src/main/java/im/zhaojun/zfile/common/exception/PreviewException.java +++ /dev/null @@ -1,29 +0,0 @@ -package im.zhaojun.zfile.common.exception; - -/** - * 文件预览异常类 - * - * @author zhaojun - */ -public class PreviewException extends RuntimeException { - - public PreviewException() { - } - - public PreviewException(String message) { - super(message); - } - - public PreviewException(String message, Throwable cause) { - super(message, cause); - } - - public PreviewException(Throwable cause) { - super(cause); - } - - public PreviewException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/exception/RefreshCacheException.java b/src/main/java/im/zhaojun/zfile/common/exception/RefreshCacheException.java deleted file mode 100644 index 90e7e72..0000000 --- a/src/main/java/im/zhaojun/zfile/common/exception/RefreshCacheException.java +++ /dev/null @@ -1,29 +0,0 @@ -package im.zhaojun.zfile.common.exception; - -/** - * 刷新缓存时出现的异常信息 - * - * @author zhaojun - */ -public class RefreshCacheException extends RuntimeException { - - public RefreshCacheException() { - } - - public RefreshCacheException(String message) { - super(message); - } - - public RefreshCacheException(String message, Throwable cause) { - super(message, cause); - } - - public RefreshCacheException(Throwable cause) { - super(cause); - } - - public RefreshCacheException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/exception/TextParseException.java b/src/main/java/im/zhaojun/zfile/common/exception/TextParseException.java deleted file mode 100644 index e7d5302..0000000 --- a/src/main/java/im/zhaojun/zfile/common/exception/TextParseException.java +++ /dev/null @@ -1,30 +0,0 @@ -package im.zhaojun.zfile.common.exception; - -/** - * 文件解析异常 - * - * @author zhaojun - */ -public class TextParseException extends RuntimeException { - - public TextParseException() { - super(); - } - - public TextParseException(String message) { - super(message); - } - - public TextParseException(String message, Throwable cause) { - super(message, cause); - } - - public TextParseException(Throwable cause) { - super(cause); - } - - protected TextParseException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/exception/UnSupportedOperation.java b/src/main/java/im/zhaojun/zfile/common/exception/UnSupportedOperation.java deleted file mode 100644 index ea4911f..0000000 --- a/src/main/java/im/zhaojun/zfile/common/exception/UnSupportedOperation.java +++ /dev/null @@ -1,29 +0,0 @@ -package im.zhaojun.zfile.common.exception; - -/** - * 不支持的操作异常 - * - * @author zhaojun - */ -public class UnSupportedOperation extends RuntimeException { - - public UnSupportedOperation() { - super(); - } - - public UnSupportedOperation(String message) { - super(message); - } - - public UnSupportedOperation(String message, Throwable cause) { - super(message, cause); - } - - public UnSupportedOperation(Throwable cause) { - super(cause); - } - - protected UnSupportedOperation(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/exception/file/StorageSourceException.java b/src/main/java/im/zhaojun/zfile/common/exception/file/StorageSourceException.java deleted file mode 100644 index 4a4f510..0000000 --- a/src/main/java/im/zhaojun/zfile/common/exception/file/StorageSourceException.java +++ /dev/null @@ -1,37 +0,0 @@ -package im.zhaojun.zfile.common.exception.file; - -import lombok.Getter; -import lombok.Setter; - -/** - * 存储源异常 - * - * @author zhaojun - */ -@Getter -@Setter -public class StorageSourceException extends RuntimeException { - - // 存储源 ID - private Integer storageId; - - public StorageSourceException(Integer storageId) { - this.storageId = storageId; - } - - public StorageSourceException(Integer storageId, String message) { - super(message); - this.storageId = storageId; - } - - public StorageSourceException(Integer storageId, Throwable cause) { - super(cause); - this.storageId = storageId; - } - - public StorageSourceException(Integer storageId, String message, Throwable cause) { - super(message, cause); - this.storageId = storageId; - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/exception/file/operator/DownloadFileException.java b/src/main/java/im/zhaojun/zfile/common/exception/file/operator/DownloadFileException.java deleted file mode 100644 index 708d572..0000000 --- a/src/main/java/im/zhaojun/zfile/common/exception/file/operator/DownloadFileException.java +++ /dev/null @@ -1,24 +0,0 @@ -package im.zhaojun.zfile.common.exception.file.operator; - -import im.zhaojun.zfile.common.exception.file.StorageSourceException; -import lombok.Getter; -import lombok.Setter; - -/** - * 文件下载异常 - * - * @author zhaojun - */ -@Getter -@Setter -public class DownloadFileException extends StorageSourceException { - - // 下载文件路径 - private String pathAndName; - - public DownloadFileException(Integer storageId, String pathAndName, Throwable cause) { - super(storageId, cause); - this.pathAndName = pathAndName; - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/exception/file/operator/GetFileInfoException.java b/src/main/java/im/zhaojun/zfile/common/exception/file/operator/GetFileInfoException.java deleted file mode 100644 index 09c5ced..0000000 --- a/src/main/java/im/zhaojun/zfile/common/exception/file/operator/GetFileInfoException.java +++ /dev/null @@ -1,35 +0,0 @@ -package im.zhaojun.zfile.common.exception.file.operator; - -import im.zhaojun.zfile.common.exception.file.StorageSourceException; -import lombok.Getter; -import lombok.Setter; - -/** - * 获取文件信息异常 - * - * @author zhaojun - */ -@Getter -@Setter -public class GetFileInfoException extends StorageSourceException { - - // 文件信息路径 - private String pathAndName; - - public GetFileInfoException(Integer storageId, String pathAndName) { - super(storageId); - this.pathAndName = pathAndName; - } - - public GetFileInfoException(Integer storageId, String pathAndName, String message) { - super(storageId, message); - this.pathAndName = pathAndName; - } - - - public GetFileInfoException(Integer storageId, String pathAndName, Throwable cause) { - super(storageId, cause); - this.pathAndName = pathAndName; - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/exception/file/operator/ProxyDownloadFileException.java b/src/main/java/im/zhaojun/zfile/common/exception/file/operator/ProxyDownloadFileException.java deleted file mode 100644 index 278016f..0000000 --- a/src/main/java/im/zhaojun/zfile/common/exception/file/operator/ProxyDownloadFileException.java +++ /dev/null @@ -1,24 +0,0 @@ -package im.zhaojun.zfile.common.exception.file.operator; - -import im.zhaojun.zfile.common.exception.file.StorageSourceException; -import lombok.Getter; -import lombok.Setter; - -/** - * 代理文件下载异常 - * - * @author zhaojun - */ -@Getter -@Setter -public class ProxyDownloadFileException extends StorageSourceException { - - // 下载文件路径 - private String pathAndName; - - public ProxyDownloadFileException(Integer storageId, String pathAndName, Throwable cause) { - super(storageId, cause); - this.pathAndName = pathAndName; - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/util/AjaxJson.java b/src/main/java/im/zhaojun/zfile/common/util/AjaxJson.java deleted file mode 100644 index bf05659..0000000 --- a/src/main/java/im/zhaojun/zfile/common/util/AjaxJson.java +++ /dev/null @@ -1 +0,0 @@ -package im.zhaojun.zfile.common.util; import io.swagger.annotations.ApiModelProperty; import java.io.Serializable; import java.util.List; /** * ajax 请求返回 JSON 格式数据的封装 * * @author zhaojun */ public class AjaxJson implements Serializable { private static final long serialVersionUID = 1L; // 序列化版本号 public static final int CODE_SUCCESS = 0; // 成功状态码 public static final int CODE_ERROR = 500; // 错误状态码 public static final int CODE_WARNING = 501; // 警告状态码 public static final int CODE_NOT_JUR = 403; // 无权限状态码 public static final int CODE_NOT_LOGIN = 401; // 未登录状态码 public static final int CODE_INVALID_REQUEST = 400; // 无效请求状态码 public static final int REQUIRED_PASSWORD = 405; // 未输入密码 public static final int INVALID_PASSWORD = 406; // 无效的密码 @ApiModelProperty(value = "业务状态码,0 为正常,其他值均为异常,异常情况下见响应消息", example = "0") private final int code; @ApiModelProperty(value = "响应消息", example = "ok") private String msg; @ApiModelProperty(value = "响应数据") private T data; @ApiModelProperty(value = "数据总条数,分页情况有效") private final Long dataCount; /** * 返回code */ public int getCode() { return this.code; } /** * 给 msg 赋值,连缀风格 */ public AjaxJson setMsg(String msg) { this.msg = msg; return this; } public String getMsg() { return this.msg; } /** * 给data赋值,连缀风格 */ public AjaxJson setData(T data) { this.data = data; return this; } // ============================ 构建 ================================== public AjaxJson(int code, String msg, T data) { this.code = code; this.msg = msg; this.data = data; this.dataCount = null; } public AjaxJson(int code, String msg, T data, Long dataCount) { this.code = code; this.msg = msg; this.data = data; this.dataCount = dataCount; } // 返回成功 public static AjaxJson getSuccess() { return new AjaxJson<>(CODE_SUCCESS, "ok", null, null); } public static AjaxJson getSuccess(String msg) { return new AjaxJson<>(CODE_SUCCESS, msg, null, null); } public static AjaxJson getSuccess(String msg, Object data) { return new AjaxJson<>(CODE_SUCCESS, msg, data, null); } public static AjaxJson getSuccessData(T data) { return new AjaxJson<>(CODE_SUCCESS, "ok", data, null); } public static AjaxJson getSuccessArray(Object... data) { return new AjaxJson<>(CODE_SUCCESS, "ok", data, null); } // 返回失败 public static AjaxJson getError() { return new AjaxJson<>(CODE_ERROR, "error", null, null); } public static AjaxJson getError(String msg) { return new AjaxJson<>(CODE_ERROR, msg, null, null); } public static AjaxJson getBadRequestError(String msg) { return new AjaxJson<>(CODE_INVALID_REQUEST, msg, null, null); } // 返回警告 public static AjaxJson getWarning() { return new AjaxJson<>(CODE_ERROR, "warning", null, null); } public static AjaxJson getWarning(String msg) { return new AjaxJson<>(CODE_WARNING, msg, null, null); } // 返回未登录 public static AjaxJson getNotLogin() { return new AjaxJson<>(CODE_NOT_LOGIN, "未登录,请登录后再次访问", null, null); } // 返回没有权限的 public static AjaxJson getNotJur(String msg) { return new AjaxJson<>(CODE_NOT_JUR, msg, null, null); } // 返回一个自定义状态码的 public static AjaxJson get(int code, String msg) { return new AjaxJson<>(code, msg, null, null); } // 返回分页和数据的 public static AjaxJson getPageData(Long dataCount, Object data) { return new AjaxJson<>(CODE_SUCCESS, "ok", data, dataCount); } // 返回,根据布尔值来确定最终结果的 (true=ok,false=error) public static AjaxJson getByBoolean(boolean b) { return b ? getSuccess("ok") : getError("error"); } @SuppressWarnings("rawtypes") @Override public String toString() { String data_string = null; if (data == null) { } else if (data instanceof List) { data_string = "List(length=" + ((List) data).size() + ")"; } else { data_string = data.toString(); } return "{" + "\"code\": " + this.getCode() + ", \"msg\": \"" + this.getMsg() + "\"" + ", \"data\": " + data_string + ", \"dataCount\": " + dataCount + "}"; } public T getData() { return data; } public Long getDataCount() { return dataCount; } } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/core/CommonResultControllerAdvice.java b/src/main/java/im/zhaojun/zfile/core/CommonResultControllerAdvice.java new file mode 100644 index 0000000..8a89fa0 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/CommonResultControllerAdvice.java @@ -0,0 +1,67 @@ +package im.zhaojun.zfile.core; + +import im.zhaojun.zfile.core.util.AjaxJson; +import org.slf4j.MDC; +import org.springframework.core.MethodParameter; +import org.springframework.http.MediaType; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter; +import org.springframework.http.converter.json.MappingJacksonValue; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; + +/** + * @author zhaojun + */ +@ControllerAdvice +public class CommonResultControllerAdvice implements ResponseBodyAdvice { + + @Override + public boolean supports(MethodParameter returnType, + @NonNull Class> converterType) { + return AbstractJackson2HttpMessageConverter.class.isAssignableFrom(converterType); + } + + @Override + @NonNull + public final Object beforeBodyWrite(@Nullable Object body, + @NonNull MethodParameter returnType, + @NonNull MediaType contentType, + @NonNull Class> converterType, + @NonNull ServerHttpRequest request, + @NonNull ServerHttpResponse response) { + MappingJacksonValue container = getOrCreateContainer(body); + // The contain body will never be null + beforeBodyWriteInternal(container, contentType, returnType, request, response); + return container; + } + + /** + * Wrap the body in a {@link MappingJacksonValue} value container (for providing + * additional serialization instructions) or simply cast it if already wrapped. + */ + private MappingJacksonValue getOrCreateContainer(Object body) { + return body instanceof MappingJacksonValue ? (MappingJacksonValue) body : + new MappingJacksonValue(body); + } + + private void beforeBodyWriteInternal(MappingJacksonValue bodyContainer, + MediaType contentType, + MethodParameter returnType, + ServerHttpRequest request, + ServerHttpResponse response) { + // Get return body + Object returnBody = bodyContainer.getValue(); + + if (returnBody instanceof AjaxJson) { + // If the return body is instance of BaseResponse, then just do nothing + AjaxJson baseResponse = (AjaxJson) returnBody; + baseResponse.setTraceId(MDC.get("traceId")); + } + } + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/core/config/FlywayDbInitializer.java b/src/main/java/im/zhaojun/zfile/core/config/FlywayDbInitializer.java new file mode 100644 index 0000000..1174b48 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/config/FlywayDbInitializer.java @@ -0,0 +1 @@ +package im.zhaojun.zfile.core.config; import cn.hutool.core.util.StrUtil; import org.flywaydb.core.Flyway; import org.springframework.context.annotation.Configuration; import javax.annotation.PostConstruct; import javax.annotation.Resource; import javax.sql.DataSource; import java.sql.SQLException; import java.util.Locale; /** * 数据库初始化 * * @author zhaojun */ @Configuration public class FlywayDbInitializer { public static final String[] SUPPORT_DB_TYPE = new String[]{"mysql", "sqlite"}; @Resource private DataSource dataSource; /** * 启动时根据当前数据库类型执行数据库初始化 */ @PostConstruct public void migrateFlyway() { try { String databaseProductName = dataSource.getConnection().getMetaData().getDatabaseProductName(); String dbType = databaseProductName.toLowerCase(Locale.ROOT); // 检查当前数据库类型是否支持 if (!StrUtil.equalsAnyIgnoreCase(dbType, SUPPORT_DB_TYPE)) { throw new RuntimeException("不支持的数据库类型 [" + dbType + "]"); } Flyway load = Flyway.configure().dataSource(dataSource).outOfOrder(true).locations("db/migration-" + dbType).load(); load.migrate(); } catch (SQLException e) { e.printStackTrace(); } } } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/config/JacksonEnumDeserializer.java b/src/main/java/im/zhaojun/zfile/core/config/JacksonEnumDeserializer.java similarity index 98% rename from src/main/java/im/zhaojun/zfile/common/config/JacksonEnumDeserializer.java rename to src/main/java/im/zhaojun/zfile/core/config/JacksonEnumDeserializer.java index cc7fab6..b3c6732 100644 --- a/src/main/java/im/zhaojun/zfile/common/config/JacksonEnumDeserializer.java +++ b/src/main/java/im/zhaojun/zfile/core/config/JacksonEnumDeserializer.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.common.config; +package im.zhaojun.zfile.core.config; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.BeanProperty; diff --git a/src/main/java/im/zhaojun/zfile/core/config/Knife4jConfiguration.java b/src/main/java/im/zhaojun/zfile/core/config/Knife4jConfiguration.java new file mode 100644 index 0000000..c3eda55 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/config/Knife4jConfiguration.java @@ -0,0 +1 @@ +package im.zhaojun.zfile.core.config; import com.github.xiaoymin.knife4j.spring.extension.OpenApiExtensionResolver; import io.swagger.models.auth.In; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.builders.RequestParameterBuilder; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.Contact; import springfox.documentation.service.RequestParameter; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; import java.util.ArrayList; import java.util.List; /** * @author zhaojun */ @Configuration @EnableSwagger2 public class Knife4jConfiguration { private final OpenApiExtensionResolver openApiExtensionResolver; @Autowired public Knife4jConfiguration(OpenApiExtensionResolver openApiExtensionResolver) { this.openApiExtensionResolver = openApiExtensionResolver; } /** * base api docket * * @return docket */ @Bean(value = "baseApi") public Docket baseApi() { String groupName = "前台功能"; return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("im.zhaojun.zfile.module")) .paths(PathSelectors.ant("/admin/**").negate()) .build() .groupName(groupName) .extensions(openApiExtensionResolver.buildExtensions(groupName)); } /** * admin api docket * * @return docket */ @Bean(value = "adminApi") public Docket adminApi() { String groupName = "管理员功能"; return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) // 全局请求参数 .globalRequestParameters(generateRequestParameters()) .select() .apis(RequestHandlerSelectors.basePackage("im.zhaojun.zfile.module")) .paths(PathSelectors.ant("/admin/**")) .build() .groupName(groupName) .extensions(openApiExtensionResolver.buildExtensions(groupName)); } /** * 获取通用的全局参数 * * @return 全局参数列表 */ private List generateRequestParameters(){ RequestParameterBuilder token = new RequestParameterBuilder(); List parameters = new ArrayList<>(); token.name("zfile-token").description("token").in(In.HEADER.toValue()).required(true).build(); parameters.add(token.build()); return parameters; } /** * api 基本信息描述 * * @return ApiInfo */ private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("ZFILE 文档") .description("# 这是 ZFILE Restful 接口文档展示页面") .termsOfServiceUrl("https://www.zfile.vip") .contact(new Contact("zhaojun", "https://zfile.vip", "admin@zfile.vip")) .version("1.0") .build(); } } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/config/MyBatisPlusConfig.java b/src/main/java/im/zhaojun/zfile/core/config/MyBatisPlusConfig.java similarity index 97% rename from src/main/java/im/zhaojun/zfile/common/config/MyBatisPlusConfig.java rename to src/main/java/im/zhaojun/zfile/core/config/MyBatisPlusConfig.java index ef225e3..12b21eb 100644 --- a/src/main/java/im/zhaojun/zfile/common/config/MyBatisPlusConfig.java +++ b/src/main/java/im/zhaojun/zfile/core/config/MyBatisPlusConfig.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.common.config; +package im.zhaojun.zfile.core.config; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; diff --git a/src/main/java/im/zhaojun/zfile/common/config/RestTemplateConfig.java b/src/main/java/im/zhaojun/zfile/core/config/RestTemplateConfig.java similarity index 92% rename from src/main/java/im/zhaojun/zfile/common/config/RestTemplateConfig.java rename to src/main/java/im/zhaojun/zfile/core/config/RestTemplateConfig.java index 20baf15..d3e485b 100644 --- a/src/main/java/im/zhaojun/zfile/common/config/RestTemplateConfig.java +++ b/src/main/java/im/zhaojun/zfile/core/config/RestTemplateConfig.java @@ -1,8 +1,8 @@ -package im.zhaojun.zfile.common.config; +package im.zhaojun.zfile.core.config; -import im.zhaojun.zfile.admin.constant.StorageConfigConstant; -import im.zhaojun.zfile.admin.model.entity.StorageSourceConfig; -import im.zhaojun.zfile.admin.service.StorageSourceConfigService; +import im.zhaojun.zfile.module.storage.constant.StorageConfigConstant; +import im.zhaojun.zfile.module.storage.model.entity.StorageSourceConfig; +import im.zhaojun.zfile.module.storage.service.StorageSourceConfigService; import org.apache.http.client.HttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.springframework.context.annotation.Bean; diff --git a/src/main/java/im/zhaojun/zfile/core/config/SaTokenConfigure.java b/src/main/java/im/zhaojun/zfile/core/config/SaTokenConfigure.java new file mode 100644 index 0000000..48a79e5 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/config/SaTokenConfigure.java @@ -0,0 +1 @@ +package im.zhaojun.zfile.core.config; import cn.dev33.satoken.interceptor.SaRouteInterceptor; import cn.dev33.satoken.router.SaRouter; import cn.dev33.satoken.stp.StpUtil; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * SaToken 权限配置, 配置管理员才能访问管理员功能. * * @author zhaojun */ @Configuration public class SaTokenConfigure implements WebMvcConfigurer { /** * 注册权限校验拦截器, 拦截所有 /admin/** 请求, 但登陆相关的接口不需要认证. * @param registry * 拦截器注册器 */ @Override public void addInterceptors(InterceptorRegistry registry) { // 注册路由拦截器,自定义验证规则 registry.addInterceptor(new SaRouteInterceptor((req, res, handler) -> { // 根据路由划分模块,不同模块不同鉴权 SaRouter.match("/admin/**", StpUtil::checkLogin); // 忽略所有登陆相关接口 })).addPathPatterns("/**").excludePathPatterns("/admin/login", "/admin/login/**", "/admin"); } } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/core/config/SpringCacheConfig.java b/src/main/java/im/zhaojun/zfile/core/config/SpringCacheConfig.java new file mode 100644 index 0000000..8d4a437 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/config/SpringCacheConfig.java @@ -0,0 +1,27 @@ +package im.zhaojun.zfile.core.config; + +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cache.concurrent.ConcurrentMapCacheManager; +import org.springframework.cache.transaction.TransactionAwareCacheManagerProxy; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Spring Cache 相关配置 + * + * @author zhaojun + */ +@Configuration +@EnableCaching +public class SpringCacheConfig { + + /** + * 使用 TransactionAwareCacheManagerProxy 装饰 ConcurrentMapCacheManager,使其支持事务 (将 put、evict、clear 操作延迟到事务成功提交再执行.) + */ + @Bean + public CacheManager cacheManager() { + return new TransactionAwareCacheManagerProxy(new ConcurrentMapCacheManager()); + } + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/config/StringToEnumConverterFactory.java b/src/main/java/im/zhaojun/zfile/core/config/StringToEnumConverterFactory.java similarity index 99% rename from src/main/java/im/zhaojun/zfile/common/config/StringToEnumConverterFactory.java rename to src/main/java/im/zhaojun/zfile/core/config/StringToEnumConverterFactory.java index 914b73f..2ad353b 100644 --- a/src/main/java/im/zhaojun/zfile/common/config/StringToEnumConverterFactory.java +++ b/src/main/java/im/zhaojun/zfile/core/config/StringToEnumConverterFactory.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.common.config; +package im.zhaojun.zfile.core.config; import com.baomidou.mybatisplus.annotation.EnumValue; import com.baomidou.mybatisplus.annotation.IEnum; diff --git a/src/main/java/im/zhaojun/zfile/common/config/WebMvcConfig.java b/src/main/java/im/zhaojun/zfile/core/config/WebMvcConfig.java similarity index 93% rename from src/main/java/im/zhaojun/zfile/common/config/WebMvcConfig.java rename to src/main/java/im/zhaojun/zfile/core/config/WebMvcConfig.java index 591c142..18ce863 100644 --- a/src/main/java/im/zhaojun/zfile/common/config/WebMvcConfig.java +++ b/src/main/java/im/zhaojun/zfile/core/config/WebMvcConfig.java @@ -1,5 +1,6 @@ -package im.zhaojun.zfile.common.config; +package im.zhaojun.zfile.core.config; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.server.ConfigurableWebServerFactory; import org.springframework.boot.web.server.ErrorPage; @@ -25,7 +26,7 @@ public class WebMvcConfig implements WebMvcConfigurer { /** * 添加自定义枚举格式化器. - * @see im.zhaojun.zfile.home.model.enums.StorageTypeEnum + * @see StorageTypeEnum */ @Override public void addFormatters(FormatterRegistry registry) { @@ -60,5 +61,8 @@ public class WebMvcConfig implements WebMvcConfigurer { factory.setErrorPages(errorPages); }; } - + + + + } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/config/ZFileProperties.java b/src/main/java/im/zhaojun/zfile/core/config/ZFileProperties.java similarity index 84% rename from src/main/java/im/zhaojun/zfile/common/config/ZFileProperties.java rename to src/main/java/im/zhaojun/zfile/core/config/ZFileProperties.java index 74679de..8a5f74f 100644 --- a/src/main/java/im/zhaojun/zfile/common/config/ZFileProperties.java +++ b/src/main/java/im/zhaojun/zfile/core/config/ZFileProperties.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.common.config; +package im.zhaojun.zfile.core.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -7,8 +7,6 @@ import org.springframework.stereotype.Component; /** * @author zhaojun - * @version V1.0 - * @date 2022-4-26 */ @Data @EnableConfigurationProperties diff --git a/src/main/java/im/zhaojun/zfile/core/constant/MdcConstant.java b/src/main/java/im/zhaojun/zfile/core/constant/MdcConstant.java new file mode 100644 index 0000000..6df124e --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/constant/MdcConstant.java @@ -0,0 +1,16 @@ +package im.zhaojun.zfile.core.constant; + +/** + * Slf4j mdc 常量 + * + * @author zhaojun + */ +public class MdcConstant { + + public static final String TRACE_ID = "traceId"; + + public static final String IP = "ip"; + + public static final String USER = "user"; + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/constant/ZFileConstant.java b/src/main/java/im/zhaojun/zfile/core/constant/ZFileConstant.java similarity index 51% rename from src/main/java/im/zhaojun/zfile/common/constant/ZFileConstant.java rename to src/main/java/im/zhaojun/zfile/core/constant/ZFileConstant.java index 569927b..ee1a950 100644 --- a/src/main/java/im/zhaojun/zfile/common/constant/ZFileConstant.java +++ b/src/main/java/im/zhaojun/zfile/core/constant/ZFileConstant.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.common.constant; +package im.zhaojun.zfile.core.constant; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -16,37 +16,11 @@ public class ZFileConstant { public static final String PATH_SEPARATOR = "/"; - - /** - * 系统产生的临时文件路径 - */ - public static String TEMP_FILE_PATH = "/.zfile/temp/"; - - - /** - * 最大支持文件大小为 ? MB 的音乐文件解析封面, 歌手等信息. - */ - public static Long AUDIO_MAX_FILE_SIZE_MB = 1L; - - /** * 最大支持文本文件大小为 ? KB 的文件内容. */ public static Long TEXT_MAX_FILE_SIZE_KB = 100L; - - @Autowired(required = false) - public void setTmpFilePath(@Value("${zfile.temp.path}") String tmpFilePath) { - ZFileConstant.TEMP_FILE_PATH = tmpFilePath; - } - - - @Autowired(required = false) - public void setAudioMaxFileSizeMb(@Value("${zfile.preview.audio.maxFileSizeMb}") Long maxFileSizeMb) { - ZFileConstant.AUDIO_MAX_FILE_SIZE_MB = maxFileSizeMb; - } - - @Autowired(required = false) public void setTextMaxFileSizeMb(@Value("${zfile.preview.text.maxFileSizeKb}") Long maxFileSizeKb) { ZFileConstant.TEXT_MAX_FILE_SIZE_KB = maxFileSizeKb; diff --git a/src/main/java/im/zhaojun/zfile/common/controller/front/FrontIndexController.java b/src/main/java/im/zhaojun/zfile/core/controller/FrontIndexController.java similarity index 91% rename from src/main/java/im/zhaojun/zfile/common/controller/front/FrontIndexController.java rename to src/main/java/im/zhaojun/zfile/core/controller/FrontIndexController.java index 013a980..496550a 100644 --- a/src/main/java/im/zhaojun/zfile/common/controller/front/FrontIndexController.java +++ b/src/main/java/im/zhaojun/zfile/core/controller/FrontIndexController.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.common.controller.front; +package im.zhaojun.zfile.core.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; diff --git a/src/main/java/im/zhaojun/zfile/admin/controller/LogController.java b/src/main/java/im/zhaojun/zfile/core/controller/LogController.java similarity index 93% rename from src/main/java/im/zhaojun/zfile/admin/controller/LogController.java rename to src/main/java/im/zhaojun/zfile/core/controller/LogController.java index a546039..b2529e8 100644 --- a/src/main/java/im/zhaojun/zfile/admin/controller/LogController.java +++ b/src/main/java/im/zhaojun/zfile/core/controller/LogController.java @@ -1,9 +1,9 @@ -package im.zhaojun.zfile.admin.controller; +package im.zhaojun.zfile.core.controller; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.ZipUtil; import com.github.xiaoymin.knife4j.annotations.ApiSort; -import im.zhaojun.zfile.common.util.FileResponseUtil; +import im.zhaojun.zfile.core.util.FileResponseUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; diff --git a/src/main/java/im/zhaojun/zfile/core/exception/IllegalDownloadLinkException.java b/src/main/java/im/zhaojun/zfile/core/exception/IllegalDownloadLinkException.java new file mode 100644 index 0000000..e0ba482 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/exception/IllegalDownloadLinkException.java @@ -0,0 +1,14 @@ +package im.zhaojun.zfile.core.exception; + +/** + * 非法使用下载链接异常. + * + * @author zhaojun + */ +public class IllegalDownloadLinkException extends ZFileRuntimeException { + + public IllegalDownloadLinkException(String message) { + super(message); + } + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/core/exception/InstallSystemException.java b/src/main/java/im/zhaojun/zfile/core/exception/InstallSystemException.java new file mode 100644 index 0000000..750f774 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/exception/InstallSystemException.java @@ -0,0 +1,14 @@ +package im.zhaojun.zfile.core.exception; + +/** + * 系统初始化异常 + * + * @author zhaojun + */ +public class InstallSystemException extends ZFileRuntimeException { + + public InstallSystemException(String message) { + super(message); + } + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/core/exception/InvalidShortLinkException.java b/src/main/java/im/zhaojun/zfile/core/exception/InvalidShortLinkException.java new file mode 100644 index 0000000..23e484c --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/exception/InvalidShortLinkException.java @@ -0,0 +1,14 @@ +package im.zhaojun.zfile.core.exception; + +/** + * 无效的直链异常 + * + * @author zhaojun + */ +public class InvalidShortLinkException extends ZFileRuntimeException { + + public InvalidShortLinkException(String message) { + super(message); + } + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/exception/LoginVerifyException.java b/src/main/java/im/zhaojun/zfile/core/exception/LoginVerifyException.java similarity index 55% rename from src/main/java/im/zhaojun/zfile/common/exception/LoginVerifyException.java rename to src/main/java/im/zhaojun/zfile/core/exception/LoginVerifyException.java index 5e10011..c6b8043 100644 --- a/src/main/java/im/zhaojun/zfile/common/exception/LoginVerifyException.java +++ b/src/main/java/im/zhaojun/zfile/core/exception/LoginVerifyException.java @@ -1,11 +1,11 @@ -package im.zhaojun.zfile.common.exception; +package im.zhaojun.zfile.core.exception; /** * 登陆验证码验证异常 * * @author zhaojun */ -public class LoginVerifyException extends RuntimeException { +public class LoginVerifyException extends ZFileRuntimeException { public LoginVerifyException(String message) { super(message); diff --git a/src/main/java/im/zhaojun/zfile/common/exception/PasswordVerifyException.java b/src/main/java/im/zhaojun/zfile/core/exception/PasswordVerifyException.java similarity index 88% rename from src/main/java/im/zhaojun/zfile/common/exception/PasswordVerifyException.java rename to src/main/java/im/zhaojun/zfile/core/exception/PasswordVerifyException.java index 401b68a..8ee0ed3 100644 --- a/src/main/java/im/zhaojun/zfile/common/exception/PasswordVerifyException.java +++ b/src/main/java/im/zhaojun/zfile/core/exception/PasswordVerifyException.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.common.exception; +package im.zhaojun.zfile.core.exception; /** diff --git a/src/main/java/im/zhaojun/zfile/core/exception/PreviewException.java b/src/main/java/im/zhaojun/zfile/core/exception/PreviewException.java new file mode 100644 index 0000000..545f03b --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/exception/PreviewException.java @@ -0,0 +1,14 @@ +package im.zhaojun.zfile.core.exception; + +/** + * 文件预览异常类 + * + * @author zhaojun + */ +public class PreviewException extends ZFileRuntimeException { + + public PreviewException(String message) { + super(message); + } + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/core/exception/ServiceException.java b/src/main/java/im/zhaojun/zfile/core/exception/ServiceException.java new file mode 100644 index 0000000..52d6e37 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/exception/ServiceException.java @@ -0,0 +1,42 @@ +package im.zhaojun.zfile.core.exception; + +import im.zhaojun.zfile.core.util.CodeMsg; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * Service 层异常 + * 所有 message 均为系统日志打印输出, CodeMsg 中的消息才是返回给客户端的消息. + * + * @author zhaojun + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class ServiceException extends RuntimeException { + + private CodeMsg codeMsg; + + public ServiceException(CodeMsg codeMsg) { + this.codeMsg = codeMsg; + } + + public ServiceException(String message, CodeMsg codeMsg) { + super(message); + this.codeMsg = codeMsg; + } + + public ServiceException(String message, Throwable cause, CodeMsg codeMsg) { + super(message, cause); + this.codeMsg = codeMsg; + } + + public ServiceException(Throwable cause, CodeMsg codeMsg) { + super(cause); + this.codeMsg = codeMsg; + } + + public ServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, CodeMsg codeMsg) { + super(message, cause, enableSuppression, writableStackTrace); + this.codeMsg = codeMsg; + } +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/exception/StorageSourceAutoConfigCorsException.java b/src/main/java/im/zhaojun/zfile/core/exception/StorageSourceAutoConfigCorsException.java similarity index 78% rename from src/main/java/im/zhaojun/zfile/admin/exception/StorageSourceAutoConfigCorsException.java rename to src/main/java/im/zhaojun/zfile/core/exception/StorageSourceAutoConfigCorsException.java index 5664ef1..0b71077 100644 --- a/src/main/java/im/zhaojun/zfile/admin/exception/StorageSourceAutoConfigCorsException.java +++ b/src/main/java/im/zhaojun/zfile/core/exception/StorageSourceAutoConfigCorsException.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.admin.exception; +package im.zhaojun.zfile.core.exception; -import im.zhaojun.zfile.admin.model.param.IStorageParam; +import im.zhaojun.zfile.module.storage.model.param.IStorageParam; import lombok.Getter; /** diff --git a/src/main/java/im/zhaojun/zfile/core/exception/StorageSourceException.java b/src/main/java/im/zhaojun/zfile/core/exception/StorageSourceException.java new file mode 100644 index 0000000..303124d --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/exception/StorageSourceException.java @@ -0,0 +1,60 @@ +package im.zhaojun.zfile.core.exception; + +import im.zhaojun.zfile.core.util.CodeMsg; +import lombok.EqualsAndHashCode; +import lombok.Getter; + +/** + * 存储源异常 + * + * @author zhaojun + */ +@EqualsAndHashCode(callSuper = true) +@Getter +public class StorageSourceException extends ServiceException { + + /** + * 是否使用异常消息进行接口返回,如果是则取异常的 message, 否则取 CodeMsg 中的 message + */ + private boolean responseExceptionMessage; + + /** + * 存储源 ID + */ + private final Integer storageId; + + public StorageSourceException(CodeMsg codeMsg, Integer storageId, String message) { + super(message, codeMsg); + this.storageId = storageId; + } + + public StorageSourceException(CodeMsg codeMsg, Integer storageId, String message, Throwable cause) { + super(message, cause, codeMsg); + this.storageId = storageId; + } + + + /** + * 根据 responseExceptionMessage 判断使用异常消息进行接口返回,如果是则取异常的 message, 否则取 CodeMsg 中的 message + * + * @return 异常消息 + */ + public String getResultMessage() { + return responseExceptionMessage ? super.getMessage() : super.getCodeMsg().getMsg(); + } + + + /** + * 设置值是否使用异常消息进行接口返回 + * + * @param responseExceptionMessage + * 是否使用异常消息进行接口返回 + * + * @return 当前对象 + */ + public StorageSourceException setResponseExceptionMessage(boolean responseExceptionMessage) { + this.responseExceptionMessage = responseExceptionMessage; + return this; + } + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/exception/StorageSourceNotSupportProxyUploadException.java b/src/main/java/im/zhaojun/zfile/core/exception/StorageSourceNotSupportProxyUploadException.java similarity index 77% rename from src/main/java/im/zhaojun/zfile/common/exception/StorageSourceNotSupportProxyUploadException.java rename to src/main/java/im/zhaojun/zfile/core/exception/StorageSourceNotSupportProxyUploadException.java index d6ff23c..5600bf6 100644 --- a/src/main/java/im/zhaojun/zfile/common/exception/StorageSourceNotSupportProxyUploadException.java +++ b/src/main/java/im/zhaojun/zfile/core/exception/StorageSourceNotSupportProxyUploadException.java @@ -1,11 +1,11 @@ -package im.zhaojun.zfile.common.exception; +package im.zhaojun.zfile.core.exception; /** * 存储源不支持代理上传异常 * * @author zhaojun */ -public class StorageSourceNotSupportProxyUploadException extends RuntimeException { +public class StorageSourceNotSupportProxyUploadException extends ZFileRuntimeException { public StorageSourceNotSupportProxyUploadException(String message) { super(message); diff --git a/src/main/java/im/zhaojun/zfile/common/exception/StorageSourceRefreshTokenException.java b/src/main/java/im/zhaojun/zfile/core/exception/StorageSourceRefreshTokenException.java similarity index 76% rename from src/main/java/im/zhaojun/zfile/common/exception/StorageSourceRefreshTokenException.java rename to src/main/java/im/zhaojun/zfile/core/exception/StorageSourceRefreshTokenException.java index 60cbfa3..f908dee 100644 --- a/src/main/java/im/zhaojun/zfile/common/exception/StorageSourceRefreshTokenException.java +++ b/src/main/java/im/zhaojun/zfile/core/exception/StorageSourceRefreshTokenException.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.common.exception; +package im.zhaojun.zfile.core.exception; import lombok.Getter; @@ -10,10 +10,6 @@ public class StorageSourceRefreshTokenException extends RuntimeException { private final Integer storageId; - public StorageSourceRefreshTokenException(Integer storageId) { - this.storageId = storageId; - } - public StorageSourceRefreshTokenException(String message, Integer storageId) { super(message); this.storageId = storageId; diff --git a/src/main/java/im/zhaojun/zfile/core/exception/TextParseException.java b/src/main/java/im/zhaojun/zfile/core/exception/TextParseException.java new file mode 100644 index 0000000..b47df15 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/exception/TextParseException.java @@ -0,0 +1,17 @@ +package im.zhaojun.zfile.core.exception; + +/** + * 文件解析异常 + * + * @author zhaojun + */ +public class TextParseException extends ZFileRuntimeException { + + public TextParseException(String message) { + super(message); + } + + public TextParseException(String message, Throwable cause) { + super(message, cause); + } +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/core/exception/ZFileRuntimeException.java b/src/main/java/im/zhaojun/zfile/core/exception/ZFileRuntimeException.java new file mode 100644 index 0000000..45d457c --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/exception/ZFileRuntimeException.java @@ -0,0 +1,15 @@ +package im.zhaojun.zfile.core.exception; + +/** + * @author zhaojun + */ +public class ZFileRuntimeException extends RuntimeException { + + public ZFileRuntimeException(String message) { + super(message); + } + + public ZFileRuntimeException(String message, Throwable cause) { + super(message, cause); + } +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/core/exception/file/InvalidStorageSourceException.java b/src/main/java/im/zhaojun/zfile/core/exception/file/InvalidStorageSourceException.java new file mode 100644 index 0000000..6ce388f --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/exception/file/InvalidStorageSourceException.java @@ -0,0 +1,25 @@ +package im.zhaojun.zfile.core.exception.file; + +import im.zhaojun.zfile.core.exception.StorageSourceException; +import im.zhaojun.zfile.core.util.CodeMsg; + +/** + * 无效的存储源异常 + * + * @author zhaojun + */ +public class InvalidStorageSourceException extends StorageSourceException { + + public InvalidStorageSourceException(String message) { + super(CodeMsg.STORAGE_SOURCE_NOT_FOUND, null, message); + } + + public InvalidStorageSourceException(Integer storageId) { + super(CodeMsg.STORAGE_SOURCE_NOT_FOUND, storageId, CodeMsg.STORAGE_SOURCE_NOT_FOUND.getMsg()); + } + + public InvalidStorageSourceException(Integer storageId, String message) { + super(CodeMsg.STORAGE_SOURCE_NOT_FOUND, storageId, message); + } + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/core/exception/file/init/InitializeStorageSourceException.java b/src/main/java/im/zhaojun/zfile/core/exception/file/init/InitializeStorageSourceException.java new file mode 100644 index 0000000..e33a5e0 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/exception/file/init/InitializeStorageSourceException.java @@ -0,0 +1,21 @@ +package im.zhaojun.zfile.core.exception.file.init; + +import im.zhaojun.zfile.core.exception.StorageSourceException; +import im.zhaojun.zfile.core.util.CodeMsg; + +/** + * 存储源初始化异常 + * + * @author zhaojun + */ +public class InitializeStorageSourceException extends StorageSourceException { + + public InitializeStorageSourceException(CodeMsg codeMsg, Integer storageId, String message) { + super(codeMsg, storageId, message); + } + + public InitializeStorageSourceException(CodeMsg codeMsg, Integer storageId, String message, Throwable cause) { + super(codeMsg, storageId, message, cause); + } + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/core/exception/file/operator/DisableProxyDownloadException.java b/src/main/java/im/zhaojun/zfile/core/exception/file/operator/DisableProxyDownloadException.java new file mode 100644 index 0000000..d398fb1 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/exception/file/operator/DisableProxyDownloadException.java @@ -0,0 +1,24 @@ +package im.zhaojun.zfile.core.exception.file.operator; + +import im.zhaojun.zfile.core.exception.StorageSourceException; +import im.zhaojun.zfile.core.util.CodeMsg; + +/** + * 禁止服务器代理下载异常 + * + * @author zhaojun + */ +public class DisableProxyDownloadException extends StorageSourceException { + + public DisableProxyDownloadException(CodeMsg codeMsg, Integer storageId) { + super(codeMsg, storageId, null); + } + + public DisableProxyDownloadException(CodeMsg codeMsg, Integer storageId, String message) { + super(codeMsg, storageId, message); + } + + public DisableProxyDownloadException(CodeMsg codeMsg, Integer storageId, String message, Throwable cause) { + super(codeMsg, storageId, message, cause); + } +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/core/exception/file/operator/StorageSourceFileOperatorException.java b/src/main/java/im/zhaojun/zfile/core/exception/file/operator/StorageSourceFileOperatorException.java new file mode 100644 index 0000000..a78d434 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/exception/file/operator/StorageSourceFileOperatorException.java @@ -0,0 +1,18 @@ +package im.zhaojun.zfile.core.exception.file.operator; + +import im.zhaojun.zfile.core.exception.StorageSourceException; +import im.zhaojun.zfile.core.util.CodeMsg; +import lombok.Getter; + +/** + * 存储源文件操作异常 + * @author zhaojun + */ +@Getter +public class StorageSourceFileOperatorException extends StorageSourceException { + + public StorageSourceFileOperatorException(CodeMsg codeMsg, Integer storageId, String message, Throwable cause) { + super(codeMsg, storageId, message, cause); + } + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/core/exception/handler/GlobalExceptionHandler.java b/src/main/java/im/zhaojun/zfile/core/exception/handler/GlobalExceptionHandler.java new file mode 100644 index 0000000..94ebd21 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/exception/handler/GlobalExceptionHandler.java @@ -0,0 +1 @@ +package im.zhaojun.zfile.core.exception.handler; import cn.dev33.satoken.exception.NotLoginException; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import im.zhaojun.zfile.core.exception.PasswordVerifyException; import im.zhaojun.zfile.core.exception.StorageSourceException; import im.zhaojun.zfile.core.exception.file.init.InitializeStorageSourceException; import im.zhaojun.zfile.core.exception.file.operator.DisableProxyDownloadException; import im.zhaojun.zfile.core.exception.file.operator.StorageSourceFileOperatorException; import im.zhaojun.zfile.core.exception.IllegalDownloadLinkException; import im.zhaojun.zfile.core.exception.InvalidShortLinkException; import im.zhaojun.zfile.core.exception.LoginVerifyException; import im.zhaojun.zfile.core.exception.StorageSourceAutoConfigCorsException; import im.zhaojun.zfile.core.exception.StorageSourceNotSupportProxyUploadException; import im.zhaojun.zfile.core.exception.ZFileRuntimeException; import im.zhaojun.zfile.core.util.AjaxJson; import im.zhaojun.zfile.core.util.RequestHolder; import im.zhaojun.zfile.core.util.StringUtils; import im.zhaojun.zfile.module.config.service.SystemConfigService; import lombok.extern.slf4j.Slf4j; import org.apache.catalina.connector.ClientAbortException; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.validation.BindException; import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.io.FileNotFoundException; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Optional; /** * 全局异常处理 * * @author zhaojun */ @ControllerAdvice @Slf4j @Order(1) public class GlobalExceptionHandler { @Resource private SystemConfigService systemConfigService; /** * 存储源文件操作相关异常处理 */ @ExceptionHandler(value = StorageSourceException.class) @ResponseBody @ResponseStatus public AjaxJson storageSourceException(StorageSourceException e) { log.error("存储源 {} 出现异常", e.getStorageId(), e); return AjaxJson.getError(e.getResultMessage()); } /** * 存储源初始化相关异常处理 */ @ExceptionHandler(value = InitializeStorageSourceException.class) @ResponseBody @ResponseStatus public AjaxJson initializeException(InitializeStorageSourceException e) { log.error("初始化存储源 {} 失败", e.getStorageId(), e); return AjaxJson.getError(e.getResultMessage()); } /** * 存储源文件操作相关异常处理 */ @ExceptionHandler(value = StorageSourceFileOperatorException.class) @ResponseBody @ResponseStatus public AjaxJson storageSourceFileOperatorException(StorageSourceFileOperatorException e) { log.error("存储源 {} 文件操作异常", e.getStorageId(), e); return AjaxJson.getError(e.getResultMessage()); } @ExceptionHandler({ZFileRuntimeException.class}) @ResponseBody @ResponseStatus public AjaxJson getFileInfoException(ZFileRuntimeException e) { if (e.getCause() != null) { log.error("ZFileRuntimeException", e); } return AjaxJson.getError(e.getMessage()); } @ExceptionHandler({InvalidShortLinkException.class}) @ResponseBody @ResponseStatus(HttpStatus.NOT_FOUND) public AjaxJson getFileInfoException(InvalidShortLinkException e) { return AjaxJson.getError(e.getMessage()); } @ExceptionHandler({IllegalDownloadLinkException.class}) @ResponseBody @ResponseStatus(HttpStatus.FORBIDDEN) public AjaxJson getFileInfoException(IllegalDownloadLinkException e) { return AjaxJson.getError(e.getMessage()); } @ExceptionHandler({LoginVerifyException.class}) @ResponseBody @ResponseStatus(HttpStatus.FORBIDDEN) public AjaxJson loginVerifyException(LoginVerifyException e) { return AjaxJson.getError(e.getMessage()); } @ExceptionHandler(value = {MethodArgumentNotValidException.class, BindException.class}) @ResponseBody public AjaxJson> handleValidException(Exception e) { BindingResult bindingResult = null; if (e instanceof MethodArgumentNotValidException) { bindingResult = ((MethodArgumentNotValidException) e).getBindingResult(); } else if (e instanceof BindException) { bindingResult = ((BindException) e).getBindingResult(); } Map errorMap = new HashMap<>(16); Optional.ofNullable(bindingResult) .map(BindingResult::getFieldErrors) .ifPresent(fieldErrors -> { for (FieldError fieldError : fieldErrors) { errorMap.put(fieldError.getField(), fieldError.getDefaultMessage()); } }); return new AjaxJson<>(400, "非法参数 !", errorMap); } @ExceptionHandler({FileNotFoundException.class}) @ResponseBody @ResponseStatus(HttpStatus.NOT_FOUND) public AjaxJson fileNotFound() { return AjaxJson.getError("文件不存在"); } /** * 密码校验异常 */ @ExceptionHandler({PasswordVerifyException.class}) @ResponseBody @ResponseStatus public AjaxJson passwordVerifyException(PasswordVerifyException ex) { return AjaxJson.get(ex.getCode(), ex.getMessage()); } /** * 初始化时自动设置 cors 异常 */ @ExceptionHandler({StorageSourceAutoConfigCorsException.class}) @ResponseBody @ResponseStatus public AjaxJson autoConfigCorsException(StorageSourceAutoConfigCorsException ex) { log.error("跨域配置失败, 存储源初始化信息 {}, 异常信息: ", JSON.toJSON(ex.getIStorageParam()), ex); return AjaxJson.getError(ex.getMessage()); } @ExceptionHandler({StorageSourceNotSupportProxyUploadException.class}) @ResponseBody @ResponseStatus(HttpStatus.BAD_REQUEST) public AjaxJson storageSourceNotSupportProxyUploadException(StorageSourceNotSupportProxyUploadException e) { return AjaxJson.getError("非法操作, 当前存储源不支持此方式上传."); } @ExceptionHandler(value = DisableProxyDownloadException.class) @ResponseBody @ResponseStatus(HttpStatus.BAD_REQUEST) public AjaxJson disableProxyDownloadException(DisableProxyDownloadException e) { return AjaxJson.getError(e.getResultMessage()); } @ExceptionHandler({HttpMessageNotReadableException.class}) @ResponseBody @ResponseStatus(HttpStatus.BAD_REQUEST) public AjaxJson handlerHttpMessageNotReadableException(HttpMessageNotReadableException e) { return AjaxJson.getBadRequestError("请求参数不合法"); } /** * 捕获 ClientAbortException 异常, 不做任何处理, 防止出现大量堆栈日志输出, 此异常不影响功能. */ @ExceptionHandler({HttpMediaTypeNotAcceptableException.class, ClientAbortException.class}) @ResponseBody @ResponseStatus public void clientAbortException() { // if (log.isDebugEnabled()) { // log.debug("出现了断开异常:", ex); // } } @ExceptionHandler @ResponseBody @ResponseStatus public AjaxJson extraExceptionHandler(Exception e) { log.error(e.getMessage(), e); if (e.getClass() == Exception.class) { return AjaxJson.getError("系统异常, 请联系管理员"); } else { return AjaxJson.getError(e.getMessage()); } } /** * 登录异常拦截器 */ @ExceptionHandler(NotLoginException.class) @ResponseStatus(HttpStatus.UNAUTHORIZED) @ResponseBody public AjaxJson handlerNotLoginException(NotLoginException e) { HttpServletRequest request = RequestHolder.getRequest(); String axiosRequest = request.getHeader("axios-request"); if (StrUtil.isNotEmpty(axiosRequest)){ return AjaxJson.getNotLogin(); } try { String domain = systemConfigService.getRealFrontDomain(); String loginUrl = StringUtils.removeDuplicateSlashes(domain + "/login"); RequestHolder.getResponse().sendRedirect(loginUrl); } catch (IOException ex) { throw new RuntimeException(ex); } return null; } } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/core/exception/http/HttpResponseStatusErrorException.java b/src/main/java/im/zhaojun/zfile/core/exception/http/HttpResponseStatusErrorException.java new file mode 100644 index 0000000..6db55cc --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/exception/http/HttpResponseStatusErrorException.java @@ -0,0 +1,12 @@ +package im.zhaojun.zfile.core.exception.http; + +/** + * Http 请求状态码异常 (返回状态码为 5xx 抛出此异常) + * @author zhaojun + */ +public class HttpResponseStatusErrorException extends RuntimeException { + + public HttpResponseStatusErrorException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/filter/CorsFilter.java b/src/main/java/im/zhaojun/zfile/core/filter/CorsFilter.java similarity index 97% rename from src/main/java/im/zhaojun/zfile/common/filter/CorsFilter.java rename to src/main/java/im/zhaojun/zfile/core/filter/CorsFilter.java index e9fb5b0..469cd64 100644 --- a/src/main/java/im/zhaojun/zfile/common/filter/CorsFilter.java +++ b/src/main/java/im/zhaojun/zfile/core/filter/CorsFilter.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.common.filter; +package im.zhaojun.zfile.core.filter; import cn.hutool.core.util.ObjectUtil; import org.springframework.http.HttpHeaders; diff --git a/src/main/java/im/zhaojun/zfile/core/filter/MDCFilter.java b/src/main/java/im/zhaojun/zfile/core/filter/MDCFilter.java new file mode 100644 index 0000000..fdb045b --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/filter/MDCFilter.java @@ -0,0 +1,41 @@ +package im.zhaojun.zfile.core.filter; + +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.extra.servlet.ServletUtil; +import im.zhaojun.zfile.core.constant.MdcConstant; +import org.slf4j.MDC; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.annotation.WebFilter; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author zhaojun + */ +@WebFilter(urlPatterns = "/*") +public class MDCFilter implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest httpServletRequest = (HttpServletRequest) request; + HttpServletResponse httpServletResponse = (HttpServletResponse) response; + + MDC.put(MdcConstant.TRACE_ID, IdUtil.fastUUID()); + MDC.put(MdcConstant.IP, ServletUtil.getClientIP(httpServletRequest)); + MDC.put(MdcConstant.USER, StpUtil.isLogin() ? StpUtil.getLoginIdAsString() : "anonymous"); + + try { + filterChain.doFilter(httpServletRequest, httpServletResponse); + } finally { + MDC.clear(); + } + } + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/core/model/request/PageQueryRequest.java b/src/main/java/im/zhaojun/zfile/core/model/request/PageQueryRequest.java new file mode 100644 index 0000000..877d99f --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/model/request/PageQueryRequest.java @@ -0,0 +1,24 @@ +package im.zhaojun.zfile.core.model.request; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author zhaojun + */ +@Data +public class PageQueryRequest { + + @ApiModelProperty(value="分页页数") + private Integer page = 1; + + @ApiModelProperty(value="每页条数") + private Integer limit = 10; + + @ApiModelProperty(value="排序字段") + private String orderBy = "create_date"; + + @ApiModelProperty(value="排序顺序") + private String orderDirection = "desc"; + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/core/util/AjaxJson.java b/src/main/java/im/zhaojun/zfile/core/util/AjaxJson.java new file mode 100644 index 0000000..c4f0a1f --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/util/AjaxJson.java @@ -0,0 +1 @@ +package im.zhaojun.zfile.core.util; import io.swagger.annotations.ApiModelProperty; import java.io.Serializable; /** * ajax 请求返回 JSON 格式数据的封装 * * @author zhaojun */ public class AjaxJson implements Serializable { private static final long serialVersionUID = 1L; // 序列化版本号 public static final int CODE_SUCCESS = 0; // 成功状态码 public static final int CODE_ERROR = 500; // 错误状态码 public static final int CODE_WARNING = 501; // 警告状态码 public static final int CODE_NOT_JUR = 403; // 无权限状态码 public static final int CODE_NOT_LOGIN = 401; // 未登录状态码 public static final int CODE_INVALID_REQUEST = 400; // 无效请求状态码 public static final int REQUIRED_PASSWORD = 405; // 未输入密码 public static final int INVALID_PASSWORD = 406; // 无效的密码 @ApiModelProperty(value = "业务状态码,0 为正常,其他值均为异常,异常情况下见响应消息", example = "0") private final int code; @ApiModelProperty(value = "响应消息", example = "ok") private String msg; @ApiModelProperty(value = "响应数据") private T data; @ApiModelProperty(value = "数据总条数,分页情况有效") private final Long dataCount; @ApiModelProperty(value = "跟踪 ID") private String traceId; /** * 返回code */ public int getCode() { return this.code; } /** * 给 msg 赋值,连缀风格 */ public AjaxJson setMsg(String msg) { this.msg = msg; return this; } public String getMsg() { return this.msg; } /** * 给data赋值,连缀风格 */ public AjaxJson setData(T data) { this.data = data; return this; } // ============================ 构建 ================================== public AjaxJson(int code, String msg, T data) { this.code = code; this.msg = msg; this.data = data; this.dataCount = null; } public AjaxJson(int code, String msg, T data, Long dataCount) { this.code = code; this.msg = msg; this.data = data; this.dataCount = dataCount; } // 返回成功 public static AjaxJson getSuccess() { return new AjaxJson<>(CODE_SUCCESS, "ok", null, null); } public static AjaxJson getSuccess(String msg) { return new AjaxJson<>(CODE_SUCCESS, msg, null, null); } public static AjaxJson getSuccess(String msg, Object data) { return new AjaxJson<>(CODE_SUCCESS, msg, data, null); } public static AjaxJson getSuccessData(T data) { return new AjaxJson<>(CODE_SUCCESS, "ok", data, null); } public static AjaxJson getSuccessArray(Object... data) { return new AjaxJson<>(CODE_SUCCESS, "ok", data, null); } // 返回失败 public static AjaxJson getError() { return new AjaxJson<>(CODE_ERROR, "error", null, null); } public static AjaxJson getError(String msg) { return new AjaxJson<>(CODE_ERROR, msg, null, null); } public static AjaxJson getBadRequestError(String msg) { return new AjaxJson<>(CODE_INVALID_REQUEST, msg, null, null); } // 返回警告 public static AjaxJson getWarning() { return new AjaxJson<>(CODE_ERROR, "warning", null, null); } public static AjaxJson getWarning(String msg) { return new AjaxJson<>(CODE_WARNING, msg, null, null); } // 返回未登录 public static AjaxJson getNotLogin() { return new AjaxJson<>(CODE_NOT_LOGIN, "未登录,请登录后再次访问", null, null); } // 返回没有权限的 public static AjaxJson getNotJur(String msg) { return new AjaxJson<>(CODE_NOT_JUR, msg, null, null); } // 返回一个自定义状态码的 public static AjaxJson get(int code, String msg) { return new AjaxJson<>(code, msg, null, null); } // 返回分页和数据的 public static AjaxJson getPageData(Long dataCount, Object data) { return new AjaxJson<>(CODE_SUCCESS, "ok", data, dataCount); } // 返回,根据布尔值来确定最终结果的 (true=ok,false=error) public static AjaxJson getByBoolean(boolean b) { return b ? getSuccess("ok") : getError("error"); } @Override public String toString() { return "AjaxJson{" + "code=" + code + ", msg='" + msg + '\'' + ", data=" + data + ", dataCount=" + dataCount + ", traceId='" + traceId + '\'' + '}'; } public T getData() { return data; } public Long getDataCount() { return dataCount; } public void setTraceId(String traceId) { this.traceId = traceId; } public String getTraceId() { return traceId; } } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/util/ClassUtils.java b/src/main/java/im/zhaojun/zfile/core/util/ClassUtils.java similarity index 93% rename from src/main/java/im/zhaojun/zfile/common/util/ClassUtils.java rename to src/main/java/im/zhaojun/zfile/core/util/ClassUtils.java index ab6b5cf..14a2543 100644 --- a/src/main/java/im/zhaojun/zfile/common/util/ClassUtils.java +++ b/src/main/java/im/zhaojun/zfile/core/util/ClassUtils.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.common.util; +package im.zhaojun.zfile.core.util; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; diff --git a/src/main/java/im/zhaojun/zfile/core/util/CodeMsg.java b/src/main/java/im/zhaojun/zfile/core/util/CodeMsg.java new file mode 100644 index 0000000..59f23f0 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/util/CodeMsg.java @@ -0,0 +1,76 @@ +package im.zhaojun.zfile.core.util; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * @author zhaojun + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Accessors(chain = true) +public class CodeMsg { + + /** + * 错误码 + *

+ * 均为 5 位数, 如 00000, 10100, 20105 等. + *
+ * 第一位表示错误类型, 4 为用户请求输入错误, 5 为服务端处理错误, 6 为警告信息 + *
+ * 第二位到第三位为二级类型 + *
+ * 第四位到第五位为具体错误代码, 根据业务场景自行定义 + *

+ * 以上三种类型均不允许重复, 且都需保持递增. + */ + private String code; + + /** + * 错误消息 + */ + private String msg; + + // 通用返回值 + public static CodeMsg SUCCESS = new CodeMsg("00000", "success"); + public static CodeMsg BAD_REQUEST = new CodeMsg("40000", "非法请求"); + public static CodeMsg ERROR = new CodeMsg("50000", "服务端异常"); + + + // -------------- 用户输入级错误 -------------- + public static CodeMsg REQUIRED_PASSWORD = new CodeMsg("40100", "请输入密码"); + public static CodeMsg PASSWORD_FAULT = new CodeMsg("40101", "密码输入错误"); + + public static CodeMsg STORAGE_SOURCE_NOT_FOUND = new CodeMsg("40102", "无效的或初始化失败的存储源"); + public static CodeMsg STORAGE_SOURCE_FORBIDDEN = new CodeMsg("40103", "无权访问存储源"); + public static CodeMsg STORAGE_SOURCE_FILE_FORBIDDEN = new CodeMsg("40104", "无权访问该目录"); + public static CodeMsg STORAGE_SOURCE_ILLEGAL_OPERATION = new CodeMsg("40105", "非法操作"); + + + + // -------------- 服务端处理错误 -------------- + + // 初始化相关错误 + public static CodeMsg STORAGE_SOURCE_INIT_FAIL = new CodeMsg("50100", "初始化存储源失败"); + public static CodeMsg STORAGE_SOURCE_INIT_STORAGE_CONFIG_FAIL = new CodeMsg("50101", "初始化存储源参数失败"); + public static CodeMsg STORAGE_SOURCE_INIT_STORAGE_PARAM_FIELD_FAIL = new CodeMsg("50102", "填充存储源字段失败"); + + + // 文件操作相关错误 + public static CodeMsg STORAGE_SOURCE_FILE_NEW_FOLDER_FAIL = new CodeMsg("50201", "新建文件夹失败"); + public static CodeMsg STORAGE_SOURCE_FILE_DELETE_FAIL = new CodeMsg("50202", "删除失败"); + public static CodeMsg STORAGE_SOURCE_FILE_RENAME_FAIL = new CodeMsg("50203", "重命名失败"); + public static CodeMsg STORAGE_SOURCE_FILE_GET_UPLOAD_FAIL = new CodeMsg("50204", "获取上传链接失败"); + public static CodeMsg STORAGE_SOURCE_FILE_PROXY_UPLOAD_FAIL = new CodeMsg("50205", "文件上传失败"); + public static CodeMsg STORAGE_SOURCE_FILE_PROXY_DOWNLOAD_FAIL = new CodeMsg("50206", "文件下载失败"); + public static CodeMsg STORAGE_SOURCE_FILE_GET_ITEM_FAIL = new CodeMsg("50207", "文件不存在或请求异常"); + public static CodeMsg STORAGE_SOURCE_FILE_DISABLE_PROXY_DOWNLOAD = new CodeMsg("50208", "非法操作, 当前文件不支持此类下载方式"); + + + + + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/util/EnumConvertUtils.java b/src/main/java/im/zhaojun/zfile/core/util/EnumConvertUtils.java similarity index 98% rename from src/main/java/im/zhaojun/zfile/common/util/EnumConvertUtils.java rename to src/main/java/im/zhaojun/zfile/core/util/EnumConvertUtils.java index b417d7d..0904836 100644 --- a/src/main/java/im/zhaojun/zfile/common/util/EnumConvertUtils.java +++ b/src/main/java/im/zhaojun/zfile/core/util/EnumConvertUtils.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.common.util; +package im.zhaojun.zfile.core.util; import cn.hutool.core.convert.Convert; import cn.hutool.core.util.ClassUtil; diff --git a/src/main/java/im/zhaojun/zfile/common/util/FileComparator.java b/src/main/java/im/zhaojun/zfile/core/util/FileComparator.java similarity index 90% rename from src/main/java/im/zhaojun/zfile/common/util/FileComparator.java rename to src/main/java/im/zhaojun/zfile/core/util/FileComparator.java index ec5e35b..41cdc61 100644 --- a/src/main/java/im/zhaojun/zfile/common/util/FileComparator.java +++ b/src/main/java/im/zhaojun/zfile/core/util/FileComparator.java @@ -1,8 +1,8 @@ -package im.zhaojun.zfile.common.util; +package im.zhaojun.zfile.core.util; import cn.hutool.core.comparator.CompareUtil; -import im.zhaojun.zfile.home.model.result.FileItemResult; -import im.zhaojun.zfile.home.model.enums.FileTypeEnum; +import im.zhaojun.zfile.module.storage.model.result.FileItemResult; +import im.zhaojun.zfile.module.storage.model.enums.FileTypeEnum; import java.util.Comparator; diff --git a/src/main/java/im/zhaojun/zfile/common/util/FileResponseUtil.java b/src/main/java/im/zhaojun/zfile/core/util/FileResponseUtil.java similarity index 95% rename from src/main/java/im/zhaojun/zfile/common/util/FileResponseUtil.java rename to src/main/java/im/zhaojun/zfile/core/util/FileResponseUtil.java index 24adb37..0b83d9b 100644 --- a/src/main/java/im/zhaojun/zfile/common/util/FileResponseUtil.java +++ b/src/main/java/im/zhaojun/zfile/core/util/FileResponseUtil.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.common.util; +package im.zhaojun.zfile.core.util; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; @@ -58,7 +58,6 @@ public class FileResponseUtil { .contentLength(file.length()) .contentType(mediaType) .body(new InputStreamResource(FileUtil.getInputStream(file))); - // .body(new FileSystemResource(file)); } } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/util/HttpUtil.java b/src/main/java/im/zhaojun/zfile/core/util/HttpUtil.java similarity index 80% rename from src/main/java/im/zhaojun/zfile/common/util/HttpUtil.java rename to src/main/java/im/zhaojun/zfile/core/util/HttpUtil.java index 985f45b..88f19bb 100644 --- a/src/main/java/im/zhaojun/zfile/common/util/HttpUtil.java +++ b/src/main/java/im/zhaojun/zfile/core/util/HttpUtil.java @@ -1,9 +1,10 @@ -package im.zhaojun.zfile.common.util; +package im.zhaojun.zfile.core.util; import cn.hutool.core.io.FileUtil; -import im.zhaojun.zfile.common.constant.ZFileConstant; -import im.zhaojun.zfile.common.exception.PreviewException; -import im.zhaojun.zfile.common.exception.TextParseException; +import cn.hutool.core.util.StrUtil; +import im.zhaojun.zfile.core.constant.ZFileConstant; +import im.zhaojun.zfile.core.exception.PreviewException; +import im.zhaojun.zfile.core.exception.TextParseException; import lombok.extern.slf4j.Slf4j; import java.io.IOException; @@ -38,7 +39,7 @@ public class HttpUtil { try { result = cn.hutool.http.HttpUtil.get(url); } catch (Exception e) { - throw new TextParseException("文件解析异常, 请求 url = " + url + ", 异常信息为 = " + e.getMessage()); + throw new TextParseException(StrUtil.format("获取文件内容失败, URL: {}", url), e); } return result == null ? "" : result; diff --git a/src/main/java/im/zhaojun/zfile/common/util/NaturalOrderComparator.java b/src/main/java/im/zhaojun/zfile/core/util/NaturalOrderComparator.java similarity index 99% rename from src/main/java/im/zhaojun/zfile/common/util/NaturalOrderComparator.java rename to src/main/java/im/zhaojun/zfile/core/util/NaturalOrderComparator.java index b162ed0..3a9b336 100644 --- a/src/main/java/im/zhaojun/zfile/common/util/NaturalOrderComparator.java +++ b/src/main/java/im/zhaojun/zfile/core/util/NaturalOrderComparator.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.common.util; +package im.zhaojun.zfile.core.util; /* NaturalOrderComparator.java -- Perform 'natural order' comparisons of strings in Java. Copyright (C) 2003 by Pierre-Luc Paour diff --git a/src/main/java/im/zhaojun/zfile/core/util/PatternMatcherUtils.java b/src/main/java/im/zhaojun/zfile/core/util/PatternMatcherUtils.java new file mode 100644 index 0000000..c05606e --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/util/PatternMatcherUtils.java @@ -0,0 +1,72 @@ +package im.zhaojun.zfile.core.util; + +import cn.hutool.core.util.StrUtil; +import im.zhaojun.zfile.core.constant.ZFileConstant; + +import java.nio.file.FileSystems; +import java.nio.file.PathMatcher; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; + +/** + * 规则表达式工具类 + * + * @author zhaojun + */ +public class PatternMatcherUtils { + + private static final Map PATH_MATCHER_MAP = new HashMap<>(); + + /** + * 兼容模式的 glob 表达式匹配. + * 默认的 glob 表达式是不支持以下情况的:
+ *

    + *
  • pattern: /a/**
  • + *
  • test1: /a
  • + *
  • test2: /a/
  • + *
      + *

      test1 和 test 2 均无法匹配这种情况, 此方法兼容了这种情况, 即对 test 内容后拼接 "/xx", 使其可以匹配上 pattern. + *

      注意:但此方法对包含文件名的情况无效, 仅支持 test 为 路径的情况. + * + * @param pattern + * glob 规则表达式 + * + * @param test + * 匹配内容 + * + * @return 是否匹配. + */ + public static boolean testCompatibilityGlobPattern(String pattern, String test) { + // 如果规则表达式最开始没有 /, 则兼容在最前方加上 /. + if (!StrUtil.startWith(pattern, ZFileConstant.PATH_SEPARATOR)) { + pattern = ZFileConstant.PATH_SEPARATOR + pattern; + } + + // 兼容性处理. + test = StringUtils.concat(test, ZFileConstant.PATH_SEPARATOR); + if (StrUtil.endWith(pattern, "/**")) { + test += "xxx"; + } + return testGlobPattern(pattern, test); + } + + + /** + * 测试密码规则表达式和文件路径是否匹配 + * + * @param pattern + * glob 规则表达式 + * + * @param test + * 测试字符串 + */ + private static boolean testGlobPattern(String pattern, String test) { + // 从缓存取出 PathMatcher, 防止重复初始化 + PathMatcher pathMatcher = PATH_MATCHER_MAP.getOrDefault(pattern, FileSystems.getDefault().getPathMatcher("glob:" + pattern)); + PATH_MATCHER_MAP.put(pattern, pathMatcher); + + return pathMatcher.matches(Paths.get(test)) || StrUtil.equals(pattern, test); + } + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/util/PlaceholderUtils.java b/src/main/java/im/zhaojun/zfile/core/util/PlaceholderUtils.java similarity index 94% rename from src/main/java/im/zhaojun/zfile/common/util/PlaceholderUtils.java rename to src/main/java/im/zhaojun/zfile/core/util/PlaceholderUtils.java index 03e6e67..043c13e 100644 --- a/src/main/java/im/zhaojun/zfile/common/util/PlaceholderUtils.java +++ b/src/main/java/im/zhaojun/zfile/core/util/PlaceholderUtils.java @@ -1,8 +1,9 @@ -package im.zhaojun.zfile.common.util; +package im.zhaojun.zfile.core.util; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.spring.SpringUtil; +import lombok.extern.slf4j.Slf4j; import java.util.ArrayList; import java.util.Collections; @@ -15,6 +16,7 @@ import java.util.Map; * * @author zhaojun */ +@Slf4j public class PlaceholderUtils { /** @@ -79,10 +81,10 @@ public class PlaceholderUtils { buf.replace(startIndex, endIndex + PLACEHOLDER_SUFFIX.length(), propVal); nextIndex = startIndex + propVal.length(); } else { - System.out.println("Could not resolve placeholder '" + placeholder + "' in [" + formatStr + "] "); + log.warn("Could not resolve placeholder '{}' in [{}] ", placeholder, formatStr); } } catch (Exception ex) { - System.out.println("Could not resolve placeholder '" + placeholder + "' in [" + formatStr + "]: " + ex); + log.error("Could not resolve placeholder '{}' in [{}]: ", placeholder, formatStr, ex); } startIndex = buf.indexOf(PLACEHOLDER_PREFIX, nextIndex); } else { diff --git a/src/main/java/im/zhaojun/zfile/common/util/ProxyDownloadUrlUtils.java b/src/main/java/im/zhaojun/zfile/core/util/ProxyDownloadUrlUtils.java similarity index 71% rename from src/main/java/im/zhaojun/zfile/common/util/ProxyDownloadUrlUtils.java rename to src/main/java/im/zhaojun/zfile/core/util/ProxyDownloadUrlUtils.java index 568a13d..b80e82d 100644 --- a/src/main/java/im/zhaojun/zfile/common/util/ProxyDownloadUrlUtils.java +++ b/src/main/java/im/zhaojun/zfile/core/util/ProxyDownloadUrlUtils.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.common.util; +package im.zhaojun.zfile.core.util; import cn.hutool.core.convert.Convert; import cn.hutool.core.date.DateUtil; @@ -7,10 +7,9 @@ import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.symmetric.SymmetricAlgorithm; import cn.hutool.crypto.symmetric.SymmetricCrypto; import cn.hutool.extra.spring.SpringUtil; -import im.zhaojun.zfile.admin.service.SystemConfigService; +import im.zhaojun.zfile.module.config.service.SystemConfigService; import lombok.extern.slf4j.Slf4j; -import java.util.Date; import java.util.List; /** @@ -23,7 +22,6 @@ public class ProxyDownloadUrlUtils { private static SystemConfigService systemConfigService; - private static final String PROXY_DOWNLOAD_LINK_DELIMITER= ":"; @@ -46,7 +44,7 @@ public class ProxyDownloadUrlUtils { long second = DateUtil.offsetSecond(DateUtil.date(), effectiveSecond).getTime(); String content = storageId + PROXY_DOWNLOAD_LINK_DELIMITER + pathAndName + PROXY_DOWNLOAD_LINK_DELIMITER + second; - String rsaHexKey = systemConfigService.getRsaHexKey(); + String rsaHexKey = systemConfigService.getRsaHexKeyOrGenerate(); byte[] key = HexUtil.decodeHex(rsaHexKey); //构建 SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.AES, key); @@ -61,28 +59,34 @@ public class ProxyDownloadUrlUtils { systemConfigService = SpringUtil.getBean(SystemConfigService.class); } - String rsaHexKey = systemConfigService.getRsaHexKey(); + String rsaHexKey = systemConfigService.getRsaHexKeyOrGenerate(); byte[] key = HexUtil.decodeHex(rsaHexKey); SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.AES, key); - + + long currentTimeMillis = System.currentTimeMillis(); + + String storageId = null; + String pathAndName = null; + String expiredSecond = null; + try { //解密 String decryptStr = aes.decryptStr(signature); List split = StrUtil.split(decryptStr, PROXY_DOWNLOAD_LINK_DELIMITER); - String storageId = split.get(0); - String pathAndName = split.get(1); - String expiredSecond = split.get(2); + storageId = split.get(0); + pathAndName = split.get(1); + expiredSecond = split.get(2); // 校验存储源 ID 和文件路径及是否过期. if (StrUtil.equals(storageId, Convert.toStr(expectedStorageId)) && StrUtil.equals(StringUtils.concat(pathAndName), StringUtils.concat(expectedPathAndName)) - && new Date().getTime() < Convert.toLong(expiredSecond)) { + && currentTimeMillis < Convert.toLong(expiredSecond)) { return true; } - log.debug("校验链接已过期或不匹配, storageId={}, pathAndName={}, expiredSecond={}, now:={}", storageId, pathAndName, expiredSecond, new Date().getTime()); + log.warn("校验链接已过期或不匹配, signature: {}, storageId={}, pathAndName={}, expiredSecond={}, now:={}", signature, storageId, pathAndName, expiredSecond, currentTimeMillis); } catch (Exception e) { - log.error("校验链接是否过期异常", e); + log.error("校验签名链接异常, signature: {}, storageId={}, pathAndName={}, expiredSecond={}, now:={}", signature, storageId, pathAndName, expiredSecond, currentTimeMillis); return false; } diff --git a/src/main/java/im/zhaojun/zfile/common/util/RequestHolder.java b/src/main/java/im/zhaojun/zfile/core/util/RequestHolder.java similarity index 98% rename from src/main/java/im/zhaojun/zfile/common/util/RequestHolder.java rename to src/main/java/im/zhaojun/zfile/core/util/RequestHolder.java index 70bd116..2ab0631 100644 --- a/src/main/java/im/zhaojun/zfile/common/util/RequestHolder.java +++ b/src/main/java/im/zhaojun/zfile/core/util/RequestHolder.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.common.util; +package im.zhaojun.zfile.core.util; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IoUtil; diff --git a/src/main/java/im/zhaojun/zfile/common/util/SizeToStrUtils.java b/src/main/java/im/zhaojun/zfile/core/util/SizeToStrUtils.java similarity index 96% rename from src/main/java/im/zhaojun/zfile/common/util/SizeToStrUtils.java rename to src/main/java/im/zhaojun/zfile/core/util/SizeToStrUtils.java index ec6f1f0..4eba421 100644 --- a/src/main/java/im/zhaojun/zfile/common/util/SizeToStrUtils.java +++ b/src/main/java/im/zhaojun/zfile/core/util/SizeToStrUtils.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.common.util; +package im.zhaojun.zfile.core.util; import cn.hutool.core.util.NumberUtil; diff --git a/src/main/java/im/zhaojun/zfile/common/util/StringUtils.java b/src/main/java/im/zhaojun/zfile/core/util/StringUtils.java similarity index 96% rename from src/main/java/im/zhaojun/zfile/common/util/StringUtils.java rename to src/main/java/im/zhaojun/zfile/core/util/StringUtils.java index 44757cd..9fc236d 100644 --- a/src/main/java/im/zhaojun/zfile/common/util/StringUtils.java +++ b/src/main/java/im/zhaojun/zfile/core/util/StringUtils.java @@ -1,12 +1,12 @@ -package im.zhaojun.zfile.common.util; +package im.zhaojun.zfile.core.util; import cn.hutool.core.net.URLEncodeUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.URLUtil; import cn.hutool.extra.spring.SpringUtil; -import im.zhaojun.zfile.admin.service.SystemConfigService; -import im.zhaojun.zfile.common.constant.ZFileConstant; -import im.zhaojun.zfile.home.model.dto.SystemConfigDTO; +import im.zhaojun.zfile.module.config.service.SystemConfigService; +import im.zhaojun.zfile.core.constant.ZFileConstant; +import im.zhaojun.zfile.module.config.model.dto.SystemConfigDTO; import java.net.MalformedURLException; import java.net.URL; @@ -393,6 +393,10 @@ public class StringUtils { return StrUtil.sub(path, 0, toIndex); } } - + + public static String removeAllLineBreaksAndTrim(String str) { + String removeResult = StrUtil.removeAllLineBreaks(str); + return StrUtil.trim(removeResult); + } } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/core/util/UrlUtils.java b/src/main/java/im/zhaojun/zfile/core/util/UrlUtils.java new file mode 100644 index 0000000..e88ad3b --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/core/util/UrlUtils.java @@ -0,0 +1,34 @@ +package im.zhaojun.zfile.core.util; + +import cn.hutool.core.util.StrUtil; + +/** + * url 相关工具类 + * + * @author zhaojun + */ +public class UrlUtils { + + /** + * 给 url 拼接参数 + * + * @param url + * 原始 URL + * + * @param name + * 参数名称 + * + * @param value + * 参数值 + * + * @return 拼接后的 URL + */ + public static String concatQueryParam(String url, String name, String value) { + if (StrUtil.contains(url, "?")) { + return url + "&" + name + "=" + value; + } else { + return url + "?" + name + "=" + value; + } + } + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/common/validation/StringListValue.java b/src/main/java/im/zhaojun/zfile/core/validation/StringListValue.java similarity index 94% rename from src/main/java/im/zhaojun/zfile/common/validation/StringListValue.java rename to src/main/java/im/zhaojun/zfile/core/validation/StringListValue.java index 5561b88..be5868d 100644 --- a/src/main/java/im/zhaojun/zfile/common/validation/StringListValue.java +++ b/src/main/java/im/zhaojun/zfile/core/validation/StringListValue.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.common.validation; +package im.zhaojun.zfile.core.validation; import javax.validation.Constraint; import javax.validation.Payload; diff --git a/src/main/java/im/zhaojun/zfile/common/validation/StringListValueConstraintValidator.java b/src/main/java/im/zhaojun/zfile/core/validation/StringListValueConstraintValidator.java similarity index 95% rename from src/main/java/im/zhaojun/zfile/common/validation/StringListValueConstraintValidator.java rename to src/main/java/im/zhaojun/zfile/core/validation/StringListValueConstraintValidator.java index d1761cc..b7a3f57 100644 --- a/src/main/java/im/zhaojun/zfile/common/validation/StringListValueConstraintValidator.java +++ b/src/main/java/im/zhaojun/zfile/core/validation/StringListValueConstraintValidator.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.common.validation; +package im.zhaojun.zfile.core.validation; import cn.hutool.core.util.StrUtil; diff --git a/src/main/java/im/zhaojun/zfile/home/aspect/FileListCacheAspect.java b/src/main/java/im/zhaojun/zfile/home/aspect/FileListCacheAspect.java deleted file mode 100644 index 9321e2d..0000000 --- a/src/main/java/im/zhaojun/zfile/home/aspect/FileListCacheAspect.java +++ /dev/null @@ -1,66 +0,0 @@ -package im.zhaojun.zfile.home.aspect; - -import im.zhaojun.zfile.common.cache.ZFileCache; -import im.zhaojun.zfile.home.model.result.FileItemResult; -import im.zhaojun.zfile.admin.model.entity.StorageSource; -import im.zhaojun.zfile.admin.service.StorageSourceService; -import im.zhaojun.zfile.home.service.base.AbstractBaseFileService; -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.annotation.Around; -import org.aspectj.lang.annotation.Aspect; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; -import java.util.Collections; -import java.util.List; - -/** - * 缓存切面类, 用于访问文件夹时, 缓存文件列表内容. - * - * @author zhaojun - */ -@Aspect -@Component -public class FileListCacheAspect { - - @Resource - private ZFileCache zFileCache; - - @Resource - private StorageSourceService storageSourceService; - - /** - * 缓存切面, 如果此存储源开启了缓存, 则从缓存中取数据, 没有开启, 则直接调用方法. - */ - @Around(value = "execution(public * im.zhaojun.zfile.home.service.base.AbstractBaseFileService.fileList(..))") - public Object around(ProceedingJoinPoint point) throws Throwable { - List result; - - // 获取请求路径 - Object[] args = point.getArgs(); - String path = String.valueOf(args[0]); - - // 获取当前存储源 - AbstractBaseFileService fileService = ((AbstractBaseFileService) point.getTarget()); - Integer storageId = fileService.storageId; - - // 判断存储源是否开启了缓存 - StorageSource storageSource = storageSourceService.findById(storageId); - boolean enableCache = storageSource.getEnableCache(); - - if (enableCache) { - List cacheFileList = zFileCache.get(storageId, path); - if (cacheFileList == null) { - result = Collections.unmodifiableList((List) point.proceed()); - zFileCache.put(storageId, path, result); - } else { - result = cacheFileList; - } - } else { - result = (List) point.proceed(); - } - - return result; - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/controller/FileController.java b/src/main/java/im/zhaojun/zfile/home/controller/FileController.java deleted file mode 100644 index 50f3797..0000000 --- a/src/main/java/im/zhaojun/zfile/home/controller/FileController.java +++ /dev/null @@ -1 +0,0 @@ -package im.zhaojun.zfile.home.controller; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiSort; import im.zhaojun.zfile.admin.model.entity.StorageSource; import im.zhaojun.zfile.admin.service.StorageSourceService; import im.zhaojun.zfile.common.context.StorageSourceContext; import im.zhaojun.zfile.common.exception.InvalidStorageSourceException; import im.zhaojun.zfile.common.util.AjaxJson; import im.zhaojun.zfile.home.chain.FileChain; import im.zhaojun.zfile.home.chain.FileContext; import im.zhaojun.zfile.home.convert.StorageSourceConvert; import im.zhaojun.zfile.home.model.request.FileItemRequest; import im.zhaojun.zfile.home.model.request.FileListRequest; import im.zhaojun.zfile.home.model.result.FileInfoResult; import im.zhaojun.zfile.home.model.result.FileItemResult; import im.zhaojun.zfile.home.model.result.StorageSourceResult; import im.zhaojun.zfile.home.service.base.AbstractBaseFileService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import javax.validation.Valid; import java.util.List; /** * 文件列表相关接口, 如展示存储源列表, 展示文件列表, 搜索文件列表等. * * @author zhaojun */ @Api(tags = "文件列表模块") @ApiSort(2) @Slf4j @RequestMapping("/api/storage") @RestController public class FileController { @Resource private StorageSourceContext storageSourceContext; @Resource private StorageSourceService storageSourceService; @Resource private FileChain fileChain; @Resource private StorageSourceConvert storageSourceConvert; @ApiOperationSupport(order = 1) @ApiOperation(value = "获取存储源列表", notes = "获取所有已启用的存储源, 并且按照后台顺序排序") @GetMapping("/list") public AjaxJson> storageList() { List storageList = storageSourceService.findListByEnableOrderByOrderNum(); List storageSourceResultList = storageSourceConvert.entityToResultList(storageList); return AjaxJson.getSuccessData(storageSourceResultList); } @ApiOperationSupport(order = 2) @ApiOperation(value = "获取文件列表", notes = "获取某个存储源下, 指定路径的文件&文件夹列表") @PostMapping("/files") public AjaxJson list(@Valid @RequestBody FileListRequest fileListRequest) throws Exception { StorageSource storageSource = storageSourceService.findByStorageKey(fileListRequest.getStorageKey()); if (storageSource == null) { throw new InvalidStorageSourceException("存储源不存在"); } Integer storageId = storageSource.getId(); // 处理请求参数默认值 fileListRequest.handleDefaultValue(); // 获取文件列表 AbstractBaseFileService fileService = storageSourceContext.get(storageId); List fileItemList = fileService.fileList(fileListRequest.getPath()); // 执行责任链 FileContext fileContext = FileContext.builder() .storageId(storageId) .fileListRequest(fileListRequest) .fileItemList(fileItemList).build(); fileChain.execute(fileContext); return AjaxJson.getSuccessData(new FileInfoResult(fileContext.getFileItemList(), fileContext.getPasswordPattern())); } @ApiOperationSupport(order = 3) @ApiOperation(value = "获取单个文件信息", notes = "获取某个存储源下, 单个文件的信息") @PostMapping("/file/item") public AjaxJson fileItem(@Valid @RequestBody FileItemRequest fileItemRequest) { StorageSource storageSource = storageSourceService.findByStorageKey(fileItemRequest.getStorageKey()); if (storageSource == null) { throw new InvalidStorageSourceException("存储源不存在"); } Integer storageId = storageSource.getId(); // 处理请求参数默认值 fileItemRequest.handleDefaultValue(); // 获取文件列表 AbstractBaseFileService fileService = storageSourceContext.get(storageId); FileItemResult fileItemResult; try { fileItemResult = fileService.getFileItem(fileItemRequest.getPath()); } catch (Exception e) { return AjaxJson.getError("获取文件信息失败: " + e.getMessage()); } return AjaxJson.getSuccessData(fileItemResult); } } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/controller/SiteController.java b/src/main/java/im/zhaojun/zfile/home/controller/SiteController.java deleted file mode 100644 index 0f071e1..0000000 --- a/src/main/java/im/zhaojun/zfile/home/controller/SiteController.java +++ /dev/null @@ -1,158 +0,0 @@ -package im.zhaojun.zfile.home.controller; - -import cn.hutool.core.util.BooleanUtil; -import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; -import com.github.xiaoymin.knife4j.annotations.ApiSort; -import im.zhaojun.zfile.admin.model.entity.ReadmeConfig; -import im.zhaojun.zfile.admin.model.entity.StorageSource; -import im.zhaojun.zfile.admin.model.enums.ReadmeDisplayModeEnum; -import im.zhaojun.zfile.admin.model.param.IStorageParam; -import im.zhaojun.zfile.admin.service.ReadmeConfigService; -import im.zhaojun.zfile.admin.service.StorageSourceService; -import im.zhaojun.zfile.admin.service.SystemConfigService; -import im.zhaojun.zfile.common.config.ZFileProperties; -import im.zhaojun.zfile.common.context.StorageSourceContext; -import im.zhaojun.zfile.common.exception.InvalidStorageSourceException; -import im.zhaojun.zfile.common.exception.NotExistFileException; -import im.zhaojun.zfile.common.util.AjaxJson; -import im.zhaojun.zfile.common.util.HttpUtil; -import im.zhaojun.zfile.common.util.StringUtils; -import im.zhaojun.zfile.home.convert.StorageSourceConvert; -import im.zhaojun.zfile.home.model.dto.SystemConfigDTO; -import im.zhaojun.zfile.home.model.request.FileListConfigRequest; -import im.zhaojun.zfile.home.model.result.FileItemResult; -import im.zhaojun.zfile.home.model.result.SiteConfigResult; -import im.zhaojun.zfile.home.model.result.StorageSourceConfigResult; -import im.zhaojun.zfile.home.service.base.AbstractBaseFileService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.BeanUtils; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; - -import javax.annotation.Resource; -import javax.validation.Valid; - -/** - * 站点基础模块接口 - * - * @author zhaojun - */ -@Api(tags = "站点基础模块") -@ApiSort(1) -@Slf4j -@RequestMapping("/api/site") -@RestController -public class SiteController { - - @Resource - private ZFileProperties zFileProperties; - - @Resource - private StorageSourceConvert storageSourceConvert; - - @Resource - private StorageSourceService storageSourceService; - - @Resource - private SystemConfigService systemConfigService; - - @Resource - private ReadmeConfigService readmeConfigService; - - @Resource - private StorageSourceContext storageSourceContext; - - - @ApiOperationSupport(order = 1) - @ApiOperation(value = "获取站点全局设置", notes = "获取站点全局设置, 包括是否页面布局、列表尺寸、公告、配置信息") - @GetMapping("/config/global") - public AjaxJson globalConfig() { - SystemConfigDTO systemConfig = systemConfigService.getSystemConfig(); - - SiteConfigResult siteConfigResult = new SiteConfigResult(); - BeanUtils.copyProperties(systemConfig, siteConfigResult); - - siteConfigResult.setDebugMode(zFileProperties.isDebug()); - return AjaxJson.getSuccessData(siteConfigResult); - } - - - @ApiOperationSupport(order = 2) - @ApiOperation(value = "获取存储源设置", notes = "获取某个存储源的设置信息, 包括是否启用, 名称, 存储源类型, 存储源配置信息") - @PostMapping("/config/storage") - public AjaxJson storageList(@Valid @RequestBody FileListConfigRequest fileListConfigRequest) { - - String storageKey = fileListConfigRequest.getStorageKey(); - String path = fileListConfigRequest.getPath(); - - StorageSource storageSource = storageSourceService.findByStorageKey(storageKey); - if (storageSource == null) { - throw new InvalidStorageSourceException("存储源不存在"); - } - - StorageSourceConfigResult storageSourceConfigResult = storageSourceConvert.entityToConfigResult(storageSource); - - // 获取是否允许文件操作 - storageSourceConfigResult.setEnableFileOperator(storageSource.allowOperator()); - - // 根据存储源 key 获取存储源 id - Integer storageId = storageSource.getId(); - - - ReadmeConfig readmeByPath = new ReadmeConfig(); - readmeByPath.setStorageId(storageId); - readmeByPath.setDisplayMode(ReadmeDisplayModeEnum.BOTTOM); - if (BooleanUtil.isTrue(storageSource.getCompatibilityReadme())) { - try { - log.info("存储源 {} 兼容获取目录 {} 下的 readme.md", storageSource.getName(), path); - AbstractBaseFileService abstractBaseFileService = storageSourceContext.get(storageId); - String pathAndName = StringUtils.concat(path, "readme.md"); - FileItemResult fileItem = abstractBaseFileService.getFileItem(pathAndName); - if (fileItem != null) { - String url = fileItem.getUrl(); - String readmeText = HttpUtil.getTextContent(url); - readmeByPath.setReadmeText(readmeText); - } - } catch (Exception e) { - if (e instanceof NotExistFileException) { - log.error("存储源 {} 兼容获取目录 {} 下的 readme.md 文件失败", storageSource.getName(), path); - } else { - log.error("存储源 {} 兼容获取目录 {} 下的 readme.md 文件失败", storageSource.getName(), path, e); - } - } - } else { - // 获取指定目录 readme 文件 - ReadmeConfig dbReadmeConfig = readmeConfigService.findReadmeByPath(storageId, path); - if (dbReadmeConfig != null) { - readmeByPath = dbReadmeConfig; - } - log.info("存储源 {} 规则模式获取目录 {} 下文档信息", storageSource.getName(), path); - } - - storageSourceConfigResult.setReadmeDisplayMode(readmeByPath.getDisplayMode()); - storageSourceConfigResult.setReadmeText(readmeByPath.getReadmeText()); - - return AjaxJson.getSuccessData(storageSourceConfigResult); - } - - - @ResponseBody - @ApiOperationSupport(order = 3) - @ApiOperation(value = "重置管理员密码", notes = "开启 debug 模式时,访问此接口会强制将管理员账户密码修改为 admin 123456, 并修改登录验证方式为图片验证码, 详见:https://docs.zfile.vip/#/question?id=reset-pwd") - @GetMapping("/reset-password") - public AjaxJson resetPwd() { - if (zFileProperties.isDebug()) { - systemConfigService.resetAdminLoginInfo(); - return AjaxJson.getSuccess(); - } else { - return AjaxJson.getError("未开启 DEBUG 模式,不允许进行此操作。"); - } - } - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/convert/StorageSourceConvert.java b/src/main/java/im/zhaojun/zfile/home/convert/StorageSourceConvert.java deleted file mode 100644 index ec271c4..0000000 --- a/src/main/java/im/zhaojun/zfile/home/convert/StorageSourceConvert.java +++ /dev/null @@ -1,55 +0,0 @@ -package im.zhaojun.zfile.home.convert; - -import im.zhaojun.zfile.admin.model.result.storage.StorageSourceAdminResult; -import im.zhaojun.zfile.home.model.result.StorageSourceConfigResult; -import im.zhaojun.zfile.home.model.result.StorageSourceResult; -import im.zhaojun.zfile.admin.model.entity.StorageSource; -import org.mapstruct.Mapper; -import org.springframework.stereotype.Component; - -import java.util.List; - -/** - * StorageSource 转换器 - * - * @author zhaojun - */ -@Component -@Mapper(componentModel = "spring") -public interface StorageSourceConvert { - - - /** - * 将 StorageSource 转换为 StorageSourceResult - * - * @param list - * StorageSource 列表 - * - * @return StorageSourceResult 列表 - */ - List entityToResultList(List list); - - - /** - * 将 StorageSource 转换为 StorageSourceConfigResult - * - * @param storageSource - * StorageSource 实体 - * - * @return StorageSourceConfigResult 实体 - */ - StorageSourceConfigResult entityToConfigResult(StorageSource storageSource); - - - /** - * 将 StorageSource 转换为 StorageSourceAdminResult - * - * @param list - * StorageSource 列表 - * - * @return StorageSourceAdminResult 列表 - */ - List entityToAdminResultList(List list); - - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/model/dto/CacheInfoDTO.java b/src/main/java/im/zhaojun/zfile/home/model/dto/CacheInfoDTO.java deleted file mode 100644 index 4c68caf..0000000 --- a/src/main/java/im/zhaojun/zfile/home/model/dto/CacheInfoDTO.java +++ /dev/null @@ -1,32 +0,0 @@ -package im.zhaojun.zfile.home.model.dto; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Data; - -import java.util.Set; - -/** - * 缓存信息 DTO - * - * @author zhaojun - */ -@Data -@AllArgsConstructor -@ApiModel(description = "缓存信息类") -public class CacheInfoDTO { - - @ApiModelProperty(value = "缓存的 key 个数", required = true, example = "100") - private Integer cacheCount; - - @ApiModelProperty(value = "缓存命中数", required = true, example = "70") - private Long hitCount; - - @ApiModelProperty(value = "缓存未命中数", required = true, example = "30") - private Long missCount; - - @ApiModelProperty(value = "缓存的路径", required = true) - private Set cacheKeys; - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/model/request/UserLoginRequest.java b/src/main/java/im/zhaojun/zfile/home/model/request/UserLoginRequest.java deleted file mode 100644 index 1747e1c..0000000 --- a/src/main/java/im/zhaojun/zfile/home/model/request/UserLoginRequest.java +++ /dev/null @@ -1 +0,0 @@ -package im.zhaojun.zfile.home.model.request; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import javax.validation.constraints.NotBlank; /** * 用户登录请求参数参数 * * @author zhaojun */ @Data @ApiModel(description = "用户登录请求参数类") public class UserLoginRequest { @ApiModelProperty(value = "用户名", required = true, example = "admin") @NotBlank(message = "用户名不能为空") private String username; @ApiModelProperty(value = "密码", required = true, example = "123456") @NotBlank(message = "密码不能为空") private String password; @ApiModelProperty(value = "验证码", example = "123456") private String verifyCode; @ApiModelProperty(value = "验证码 UUID", notes = "用于图形验证码确认每个验证码图片请求的唯一值.", example = "c140a792-4ca2-4dac-8d4c-35750b78524f") private String verifyCodeUUID; } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/service/base/RefreshTokenService.java b/src/main/java/im/zhaojun/zfile/home/service/base/RefreshTokenService.java deleted file mode 100644 index 73f6d83..0000000 --- a/src/main/java/im/zhaojun/zfile/home/service/base/RefreshTokenService.java +++ /dev/null @@ -1,12 +0,0 @@ -package im.zhaojun.zfile.home.service.base; - -/** - * 需要刷新 Token 服务的存储源 - * - * @author zhaojun - */ -public interface RefreshTokenService { - - void refreshAccessToken() throws Exception; - -} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/constant/SystemConfigConstant.java b/src/main/java/im/zhaojun/zfile/module/config/constant/SystemConfigConstant.java similarity index 87% rename from src/main/java/im/zhaojun/zfile/admin/constant/SystemConfigConstant.java rename to src/main/java/im/zhaojun/zfile/module/config/constant/SystemConfigConstant.java index 18d3d8c..d0ec097 100644 --- a/src/main/java/im/zhaojun/zfile/admin/constant/SystemConfigConstant.java +++ b/src/main/java/im/zhaojun/zfile/module/config/constant/SystemConfigConstant.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.constant; +package im.zhaojun.zfile.module.config.constant; /** * 系统设置字段常量. diff --git a/src/main/java/im/zhaojun/zfile/home/install/InstallController.java b/src/main/java/im/zhaojun/zfile/module/config/controller/InstallController.java similarity index 81% rename from src/main/java/im/zhaojun/zfile/home/install/InstallController.java rename to src/main/java/im/zhaojun/zfile/module/config/controller/InstallController.java index cb82fa9..1f19453 100644 --- a/src/main/java/im/zhaojun/zfile/home/install/InstallController.java +++ b/src/main/java/im/zhaojun/zfile/module/config/controller/InstallController.java @@ -1,14 +1,13 @@ -package im.zhaojun.zfile.home.install; +package im.zhaojun.zfile.module.config.controller; import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; -import im.zhaojun.zfile.common.exception.InstallSystemException; -import im.zhaojun.zfile.home.model.dto.SystemConfigDTO; -import im.zhaojun.zfile.home.model.request.InstallSystemRequest; -import im.zhaojun.zfile.admin.service.SystemConfigService; -import im.zhaojun.zfile.common.util.AjaxJson; +import im.zhaojun.zfile.module.config.service.SystemConfigService; +import im.zhaojun.zfile.core.exception.InstallSystemException; +import im.zhaojun.zfile.core.util.AjaxJson; +import im.zhaojun.zfile.module.config.model.dto.SystemConfigDTO; +import im.zhaojun.zfile.module.config.model.request.InstallSystemRequest; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.GetMapping; @@ -45,7 +44,7 @@ public class InstallController { @ApiOperation(value = "初始化系统", notes = "根据管理员用户名是否存在判断系统已初始化, 已初始化返回 true, 未初始化返回 false") @PostMapping("/install") public AjaxJson install(@RequestBody InstallSystemRequest installSystemRequest) { - if (StrUtil.isNotEmpty(systemConfigService.getAdminUsername())) { + if (systemConfigService.getSystemIsInstalled()) { throw new InstallSystemException("请勿重复初始化"); } diff --git a/src/main/java/im/zhaojun/zfile/admin/controller/setting/SettingController.java b/src/main/java/im/zhaojun/zfile/module/config/controller/SettingController.java similarity index 87% rename from src/main/java/im/zhaojun/zfile/admin/controller/setting/SettingController.java rename to src/main/java/im/zhaojun/zfile/module/config/controller/SettingController.java index 7e88cb2..cfd0866 100644 --- a/src/main/java/im/zhaojun/zfile/admin/controller/setting/SettingController.java +++ b/src/main/java/im/zhaojun/zfile/module/config/controller/SettingController.java @@ -1,17 +1,17 @@ -package im.zhaojun.zfile.admin.controller.setting; +package im.zhaojun.zfile.module.config.controller; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiSort; -import im.zhaojun.zfile.admin.model.request.setting.UpdateLinkSettingRequest; -import im.zhaojun.zfile.admin.model.request.setting.UpdateSecuritySettingRequest; -import im.zhaojun.zfile.admin.model.request.setting.UpdateSiteSettingRequest; -import im.zhaojun.zfile.admin.model.request.setting.UpdateUserNameAndPasswordRequest; -import im.zhaojun.zfile.admin.model.request.setting.UpdateViewSettingRequest; -import im.zhaojun.zfile.admin.service.SystemConfigService; -import im.zhaojun.zfile.common.util.AjaxJson; -import im.zhaojun.zfile.home.model.dto.SystemConfigDTO; +import im.zhaojun.zfile.core.util.AjaxJson; +import im.zhaojun.zfile.module.config.model.dto.SystemConfigDTO; +import im.zhaojun.zfile.module.config.model.request.UpdateLinkSettingRequest; +import im.zhaojun.zfile.module.config.model.request.UpdateSecuritySettingRequest; +import im.zhaojun.zfile.module.config.model.request.UpdateSiteSettingRequest; +import im.zhaojun.zfile.module.config.model.request.UpdateUserNameAndPasswordRequest; +import im.zhaojun.zfile.module.config.model.request.UpdateViewSettingRequest; +import im.zhaojun.zfile.module.config.service.SystemConfigService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.BeanUtils; diff --git a/src/main/java/im/zhaojun/zfile/module/config/controller/SiteController.java b/src/main/java/im/zhaojun/zfile/module/config/controller/SiteController.java new file mode 100644 index 0000000..c227905 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/config/controller/SiteController.java @@ -0,0 +1,80 @@ +package im.zhaojun.zfile.module.config.controller; + +import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; +import com.github.xiaoymin.knife4j.annotations.ApiSort; +import im.zhaojun.zfile.module.storage.service.StorageSourceService; +import im.zhaojun.zfile.module.config.service.SystemConfigService; +import im.zhaojun.zfile.core.config.ZFileProperties; +import im.zhaojun.zfile.core.util.AjaxJson; +import im.zhaojun.zfile.module.config.model.dto.SystemConfigDTO; +import im.zhaojun.zfile.module.storage.model.request.base.FileListConfigRequest; +import im.zhaojun.zfile.module.config.model.result.SiteConfigResult; +import im.zhaojun.zfile.module.storage.model.result.StorageSourceConfigResult; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; + +/** + * 站点基础模块接口 + * + * @author zhaojun + */ +@Api(tags = "站点基础模块") +@ApiSort(1) +@Slf4j +@RequestMapping("/api/site") +@RestController +public class SiteController { + + @Resource + private ZFileProperties zFileProperties; + + @Resource + private StorageSourceService storageSourceService; + + @Resource + private SystemConfigService systemConfigService; + + @ApiOperationSupport(order = 1) + @ApiOperation(value = "获取站点全局设置", notes = "获取站点全局设置, 包括是否页面布局、列表尺寸、公告、配置信息") + @GetMapping("/config/global") + public AjaxJson globalConfig() { + SystemConfigDTO systemConfig = systemConfigService.getSystemConfig(); + + SiteConfigResult siteConfigResult = new SiteConfigResult(); + BeanUtils.copyProperties(systemConfig, siteConfigResult); + + siteConfigResult.setDebugMode(zFileProperties.isDebug()); + return AjaxJson.getSuccessData(siteConfigResult); + } + + + @ApiOperationSupport(order = 2) + @ApiOperation(value = "获取存储源设置", notes = "获取某个存储源的设置信息, 包括是否启用, 名称, 存储源类型, 存储源配置信息") + @PostMapping("/config/storage") + public AjaxJson storageList(@Valid @RequestBody FileListConfigRequest fileListConfigRequest) { + StorageSourceConfigResult storageSourceConfigResult = storageSourceService.getStorageConfigSource(fileListConfigRequest); + return AjaxJson.getSuccessData(storageSourceConfigResult); + } + + + @ResponseBody + @ApiOperationSupport(order = 3) + @ApiOperation(value = "重置管理员密码", notes = "开启 debug 模式时,访问此接口会强制将管理员账户密码修改为 admin 123456, 并修改登录验证方式为图片验证码, 详见:https://docs.zfile.vip/#/question?id=reset-pwd") + @GetMapping("/reset-password") + public AjaxJson resetPwd() { + systemConfigService.resetAdminLoginInfo(); + return AjaxJson.getSuccess(); + } + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/mapper/SystemConfigMapper.java b/src/main/java/im/zhaojun/zfile/module/config/mapper/SystemConfigMapper.java similarity index 88% rename from src/main/java/im/zhaojun/zfile/admin/mapper/SystemConfigMapper.java rename to src/main/java/im/zhaojun/zfile/module/config/mapper/SystemConfigMapper.java index 5032e11..80bda6b 100644 --- a/src/main/java/im/zhaojun/zfile/admin/mapper/SystemConfigMapper.java +++ b/src/main/java/im/zhaojun/zfile/module/config/mapper/SystemConfigMapper.java @@ -1,7 +1,7 @@ -package im.zhaojun.zfile.admin.mapper; +package im.zhaojun.zfile.module.config.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import im.zhaojun.zfile.admin.model.entity.SystemConfig; +import im.zhaojun.zfile.module.config.model.entity.SystemConfig; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; diff --git a/src/main/java/im/zhaojun/zfile/home/model/dto/SystemConfigDTO.java b/src/main/java/im/zhaojun/zfile/module/config/model/dto/SystemConfigDTO.java similarity index 91% rename from src/main/java/im/zhaojun/zfile/home/model/dto/SystemConfigDTO.java rename to src/main/java/im/zhaojun/zfile/module/config/model/dto/SystemConfigDTO.java index 6f48e52..3f6cff9 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/dto/SystemConfigDTO.java +++ b/src/main/java/im/zhaojun/zfile/module/config/model/dto/SystemConfigDTO.java @@ -1,9 +1,9 @@ -package im.zhaojun.zfile.home.model.dto; +package im.zhaojun.zfile.module.config.model.dto; import com.fasterxml.jackson.annotation.JsonIgnore; -import im.zhaojun.zfile.admin.model.enums.FileClickModeEnum; -import im.zhaojun.zfile.admin.model.enums.LoginVerifyModeEnum; -import im.zhaojun.zfile.admin.model.enums.RefererTypeEnum; +import im.zhaojun.zfile.module.config.model.enums.FileClickModeEnum; +import im.zhaojun.zfile.module.login.model.enums.LoginVerifyModeEnum; +import im.zhaojun.zfile.module.link.model.enums.RefererTypeEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -126,4 +126,7 @@ public class SystemConfigDTO { @ApiModelProperty(value = "onlyOffice 在线预览地址", example = "http://office.zfile.vip") private String onlyOfficeUrl; + @ApiModelProperty(value = "是否允许路径直链可直接访问", example = "true", required = true) + private Boolean allowPathLinkAnonAccess; + } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/model/entity/SystemConfig.java b/src/main/java/im/zhaojun/zfile/module/config/model/entity/SystemConfig.java similarity index 93% rename from src/main/java/im/zhaojun/zfile/admin/model/entity/SystemConfig.java rename to src/main/java/im/zhaojun/zfile/module/config/model/entity/SystemConfig.java index fdfdb0b..fe82aa7 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/entity/SystemConfig.java +++ b/src/main/java/im/zhaojun/zfile/module/config/model/entity/SystemConfig.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.entity; +package im.zhaojun.zfile.module.config.model.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; @@ -12,6 +12,8 @@ import java.io.Serializable; /** * 系统设置 entity + * + * @author zhaojun */ @Data @ApiModel(description = "系统设置") diff --git a/src/main/java/im/zhaojun/zfile/admin/model/enums/FileClickModeEnum.java b/src/main/java/im/zhaojun/zfile/module/config/model/enums/FileClickModeEnum.java similarity index 90% rename from src/main/java/im/zhaojun/zfile/admin/model/enums/FileClickModeEnum.java rename to src/main/java/im/zhaojun/zfile/module/config/model/enums/FileClickModeEnum.java index b65ee82..c3d7982 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/enums/FileClickModeEnum.java +++ b/src/main/java/im/zhaojun/zfile/module/config/model/enums/FileClickModeEnum.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.enums; +package im.zhaojun.zfile.module.config.model.enums; import com.baomidou.mybatisplus.annotation.EnumValue; import com.fasterxml.jackson.annotation.JsonValue; diff --git a/src/main/java/im/zhaojun/zfile/home/model/request/InstallSystemRequest.java b/src/main/java/im/zhaojun/zfile/module/config/model/request/InstallSystemRequest.java similarity index 92% rename from src/main/java/im/zhaojun/zfile/home/model/request/InstallSystemRequest.java rename to src/main/java/im/zhaojun/zfile/module/config/model/request/InstallSystemRequest.java index 94f7725..0257215 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/request/InstallSystemRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/config/model/request/InstallSystemRequest.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.home.model.request; +package im.zhaojun.zfile.module.config.model.request; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/request/setting/UpdateLinkSettingRequest.java b/src/main/java/im/zhaojun/zfile/module/config/model/request/UpdateLinkSettingRequest.java similarity index 81% rename from src/main/java/im/zhaojun/zfile/admin/model/request/setting/UpdateLinkSettingRequest.java rename to src/main/java/im/zhaojun/zfile/module/config/model/request/UpdateLinkSettingRequest.java index ecbebcd..dff42ab 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/request/setting/UpdateLinkSettingRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/config/model/request/UpdateLinkSettingRequest.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.admin.model.request.setting; +package im.zhaojun.zfile.module.config.model.request; -import im.zhaojun.zfile.admin.model.enums.RefererTypeEnum; +import im.zhaojun.zfile.module.link.model.enums.RefererTypeEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -37,5 +37,8 @@ public class UpdateLinkSettingRequest { @ApiModelProperty(value = "是否显示生成路径链接功能", example = "true", required = true) private Boolean showPathLink; + + @ApiModelProperty(value = "是否允许路径直链可直接访问", example = "true", required = true) + private Boolean allowPathLinkAnonAccess; } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/model/request/setting/UpdateSecuritySettingRequest.java b/src/main/java/im/zhaojun/zfile/module/config/model/request/UpdateSecuritySettingRequest.java similarity index 83% rename from src/main/java/im/zhaojun/zfile/admin/model/request/setting/UpdateSecuritySettingRequest.java rename to src/main/java/im/zhaojun/zfile/module/config/model/request/UpdateSecuritySettingRequest.java index f3343be..9caf9c5 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/request/setting/UpdateSecuritySettingRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/config/model/request/UpdateSecuritySettingRequest.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.admin.model.request.setting; +package im.zhaojun.zfile.module.config.model.request; -import im.zhaojun.zfile.admin.model.enums.LoginVerifyModeEnum; +import im.zhaojun.zfile.module.login.model.enums.LoginVerifyModeEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/request/setting/UpdateSiteSettingRequest.java b/src/main/java/im/zhaojun/zfile/module/config/model/request/UpdateSiteSettingRequest.java similarity index 95% rename from src/main/java/im/zhaojun/zfile/admin/model/request/setting/UpdateSiteSettingRequest.java rename to src/main/java/im/zhaojun/zfile/module/config/model/request/UpdateSiteSettingRequest.java index be69e04..8deacb5 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/request/setting/UpdateSiteSettingRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/config/model/request/UpdateSiteSettingRequest.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.request.setting; +package im.zhaojun.zfile.module.config.model.request; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/request/setting/UpdateUserNameAndPasswordRequest.java b/src/main/java/im/zhaojun/zfile/module/config/model/request/UpdateUserNameAndPasswordRequest.java similarity index 90% rename from src/main/java/im/zhaojun/zfile/admin/model/request/setting/UpdateUserNameAndPasswordRequest.java rename to src/main/java/im/zhaojun/zfile/module/config/model/request/UpdateUserNameAndPasswordRequest.java index c18d631..78bcf9c 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/request/setting/UpdateUserNameAndPasswordRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/config/model/request/UpdateUserNameAndPasswordRequest.java @@ -1 +1 @@ -package im.zhaojun.zfile.admin.model.request.setting; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import javax.validation.constraints.NotBlank; /** * 用户修改密码请求参数类 * * @author zhaojun */ @Data @ApiModel(description = "用户修改密码请求参数类") public class UpdateUserNameAndPasswordRequest { @ApiModelProperty(value = "用户名", required = true, example = "admin") @NotBlank(message = "用户名不能为空") private String username; @ApiModelProperty(value = "密码", required = true, example = "123456") @NotBlank(message = "密码不能为空") private String password; } \ No newline at end of file +package im.zhaojun.zfile.module.config.model.request; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import javax.validation.constraints.NotBlank; /** * 用户修改密码请求参数类 * * @author zhaojun */ @Data @ApiModel(description = "用户修改密码请求参数类") public class UpdateUserNameAndPasswordRequest { @ApiModelProperty(value = "用户名", required = true, example = "admin") @NotBlank(message = "用户名不能为空") private String username; @ApiModelProperty(value = "密码", required = true, example = "123456") @NotBlank(message = "密码不能为空") private String password; } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/model/request/setting/UpdateViewSettingRequest.java b/src/main/java/im/zhaojun/zfile/module/config/model/request/UpdateViewSettingRequest.java similarity index 94% rename from src/main/java/im/zhaojun/zfile/admin/model/request/setting/UpdateViewSettingRequest.java rename to src/main/java/im/zhaojun/zfile/module/config/model/request/UpdateViewSettingRequest.java index 45a4f17..c84a985 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/request/setting/UpdateViewSettingRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/config/model/request/UpdateViewSettingRequest.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.admin.model.request.setting; +package im.zhaojun.zfile.module.config.model.request; -import im.zhaojun.zfile.admin.model.enums.FileClickModeEnum; +import im.zhaojun.zfile.module.config.model.enums.FileClickModeEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; diff --git a/src/main/java/im/zhaojun/zfile/module/config/model/request/UpdateWebDAVRequest.java b/src/main/java/im/zhaojun/zfile/module/config/model/request/UpdateWebDAVRequest.java new file mode 100644 index 0000000..fef9526 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/config/model/request/UpdateWebDAVRequest.java @@ -0,0 +1,26 @@ +package im.zhaojun.zfile.module.config.model.request; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author zhaojun + */ +@Data +@ApiModel(description = "WebDAV 设置请求参数类") +public class UpdateWebDAVRequest { + + @ApiModelProperty(value = "启用 WebDAV", example = "true") + private Boolean webdavEnable; + + @ApiModelProperty(value = "WebDAV 服务器中转下载", example = "true") + private Boolean webdavProxy; + + @ApiModelProperty(value = "WebDAV 账号", example = "admin") + private String webdavUsername; + + @ApiModelProperty(value = "WebDAV 密码", example = "123456") + private String webdavPassword; + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/model/result/SiteConfigResult.java b/src/main/java/im/zhaojun/zfile/module/config/model/result/SiteConfigResult.java similarity index 96% rename from src/main/java/im/zhaojun/zfile/home/model/result/SiteConfigResult.java rename to src/main/java/im/zhaojun/zfile/module/config/model/result/SiteConfigResult.java index 41a1025..e8a3385 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/result/SiteConfigResult.java +++ b/src/main/java/im/zhaojun/zfile/module/config/model/result/SiteConfigResult.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.home.model.result; +package im.zhaojun.zfile.module.config.model.result; -import im.zhaojun.zfile.admin.model.enums.FileClickModeEnum; +import im.zhaojun.zfile.module.config.model.enums.FileClickModeEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -46,7 +46,7 @@ public class SiteConfigResult { @ApiModelProperty(value = "是否显示生成路径链接功能", example = "true", required = true) private Boolean showPathLink; - + @ApiModelProperty(value = "是否显示文档区", example = "true", required = true) private Boolean showDocument; diff --git a/src/main/java/im/zhaojun/zfile/admin/service/SystemConfigService.java b/src/main/java/im/zhaojun/zfile/module/config/service/SystemConfigService.java similarity index 66% rename from src/main/java/im/zhaojun/zfile/admin/service/SystemConfigService.java rename to src/main/java/im/zhaojun/zfile/module/config/service/SystemConfigService.java index 6e0e297..8973ae5 100644 --- a/src/main/java/im/zhaojun/zfile/admin/service/SystemConfigService.java +++ b/src/main/java/im/zhaojun/zfile/module/config/service/SystemConfigService.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.service; +package im.zhaojun.zfile.module.config.service; import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.ConvertException; @@ -7,22 +7,31 @@ import cn.hutool.core.util.HexUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; import cn.hutool.crypto.symmetric.SymmetricAlgorithm; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import im.zhaojun.zfile.admin.constant.SystemConfigConstant; -import im.zhaojun.zfile.admin.mapper.SystemConfigMapper; -import im.zhaojun.zfile.admin.model.entity.SystemConfig; -import im.zhaojun.zfile.admin.model.enums.LoginVerifyModeEnum; -import im.zhaojun.zfile.common.cache.ZFileCache; -import im.zhaojun.zfile.common.util.EnumConvertUtils; -import im.zhaojun.zfile.home.model.dto.SystemConfigDTO; +import im.zhaojun.zfile.module.config.constant.SystemConfigConstant; +import im.zhaojun.zfile.module.config.mapper.SystemConfigMapper; +import im.zhaojun.zfile.module.config.model.entity.SystemConfig; +import im.zhaojun.zfile.module.login.model.enums.LoginVerifyModeEnum; +import im.zhaojun.zfile.core.config.ZFileProperties; +import im.zhaojun.zfile.core.exception.ServiceException; +import im.zhaojun.zfile.core.util.CodeMsg; +import im.zhaojun.zfile.core.util.EnumConvertUtils; +import im.zhaojun.zfile.module.config.model.dto.SystemConfigDTO; import lombok.extern.slf4j.Slf4j; -import org.springframework.context.annotation.DependsOn; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; +import java.util.Optional; + +import static im.zhaojun.zfile.module.config.service.SystemConfigService.CACHE_NAME; /** * 系统设置 Service @@ -31,34 +40,39 @@ import java.util.List; */ @Slf4j @Service -@DependsOn("zFileCache") -public class SystemConfigService extends ServiceImpl { - +@CacheConfig(cacheNames = CACHE_NAME) +public class SystemConfigService { + + public static final String CACHE_NAME = "systemConfig"; + private static final String DEFAULT_USERNAME = "admin"; private static final String DEFAULT_PASSWORD = "123456"; private static final LoginVerifyModeEnum DEFAULT_LOGIN_VERIFY_MODE = LoginVerifyModeEnum.IMG_VERIFY_MODE; - @Resource - private ZFileCache zFileCache; - @Resource private SystemConfigMapper systemConfigMapper; - + + @Resource + private SystemConfigService systemConfigService; + + @Resource + private ZFileProperties zFileProperties; + + @Resource + private CacheManager cacheManager; + private final Class systemConfigClazz = SystemConfigDTO.class; + /** * 获取系统设置, 如果缓存中有, 则去缓存取, 没有则查询数据库并写入到缓存中. * * @return 系统设置 */ + @Cacheable(key = "'dto'") public SystemConfigDTO getSystemConfig() { - SystemConfigDTO cacheConfig = zFileCache.getConfig(); - if (cacheConfig != null) { - return cacheConfig; - } - SystemConfigDTO systemConfigDTO = new SystemConfigDTO(); List systemConfigList = systemConfigMapper.findAll(); @@ -83,7 +97,6 @@ public class SystemConfigService extends ServiceImpl systemConfigList = new ArrayList<>(); @@ -122,8 +137,6 @@ public class SystemConfigService extends ServiceImpl systemConfigMapper.updateById(systemConfig)); } @@ -131,98 +144,98 @@ public class SystemConfigService extends ServiceImpl cache1.put("dto", systemConfigDTO)); + } + return rsaHexKey; } - - - /** - * 获取管理员名称 - * - * @return 管理员名称 - */ - public String getAdminUsername() { - SystemConfigDTO systemConfigDTO = getSystemConfig(); - return systemConfigDTO.getUsername(); - } - - + + /** * 获取系统是否已初始化 * * @return 管理员名称 */ public Boolean getSystemIsInstalled() { - return getSystemConfig().getInstalled(); + return systemConfigService.getSystemConfig().getInstalled(); } - - + + /** * 获取后端站点域名 * * @return 后端站点域名 */ public String getDomain() { - SystemConfigDTO systemConfigDTO = getSystemConfig(); + SystemConfigDTO systemConfigDTO = systemConfigService.getSystemConfig(); return systemConfigDTO.getDomain(); } - - + + /** * 获取前端站点域名 * * @return 前端站点域名 */ public String getFrontDomain() { - SystemConfigDTO systemConfigDTO = getSystemConfig(); + SystemConfigDTO systemConfigDTO = systemConfigService.getSystemConfig(); return systemConfigDTO.getFrontDomain(); } - - + + /** * 获取实际的前端站点域名 * * @return 实际的前端站点域名 */ public String getRealFrontDomain() { - SystemConfigDTO systemConfigDTO = getSystemConfig(); - - String baseUrl = ""; - - if (StrUtil.isNotEmpty(systemConfigDTO.getFrontDomain())) { - baseUrl = systemConfigDTO.getFrontDomain(); - } else if (StrUtil.isNotEmpty(systemConfigDTO.getDomain())) { - baseUrl = systemConfigDTO.getDomain(); - } - - return baseUrl; + SystemConfigDTO systemConfigDTO = systemConfigService.getSystemConfig(); + return StrUtil.firstNonNull(systemConfigDTO.getFrontDomain(), systemConfigDTO.getDomain()); } - - + + /** * 获取前端地址下的 403 页面地址. * @@ -233,38 +246,4 @@ public class SystemConfigService extends ServiceImpl> getFilters(@PathVariable Integer storageId) { return AjaxJson.getSuccessData(filterConfigService.findByStorageId(storageId)); @@ -43,7 +43,7 @@ public class StorageSourceFilterController { @ApiOperationSupport(order = 2) @ApiOperation(value = "保存存储源过滤文件列表", notes = "保存指定存储源 ID 设置的过滤文件列表") - @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true) + @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true, dataTypeClass = Integer.class) @PostMapping("/storage/{storageId}/filters") public AjaxJson saveFilters(@PathVariable Integer storageId, @RequestBody List filter) { filterConfigService.batchSave(storageId, filter); diff --git a/src/main/java/im/zhaojun/zfile/admin/mapper/FilterConfigMapper.java b/src/main/java/im/zhaojun/zfile/module/filter/mapper/FilterConfigMapper.java similarity index 92% rename from src/main/java/im/zhaojun/zfile/admin/mapper/FilterConfigMapper.java rename to src/main/java/im/zhaojun/zfile/module/filter/mapper/FilterConfigMapper.java index 0478d8c..26801b4 100644 --- a/src/main/java/im/zhaojun/zfile/admin/mapper/FilterConfigMapper.java +++ b/src/main/java/im/zhaojun/zfile/module/filter/mapper/FilterConfigMapper.java @@ -1,7 +1,7 @@ -package im.zhaojun.zfile.admin.mapper; +package im.zhaojun.zfile.module.filter.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import im.zhaojun.zfile.admin.model.entity.FilterConfig; +import im.zhaojun.zfile.module.filter.model.entity.FilterConfig; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/entity/FilterConfig.java b/src/main/java/im/zhaojun/zfile/module/filter/model/entity/FilterConfig.java similarity index 92% rename from src/main/java/im/zhaojun/zfile/admin/model/entity/FilterConfig.java rename to src/main/java/im/zhaojun/zfile/module/filter/model/entity/FilterConfig.java index 7ad50d3..d54d9b0 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/entity/FilterConfig.java +++ b/src/main/java/im/zhaojun/zfile/module/filter/model/entity/FilterConfig.java @@ -1,11 +1,11 @@ -package im.zhaojun.zfile.admin.model.entity; +package im.zhaojun.zfile.module.filter.model.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonIgnore; -import im.zhaojun.zfile.admin.model.enums.FilterConfigHiddenModeEnum; +import im.zhaojun.zfile.module.filter.model.enums.FilterConfigHiddenModeEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/enums/FilterConfigHiddenModeEnum.java b/src/main/java/im/zhaojun/zfile/module/filter/model/enums/FilterConfigHiddenModeEnum.java similarity index 91% rename from src/main/java/im/zhaojun/zfile/admin/model/enums/FilterConfigHiddenModeEnum.java rename to src/main/java/im/zhaojun/zfile/module/filter/model/enums/FilterConfigHiddenModeEnum.java index 8c68648..97d50a1 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/enums/FilterConfigHiddenModeEnum.java +++ b/src/main/java/im/zhaojun/zfile/module/filter/model/enums/FilterConfigHiddenModeEnum.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.enums; +package im.zhaojun.zfile.module.filter.model.enums; import com.baomidou.mybatisplus.annotation.EnumValue; import com.fasterxml.jackson.annotation.JsonValue; diff --git a/src/main/java/im/zhaojun/zfile/module/filter/service/FilterConfigService.java b/src/main/java/im/zhaojun/zfile/module/filter/service/FilterConfigService.java new file mode 100644 index 0000000..da9fb38 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/filter/service/FilterConfigService.java @@ -0,0 +1,229 @@ +package im.zhaojun.zfile.module.filter.service; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.StrUtil; +import im.zhaojun.zfile.core.util.PatternMatcherUtils; +import im.zhaojun.zfile.module.filter.mapper.FilterConfigMapper; +import im.zhaojun.zfile.module.filter.model.entity.FilterConfig; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 存储源过滤规则 Service + * + * @author zhaojun + */ +@Slf4j +@Service +@CacheConfig(cacheNames = "filterConfig") +public class FilterConfigService { + + @Resource + private FilterConfigMapper filterConfigMapper; + + @Resource + private FilterConfigService filterConfigService; + + /** + * 根据存储源 ID 获取存储源配置列表 + * + * @param storageId + * 存储源 ID + * + * @return 存储源过滤规则配置列表 + */ + @Cacheable(key = "'filter-base-' + #storageId") + public List findByStorageId(Integer storageId) { + return filterConfigMapper.findByStorageId(storageId); + } + + + /** + * 获取所有类型为禁止访问的过滤规则 + * + * @param storageId + * 存储 ID + * + * @return 禁止访问的过滤规则列表 + */ + @Cacheable(key = "'filter-inaccessible-' + #storageId") + public List findByStorageIdAndInaccessible(Integer storageId) { + return filterConfigMapper.findByStorageIdAndInaccessible(storageId); + } + + + /** + * 获取所有类型为禁止下载的过滤规则 + * + * @param storageId + * 存储 ID + * + * @return 禁止下载的过滤规则列表 + */ + @Cacheable(key = "'filter-disable-download-' + #storageId") + public List findByStorageIdAndDisableDownload(Integer storageId) { + return filterConfigMapper.findByStorageIdAndDisableDownload(storageId); + } + + + /** + * 批量保存存储源过滤规则配置, 会先删除之前的所有配置(在事务中运行) + * + * @param storageId + * 存储源 ID + * + * @param filterConfigList + * 存储源过滤规则配置列表 + */ + @Transactional(rollbackFor = Exception.class) + public void batchSave(Integer storageId, List filterConfigList) { + filterConfigService.deleteByStorageId(storageId); + log.info("更新存储源 ID 为 {} 的过滤规则 {} 条", storageId, filterConfigList.size()); + + for (FilterConfig filterConfig : filterConfigList) { + filterConfig.setStorageId(storageId); + filterConfigMapper.insert(filterConfig); + + if (log.isDebugEnabled()) { + log.debug("新增过滤规则, 存储源 ID: {}, 表达式: {}, 描述: {}, 隐藏模式: {}", + filterConfig.getStorageId(), filterConfig.getExpression(), + filterConfig.getDescription(), filterConfig.getMode().getValue()); + } + } + } + + + /** + * 根据存储源 ID 删除所有过滤规则配置 + * + * @param storageId + * 存储源 ID + */ + @Caching(evict = { + @CacheEvict(key = "'filter-base-' + #storageId"), + @CacheEvict(key = "'filter-inaccessible-' + #storageId"), + @CacheEvict(key = "'filter-disable-download-' + #storageId") + }) + public int deleteByStorageId(Integer storageId) { + int deleteSize = filterConfigMapper.deleteByStorageId(storageId); + log.info("删除存储源 ID 为 {} 的过滤规则 {} 条", storageId, deleteSize); + return deleteSize; + } + + + /** + * 判断访问的路径是否是不允许访问的 + * + * @param storageId + * 存储源 ID + * + * @param path + * 请求路径 + * + */ + public boolean checkFileIsInaccessible(Integer storageId, String path) { + List filterConfigList = filterConfigService.findByStorageIdAndInaccessible(storageId); + return testPattern(storageId, filterConfigList, path); + } + + + /** + * 指定存储源下的文件名称, 根据过滤表达式判断是否会显示, 如果符合任意一条表达式, 表示隐藏则返回 true, 反之表示不隐藏则返回 false. + * + * @param storageId + * 存储源 ID + * + * @param fileName + * 文件名 + * + * @return 是否是隐藏文件夹 + */ + public boolean checkFileIsHidden(Integer storageId, String fileName) { + List filterConfigList = filterConfigService.findByStorageId(storageId); + return testPattern(storageId, filterConfigList, fileName); + } + + + /** + * 指定存储源下的文件名称, 根据过滤表达式判断文件名和所在路径是否禁止下载, 如果符合任意一条表达式, 则返回 true, 反之则返回 false. + * + * @param storageId + * 存储源 ID + * + * @param fileName + * 文件名 + * + * @return 是否显示 + */ + public boolean checkFileIsDisableDownload(Integer storageId, String fileName) { + List filterConfigList = filterConfigService.findByStorageIdAndDisableDownload(storageId); + String filePath = FileUtil.getParent(fileName, 1); + if (StrUtil.isEmpty(filePath)) { + return testPattern(storageId, filterConfigList, fileName); + } else { + return testPattern(storageId, filterConfigList, fileName) || testPattern(storageId, filterConfigList, filePath); + } + } + + + /** + * 根据规则表达式和测试字符串进行匹配,如测试字符串和其中一个规则匹配上,则返回 true,反之返回 false。 + * + * @param patternList + * 规则列表 + * + * @param test + * + * 测试字符串 + * + * @return 是否显示 + */ + private boolean testPattern(Integer storageId, List patternList, String test) { + // 如果规则列表为空, 则表示不需要过滤, 直接返回 false + if (CollUtil.isEmpty(patternList)) { + if (log.isDebugEnabled()) { + log.debug("过滤规则列表为空, 存储源 ID: {}, 测试字符串: {}", storageId, test); + } + return false; + } + + // 校验表达式 + for (FilterConfig filterConfig : patternList) { + String expression = filterConfig.getExpression(); + + if (StrUtil.isEmpty(expression)) { + if (log.isDebugEnabled()) { + log.debug("存储源 {} 过滤文件测试表达式: {}, 测试字符串: {}, 表达式为空,跳过该规则校验", storageId, expression, test); + } + continue; + } + + try { + boolean match = PatternMatcherUtils.testCompatibilityGlobPattern(expression, test); + + if (log.isDebugEnabled()) { + log.debug("存储源 {} 过滤文件测试表达式: {}, 测试字符串: {}, 匹配结果: {}", storageId, expression, test, match); + } + + if (match) { + return true; + } + } catch (Exception e) { + log.error("存储源 {} 过滤文件测试表达式: {}, 测试字符串: {}, 匹配异常,跳过该规则.", storageId, expression, test, e); + } + } + + return false; + } + + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/aspect/RefererCheckAspect.java b/src/main/java/im/zhaojun/zfile/module/link/aspect/RefererCheckAspect.java similarity index 90% rename from src/main/java/im/zhaojun/zfile/home/aspect/RefererCheckAspect.java rename to src/main/java/im/zhaojun/zfile/module/link/aspect/RefererCheckAspect.java index b4049b4..94c41c0 100644 --- a/src/main/java/im/zhaojun/zfile/home/aspect/RefererCheckAspect.java +++ b/src/main/java/im/zhaojun/zfile/module/link/aspect/RefererCheckAspect.java @@ -1,11 +1,11 @@ -package im.zhaojun.zfile.home.aspect; +package im.zhaojun.zfile.module.link.aspect; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; -import im.zhaojun.zfile.admin.annotation.RefererCheck; -import im.zhaojun.zfile.admin.model.enums.RefererTypeEnum; -import im.zhaojun.zfile.admin.service.SystemConfigService; -import im.zhaojun.zfile.home.model.dto.SystemConfigDTO; +import im.zhaojun.zfile.module.storage.annotation.RefererCheck; +import im.zhaojun.zfile.module.link.model.enums.RefererTypeEnum; +import im.zhaojun.zfile.module.config.service.SystemConfigService; +import im.zhaojun.zfile.module.config.model.dto.SystemConfigDTO; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; @@ -51,7 +51,7 @@ public class RefererCheckAspect { * * @return 方法运行结果 */ - @Around(value = "@annotation(im.zhaojun.zfile.admin.annotation.RefererCheck)") + @Around(value = "@annotation(im.zhaojun.zfile.module.storage.annotation.RefererCheck)") public Object around(ProceedingJoinPoint point) throws Throwable { // 获取配置的 referer 类型 SystemConfigDTO systemConfig = systemConfigService.getSystemConfig(); diff --git a/src/main/java/im/zhaojun/zfile/home/controller/ShortLinkController.java b/src/main/java/im/zhaojun/zfile/module/link/controller/ShortLinkController.java similarity index 63% rename from src/main/java/im/zhaojun/zfile/home/controller/ShortLinkController.java rename to src/main/java/im/zhaojun/zfile/module/link/controller/ShortLinkController.java index a0b723b..ec6c366 100644 --- a/src/main/java/im/zhaojun/zfile/home/controller/ShortLinkController.java +++ b/src/main/java/im/zhaojun/zfile/module/link/controller/ShortLinkController.java @@ -1,24 +1,22 @@ -package im.zhaojun.zfile.home.controller; +package im.zhaojun.zfile.module.link.controller; import cn.hutool.core.util.BooleanUtil; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiSort; -import com.github.xiaoymin.knife4j.annotations.DynamicParameter; -import com.github.xiaoymin.knife4j.annotations.DynamicResponseParameters; -import im.zhaojun.zfile.admin.model.entity.ShortLink; -import im.zhaojun.zfile.admin.model.entity.StorageSource; -import im.zhaojun.zfile.admin.service.ShortLinkService; -import im.zhaojun.zfile.admin.service.StorageSourceService; -import im.zhaojun.zfile.admin.service.SystemConfigService; -import im.zhaojun.zfile.common.exception.IllegalDownloadLinkException; -import im.zhaojun.zfile.common.util.AjaxJson; -import im.zhaojun.zfile.common.util.StringUtils; -import im.zhaojun.zfile.home.model.dto.SystemConfigDTO; -import im.zhaojun.zfile.home.model.request.BatchGenerateLinkRequest; -import im.zhaojun.zfile.home.model.result.BatchGenerateLinkResponse; +import im.zhaojun.zfile.core.exception.IllegalDownloadLinkException; +import im.zhaojun.zfile.core.exception.InvalidShortLinkException; +import im.zhaojun.zfile.core.util.AjaxJson; +import im.zhaojun.zfile.core.util.StringUtils; +import im.zhaojun.zfile.module.config.model.dto.SystemConfigDTO; +import im.zhaojun.zfile.module.config.service.SystemConfigService; +import im.zhaojun.zfile.module.link.model.entity.ShortLink; +import im.zhaojun.zfile.module.link.model.request.BatchGenerateLinkRequest; +import im.zhaojun.zfile.module.link.model.result.BatchGenerateLinkResponse; +import im.zhaojun.zfile.module.link.service.ShortLinkService; +import im.zhaojun.zfile.module.storage.model.entity.StorageSource; +import im.zhaojun.zfile.module.storage.service.StorageSourceService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; @@ -60,43 +58,34 @@ public class ShortLinkController { @ResponseBody @ApiOperationSupport(order = 1) @ApiOperation(value = "生成短链", notes = "对指定存储源的某文件路径生成短链") - @ApiImplicitParams({ - @ApiImplicitParam(paramType = "query", name = "storageKey", value = "存储源 id", required = true), - @ApiImplicitParam(paramType = "query", name = "path", value = "文件路径", required = true) - }) - @DynamicResponseParameters(name = "AjaxJson",properties = { - @DynamicParameter(name = "msg", value = "响应消息", example = "ok"), - @DynamicParameter(name = "code", value = "业务状态码,0 为正常,其他值均为异常,异常情况下见响应消息", example = "0"), - @DynamicParameter(name = "data", value = "短链地址", example = "https://zfile.vip/s/btz4tu") - }) public AjaxJson> generatorShortLink(@RequestBody @Valid BatchGenerateLinkRequest batchGenerateLinkRequest) { List result = new ArrayList<>(); // 获取站点域名 SystemConfigDTO systemConfig = systemConfigService.getSystemConfig(); - + // 是否允许使用短链和短链,如果都不允许,则提示禁止生成. Boolean showShortLink = systemConfig.getShowShortLink(); Boolean showPathLink = systemConfig.getShowPathLink(); if ( BooleanUtil.isFalse(showShortLink) && BooleanUtil.isFalse(showPathLink)) { throw new IllegalDownloadLinkException("当前系统不允许使用直链和短链."); } - + String domain = systemConfig.getDomain(); String storageKey = batchGenerateLinkRequest.getStorageKey(); + Integer storageId = storageSourceService.findIdByKey(storageKey); + for (String path : batchGenerateLinkRequest.getPaths()) { // 拼接全路径地址. - String fullPath = StringUtils.concat(path); + String fullPath = StringUtils.concat(path); - // 生成短链 - ShortLink shortLink = shortLinkService.findByStorageKeyAndUrl(storageKey, fullPath); - // 如果没有短链,则生成短链 - if (shortLink == null) { - Integer storageId = storageSourceService.findIdByKey(storageKey); - shortLink = shortLinkService.generatorShortLink(storageId, fullPath); - } - - String shortUrl = StringUtils.removeDuplicateSlashes(domain + "/s/" + shortLink.getShortKey()); + // 如果没有短链,则生成短链 + ShortLink shortLink = shortLinkService.findByStorageIdAndUrl(storageId, fullPath); + if (shortLink == null) { + shortLink = shortLinkService.generatorShortLink(storageId, fullPath); + } + + String shortUrl = StringUtils.removeDuplicateSlashes(domain + "/s/" + shortLink.getShortKey()); String pathLink = StringUtils.generatorPathLink(storageKey, fullPath); result.add(new BatchGenerateLinkResponse(shortUrl, pathLink)); @@ -109,11 +98,11 @@ public class ShortLinkController { @ResponseStatus(HttpStatus.FOUND) @ApiOperationSupport(order = 2) @ApiOperation(value = "跳转短链", notes = "根据短链 key 跳转(302 重定向)到对应的直链.") - @ApiImplicitParam(paramType = "path", name = "key", value = "短链 key", required = true) + @ApiImplicitParam(paramType = "path", name = "key", value = "短链 key", required = true, dataTypeClass = String.class) public String parseShortKey(@PathVariable String key) throws IOException { ShortLink shortLink = shortLinkService.findByKey(key); if (shortLink == null) { - throw new RuntimeException("此直链不存在或已失效."); + throw new InvalidShortLinkException("此直链不存在或已失效."); } // 获取站点域名 diff --git a/src/main/java/im/zhaojun/zfile/module/link/controller/ShortLinkManagerController.java b/src/main/java/im/zhaojun/zfile/module/link/controller/ShortLinkManagerController.java new file mode 100644 index 0000000..89ed12f --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/link/controller/ShortLinkManagerController.java @@ -0,0 +1,132 @@ +package im.zhaojun.zfile.module.link.controller; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.OrderItem; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; +import com.github.xiaoymin.knife4j.annotations.ApiSort; +import im.zhaojun.zfile.core.util.AjaxJson; +import im.zhaojun.zfile.module.link.convert.ShortLinkConvert; +import im.zhaojun.zfile.module.link.model.entity.ShortLink; +import im.zhaojun.zfile.module.link.model.request.BatchDeleteRequest; +import im.zhaojun.zfile.module.link.model.request.QueryShortLinkLogRequest; +import im.zhaojun.zfile.module.link.model.request.ShortLinkResult; +import im.zhaojun.zfile.module.link.service.ShortLinkService; +import im.zhaojun.zfile.module.storage.model.entity.StorageSource; +import im.zhaojun.zfile.module.storage.service.StorageSourceService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Stream; + +/** + * 直链管理接口 + * + * @author zhaojun + */ +@Api(tags = "直链管理") +@ApiSort(7) +@Controller +@RequestMapping("/admin") +public class ShortLinkManagerController { + + @Resource + private ShortLinkService shortLinkService; + + @Resource + private StorageSourceService storageSourceService; + + @Resource + private ShortLinkConvert shortLinkConvert; + + @Value("${spring.datasource.driver-class-name}") + private String datasourceDriveClassName; + + @ApiOperationSupport(order = 1) + @GetMapping("/link/list") + @ApiOperation(value = "搜索短链") + @ResponseBody + public AjaxJson list(QueryShortLinkLogRequest queryObj) { + // 分页和排序 + boolean asc = Objects.equals(queryObj.getOrderDirection(), "asc"); + Page pages = new Page(queryObj.getPage(), queryObj.getLimit()) + .addOrder(new OrderItem(queryObj.getOrderBy(), asc)); + + + String dateFrom = queryObj.getDateFrom(); + String dateTo = queryObj.getDateTo(); + + boolean isSqlite = StrUtil.equals(datasourceDriveClassName, "org.sqlite.JDBC"); + if (isSqlite) { + if (StrUtil.isNotEmpty(queryObj.getDateFrom())) { + dateFrom = Convert.toStr(DateUtil.parseDateTime(dateFrom).getTime()); + } + if (StrUtil.isNotEmpty(queryObj.getDateTo())) { + dateTo = Convert.toStr(DateUtil.parseDateTime(dateTo).getTime()); + } + } + + // 搜索条件 + QueryWrapper queryWrapper = + new QueryWrapper<>(new ShortLink()) + .eq(StrUtil.isNotEmpty(queryObj.getStorageId()), "storage_id", queryObj.getStorageId()) + .like(StrUtil.isNotEmpty(queryObj.getKey()), "short_key", queryObj.getKey()) + .like(StrUtil.isNotEmpty(queryObj.getUrl()), "url", queryObj.getUrl()) + .ge(StrUtil.isNotEmpty(queryObj.getDateFrom()), "create_date", dateFrom) + .le(StrUtil.isNotEmpty(queryObj.getDateTo()), "create_date", dateTo); + + // 执行查询 + Page selectResult = shortLinkService.selectPage(pages, queryWrapper); + + // 转换为结果集 + Map cache = new HashMap<>(); + Stream shortLinkResultList = selectResult.getRecords().stream().map(shortLink -> { + Integer shortLinkStorageId = shortLink.getStorageId(); + + StorageSource storageSource = cache.getOrDefault(shortLinkStorageId, storageSourceService.findById(shortLinkStorageId)); + cache.put(shortLinkStorageId, storageSource); + + return shortLinkConvert.entityToResultList(shortLink, storageSource); + }); + return AjaxJson.getPageData(selectResult.getTotal(), shortLinkResultList); + } + + + @ApiOperationSupport(order = 2) + @DeleteMapping("/link/delete/{id}") + @ApiOperation(value = "删除短链") + @ApiImplicitParam(paramType = "path", name = "id", value = "短链 id", required = true, dataTypeClass = Integer.class) + @ResponseBody + public AjaxJson deleteById(@PathVariable Integer id) { + shortLinkService.removeById(id); + return AjaxJson.getSuccess(); + } + + + @ApiOperationSupport(order = 3) + @PostMapping("/link/delete/batch") + @ResponseBody + @ApiOperation(value = "批量删除短链") + public AjaxJson batchDelete(@RequestBody BatchDeleteRequest batchDeleteRequest) { + shortLinkService.removeBatchByIds(batchDeleteRequest.getIds()); + return AjaxJson.getSuccess(); + } + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/convert/ShortLinkConvert.java b/src/main/java/im/zhaojun/zfile/module/link/convert/ShortLinkConvert.java similarity index 68% rename from src/main/java/im/zhaojun/zfile/admin/convert/ShortLinkConvert.java rename to src/main/java/im/zhaojun/zfile/module/link/convert/ShortLinkConvert.java index 65abf39..d0b8ec2 100644 --- a/src/main/java/im/zhaojun/zfile/admin/convert/ShortLinkConvert.java +++ b/src/main/java/im/zhaojun/zfile/module/link/convert/ShortLinkConvert.java @@ -1,8 +1,8 @@ -package im.zhaojun.zfile.admin.convert; +package im.zhaojun.zfile.module.link.convert; -import im.zhaojun.zfile.admin.model.entity.ShortLink; -import im.zhaojun.zfile.admin.model.entity.StorageSource; -import im.zhaojun.zfile.admin.model.result.link.ShortLinkResult; +import im.zhaojun.zfile.module.link.model.entity.ShortLink; +import im.zhaojun.zfile.module.storage.model.entity.StorageSource; +import im.zhaojun.zfile.module.link.model.request.ShortLinkResult; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.springframework.stereotype.Component; diff --git a/src/main/java/im/zhaojun/zfile/admin/mapper/ShortLinkMapper.java b/src/main/java/im/zhaojun/zfile/module/link/mapper/ShortLinkMapper.java similarity index 75% rename from src/main/java/im/zhaojun/zfile/admin/mapper/ShortLinkMapper.java rename to src/main/java/im/zhaojun/zfile/module/link/mapper/ShortLinkMapper.java index a8fc82c..cd01847 100644 --- a/src/main/java/im/zhaojun/zfile/admin/mapper/ShortLinkMapper.java +++ b/src/main/java/im/zhaojun/zfile/module/link/mapper/ShortLinkMapper.java @@ -1,7 +1,7 @@ -package im.zhaojun.zfile.admin.mapper; +package im.zhaojun.zfile.module.link.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import im.zhaojun.zfile.admin.model.entity.ShortLink; +import im.zhaojun.zfile.module.link.model.entity.ShortLink; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -36,6 +36,14 @@ public interface ShortLinkMapper extends BaseMapper { * @return 短链接信息 */ ShortLink findByStorageIdAndUrl(@Param("storageId") Integer storageId, @Param("url") String url); - - + + + /** + * 根据存储源 ID 删除所有数据 + * + * @param storageId + * 存储源 ID + */ + int deleteByStorageId(@Param("storageId") Integer storageId); + } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/model/entity/ShortLink.java b/src/main/java/im/zhaojun/zfile/module/link/model/entity/ShortLink.java similarity index 94% rename from src/main/java/im/zhaojun/zfile/admin/model/entity/ShortLink.java rename to src/main/java/im/zhaojun/zfile/module/link/model/entity/ShortLink.java index 3229f89..1ce5b52 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/entity/ShortLink.java +++ b/src/main/java/im/zhaojun/zfile/module/link/model/entity/ShortLink.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.entity; +package im.zhaojun.zfile.module.link.model.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; @@ -13,6 +13,8 @@ import java.util.Date; /** * 短链信息 entity + * + * @author zhaojun */ @Data @ApiModel(description = "短链信息") diff --git a/src/main/java/im/zhaojun/zfile/admin/model/enums/RefererTypeEnum.java b/src/main/java/im/zhaojun/zfile/module/link/model/enums/RefererTypeEnum.java similarity index 91% rename from src/main/java/im/zhaojun/zfile/admin/model/enums/RefererTypeEnum.java rename to src/main/java/im/zhaojun/zfile/module/link/model/enums/RefererTypeEnum.java index 4829218..f4b77d0 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/enums/RefererTypeEnum.java +++ b/src/main/java/im/zhaojun/zfile/module/link/model/enums/RefererTypeEnum.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.enums; +package im.zhaojun.zfile.module.link.model.enums; import com.baomidou.mybatisplus.annotation.EnumValue; import com.fasterxml.jackson.annotation.JsonValue; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/request/link/BatchDeleteRequest.java b/src/main/java/im/zhaojun/zfile/module/link/model/request/BatchDeleteRequest.java similarity index 73% rename from src/main/java/im/zhaojun/zfile/admin/model/request/link/BatchDeleteRequest.java rename to src/main/java/im/zhaojun/zfile/module/link/model/request/BatchDeleteRequest.java index e3d721b..0f23dd7 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/request/link/BatchDeleteRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/link/model/request/BatchDeleteRequest.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.request.link; +package im.zhaojun.zfile.module.link.model.request; import lombok.Data; diff --git a/src/main/java/im/zhaojun/zfile/home/model/request/BatchGenerateLinkRequest.java b/src/main/java/im/zhaojun/zfile/module/link/model/request/BatchGenerateLinkRequest.java similarity index 90% rename from src/main/java/im/zhaojun/zfile/home/model/request/BatchGenerateLinkRequest.java rename to src/main/java/im/zhaojun/zfile/module/link/model/request/BatchGenerateLinkRequest.java index ada929b..c3f6263 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/request/BatchGenerateLinkRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/link/model/request/BatchGenerateLinkRequest.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.home.model.request; +package im.zhaojun.zfile.module.link.model.request; import io.swagger.annotations.ApiModel; import lombok.Data; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/request/link/QueryDownloadLogRequest.java b/src/main/java/im/zhaojun/zfile/module/link/model/request/QueryDownloadLogRequest.java similarity index 67% rename from src/main/java/im/zhaojun/zfile/admin/model/request/link/QueryDownloadLogRequest.java rename to src/main/java/im/zhaojun/zfile/module/link/model/request/QueryDownloadLogRequest.java index d51155a..95330df 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/request/link/QueryDownloadLogRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/link/model/request/QueryDownloadLogRequest.java @@ -1,9 +1,9 @@ -package im.zhaojun.zfile.admin.model.request.link; +package im.zhaojun.zfile.module.link.model.request; +import im.zhaojun.zfile.core.model.request.PageQueryRequest; import io.swagger.annotations.ApiModelProperty; import lombok.Data; - -import javax.validation.constraints.NotEmpty; +import lombok.EqualsAndHashCode; /** * 查询下载日志请求参数 @@ -11,7 +11,8 @@ import javax.validation.constraints.NotEmpty; * @author zhaojun */ @Data -public class QueryDownloadLogRequest { +@EqualsAndHashCode(callSuper = true) +public class QueryDownloadLogRequest extends PageQueryRequest { @ApiModelProperty(value="文件路径") private String path; @@ -36,11 +37,8 @@ public class QueryDownloadLogRequest { @ApiModelProperty(value="访问 referer") private String referer; - - @NotEmpty(message = "分页页数不能为空") - private Integer page; - - @NotEmpty(message = "每页条数不能为空") - private Integer limit; - + + @ApiModelProperty(value="排序字段") + private String orderBy = "create_time"; + } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/module/link/model/request/QueryShortLinkLogRequest.java b/src/main/java/im/zhaojun/zfile/module/link/model/request/QueryShortLinkLogRequest.java new file mode 100644 index 0000000..21462bf --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/link/model/request/QueryShortLinkLogRequest.java @@ -0,0 +1,30 @@ +package im.zhaojun.zfile.module.link.model.request; + +import im.zhaojun.zfile.core.model.request.PageQueryRequest; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author zhaojun + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class QueryShortLinkLogRequest extends PageQueryRequest { + + @ApiModelProperty(value="短链 key") + private String key; + + @ApiModelProperty(value="存储源 id") + private String storageId; + + @ApiModelProperty(value="短链文件路径") + private String url; + + @ApiModelProperty(value="访问时间从") + private String dateFrom; + + @ApiModelProperty(value="访问时间至") + private String dateTo; + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/model/result/link/ShortLinkResult.java b/src/main/java/im/zhaojun/zfile/module/link/model/request/ShortLinkResult.java similarity index 86% rename from src/main/java/im/zhaojun/zfile/admin/model/result/link/ShortLinkResult.java rename to src/main/java/im/zhaojun/zfile/module/link/model/request/ShortLinkResult.java index 37fd773..e9e8e7c 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/result/link/ShortLinkResult.java +++ b/src/main/java/im/zhaojun/zfile/module/link/model/request/ShortLinkResult.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.admin.model.result.link; +package im.zhaojun.zfile.module.link.model.request; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; import io.swagger.annotations.ApiModelProperty; import lombok.Data; diff --git a/src/main/java/im/zhaojun/zfile/home/model/request/ShortLinkSearchRequest.java b/src/main/java/im/zhaojun/zfile/module/link/model/request/ShortLinkSearchRequest.java similarity index 96% rename from src/main/java/im/zhaojun/zfile/home/model/request/ShortLinkSearchRequest.java rename to src/main/java/im/zhaojun/zfile/module/link/model/request/ShortLinkSearchRequest.java index d6e8088..ab88612 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/request/ShortLinkSearchRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/link/model/request/ShortLinkSearchRequest.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.home.model.request; +package im.zhaojun.zfile.module.link.model.request; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; diff --git a/src/main/java/im/zhaojun/zfile/home/model/result/BatchGenerateLinkResponse.java b/src/main/java/im/zhaojun/zfile/module/link/model/result/BatchGenerateLinkResponse.java similarity index 85% rename from src/main/java/im/zhaojun/zfile/home/model/result/BatchGenerateLinkResponse.java rename to src/main/java/im/zhaojun/zfile/module/link/model/result/BatchGenerateLinkResponse.java index d75c726..0f1baa2 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/result/BatchGenerateLinkResponse.java +++ b/src/main/java/im/zhaojun/zfile/module/link/model/result/BatchGenerateLinkResponse.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.home.model.result; +package im.zhaojun.zfile.module.link.model.result; import io.swagger.annotations.ApiModel; import lombok.AllArgsConstructor; diff --git a/src/main/java/im/zhaojun/zfile/admin/service/ShortLinkService.java b/src/main/java/im/zhaojun/zfile/module/link/service/ShortLinkService.java similarity index 58% rename from src/main/java/im/zhaojun/zfile/admin/service/ShortLinkService.java rename to src/main/java/im/zhaojun/zfile/module/link/service/ShortLinkService.java index 0454330..f9301e6 100644 --- a/src/main/java/im/zhaojun/zfile/admin/service/ShortLinkService.java +++ b/src/main/java/im/zhaojun/zfile/module/link/service/ShortLinkService.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.service; +package im.zhaojun.zfile.module.link.service; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IoUtil; @@ -6,28 +6,37 @@ import cn.hutool.core.util.BooleanUtil; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.extension.service.IService; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import im.zhaojun.zfile.admin.mapper.ShortLinkMapper; -import im.zhaojun.zfile.admin.model.entity.DownloadLog; -import im.zhaojun.zfile.admin.model.entity.ShortLink; -import im.zhaojun.zfile.common.context.StorageSourceContext; -import im.zhaojun.zfile.common.exception.InvalidStorageSourceException; -import im.zhaojun.zfile.common.exception.file.operator.DownloadFileException; -import im.zhaojun.zfile.common.util.HttpUtil; -import im.zhaojun.zfile.common.util.RequestHolder; -import im.zhaojun.zfile.home.model.dto.SystemConfigDTO; -import im.zhaojun.zfile.home.service.base.AbstractBaseFileService; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import im.zhaojun.zfile.module.storage.context.StorageSourceContext; +import im.zhaojun.zfile.core.exception.file.InvalidStorageSourceException; +import im.zhaojun.zfile.core.exception.file.operator.StorageSourceFileOperatorException; +import im.zhaojun.zfile.core.util.HttpUtil; +import im.zhaojun.zfile.core.util.RequestHolder; +import im.zhaojun.zfile.core.util.UrlUtils; +import im.zhaojun.zfile.module.config.model.dto.SystemConfigDTO; +import im.zhaojun.zfile.module.config.service.SystemConfigService; +import im.zhaojun.zfile.module.link.mapper.ShortLinkMapper; +import im.zhaojun.zfile.module.link.model.entity.ShortLink; +import im.zhaojun.zfile.module.log.model.entity.DownloadLog; +import im.zhaojun.zfile.module.log.service.DownloadLogService; +import im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService; import lombok.extern.slf4j.Slf4j; import org.apache.http.util.EncodingUtils; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.OutputStream; import java.util.Date; +import java.util.List; /** * 短链 Service @@ -36,13 +45,14 @@ import java.util.Date; */ @Service @Slf4j -public class ShortLinkService extends ServiceImpl implements IService { +@CacheConfig(cacheNames = "shortLink") +public class ShortLinkService { @Resource private ShortLinkMapper shortLinkMapper; - + @Resource - private StorageSourceService storageSourceService; + private ShortLinkService shortLinkService; @Resource private StorageSourceContext storageSourceContext; @@ -61,54 +71,26 @@ public class ShortLinkService extends ServiceImpl im * * @return 短链接信息 */ + @Cacheable(key = "#key", unless = "#result == null") public ShortLink findByKey(String key) { return shortLinkMapper.findByKey(key); } - /** - * 根据短链接 id 查询短链接 - * - * @param id - * 短链接 id - * - * @return 短链接信息 - */ - public ShortLink findById(Integer id) { - return shortLinkMapper.selectById(id); - } - - /** * 根据存储源 ID 和文件路径查询短链接 * * @param storageId * 存储源 ID * - * @param url - * 短链接 url + * @param fileFullPath + * 文件全路径 * * @return 短链接信息 */ - public ShortLink findByStorageIdAndUrl(Integer storageId, String url) { - return shortLinkMapper.findByStorageIdAndUrl(storageId, url); - } - - - /** - * 根据存储源 KEY 和文件路径查询短链接 - * - * @param storageKey - * 存储源 KEY - * - * @param url - * 短链接 url - * - * @return 短链接信息 - */ - public ShortLink findByStorageKeyAndUrl(String storageKey,String url) { - Integer storageId = storageSourceService.findIdByKey(storageKey); - return findByStorageIdAndUrl(storageId, url); + @Cacheable(key = "#storageId + #fileFullPath", unless = "#result == null") + public ShortLink findByStorageIdAndUrl(Integer storageId, String fileFullPath) { + return shortLinkMapper.findByStorageIdAndUrl(storageId, fileFullPath); } @@ -126,19 +108,26 @@ public class ShortLinkService extends ServiceImpl im public ShortLink generatorShortLink(Integer storageId, String fullPath) { ShortLink shortLink; String randomKey; + int generateCount = 0; do { // 获取短链 randomKey = RandomUtil.randomString(6); - shortLink = findByKey(randomKey); + shortLink = shortLinkService.findByKey(randomKey); + generateCount++; } while (shortLink != null); shortLink = new ShortLink(); - shortLink.setShortKey(randomKey); + shortLink.setStorageId(storageId); shortLink.setUrl(fullPath); shortLink.setCreateDate(new Date()); - shortLink.setStorageId(storageId); - save(shortLink); - + shortLink.setShortKey(randomKey); + + if (log.isDebugEnabled()) { + log.debug("生成直/短链: 存储源 ID: {}, 文件路径: {}, 短链 key {}, 随机生成直链冲突次数: {}", + shortLink.getStorageId(), shortLink.getUrl(), shortLink.getShortKey(), generateCount); + } + + shortLinkMapper.insert(shortLink); return shortLink; } @@ -158,14 +147,15 @@ public class ShortLinkService extends ServiceImpl im * @throws IOException 可能抛出的 IO 异常 */ public void handlerDownload(String storageKey, String filePath, String shortKey) throws IOException { + HttpServletRequest request = RequestHolder.getRequest(); HttpServletResponse response = RequestHolder.getResponse(); // 获取存储源 Service AbstractBaseFileService fileService; try { - fileService = storageSourceContext.getByKey(storageKey); + fileService = storageSourceContext.getByStorageKey(storageKey); } catch (InvalidStorageSourceException e) { - log.error("无效的存储源,存储源 key {}, 文件路径 {}", storageKey, filePath); + log.error("无效的存储源,存储源 ID: {}, 文件路径: {}", e.getStorageId(), filePath, e); response.setHeader(HttpHeaders.CONTENT_TYPE, "text/plain;charset=utf-8"); response.getWriter().write("无效的或初始化失败的存储源, 请联系管理员!"); return; @@ -175,8 +165,8 @@ public class ShortLinkService extends ServiceImpl im String downloadUrl; try { downloadUrl = fileService.getDownloadUrl(filePath); - } catch (DownloadFileException e) { - log.error("获取文件下载链接异常 {}. 存储源 ID: {}, 文件路径: {}", e.getMessage(), e.getStorageId(), e.getPathAndName()); + } catch (StorageSourceFileOperatorException e) { + log.error("获取文件下载链接异常. 存储源 ID: {}, 文件路径: {}", e.getStorageId(), filePath, e); response.setHeader(HttpHeaders.CONTENT_TYPE, "text/plain;charset=utf-8"); response.getWriter().write("获取下载链接异常,请联系管理员!"); return; @@ -213,7 +203,39 @@ public class ShortLinkService extends ServiceImpl im response.setHeader(HttpHeaders.EXPIRES, "0"); // 重定向到下载链接. + + String parameterType = request.getParameter("type"); + if (StrUtil.equals(parameterType, "preview")) { + downloadUrl = UrlUtils.concatQueryParam(downloadUrl, "type", "preview"); + } + response.sendRedirect(downloadUrl); } - + + + @CacheEvict(allEntries = true) + public void removeById(Integer id) { + log.info("删除 id 为 {} 的直/短链", id); + shortLinkMapper.deleteById(id); + } + + @Transactional(rollbackFor = Exception.class) + @CacheEvict(allEntries = true) + public void removeBatchByIds(List ids) { + log.info("批量删除直/短链,id 集合为 {}", ids); + shortLinkMapper.deleteBatchIds(ids); + } + + @CacheEvict(allEntries = true) + public int deleteByStorageId(Integer storageId) { + int deleteSize = shortLinkMapper.deleteByStorageId(storageId); + log.info("删除存储源 ID 为 {} 的直/短链 {} 条", storageId, deleteSize); + return deleteSize; + } + + public Page selectPage(Page pages, QueryWrapper queryWrapper) { + return shortLinkMapper.selectPage(pages, queryWrapper); + } + + } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/module/log/controller/DownloadLogManagerController.java b/src/main/java/im/zhaojun/zfile/module/log/controller/DownloadLogManagerController.java new file mode 100644 index 0000000..9494c1d --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/log/controller/DownloadLogManagerController.java @@ -0,0 +1,116 @@ +package im.zhaojun.zfile.module.log.controller; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.OrderItem; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; +import com.github.xiaoymin.knife4j.annotations.ApiSort; +import im.zhaojun.zfile.core.util.AjaxJson; +import im.zhaojun.zfile.module.link.model.request.BatchDeleteRequest; +import im.zhaojun.zfile.module.link.model.request.QueryDownloadLogRequest; +import im.zhaojun.zfile.module.log.convert.DownloadLogConvert; +import im.zhaojun.zfile.module.log.model.entity.DownloadLog; +import im.zhaojun.zfile.module.log.model.result.DownloadLogResult; +import im.zhaojun.zfile.module.log.service.DownloadLogService; +import im.zhaojun.zfile.module.storage.model.entity.StorageSource; +import im.zhaojun.zfile.module.storage.service.StorageSourceService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Stream; + +/** + * 直链下载日志接口 + * + * @author zhaojun + */ +@Api(tags = "直链日志管理") +@ApiSort(7) +@Controller +@RequestMapping("/admin/download/log") +public class DownloadLogManagerController { + + @Resource + private StorageSourceService storageSourceService; + + @Resource + private DownloadLogConvert downloadLogConvert; + + @Resource + private DownloadLogService downloadLogService; + + @ApiOperationSupport(order = 1) + @GetMapping("/list") + @ApiOperation(value = "直链下载日志") + @ResponseBody + public AjaxJson list(QueryDownloadLogRequest queryDownloadLogRequest) { + // 分页和排序 + boolean asc = Objects.equals(queryDownloadLogRequest.getOrderDirection(), "asc"); + Page pages = new Page(queryDownloadLogRequest.getPage(), queryDownloadLogRequest.getLimit()) + .addOrder(new OrderItem(queryDownloadLogRequest.getOrderBy(), asc)); + + DownloadLog downloadLog = new DownloadLog(); + QueryWrapper queryWrapper = + new QueryWrapper<>(downloadLog) + .eq(StrUtil.isNotEmpty(queryDownloadLogRequest.getStorageKey()), "storage_key", queryDownloadLogRequest.getStorageKey()) + .like(StrUtil.isNotEmpty(queryDownloadLogRequest.getPath()), "path", queryDownloadLogRequest.getPath()) + .like(StrUtil.isNotEmpty(queryDownloadLogRequest.getShortKey()), "short_key", queryDownloadLogRequest.getShortKey()) + .like(StrUtil.isNotEmpty(queryDownloadLogRequest.getIp()), "ip", queryDownloadLogRequest.getIp()) + .like(StrUtil.isNotEmpty(queryDownloadLogRequest.getReferer()), "referer", queryDownloadLogRequest.getReferer()) + .like(StrUtil.isNotEmpty(queryDownloadLogRequest.getUserAgent()), "user_agent", queryDownloadLogRequest.getUserAgent()) + .ge(StrUtil.isNotEmpty(queryDownloadLogRequest.getDateFrom()), "create_time", queryDownloadLogRequest.getDateFrom()) + .le(StrUtil.isNotEmpty(queryDownloadLogRequest.getDateTo()), "create_time", queryDownloadLogRequest.getDateTo()); + + Page selectResult = downloadLogService.selectPage(pages, queryWrapper); + + Map cache = new HashMap<>(); + + Stream shortLinkResultList = selectResult.getRecords().stream().map(model -> { + String storageKey = model.getStorageKey(); + + StorageSource storageSource = cache.getOrDefault(storageKey, storageSourceService.findByStorageKey(storageKey)); + cache.put(storageKey, storageSource); + + return downloadLogConvert.entityToResultList(model, storageSource); + }); + return AjaxJson.getPageData(selectResult.getTotal(), shortLinkResultList); + } + + + @ApiOperationSupport(order = 2) + @DeleteMapping("/delete/{id}") + @ApiOperation(value = "删除直链") + @ApiImplicitParam(paramType = "path", name = "id", value = "直链 id", required = true, dataTypeClass = Integer.class) + @ResponseBody + public AjaxJson deleteById(@PathVariable Integer id) { + downloadLogService.removeById(id); + return AjaxJson.getSuccess(); + } + + + @ApiOperationSupport(order = 3) + @PostMapping("/delete/batch") + @ResponseBody + @ApiOperation(value = "批量删除直链") + public AjaxJson batchDelete(@RequestBody BatchDeleteRequest batchDeleteRequest) { + List ids = batchDeleteRequest.getIds(); + downloadLogService.removeBatchByIds(ids); + return AjaxJson.getSuccess(); + } + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/convert/DownloadLogConvert.java b/src/main/java/im/zhaojun/zfile/module/log/convert/DownloadLogConvert.java similarity index 69% rename from src/main/java/im/zhaojun/zfile/admin/convert/DownloadLogConvert.java rename to src/main/java/im/zhaojun/zfile/module/log/convert/DownloadLogConvert.java index de2d4cd..ed2e181 100644 --- a/src/main/java/im/zhaojun/zfile/admin/convert/DownloadLogConvert.java +++ b/src/main/java/im/zhaojun/zfile/module/log/convert/DownloadLogConvert.java @@ -1,8 +1,8 @@ -package im.zhaojun.zfile.admin.convert; +package im.zhaojun.zfile.module.log.convert; -import im.zhaojun.zfile.admin.model.entity.DownloadLog; -import im.zhaojun.zfile.admin.model.entity.StorageSource; -import im.zhaojun.zfile.admin.model.result.link.DownloadLogResult; +import im.zhaojun.zfile.module.log.model.entity.DownloadLog; +import im.zhaojun.zfile.module.storage.model.entity.StorageSource; +import im.zhaojun.zfile.module.log.model.result.DownloadLogResult; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.springframework.stereotype.Component; diff --git a/src/main/java/im/zhaojun/zfile/module/log/mapper/DownloadLogMapper.java b/src/main/java/im/zhaojun/zfile/module/log/mapper/DownloadLogMapper.java new file mode 100644 index 0000000..a28e23e --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/log/mapper/DownloadLogMapper.java @@ -0,0 +1,23 @@ +package im.zhaojun.zfile.module.log.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import im.zhaojun.zfile.module.log.model.entity.DownloadLog; +import org.apache.ibatis.annotations.Mapper; + +/** + * 下载日志 Mapper 接口 + * + * @author zhaojun + */ +@Mapper +public interface DownloadLogMapper extends BaseMapper { + + /** + * 根据存储源 KEY 删除所有数据 + * + * @param storageKey + * 存储源 KEY + */ + int deleteByStorageKey(String storageKey); + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/module/log/model/dto/DownloadTopFileDTO.java b/src/main/java/im/zhaojun/zfile/module/log/model/dto/DownloadTopFileDTO.java new file mode 100644 index 0000000..fd8ee90 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/log/model/dto/DownloadTopFileDTO.java @@ -0,0 +1,26 @@ +package im.zhaojun.zfile.module.log.model.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 下载文件 排行 dto 类 + * + * @author zhaojun + */ +@Data +public class DownloadTopFileDTO { + + @ApiModelProperty(value = "短链 key") + private String shortKey; + + @ApiModelProperty(value = "存储源 key") + private String storageKey; + + @ApiModelProperty(value = "文件路径") + private String path; + + @ApiModelProperty(value = "下载次数") + private Integer count; + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/module/log/model/dto/DownloadTopIpDTO.java b/src/main/java/im/zhaojun/zfile/module/log/model/dto/DownloadTopIpDTO.java new file mode 100644 index 0000000..2f996b9 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/log/model/dto/DownloadTopIpDTO.java @@ -0,0 +1,19 @@ +package im.zhaojun.zfile.module.log.model.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 下载 ip 排行 dto 类 + * @author zhaojun + */ +@Data +public class DownloadTopIpDTO { + + @ApiModelProperty(value = "ip 地址") + private String ip; + + @ApiModelProperty(value = "下载次数") + private Integer count; + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/module/log/model/dto/DownloadTopRefererDTO.java b/src/main/java/im/zhaojun/zfile/module/log/model/dto/DownloadTopRefererDTO.java new file mode 100644 index 0000000..f3622eb --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/log/model/dto/DownloadTopRefererDTO.java @@ -0,0 +1,19 @@ +package im.zhaojun.zfile.module.log.model.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 下载 referer 排行 dto 类 + * @author zhaojun + */ +@Data +public class DownloadTopRefererDTO { + + @ApiModelProperty(value = "referer", notes = "来源网站") + private String referer; + + @ApiModelProperty(value = "下载次数") + private Integer count; + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/model/entity/DownloadLog.java b/src/main/java/im/zhaojun/zfile/module/log/model/entity/DownloadLog.java similarity index 95% rename from src/main/java/im/zhaojun/zfile/admin/model/entity/DownloadLog.java rename to src/main/java/im/zhaojun/zfile/module/log/model/entity/DownloadLog.java index 69da0d6..68e2efd 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/entity/DownloadLog.java +++ b/src/main/java/im/zhaojun/zfile/module/log/model/entity/DownloadLog.java @@ -1,11 +1,11 @@ -package im.zhaojun.zfile.admin.model.entity; +package im.zhaojun.zfile.module.log.model.entity; import cn.hutool.extra.servlet.ServletUtil; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import im.zhaojun.zfile.common.util.RequestHolder; +import im.zhaojun.zfile.core.util.RequestHolder; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -68,7 +68,6 @@ public class DownloadLog implements Serializable { @ApiModelProperty(value="访问 referer") private String referer; - public DownloadLog(String path, String storageKey, String shortKey) { this.path = path; this.storageKey = storageKey; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/request/DownloadTopInfoRequest.java b/src/main/java/im/zhaojun/zfile/module/log/model/request/DownloadTopInfoRequest.java similarity index 88% rename from src/main/java/im/zhaojun/zfile/admin/model/request/DownloadTopInfoRequest.java rename to src/main/java/im/zhaojun/zfile/module/log/model/request/DownloadTopInfoRequest.java index 43c80c0..d9f4a67 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/request/DownloadTopInfoRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/log/model/request/DownloadTopInfoRequest.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.request; +package im.zhaojun.zfile.module.log.model.request; import io.swagger.annotations.ApiModelProperty; import lombok.Data; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/result/link/DownloadLogResult.java b/src/main/java/im/zhaojun/zfile/module/log/model/result/DownloadLogResult.java similarity index 76% rename from src/main/java/im/zhaojun/zfile/admin/model/result/link/DownloadLogResult.java rename to src/main/java/im/zhaojun/zfile/module/log/model/result/DownloadLogResult.java index 8a5cc7b..1a51fad 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/result/link/DownloadLogResult.java +++ b/src/main/java/im/zhaojun/zfile/module/log/model/result/DownloadLogResult.java @@ -1,8 +1,6 @@ -package im.zhaojun.zfile.admin.model.result.link; +package im.zhaojun.zfile.module.log.model.result; -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -16,27 +14,26 @@ import java.util.Date; @Data public class DownloadLogResult { - @TableId(value = "id", type = IdType.INPUT) @ApiModelProperty(value="") private Integer id; @ApiModelProperty(value="文件路径") private String path; - @ApiModelProperty(value = "存储源名称", example = "我的本地存储") - private String storageName; - @ApiModelProperty(value = "存储源类型") private StorageTypeEnum storageType; - - @ApiModelProperty(value = "短链 Key") - private String shortKey; - + + @ApiModelProperty(value = "存储源名称", example = "我的本地存储") + private String storageName; + @ApiModelProperty(value="访问时间") private Date createTime; @ApiModelProperty(value="访问 ip") private String ip; + + @ApiModelProperty(value = "短链 Key") + private String shortKey; @ApiModelProperty(value="访问 user_agent") private String userAgent; diff --git a/src/main/java/im/zhaojun/zfile/module/log/service/DownloadLogService.java b/src/main/java/im/zhaojun/zfile/module/log/service/DownloadLogService.java new file mode 100644 index 0000000..6d0b25b --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/log/service/DownloadLogService.java @@ -0,0 +1,45 @@ +package im.zhaojun.zfile.module.log.service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import im.zhaojun.zfile.module.log.mapper.DownloadLogMapper; +import im.zhaojun.zfile.module.log.model.entity.DownloadLog; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 下载日志 Service + * + * @author zhaojun + */ +@Service +public class DownloadLogService { + + @Resource + private DownloadLogMapper downloadLogMapper; + + public void save(DownloadLog downloadLog) { + downloadLogMapper.insert(downloadLog); + } + + public Page selectPage(Page pages, QueryWrapper queryWrapper) { + return downloadLogMapper.selectPage(pages, queryWrapper); + } + + public void removeById(Integer id) { + downloadLogMapper.deleteById(id); + } + + @Transactional(rollbackFor = Exception.class) + public void removeBatchByIds(List ids) { + downloadLogMapper.deleteBatchIds(ids); + } + + public int deleteByStorageKey(String storageKey) { + return downloadLogMapper.deleteByStorageKey(storageKey); + } + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/module/login/controller/LoginController.java b/src/main/java/im/zhaojun/zfile/module/login/controller/LoginController.java new file mode 100644 index 0000000..0574ee2 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/login/controller/LoginController.java @@ -0,0 +1 @@ +package im.zhaojun.zfile.module.login.controller; import cn.dev33.satoken.stp.SaTokenInfo; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.crypto.SecureUtil; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiSort; import dev.samstevens.totp.exceptions.QrGenerationException; import im.zhaojun.zfile.core.util.AjaxJson; import im.zhaojun.zfile.module.config.model.dto.SystemConfigDTO; import im.zhaojun.zfile.module.config.service.SystemConfigService; import im.zhaojun.zfile.module.login.model.enums.LoginVerifyModeEnum; import im.zhaojun.zfile.module.login.model.request.VerifyLoginTwoFactorAuthenticatorRequest; import im.zhaojun.zfile.module.login.model.result.LoginTwoFactorAuthenticatorResult; import im.zhaojun.zfile.module.login.model.result.LoginVerifyImgResult; import im.zhaojun.zfile.module.login.request.UserLoginRequest; import im.zhaojun.zfile.module.login.service.ImgVerifyCodeService; import im.zhaojun.zfile.module.login.service.TwoFactorAuthenticatorVerifyService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import javax.validation.Valid; import java.util.Objects; /** * 登陆注销相关接口 * * @author zhaojun */ @Api(tags = "登录模块") @ApiSort(1) @RestController @RequestMapping("/admin") public class LoginController { @Resource private SystemConfigService systemConfigService; @Resource private ImgVerifyCodeService imgVerifyCodeService; @Resource private TwoFactorAuthenticatorVerifyService twoFactorAuthenticatorVerifyService; @ApiOperationSupport(order = 1, ignoreParameters = {"zfile-token"}) @ApiOperation(value = "登录") @PostMapping("/login") public AjaxJson doLogin(@Valid @RequestBody UserLoginRequest userLoginRequest) { SystemConfigDTO systemConfig = systemConfigService.getSystemConfig(); String verifyCode = userLoginRequest.getVerifyCode(); String verifyCodeUuid = userLoginRequest.getVerifyCodeUUID(); LoginVerifyModeEnum loginVerifyMode = systemConfig.getLoginVerifyMode(); String loginVerifySecret = systemConfig.getLoginVerifySecret(); if (Objects.equals(loginVerifyMode, LoginVerifyModeEnum.TWO_FACTOR_AUTHENTICATION_MODE)) { twoFactorAuthenticatorVerifyService.checkCode(loginVerifySecret, verifyCode); } else if (Objects.equals(loginVerifyMode, LoginVerifyModeEnum.IMG_VERIFY_MODE)) { imgVerifyCodeService.checkCaptcha(verifyCodeUuid, verifyCode); } if (Objects.equals(systemConfig.getUsername(), userLoginRequest.getUsername()) && Objects.equals(systemConfig.getPassword(), SecureUtil.md5(userLoginRequest.getPassword()))) { StpUtil.login("admin"); SaTokenInfo tokenInfo = StpUtil.getTokenInfo(); return AjaxJson.getSuccess("登录成功", tokenInfo.getTokenValue()); } return AjaxJson.getError("登录失败, 账号或密码错误"); } @ApiOperationSupport(order = 2) @ApiOperation(value = "注销") @PostMapping("/logout") public AjaxJson logout() { StpUtil.logout(); return AjaxJson.getSuccess("注销成功"); } @ApiOperationSupport(order = 3) @ApiOperation(value = "生成 2FA") @GetMapping("/2fa/setup") public AjaxJson setupDevice() throws QrGenerationException { LoginTwoFactorAuthenticatorResult loginTwoFactorAuthenticatorResult = twoFactorAuthenticatorVerifyService.setupDevice(); return AjaxJson.getSuccessData(loginTwoFactorAuthenticatorResult); } @ApiOperationSupport(order = 4) @ApiOperation(value = "2FA 验证并绑定") @PostMapping("/2fa/verify") public AjaxJson deviceVerify(@Valid @RequestBody VerifyLoginTwoFactorAuthenticatorRequest verifyLoginTwoFactorAuthenticatorRequest) { twoFactorAuthenticatorVerifyService.deviceVerify(verifyLoginTwoFactorAuthenticatorRequest); return AjaxJson.getSuccess(); } @ApiOperationSupport(order = 5) @ApiOperation(value = "获取登陆验证方式") @GetMapping("/login/verify-mode") public AjaxJson loginVerifyMode() { SystemConfigDTO systemConfig = systemConfigService.getSystemConfig(); return AjaxJson.getSuccessData(systemConfig.getLoginVerifyMode()); } @ApiOperationSupport(order = 6) @ApiOperation(value = "获取图形验证码") @GetMapping("/login/captcha") public AjaxJson captcha() { LoginVerifyImgResult loginVerifyImgResult = imgVerifyCodeService.generatorCaptcha(); return AjaxJson.getSuccessData(loginVerifyImgResult); } @ApiOperationSupport(order = 7) @ApiOperation(value = "检测是否已登录") @GetMapping("/login/check") public AjaxJson checkLogin() { return AjaxJson.getSuccessData(StpUtil.isLogin()); } } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/model/enums/LoginVerifyModeEnum.java b/src/main/java/im/zhaojun/zfile/module/login/model/enums/LoginVerifyModeEnum.java similarity index 91% rename from src/main/java/im/zhaojun/zfile/admin/model/enums/LoginVerifyModeEnum.java rename to src/main/java/im/zhaojun/zfile/module/login/model/enums/LoginVerifyModeEnum.java index 7ceec06..c1a7d6f 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/enums/LoginVerifyModeEnum.java +++ b/src/main/java/im/zhaojun/zfile/module/login/model/enums/LoginVerifyModeEnum.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.enums; +package im.zhaojun.zfile.module.login.model.enums; import com.baomidou.mybatisplus.annotation.EnumValue; import com.fasterxml.jackson.annotation.JsonValue; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/request/login/VerifyLogin2FARequest.java b/src/main/java/im/zhaojun/zfile/module/login/model/request/VerifyLoginTwoFactorAuthenticatorRequest.java similarity index 86% rename from src/main/java/im/zhaojun/zfile/admin/model/request/login/VerifyLogin2FARequest.java rename to src/main/java/im/zhaojun/zfile/module/login/model/request/VerifyLoginTwoFactorAuthenticatorRequest.java index d564cff..20b53fb 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/request/login/VerifyLogin2FARequest.java +++ b/src/main/java/im/zhaojun/zfile/module/login/model/request/VerifyLoginTwoFactorAuthenticatorRequest.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.request.login; +package im.zhaojun.zfile.module.login.model.request; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -15,7 +15,7 @@ import javax.validation.constraints.NotBlank; @Data @AllArgsConstructor @ApiModel(description = "验证二步验证结果") -public class VerifyLogin2FARequest { +public class VerifyLoginTwoFactorAuthenticatorRequest { @ApiModelProperty(value = "二步验证二维码", required = true, example = "EwBoxxxxxxxxxxxxxxxbAI=") @NotBlank(message = "二步验证密钥不能为空") diff --git a/src/main/java/im/zhaojun/zfile/admin/model/result/login/Login2FAResult.java b/src/main/java/im/zhaojun/zfile/module/login/model/result/LoginTwoFactorAuthenticatorResult.java similarity index 81% rename from src/main/java/im/zhaojun/zfile/admin/model/result/login/Login2FAResult.java rename to src/main/java/im/zhaojun/zfile/module/login/model/result/LoginTwoFactorAuthenticatorResult.java index 569b4e2..04afd1b 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/result/login/Login2FAResult.java +++ b/src/main/java/im/zhaojun/zfile/module/login/model/result/LoginTwoFactorAuthenticatorResult.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.result.login; +package im.zhaojun.zfile.module.login.model.result; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -13,7 +13,7 @@ import lombok.Data; @Data @AllArgsConstructor @ApiModel(description = "生成二步验证结果") -public class Login2FAResult { +public class LoginTwoFactorAuthenticatorResult { @ApiModelProperty(value = "二步验证二维码") private String qrcode; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/result/login/LoginVerifyImgResult.java b/src/main/java/im/zhaojun/zfile/module/login/model/result/LoginVerifyImgResult.java similarity index 90% rename from src/main/java/im/zhaojun/zfile/admin/model/result/login/LoginVerifyImgResult.java rename to src/main/java/im/zhaojun/zfile/module/login/model/result/LoginVerifyImgResult.java index 171a0c9..abc5f00 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/result/login/LoginVerifyImgResult.java +++ b/src/main/java/im/zhaojun/zfile/module/login/model/result/LoginVerifyImgResult.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.result.login; +package im.zhaojun.zfile.module.login.model.result; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; diff --git a/src/main/java/im/zhaojun/zfile/module/login/request/UserLoginRequest.java b/src/main/java/im/zhaojun/zfile/module/login/request/UserLoginRequest.java new file mode 100644 index 0000000..5a24ad3 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/login/request/UserLoginRequest.java @@ -0,0 +1 @@ +package im.zhaojun.zfile.module.login.request; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import javax.validation.constraints.NotBlank; /** * 用户登录请求参数参数 * * @author zhaojun */ @Data @ApiModel(description = "用户登录请求参数类") public class UserLoginRequest { @ApiModelProperty(value = "用户名", required = true, example = "admin") @NotBlank(message = "用户名不能为空") private String username; @ApiModelProperty(value = "密码", required = true, example = "123456") @NotBlank(message = "密码不能为空") private String password; @ApiModelProperty(value = "验证码", example = "123456") private String verifyCode; @ApiModelProperty(value = "验证码 UUID", notes = "用于图形验证码确认每个验证码图片请求的唯一值.", example = "c140a792-4ca2-4dac-8d4c-35750b78524f") private String verifyCodeUUID; } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/service/login/ImgVerifyCodeService.java b/src/main/java/im/zhaojun/zfile/module/login/service/ImgVerifyCodeService.java similarity index 91% rename from src/main/java/im/zhaojun/zfile/admin/service/login/ImgVerifyCodeService.java rename to src/main/java/im/zhaojun/zfile/module/login/service/ImgVerifyCodeService.java index c8f11a7..680a585 100644 --- a/src/main/java/im/zhaojun/zfile/admin/service/login/ImgVerifyCodeService.java +++ b/src/main/java/im/zhaojun/zfile/module/login/service/ImgVerifyCodeService.java @@ -1,12 +1,12 @@ -package im.zhaojun.zfile.admin.service.login; +package im.zhaojun.zfile.module.login.service; import cn.hutool.cache.CacheUtil; import cn.hutool.cache.impl.FIFOCache; import cn.hutool.captcha.CaptchaUtil; import cn.hutool.captcha.CircleCaptcha; import cn.hutool.core.lang.UUID; -import im.zhaojun.zfile.common.exception.LoginVerifyException; -import im.zhaojun.zfile.admin.model.result.login.LoginVerifyImgResult; +import im.zhaojun.zfile.core.exception.LoginVerifyException; +import im.zhaojun.zfile.module.login.model.result.LoginVerifyImgResult; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; diff --git a/src/main/java/im/zhaojun/zfile/admin/service/login/TwoFAVerifyService.java b/src/main/java/im/zhaojun/zfile/module/login/service/TwoFactorAuthenticatorVerifyService.java similarity index 68% rename from src/main/java/im/zhaojun/zfile/admin/service/login/TwoFAVerifyService.java rename to src/main/java/im/zhaojun/zfile/module/login/service/TwoFactorAuthenticatorVerifyService.java index f3367fb..741468d 100644 --- a/src/main/java/im/zhaojun/zfile/admin/service/login/TwoFAVerifyService.java +++ b/src/main/java/im/zhaojun/zfile/module/login/service/TwoFactorAuthenticatorVerifyService.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.service.login; +package im.zhaojun.zfile.module.login.service; import dev.samstevens.totp.code.CodeVerifier; import dev.samstevens.totp.exceptions.QrGenerationException; @@ -6,12 +6,12 @@ import dev.samstevens.totp.qr.QrData; import dev.samstevens.totp.qr.QrDataFactory; import dev.samstevens.totp.qr.QrGenerator; import dev.samstevens.totp.secret.SecretGenerator; -import im.zhaojun.zfile.common.exception.LoginVerifyException; -import im.zhaojun.zfile.admin.model.request.login.VerifyLogin2FARequest; -import im.zhaojun.zfile.admin.model.result.login.Login2FAResult; -import im.zhaojun.zfile.home.model.dto.SystemConfigDTO; -import im.zhaojun.zfile.admin.model.enums.LoginVerifyModeEnum; -import im.zhaojun.zfile.admin.service.SystemConfigService; +import im.zhaojun.zfile.core.exception.LoginVerifyException; +import im.zhaojun.zfile.module.login.model.request.VerifyLoginTwoFactorAuthenticatorRequest; +import im.zhaojun.zfile.module.login.model.result.LoginTwoFactorAuthenticatorResult; +import im.zhaojun.zfile.module.config.model.dto.SystemConfigDTO; +import im.zhaojun.zfile.module.login.model.enums.LoginVerifyModeEnum; +import im.zhaojun.zfile.module.config.service.SystemConfigService; import org.springframework.stereotype.Service; import javax.annotation.Resource; @@ -24,7 +24,7 @@ import static dev.samstevens.totp.util.Utils.getDataUriForImage; * @author zhaojun */ @Service -public class TwoFAVerifyService { +public class TwoFactorAuthenticatorVerifyService { @Resource private SecretGenerator secretGenerator; @@ -48,7 +48,7 @@ public class TwoFAVerifyService { * @return 2FA 双因素认证二维码和密钥 * @throws QrGenerationException 二维码生成异常 */ - public Login2FAResult setupDevice() throws QrGenerationException { + public LoginTwoFactorAuthenticatorResult setupDevice() throws QrGenerationException { // 生成 2FA 密钥 String secret = secretGenerator.generate(); QrData data = qrDataFactory.newBuilder().secret(secret).issuer("ZFile").build(); @@ -58,19 +58,19 @@ public class TwoFAVerifyService { qrGenerator.generate(data), qrGenerator.getImageMimeType()); - return new Login2FAResult(qrCodeImage, secret); + return new LoginTwoFactorAuthenticatorResult(qrCodeImage, secret); } /** * 验证 2FA 双因素认证是否正确,正确则进行绑定. * - * @param verifyLogin2FARequest + * @param verifyLoginTwoFactorAuthenticatorRequest * 2FA 双因素认证请求参数 */ - public void deviceVerify(VerifyLogin2FARequest verifyLogin2FARequest) { - String secret = verifyLogin2FARequest.getSecret(); - String code = verifyLogin2FARequest.getCode(); + public void deviceVerify(VerifyLoginTwoFactorAuthenticatorRequest verifyLoginTwoFactorAuthenticatorRequest) { + String secret = verifyLoginTwoFactorAuthenticatorRequest.getSecret(); + String code = verifyLoginTwoFactorAuthenticatorRequest.getCode(); if (verifier.isValidCode(secret, code)) { SystemConfigDTO systemConfig = systemConfigService.getSystemConfig(); diff --git a/src/main/java/im/zhaojun/zfile/admin/controller/stroage/StorageSourcePasswordController.java b/src/main/java/im/zhaojun/zfile/module/password/controller/StorageSourcePasswordController.java similarity index 83% rename from src/main/java/im/zhaojun/zfile/admin/controller/stroage/StorageSourcePasswordController.java rename to src/main/java/im/zhaojun/zfile/module/password/controller/StorageSourcePasswordController.java index 1947811..9d26768 100644 --- a/src/main/java/im/zhaojun/zfile/admin/controller/stroage/StorageSourcePasswordController.java +++ b/src/main/java/im/zhaojun/zfile/module/password/controller/StorageSourcePasswordController.java @@ -1,10 +1,10 @@ -package im.zhaojun.zfile.admin.controller.stroage; +package im.zhaojun.zfile.module.password.controller; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiSort; -import im.zhaojun.zfile.admin.model.entity.PasswordConfig; -import im.zhaojun.zfile.admin.service.PasswordConfigService; -import im.zhaojun.zfile.common.util.AjaxJson; +import im.zhaojun.zfile.module.password.model.entity.PasswordConfig; +import im.zhaojun.zfile.module.password.service.PasswordConfigService; +import im.zhaojun.zfile.core.util.AjaxJson; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; @@ -34,7 +34,7 @@ public class StorageSourcePasswordController { @ApiOperationSupport(order = 1) @ApiOperation(value = "获取存储源密码文件夹列表", notes = "根据存储源 ID 获取存储源设置的密码文件夹列表") - @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true) + @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true, dataTypeClass = Integer.class) @GetMapping("/storage/{storageId}/password") public AjaxJson> getPasswordList(@PathVariable Integer storageId) { return AjaxJson.getSuccessData(passwordConfigService.findByStorageId(storageId)); @@ -43,7 +43,7 @@ public class StorageSourcePasswordController { @ApiOperationSupport(order = 2) @ApiOperation(value = "保存存储源密码文件夹列表", notes = "保存指定存储源 ID 设置的密码文件夹列表") - @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true) + @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true, dataTypeClass = Integer.class) @PostMapping("/storage/{storageId}/password") public AjaxJson savePasswordList(@PathVariable Integer storageId, @RequestBody List password) { passwordConfigService.batchSave(storageId, password); diff --git a/src/main/java/im/zhaojun/zfile/admin/mapper/PasswordConfigMapper.java b/src/main/java/im/zhaojun/zfile/module/password/mapper/PasswordConfigMapper.java similarity index 87% rename from src/main/java/im/zhaojun/zfile/admin/mapper/PasswordConfigMapper.java rename to src/main/java/im/zhaojun/zfile/module/password/mapper/PasswordConfigMapper.java index 6893f35..f1b4d5b 100644 --- a/src/main/java/im/zhaojun/zfile/admin/mapper/PasswordConfigMapper.java +++ b/src/main/java/im/zhaojun/zfile/module/password/mapper/PasswordConfigMapper.java @@ -1,7 +1,7 @@ -package im.zhaojun.zfile.admin.mapper; +package im.zhaojun.zfile.module.password.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import im.zhaojun.zfile.admin.model.entity.PasswordConfig; +import im.zhaojun.zfile.module.password.model.entity.PasswordConfig; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; diff --git a/src/main/java/im/zhaojun/zfile/module/password/model/dto/VerifyResultDTO.java b/src/main/java/im/zhaojun/zfile/module/password/model/dto/VerifyResultDTO.java new file mode 100644 index 0000000..7ade890 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/password/model/dto/VerifyResultDTO.java @@ -0,0 +1,56 @@ +package im.zhaojun.zfile.module.password.model.dto; + +import lombok.Data; + +/** + * 用于表示校验结果的类 + * + * @author zhaojun + */ +@Data +public class VerifyResultDTO { + + /** + * 是否成功 + */ + private boolean passed; + + /** + * 消息 + */ + private String msg; + + /** + * 代码 + */ + private Integer code; + + /** + * 表达式 + */ + private String pattern; + + public static VerifyResultDTO success() { + VerifyResultDTO verifyResultDTO = new VerifyResultDTO(); + verifyResultDTO.setPassed(true); + return verifyResultDTO; + } + + + public static VerifyResultDTO success(String pattern) { + VerifyResultDTO verifyResultDTO = new VerifyResultDTO(); + verifyResultDTO.setPassed(true); + verifyResultDTO.setPattern(pattern); + return verifyResultDTO; + } + + + public static VerifyResultDTO fail(String msg, Integer code) { + VerifyResultDTO verifyResultDTO = new VerifyResultDTO(); + verifyResultDTO.setPassed(false); + verifyResultDTO.setMsg(msg); + verifyResultDTO.setCode(code); + return verifyResultDTO; + } + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/model/entity/PasswordConfig.java b/src/main/java/im/zhaojun/zfile/module/password/model/entity/PasswordConfig.java similarity index 96% rename from src/main/java/im/zhaojun/zfile/admin/model/entity/PasswordConfig.java rename to src/main/java/im/zhaojun/zfile/module/password/model/entity/PasswordConfig.java index daaf3fc..59fa894 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/entity/PasswordConfig.java +++ b/src/main/java/im/zhaojun/zfile/module/password/model/entity/PasswordConfig.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.entity; +package im.zhaojun.zfile.module.password.model.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; diff --git a/src/main/java/im/zhaojun/zfile/module/password/service/PasswordConfigService.java b/src/main/java/im/zhaojun/zfile/module/password/service/PasswordConfigService.java new file mode 100644 index 0000000..bf4854d --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/password/service/PasswordConfigService.java @@ -0,0 +1,208 @@ +package im.zhaojun.zfile.module.password.service; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import im.zhaojun.zfile.core.util.AjaxJson; +import im.zhaojun.zfile.core.util.PatternMatcherUtils; +import im.zhaojun.zfile.core.util.StringUtils; +import im.zhaojun.zfile.module.password.mapper.PasswordConfigMapper; +import im.zhaojun.zfile.module.password.model.dto.VerifyResultDTO; +import im.zhaojun.zfile.module.password.model.entity.PasswordConfig; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Objects; + +/** + * 存储源密码配置 Service + * + * @author zhaojun + */ +@Service +@Slf4j +@CacheConfig(cacheNames = "passwordConfig") +public class PasswordConfigService { + + @Resource + private PasswordConfigMapper passwordConfigMapper; + + @Resource + private PasswordConfigService passwordConfigService; + + + /** + * 根据存储源 ID 查询密码规则列表 + * + * @param storageId + * 存储源 ID + * + * @return 密码规则列表 + */ + @Cacheable(key = "#storageId") + public List findByStorageId(Integer storageId) { + return passwordConfigMapper.findByStorageId(storageId); + } + + + /** + * 批量保存指定存储源 ID 的密码规则列表 + * + * @param storageId + * 存储源 ID + * + * @param passwordConfigList + * 存储源类别 + */ + @Transactional(rollbackFor = Exception.class) + public void batchSave(Integer storageId, List passwordConfigList) { + passwordConfigService.deleteByStorageId(storageId); + log.info("更新存储源 ID 为 {} 的过滤规则 {} 条", storageId, passwordConfigList.size()); + + passwordConfigList.forEach(passwordConfig -> { + passwordConfig.setStorageId(storageId); + passwordConfigMapper.insert(passwordConfig); + + if (log.isDebugEnabled()) { + log.debug("新增过滤规则, 存储源 ID: {}, 表达式: {}, 描述: {}, 密码: {}", + passwordConfig.getStorageId(), passwordConfig.getExpression(), + passwordConfig.getDescription(), passwordConfig.getPassword()); + } + }); + } + + + /** + * 根据存储源 id 删除所有密码规则 + * + * @param storageId + * 存储源 ID + */ + @CacheEvict(key = "#storageId") + public int deleteByStorageId(Integer storageId) { + int deleteSize = passwordConfigMapper.deleteByStorageId(storageId); + log.info("删除存储源 ID 为 {} 的密码规则 {} 条", storageId, deleteSize); + return deleteSize; + } + + + /** + * 校验密码 + * + * @param storageId + * 存储源 ID + * + * @param path + * 请求路径 + * + * @param inputPassword + * 用户输入的密码 + * + * @return 是否校验通过 + */ + public VerifyResultDTO verifyPassword(Integer storageId, String path, String inputPassword) { + List passwordConfigList = passwordConfigService.findByStorageId(storageId); + + // 如果规则列表为空, 则表示不需要过滤, 直接返回 false + if (CollUtil.isEmpty(passwordConfigList)) { + if (log.isDebugEnabled()) { + log.debug("密码规则列表为空, 请求路径: {}, 存储源 ID: {}, 输入密码: {}", path, storageId, inputPassword); + } + return VerifyResultDTO.success(); + } + + // 校验密码 + for (PasswordConfig passwordConfig : passwordConfigList) { + String expression = passwordConfig.getExpression(); + String expectPassword = passwordConfig.getPassword(); + + // 规则为空跳过 + if (StrUtil.isEmpty(expression)) { + if (log.isDebugEnabled()) { + log.debug("密码规则测试表达式: {}, 请求路径: {}, 表达式为空,跳过该规则比对", expression, path); + } + continue; + } + + try { + // 判断当前请求路径是否和规则路径表达式匹配 + boolean match = PatternMatcherUtils.testCompatibilityGlobPattern(expression, path); + + if (log.isDebugEnabled()) { + log.debug("密码规则测试表达式: {}, 请求路径: {}, 匹配结果: {}, 预期密码: {}, 输入密码; {}", expression, path, match, expectPassword, inputPassword); + } + + // 如果匹配且输入了密码则校验 + if (match) { + if (StrUtil.isEmpty(inputPassword)) { + if (log.isDebugEnabled()) { + log.debug("密码规则匹配, 但未输入密码;" + + "表达式: {}, 请求路径: {}, 存储源 ID: {}, 预期密码:{}, 输入密码: {}", + expression, path, storageId, expectPassword, inputPassword); + } + return VerifyResultDTO.fail("此文件夹需要密码.", AjaxJson.REQUIRED_PASSWORD); + } + + if (matchPassword(expectPassword, inputPassword)) { + if (log.isDebugEnabled()) { + log.debug("密码规则匹配, 密码校验通过;" + + "表达式: {}, 请求路径: {}, 存储源 ID: {}, 预期密码:{}, 输入密码: {}", + expression, path, storageId, expectPassword, inputPassword); + } + return VerifyResultDTO.success(expression); + } + + if (log.isDebugEnabled()) { + log.debug("密码规则匹配, 但输入密码与预期密码不同;" + + "表达式: {}, 请求路径: {}, 存储源 ID: {}, 预期密码:{}, 输入密码: {}", + expression, path, storageId, expectPassword, inputPassword); + } + return VerifyResultDTO.fail("此文件夹密码错误.", AjaxJson.INVALID_PASSWORD); + } + } catch (Exception e) { + log.error("密码规则匹配出现异常,表达式: {}, 请求路径: {}, 存储源 ID: {}, 预期密码:{}, 输入密码: {}, 解析错误, 跳过此规则.", + expression, path, storageId, expectPassword, inputPassword, e); + } + } + + if (log.isDebugEnabled()) { + log.debug("校验文件夹密码 path: {}, 没有匹配的表达式, 不进行密码校验.", path); + } + + return VerifyResultDTO.success(); + } + + + /** + * 校验两个密码是否相同, 忽略空白字符 + * + * @param expectedPasswordContent + * 预期密码 + * + * @param password + * 实际输入密码 + * + * @return 是否匹配 + */ + private boolean matchPassword(String expectedPasswordContent, String password) { + if (Objects.equals(expectedPasswordContent, password)) { + return true; + } + + // 如果预期密码或输入密码为空, 则不匹配 + if (ObjectUtil.hasNull(expectedPasswordContent, password)) { + return false; + } + + expectedPasswordContent = StringUtils.removeAllLineBreaksAndTrim(expectedPasswordContent); + password = StringUtils.removeAllLineBreaksAndTrim(password); + return Objects.equals(expectedPasswordContent, password); + } + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/controller/stroage/StorageSourceReadmeController.java b/src/main/java/im/zhaojun/zfile/module/readme/controller/StorageSourceReadmeController.java similarity index 83% rename from src/main/java/im/zhaojun/zfile/admin/controller/stroage/StorageSourceReadmeController.java rename to src/main/java/im/zhaojun/zfile/module/readme/controller/StorageSourceReadmeController.java index 5a6e95f..e9326e0 100644 --- a/src/main/java/im/zhaojun/zfile/admin/controller/stroage/StorageSourceReadmeController.java +++ b/src/main/java/im/zhaojun/zfile/module/readme/controller/StorageSourceReadmeController.java @@ -1,10 +1,10 @@ -package im.zhaojun.zfile.admin.controller.stroage; +package im.zhaojun.zfile.module.readme.controller; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiSort; -import im.zhaojun.zfile.admin.model.entity.ReadmeConfig; -import im.zhaojun.zfile.admin.service.ReadmeConfigService; -import im.zhaojun.zfile.common.util.AjaxJson; +import im.zhaojun.zfile.module.readme.model.entity.ReadmeConfig; +import im.zhaojun.zfile.module.readme.service.ReadmeConfigService; +import im.zhaojun.zfile.core.util.AjaxJson; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; @@ -34,7 +34,7 @@ public class StorageSourceReadmeController { @ApiOperationSupport(order = 1) @ApiOperation(value = "获取存储源文档文件夹列表", notes = "根据存储源 ID 获取存储源设置的文档文件夹列表") - @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true) + @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true, dataTypeClass = Integer.class) @GetMapping("/storage/{storageId}/readme") public AjaxJson> getReadmeList(@PathVariable Integer storageId) { return AjaxJson.getSuccessData(readmeConfigService.findByStorageId(storageId)); @@ -43,7 +43,7 @@ public class StorageSourceReadmeController { @ApiOperationSupport(order = 2) @ApiOperation(value = "保存存储源文档文件夹列表", notes = "保存指定存储源 ID 设置的文档文件夹列表") - @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true) + @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true, dataTypeClass = Integer.class) @PostMapping("/storage/{storageId}/readme") public AjaxJson saveReadmeList(@PathVariable Integer storageId, @RequestBody List readme) { readmeConfigService.batchSave(storageId, readme); diff --git a/src/main/java/im/zhaojun/zfile/admin/mapper/ReadmeConfigMapper.java b/src/main/java/im/zhaojun/zfile/module/readme/mapper/ReadmeConfigMapper.java similarity index 87% rename from src/main/java/im/zhaojun/zfile/admin/mapper/ReadmeConfigMapper.java rename to src/main/java/im/zhaojun/zfile/module/readme/mapper/ReadmeConfigMapper.java index 87f78d7..3d1454c 100644 --- a/src/main/java/im/zhaojun/zfile/admin/mapper/ReadmeConfigMapper.java +++ b/src/main/java/im/zhaojun/zfile/module/readme/mapper/ReadmeConfigMapper.java @@ -1,7 +1,7 @@ -package im.zhaojun.zfile.admin.mapper; +package im.zhaojun.zfile.module.readme.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import im.zhaojun.zfile.admin.model.entity.ReadmeConfig; +import im.zhaojun.zfile.module.readme.model.entity.ReadmeConfig; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/entity/ReadmeConfig.java b/src/main/java/im/zhaojun/zfile/module/readme/model/entity/ReadmeConfig.java similarity index 92% rename from src/main/java/im/zhaojun/zfile/admin/model/entity/ReadmeConfig.java rename to src/main/java/im/zhaojun/zfile/module/readme/model/entity/ReadmeConfig.java index 78429cb..bc15ac7 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/entity/ReadmeConfig.java +++ b/src/main/java/im/zhaojun/zfile/module/readme/model/entity/ReadmeConfig.java @@ -1,11 +1,11 @@ -package im.zhaojun.zfile.admin.model.entity; +package im.zhaojun.zfile.module.readme.model.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonIgnore; -import im.zhaojun.zfile.admin.model.enums.ReadmeDisplayModeEnum; +import im.zhaojun.zfile.module.readme.model.enums.ReadmeDisplayModeEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/enums/ReadmeDisplayModeEnum.java b/src/main/java/im/zhaojun/zfile/module/readme/model/enums/ReadmeDisplayModeEnum.java similarity index 90% rename from src/main/java/im/zhaojun/zfile/admin/model/enums/ReadmeDisplayModeEnum.java rename to src/main/java/im/zhaojun/zfile/module/readme/model/enums/ReadmeDisplayModeEnum.java index 769acae..f2387d9 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/enums/ReadmeDisplayModeEnum.java +++ b/src/main/java/im/zhaojun/zfile/module/readme/model/enums/ReadmeDisplayModeEnum.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.enums; +package im.zhaojun.zfile.module.readme.model.enums; import com.baomidou.mybatisplus.annotation.EnumValue; import com.fasterxml.jackson.annotation.JsonValue; diff --git a/src/main/java/im/zhaojun/zfile/module/readme/service/ReadmeConfigService.java b/src/main/java/im/zhaojun/zfile/module/readme/service/ReadmeConfigService.java new file mode 100644 index 0000000..99cce94 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/readme/service/ReadmeConfigService.java @@ -0,0 +1,212 @@ +package im.zhaojun.zfile.module.readme.service; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.BooleanUtil; +import cn.hutool.core.util.StrUtil; +import im.zhaojun.zfile.module.storage.context.StorageSourceContext; +import im.zhaojun.zfile.core.util.HttpUtil; +import im.zhaojun.zfile.core.util.PatternMatcherUtils; +import im.zhaojun.zfile.core.util.StringUtils; +import im.zhaojun.zfile.module.readme.mapper.ReadmeConfigMapper; +import im.zhaojun.zfile.module.readme.model.entity.ReadmeConfig; +import im.zhaojun.zfile.module.readme.model.enums.ReadmeDisplayModeEnum; +import im.zhaojun.zfile.module.storage.model.param.IStorageParam; +import im.zhaojun.zfile.module.storage.model.result.FileItemResult; +import im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 存储源 readme 配置 Service + * + * @author zhaojun + */ +@Slf4j +@Service +@CacheConfig(cacheNames = "readmeConfig") +public class ReadmeConfigService { + + @Resource + private ReadmeConfigMapper readmeConfigMapper; + + @Resource + private ReadmeConfigService readmeConfigService; + + @Resource + private StorageSourceContext storageSourceContext; + + /** + * 根据存储源 ID 查询文档配置 + * + * @param storageId + * 存储源ID + * + * @return 存储源文档配置列表 + */ + @Cacheable(key = "#storageId") + public List findByStorageId(Integer storageId){ + return readmeConfigMapper.findByStorageId(storageId); + } + + + /** + * 批量保存存储源 readme 配置, 会先删除之前的所有配置(在事务中运行) + * + * @param storageId + * 存储源 ID + * + * @param readmeConfigList + * 存储源 readme 配置列表 + */ + @Transactional(rollbackFor = Exception.class) + public void batchSave(Integer storageId, List readmeConfigList) { + readmeConfigService.deleteByStorageId(storageId); + + log.info("更新存储源 ID 为 {} 的目录文档配置 {} 条", storageId, readmeConfigList.size()); + + readmeConfigList.forEach(readmeConfig -> { + readmeConfig.setStorageId(storageId); + readmeConfigMapper.insert(readmeConfig); + + if (log.isDebugEnabled()) { + log.debug("新增目录文档, 存储源 ID: {}, 表达式: {}, 描述: {}, 显示模式: {}", + readmeConfig.getStorageId(), readmeConfig.getExpression(), + readmeConfig.getDescription(), readmeConfig.getDisplayMode().getValue()); + } + }); + } + + + /** + * 根据存储源 ID 删除存储源 readme 配置 + * + * @param storageId + * 存储源 ID + */ + @CacheEvict(key = "#storageId") + public int deleteByStorageId(Integer storageId) { + int deleteSize = readmeConfigMapper.deleteByStorageId(storageId); + log.info("删除存储源 ID 为 {} 的目录文档配置 {} 条", storageId, deleteSize); + return deleteSize; + } + + + /** + * 根据存储源指定路径下的 readme 配置 + * + * @param storageId + * 存储源ID + * + * @param path + * 文件夹路径 + * + * @return 存储源 readme 配置列表 + */ + public ReadmeConfig findReadmeByPath(Integer storageId, String path) { + List readmeConfigList = readmeConfigService.findByStorageId(storageId); + return getReadmeByTestPattern(storageId, readmeConfigList, path); + } + + + /** + * 根据存储源指定路径下的 readme 配置,如果指定为兼容模式,则会读取指定目录下的 readme.md 文件. + * + * @param storageId + * 存储源 ID + * + * @param path + * 存储源路径 + * + * @param compatibilityReadme + * 是否兼容为读取 readme.md 文件 + * + * @return 目录下存储源 readme 配置 + */ + public ReadmeConfig getByStorageAndPath(Integer storageId, String path, Boolean compatibilityReadme) { + ReadmeConfig readmeByPath = new ReadmeConfig(); + readmeByPath.setStorageId(storageId); + readmeByPath.setDisplayMode(ReadmeDisplayModeEnum.BOTTOM); + if (BooleanUtil.isTrue(compatibilityReadme)) { + try { + log.info("存储源 {} 兼容获取目录 {} 下的 readme.md", storageId, path); + AbstractBaseFileService abstractBaseFileService = storageSourceContext.getByStorageId(storageId); + String pathAndName = StringUtils.concat(path, "readme.md"); + FileItemResult fileItem = abstractBaseFileService.getFileItem(pathAndName); + if (fileItem != null) { + String url = fileItem.getUrl(); + String readmeText = HttpUtil.getTextContent(url); + readmeByPath.setReadmeText(readmeText); + } + } catch (Exception e) { + log.error("存储源 {} 兼容获取目录 {} 下的 readme.md 文件失败", storageId, path, e); + } + } else { + // 获取指定目录 readme 文件 + ReadmeConfig dbReadmeConfig = readmeConfigService.findReadmeByPath(storageId, path); + if (dbReadmeConfig != null) { + readmeByPath = dbReadmeConfig; + } + log.info("存储源 {} 规则模式获取目录 {} 下文档信息", storageId, path); + } + + return readmeByPath; + } + + + /** + * 根据规则表达式和测试字符串进行匹配,如测试字符串和其中一个规则匹配上,则返回 true,反之返回 false。 + * + * @param patternList + * 规则列表 + * + * @param test + * 测试字符串 + * + * @return 是否显示 + */ + private ReadmeConfig getReadmeByTestPattern(Integer storageId, List patternList, String test) { + // 如果目录文档规则为空, 则可直接返回空. + if (CollUtil.isEmpty(patternList)) { + if (log.isDebugEnabled()) { + log.debug("目录文档规则列表为空, 存储源 ID: {}, 测试字符串: {}", storageId, test); + } + return null; + } + + for (ReadmeConfig filterConfig : patternList) { + String expression = filterConfig.getExpression(); + + if (StrUtil.isEmpty(expression)) { + if (log.isDebugEnabled()) { + log.debug("存储源 {} 目录文档规则表达式为空: {}, 测试字符串: {}, 表达式为空,跳过该规则比对", storageId, expression, test); + } + continue; + } + + try { + boolean match = PatternMatcherUtils.testCompatibilityGlobPattern(expression, test); + + if (log.isDebugEnabled()) { + log.debug("存储源 {} 目录文档规则表达式: {}, 测试字符串: {}, 匹配结果: {}", storageId, expression, test, match); + } + + if (match) { + return filterConfig; + } + } catch (Exception e) { + log.error("存储源 {} 目录文档规则表达式: {}, 测试字符串: {}, 匹配异常,跳过该规则.", storageId, expression, test, e); + } + } + + return null; + } + + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/module/storage/annotation/CheckPassword.java b/src/main/java/im/zhaojun/zfile/module/storage/annotation/CheckPassword.java new file mode 100644 index 0000000..d5d4296 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/storage/annotation/CheckPassword.java @@ -0,0 +1,37 @@ +package im.zhaojun.zfile.module.storage.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 检查文件夹密码规则的注解, 判断是否有权限访问文件夹 + * + * @author zhaojun + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface CheckPassword { + + /** + * 存储源 key 字段表达式 + */ + String storageKeyFieldExpression(); + + /** + * 路径字段名称 + */ + String pathFieldExpression(); + + /** + * 密码字段名称 + */ + String passwordFieldExpression(); + + /** + * 路径是否是文件夹, 如果为 false, 则会取路径的父目录作为路径 + */ + boolean pathIsDirectory() default true; + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/annotation/RefererCheck.java b/src/main/java/im/zhaojun/zfile/module/storage/annotation/RefererCheck.java similarity index 88% rename from src/main/java/im/zhaojun/zfile/admin/annotation/RefererCheck.java rename to src/main/java/im/zhaojun/zfile/module/storage/annotation/RefererCheck.java index e90d64c..e949b92 100644 --- a/src/main/java/im/zhaojun/zfile/admin/annotation/RefererCheck.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/annotation/RefererCheck.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.annotation; +package im.zhaojun.zfile.module.storage.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/im/zhaojun/zfile/admin/annotation/StorageParamItem.java b/src/main/java/im/zhaojun/zfile/module/storage/annotation/StorageParamItem.java similarity index 93% rename from src/main/java/im/zhaojun/zfile/admin/annotation/StorageParamItem.java rename to src/main/java/im/zhaojun/zfile/module/storage/annotation/StorageParamItem.java index d102bbf..d68b90a 100644 --- a/src/main/java/im/zhaojun/zfile/admin/annotation/StorageParamItem.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/annotation/StorageParamItem.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.admin.annotation; +package im.zhaojun.zfile.module.storage.annotation; -import im.zhaojun.zfile.admin.model.enums.StorageParamTypeEnum; +import im.zhaojun.zfile.module.storage.model.enums.StorageParamTypeEnum; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/im/zhaojun/zfile/admin/annotation/StorageParamSelect.java b/src/main/java/im/zhaojun/zfile/module/storage/annotation/StorageParamSelect.java similarity index 71% rename from src/main/java/im/zhaojun/zfile/admin/annotation/StorageParamSelect.java rename to src/main/java/im/zhaojun/zfile/module/storage/annotation/StorageParamSelect.java index 5cf923c..2560209 100644 --- a/src/main/java/im/zhaojun/zfile/admin/annotation/StorageParamSelect.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/annotation/StorageParamSelect.java @@ -1,7 +1,7 @@ -package im.zhaojun.zfile.admin.annotation; +package im.zhaojun.zfile.module.storage.annotation; -import im.zhaojun.zfile.admin.model.param.IStorageParam; -import im.zhaojun.zfile.admin.annotation.model.StorageSourceParamDef; +import im.zhaojun.zfile.module.storage.model.param.IStorageParam; +import im.zhaojun.zfile.module.storage.model.bo.StorageSourceParamDef; import java.util.List; diff --git a/src/main/java/im/zhaojun/zfile/admin/annotation/StorageParamSelectOption.java b/src/main/java/im/zhaojun/zfile/module/storage/annotation/StorageParamSelectOption.java similarity index 90% rename from src/main/java/im/zhaojun/zfile/admin/annotation/StorageParamSelectOption.java rename to src/main/java/im/zhaojun/zfile/module/storage/annotation/StorageParamSelectOption.java index c52ec4f..0a48fbc 100644 --- a/src/main/java/im/zhaojun/zfile/admin/annotation/StorageParamSelectOption.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/annotation/StorageParamSelectOption.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.annotation; +package im.zhaojun.zfile.module.storage.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/im/zhaojun/zfile/admin/annotation/select/impl/EncodingStorageParamSelect.java b/src/main/java/im/zhaojun/zfile/module/storage/annotation/impl/EncodingStorageParamSelect.java similarity index 64% rename from src/main/java/im/zhaojun/zfile/admin/annotation/select/impl/EncodingStorageParamSelect.java rename to src/main/java/im/zhaojun/zfile/module/storage/annotation/impl/EncodingStorageParamSelect.java index debd005..869f8b2 100644 --- a/src/main/java/im/zhaojun/zfile/admin/annotation/select/impl/EncodingStorageParamSelect.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/annotation/impl/EncodingStorageParamSelect.java @@ -1,9 +1,9 @@ -package im.zhaojun.zfile.admin.annotation.select.impl; +package im.zhaojun.zfile.module.storage.annotation.impl; -import im.zhaojun.zfile.admin.annotation.StorageParamItem; -import im.zhaojun.zfile.admin.annotation.StorageParamSelect; -import im.zhaojun.zfile.admin.model.param.IStorageParam; -import im.zhaojun.zfile.admin.annotation.model.StorageSourceParamDef; +import im.zhaojun.zfile.module.storage.annotation.StorageParamItem; +import im.zhaojun.zfile.module.storage.annotation.StorageParamSelect; +import im.zhaojun.zfile.module.storage.model.param.IStorageParam; +import im.zhaojun.zfile.module.storage.model.bo.StorageSourceParamDef; import java.nio.charset.Charset; import java.util.ArrayList; diff --git a/src/main/java/im/zhaojun/zfile/module/storage/aspect/CheckPasswordAspect.java b/src/main/java/im/zhaojun/zfile/module/storage/aspect/CheckPasswordAspect.java new file mode 100644 index 0000000..5ac4eb2 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/storage/aspect/CheckPasswordAspect.java @@ -0,0 +1,92 @@ +package im.zhaojun.zfile.module.storage.aspect; + +import cn.hutool.core.util.StrUtil; +import im.zhaojun.zfile.module.password.model.dto.VerifyResultDTO; +import im.zhaojun.zfile.module.password.service.PasswordConfigService; +import im.zhaojun.zfile.module.storage.service.StorageSourceService; +import im.zhaojun.zfile.core.exception.PasswordVerifyException; +import im.zhaojun.zfile.core.exception.StorageSourceException; +import im.zhaojun.zfile.core.util.CodeMsg; +import im.zhaojun.zfile.core.util.StringUtils; +import im.zhaojun.zfile.module.storage.annotation.CheckPassword; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.Signature; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.expression.Expression; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.lang.reflect.Method; + +/** + * 检查密码切面 + * + * @author zhaojun + */ +@Aspect +@Component +@Slf4j +public class CheckPasswordAspect { + + @Resource + private PasswordConfigService passwordConfigService; + + @Resource + private StorageSourceService storageSourceService; + + /** + * 校验密码 + * + * @param point + * 连接点 + * + * @return 方法运行结果 + */ + @Around(value = "@annotation(im.zhaojun.zfile.module.storage.annotation.CheckPassword)") + public Object around(ProceedingJoinPoint point) throws Throwable { + Signature s = point.getSignature(); + MethodSignature ms = (MethodSignature) s; + Method method = ms.getMethod(); + CheckPassword checkPassword = method.getAnnotation(CheckPassword.class); + boolean pathIsDirectory = checkPassword.pathIsDirectory(); + String storageKeyFieldExpression = checkPassword.storageKeyFieldExpression(); + String passwordFieldExpression = checkPassword.passwordFieldExpression(); + String pathFieldExpression = checkPassword.pathFieldExpression(); + + Object[] args = point.getArgs(); + + String storageKeyFieldValue = getFieldValue(args, storageKeyFieldExpression); + String passwordFieldValue = getFieldValue(args, passwordFieldExpression); + String pathFieldValue = getFieldValue(args, pathFieldExpression); + + if (!pathIsDirectory) { + pathFieldValue = StringUtils.getParentPath(pathFieldValue); + } + + Integer storageId = storageSourceService.findIdByKey(storageKeyFieldValue); + + if (storageId == null) { + String message = StrUtil.format("执行文件操作「{}」时检测到存储源不存在", storageKeyFieldValue); + throw new StorageSourceException(CodeMsg.STORAGE_SOURCE_NOT_FOUND, storageId, message); + } + + VerifyResultDTO verifyResultDTO = passwordConfigService.verifyPassword(storageId, pathFieldValue, passwordFieldValue); + if (verifyResultDTO.isPassed()) { + return point.proceed(); + } else { + throw new PasswordVerifyException(verifyResultDTO.getCode(), verifyResultDTO.getMsg()); + } + } + + + public String getFieldValue(Object target, String expression) { + SpelExpressionParser parser = new SpelExpressionParser(); + Expression exp = parser.parseExpression(expression); + return (String) exp.getValue(target); + } + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/aspect/FileOperatorCheckAspect.java b/src/main/java/im/zhaojun/zfile/module/storage/aspect/FileOperatorCheckAspect.java similarity index 66% rename from src/main/java/im/zhaojun/zfile/home/aspect/FileOperatorCheckAspect.java rename to src/main/java/im/zhaojun/zfile/module/storage/aspect/FileOperatorCheckAspect.java index 2a6ff25..8ca9007 100644 --- a/src/main/java/im/zhaojun/zfile/home/aspect/FileOperatorCheckAspect.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/aspect/FileOperatorCheckAspect.java @@ -1,11 +1,12 @@ -package im.zhaojun.zfile.home.aspect; +package im.zhaojun.zfile.module.storage.aspect; import cn.hutool.core.util.BooleanUtil; -import im.zhaojun.zfile.admin.exception.ForbidFileOperationException; -import im.zhaojun.zfile.admin.model.entity.StorageSource; -import im.zhaojun.zfile.admin.model.enums.FileOperatorTypeEnum; -import im.zhaojun.zfile.admin.service.StorageSourceService; -import im.zhaojun.zfile.home.service.base.AbstractBaseFileService; +import im.zhaojun.zfile.core.exception.StorageSourceException; +import im.zhaojun.zfile.core.util.CodeMsg; +import im.zhaojun.zfile.module.storage.model.entity.StorageSource; +import im.zhaojun.zfile.module.storage.model.enums.FileOperatorTypeEnum; +import im.zhaojun.zfile.module.storage.service.StorageSourceService; +import im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; @@ -35,7 +36,7 @@ public class FileOperatorCheckAspect { * * @return 方法运行结果 */ - @Around("execution(public * im.zhaojun.zfile.home.service.base.AbstractBaseFileService.newFolder(..))") + @Around("execution(public * im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService.newFolder(..))") public Object newFolderAround(ProceedingJoinPoint point) throws Throwable { return check(point, FileOperatorTypeEnum.NEW_FOLDER); } @@ -48,7 +49,7 @@ public class FileOperatorCheckAspect { * * @return 方法运行结果 */ - @Around("execution(public * im.zhaojun.zfile.home.service.base.AbstractBaseFileService.delete*(..))") + @Around("execution(public * im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService.delete*(..))") public Object deleteAround(ProceedingJoinPoint point) throws Throwable { return check(point, FileOperatorTypeEnum.DELETE); } @@ -61,11 +62,11 @@ public class FileOperatorCheckAspect { * * @return 方法运行结果 */ - @Around("execution(public * im.zhaojun.zfile.home.service.base.AbstractBaseFileService.getUploadUrl(..))") + @Around("execution(public * im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService.getUploadUrl(..))") public Object uploadAround(ProceedingJoinPoint point) throws Throwable { return check(point, FileOperatorTypeEnum.UPLOAD); } - + /** * 重命名文件/文件夹权限校验 * @@ -74,7 +75,7 @@ public class FileOperatorCheckAspect { * * @return 方法运行结果 */ - @Around("execution(public * im.zhaojun.zfile.home.service.base.AbstractBaseFileService.rename*(..))") + @Around("execution(public * im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService.rename*(..))") public Object renameAround(ProceedingJoinPoint point) throws Throwable { return check(point, FileOperatorTypeEnum.RENAME); } @@ -97,13 +98,13 @@ public class FileOperatorCheckAspect { // 判断是否允许文件操作. 如果不允许, 则抛出异常 StorageSource storageSource = storageSourceService.findById(storageId); - boolean allowOperator = storageSource.allowOperator(); - + boolean allowOperator = storageSource.getAllowOperator(); + if (BooleanUtil.isFalse(allowOperator)) { - throw new ForbidFileOperationException(storageId, fileOperatorType.getName()); + throw new StorageSourceException(CodeMsg.STORAGE_SOURCE_ILLEGAL_OPERATION, storageId, "非法进行无权限的操作:" + fileOperatorType.getName()); } - + return point.proceed(); } - + } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/module/storage/aspect/FileOperatorExceptionWrapperAspect.java b/src/main/java/im/zhaojun/zfile/module/storage/aspect/FileOperatorExceptionWrapperAspect.java new file mode 100644 index 0000000..14f48ea --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/storage/aspect/FileOperatorExceptionWrapperAspect.java @@ -0,0 +1,139 @@ +package im.zhaojun.zfile.module.storage.aspect; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; +import im.zhaojun.zfile.core.exception.file.operator.StorageSourceFileOperatorException; +import im.zhaojun.zfile.core.util.CodeMsg; +import im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +/** + * 文件操作异常包装切面, 用于在存储源实现中不用分别捕获异常并处理,而是在此处统一将文件操作异常包装为 {@link StorageSourceFileOperatorException} 异常 + * + * @author zhaojun + */ +@Aspect +@Component +@Slf4j +@Order(2) +public class FileOperatorExceptionWrapperAspect { + + + @AfterThrowing(throwing = "error", value = "execution(public * im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService.newFolder(..))") + public void newExceptionWrapper(JoinPoint point, Throwable error) { + Integer storageId = getStorageId(point); + String path = getArgStr(point, 0); + String name = getArgStr(point, 1); + String errMsg = StrUtil.format("新建文件夹失败, 文件路径: {}, 文件名: {}", path, name); + throw new StorageSourceFileOperatorException(CodeMsg.STORAGE_SOURCE_FILE_NEW_FOLDER_FAIL, storageId, errMsg, error); + } + + @AfterThrowing(throwing = "error", value = "execution(public * im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService.delete*(..))") + public void deleteExceptionWrapper(JoinPoint point, Throwable error) { + Integer storageId = getStorageId(point); + String path = getArgStr(point, 0); + String name = getArgStr(point, 1); + String errMsg = StrUtil.format("删除文件/文件夹失败, 文件路径: {}, 文件名: {}", path, name); + throw new StorageSourceFileOperatorException(CodeMsg.STORAGE_SOURCE_FILE_DELETE_FAIL, storageId, errMsg, error); + } + + + @AfterThrowing(throwing = "error", value = "execution(public * im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService.rename*(..))") + public void renameExceptionWrapper(JoinPoint point, Throwable error) { + Integer storageId = getStorageId(point); + String path = getArgStr(point, 0); + String name = getArgStr(point, 1); + String newName = getArgStr(point, 2); + String errMsg = StrUtil.format("重命名文件/文件夹失败, 文件路径: {}, 原文件名: {}, 修改为: {}", path, name, newName); + throw new StorageSourceFileOperatorException(CodeMsg.STORAGE_SOURCE_FILE_RENAME_FAIL, storageId, errMsg, error); + } + + + @AfterThrowing(throwing = "error", value = "execution(public * im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService.getDownloadUrl(..))") + public void getDownloadUrl(JoinPoint point, Throwable error) { + Integer storageId = getStorageId(point); + String pathAndName = getArgStr(point, 0); + String errMsg = StrUtil.format("获取下载链接失败, 文件路径: {}", pathAndName); + throw new StorageSourceFileOperatorException(CodeMsg.STORAGE_SOURCE_FILE_GET_UPLOAD_FAIL, storageId, errMsg, error); + } + + @AfterThrowing(throwing = "error", value = "execution(public * im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService.getUploadUrl(..))") + public void getUploadUrlExceptionWrapper(JoinPoint point, Throwable error) { + Integer storageId = getStorageId(point); + String path = getArgStr(point, 0); + String name = getArgStr(point, 1); + String size = getArgStr(point, 2); + String errMsg = StrUtil.format("获取文件上传链接失败, 文件路径: {}, 文件名: {}, 文件大小: {}", path, name, size); + throw new StorageSourceFileOperatorException(CodeMsg.STORAGE_SOURCE_FILE_GET_UPLOAD_FAIL, storageId, errMsg, error); + } + + + @AfterThrowing(throwing = "error", value = "execution(public * im.zhaojun.zfile.module.storage.service.base.AbstractProxyTransferService.uploadFile(..))") + public void proxyUploadExceptionWrapper(JoinPoint point, Throwable error) { + Integer storageId = getStorageId(point); + String pathAndName = getArgStr(point, 0); + String errMsg = StrUtil.format("文件代理上传失败, 文件路径: {}", pathAndName); + throw new StorageSourceFileOperatorException(CodeMsg.STORAGE_SOURCE_FILE_PROXY_UPLOAD_FAIL, storageId, errMsg, error); + } + + + @AfterThrowing(throwing = "error", value = "execution(public * im.zhaojun.zfile.module.storage.service.base.AbstractProxyTransferService.downloadToStream(..))") + public void proxyDownloadExceptionWrapper(JoinPoint point, Throwable error) { + Integer storageId = getStorageId(point); + String pathAndName = getArgStr(point, 0); + String errMsg = StrUtil.format("文件代理下载失败, 文件路径: {}", pathAndName); + throw new StorageSourceFileOperatorException(CodeMsg.STORAGE_SOURCE_FILE_PROXY_DOWNLOAD_FAIL, storageId, errMsg, error); + } + + + @AfterThrowing(throwing = "error", value = "execution(public * im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService.getFileItem(..))") + public void getFileItemExceptionWrapper(JoinPoint point, Throwable error) { + Integer storageId = getStorageId(point); + String pathAndName = getArgStr(point, 0); + String errMsg = StrUtil.format("文件代理下载失败, 文件路径: {}", pathAndName); + throw new StorageSourceFileOperatorException(CodeMsg.STORAGE_SOURCE_FILE_DISABLE_PROXY_DOWNLOAD, storageId, errMsg, error); + } + + + /** + * 获取存储源 id + * + * @param point + * 切入点 + * + * @return 存储源 id + */ + private Integer getStorageId(JoinPoint point) { + AbstractBaseFileService targetService = (AbstractBaseFileService) point.getTarget(); + return targetService.getStorageId(); + } + + /** + * 获取切入点方法第 n 个参数 + * + * @param point + * 切入点 + * + * @param index + * 参数索引 + * + * @return 参数值 + */ + private Object getArg(JoinPoint point, int index) { + Object[] args = point.getArgs(); + return ArrayUtil.get(args, index); + } + + + private String getArgStr(JoinPoint point, int index) { + Object arg = getArg(point, index); + return Convert.toStr(arg); + } + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/chain/FileChain.java b/src/main/java/im/zhaojun/zfile/module/storage/chain/FileChain.java similarity index 74% rename from src/main/java/im/zhaojun/zfile/home/chain/FileChain.java rename to src/main/java/im/zhaojun/zfile/module/storage/chain/FileChain.java index ba83524..b990a1b 100644 --- a/src/main/java/im/zhaojun/zfile/home/chain/FileChain.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/chain/FileChain.java @@ -1,10 +1,10 @@ -package im.zhaojun.zfile.home.chain; +package im.zhaojun.zfile.module.storage.chain; -import im.zhaojun.zfile.home.chain.command.FileAccessPermissionVerifyCommand; -import im.zhaojun.zfile.home.chain.command.FileHiddenCommand; -import im.zhaojun.zfile.home.chain.command.FileSortCommand; -import im.zhaojun.zfile.home.chain.command.FileUrlAddVersionCommand; -import im.zhaojun.zfile.home.chain.command.FolderPasswordVerifyCommand; +import im.zhaojun.zfile.module.storage.chain.command.FileAccessPermissionVerifyCommand; +import im.zhaojun.zfile.module.storage.chain.command.FileHiddenCommand; +import im.zhaojun.zfile.module.storage.chain.command.FileSortCommand; +import im.zhaojun.zfile.module.storage.chain.command.FileUrlAddVersionCommand; +import im.zhaojun.zfile.module.storage.chain.command.FolderPasswordVerifyCommand; import lombok.extern.slf4j.Slf4j; import org.apache.commons.chain.impl.ChainBase; import org.springframework.stereotype.Service; diff --git a/src/main/java/im/zhaojun/zfile/home/chain/FileContext.java b/src/main/java/im/zhaojun/zfile/module/storage/chain/FileContext.java similarity index 78% rename from src/main/java/im/zhaojun/zfile/home/chain/FileContext.java rename to src/main/java/im/zhaojun/zfile/module/storage/chain/FileContext.java index 11e887a..1deac94 100644 --- a/src/main/java/im/zhaojun/zfile/home/chain/FileContext.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/chain/FileContext.java @@ -1,7 +1,7 @@ -package im.zhaojun.zfile.home.chain; +package im.zhaojun.zfile.module.storage.chain; -import im.zhaojun.zfile.home.model.request.FileListRequest; -import im.zhaojun.zfile.home.model.result.FileItemResult; +import im.zhaojun.zfile.module.storage.model.request.base.FileListRequest; +import im.zhaojun.zfile.module.storage.model.result.FileItemResult; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/im/zhaojun/zfile/home/chain/command/FileAccessPermissionVerifyCommand.java b/src/main/java/im/zhaojun/zfile/module/storage/chain/command/FileAccessPermissionVerifyCommand.java similarity index 52% rename from src/main/java/im/zhaojun/zfile/home/chain/command/FileAccessPermissionVerifyCommand.java rename to src/main/java/im/zhaojun/zfile/module/storage/chain/command/FileAccessPermissionVerifyCommand.java index 92d51ab..2cf5f51 100644 --- a/src/main/java/im/zhaojun/zfile/home/chain/command/FileAccessPermissionVerifyCommand.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/chain/command/FileAccessPermissionVerifyCommand.java @@ -1,8 +1,11 @@ -package im.zhaojun.zfile.home.chain.command; +package im.zhaojun.zfile.module.storage.chain.command; -import im.zhaojun.zfile.home.chain.FileContext; -import im.zhaojun.zfile.home.model.request.FileListRequest; -import im.zhaojun.zfile.admin.service.FilterConfigService; +import cn.hutool.core.util.StrUtil; +import im.zhaojun.zfile.core.exception.StorageSourceException; +import im.zhaojun.zfile.core.util.CodeMsg; +import im.zhaojun.zfile.module.filter.service.FilterConfigService; +import im.zhaojun.zfile.module.storage.chain.FileContext; +import im.zhaojun.zfile.module.storage.model.request.base.FileListRequest; import org.apache.commons.chain.Command; import org.apache.commons.chain.Context; import org.springframework.stereotype.Service; @@ -34,8 +37,15 @@ public class FileAccessPermissionVerifyCommand implements Command { FileContext fileContext = (FileContext) context; Integer storageId = fileContext.getStorageId(); FileListRequest fileListRequest = fileContext.getFileListRequest(); - - filterConfigService.checkPathPermission(storageId, fileListRequest.getPath()); + + // 检查文件目录是否是不可访问的, 如果是则抛出异常 + boolean isInaccessible = filterConfigService.checkFileIsInaccessible(storageId, fileListRequest.getPath()); + + if (isInaccessible) { + String errorMsg = StrUtil.format("文件目录 [{}] 无访问权限", fileListRequest.getPath()); + throw new StorageSourceException(CodeMsg.STORAGE_SOURCE_FILE_FORBIDDEN, storageId, errorMsg); + } + return false; } diff --git a/src/main/java/im/zhaojun/zfile/home/chain/command/FileHiddenCommand.java b/src/main/java/im/zhaojun/zfile/module/storage/chain/command/FileHiddenCommand.java similarity index 63% rename from src/main/java/im/zhaojun/zfile/home/chain/command/FileHiddenCommand.java rename to src/main/java/im/zhaojun/zfile/module/storage/chain/command/FileHiddenCommand.java index 14cfe10..aaa286d 100644 --- a/src/main/java/im/zhaojun/zfile/home/chain/command/FileHiddenCommand.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/chain/command/FileHiddenCommand.java @@ -1,17 +1,16 @@ -package im.zhaojun.zfile.home.chain.command; +package im.zhaojun.zfile.module.storage.chain.command; import cn.hutool.core.collection.CollUtil; -import im.zhaojun.zfile.admin.service.FilterConfigService; -import im.zhaojun.zfile.common.util.StringUtils; -import im.zhaojun.zfile.home.chain.FileContext; -import im.zhaojun.zfile.home.model.result.FileItemResult; +import im.zhaojun.zfile.module.filter.service.FilterConfigService; +import im.zhaojun.zfile.module.storage.chain.FileContext; +import im.zhaojun.zfile.module.storage.model.result.FileItemResult; import org.apache.commons.chain.Command; import org.apache.commons.chain.Context; import org.springframework.stereotype.Service; import javax.annotation.Resource; -import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; /** * 文件隐藏责任链 command 命令 @@ -25,7 +24,6 @@ public class FileHiddenCommand implements Command { @Resource private FilterConfigService filterConfigService; - /** * 隐藏存储源规律规则匹配到的文件. * @@ -38,22 +36,16 @@ public class FileHiddenCommand implements Command { public boolean execute(Context context) throws Exception { FileContext fileContext = (FileContext) context; Integer storageId = fileContext.getStorageId(); + List fileItemList = fileContext.getFileItemList(); if (CollUtil.isEmpty(fileItemList)) { return false; } - // 创建副本, 防止排序和过滤对原数据产生影响 - List result = new ArrayList<>(); - - fileItemList.forEach( - fileItem -> { - if (!filterConfigService.filterResultIsHidden(storageId, StringUtils.concat(fileItem.getPath(), fileItem.getName()))) { - result.add(fileItem); - } - } - ); - + List result = fileItemList.stream() + .filter(fileItem -> !filterConfigService.checkFileIsHidden(storageId, fileItem.getFullPath())) + .collect(Collectors.toList()); + fileContext.setFileItemList(result); return false; } diff --git a/src/main/java/im/zhaojun/zfile/home/chain/command/FileSortCommand.java b/src/main/java/im/zhaojun/zfile/module/storage/chain/command/FileSortCommand.java similarity index 81% rename from src/main/java/im/zhaojun/zfile/home/chain/command/FileSortCommand.java rename to src/main/java/im/zhaojun/zfile/module/storage/chain/command/FileSortCommand.java index 7fd5414..a518e72 100644 --- a/src/main/java/im/zhaojun/zfile/home/chain/command/FileSortCommand.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/chain/command/FileSortCommand.java @@ -1,9 +1,9 @@ -package im.zhaojun.zfile.home.chain.command; +package im.zhaojun.zfile.module.storage.chain.command; -import im.zhaojun.zfile.home.chain.FileContext; -import im.zhaojun.zfile.home.model.request.FileListRequest; -import im.zhaojun.zfile.home.model.result.FileItemResult; -import im.zhaojun.zfile.common.util.FileComparator; +import im.zhaojun.zfile.module.storage.chain.FileContext; +import im.zhaojun.zfile.module.storage.model.request.base.FileListRequest; +import im.zhaojun.zfile.module.storage.model.result.FileItemResult; +import im.zhaojun.zfile.core.util.FileComparator; import org.apache.commons.chain.Command; import org.apache.commons.chain.Context; import org.springframework.stereotype.Service; diff --git a/src/main/java/im/zhaojun/zfile/home/chain/command/FileUrlAddVersionCommand.java b/src/main/java/im/zhaojun/zfile/module/storage/chain/command/FileUrlAddVersionCommand.java similarity index 86% rename from src/main/java/im/zhaojun/zfile/home/chain/command/FileUrlAddVersionCommand.java rename to src/main/java/im/zhaojun/zfile/module/storage/chain/command/FileUrlAddVersionCommand.java index 70beb0d..8e5b0e8 100644 --- a/src/main/java/im/zhaojun/zfile/home/chain/command/FileUrlAddVersionCommand.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/chain/command/FileUrlAddVersionCommand.java @@ -1,8 +1,8 @@ -package im.zhaojun.zfile.home.chain.command; +package im.zhaojun.zfile.module.storage.chain.command; import cn.hutool.core.date.DateUtil; -import im.zhaojun.zfile.home.chain.FileContext; -import im.zhaojun.zfile.home.model.result.FileItemResult; +import im.zhaojun.zfile.module.storage.chain.FileContext; +import im.zhaojun.zfile.module.storage.model.result.FileItemResult; import org.apache.commons.chain.Command; import org.apache.commons.chain.Context; import org.springframework.stereotype.Service; diff --git a/src/main/java/im/zhaojun/zfile/home/chain/command/FolderPasswordVerifyCommand.java b/src/main/java/im/zhaojun/zfile/module/storage/chain/command/FolderPasswordVerifyCommand.java similarity index 63% rename from src/main/java/im/zhaojun/zfile/home/chain/command/FolderPasswordVerifyCommand.java rename to src/main/java/im/zhaojun/zfile/module/storage/chain/command/FolderPasswordVerifyCommand.java index b6a3d72..0e284b8 100644 --- a/src/main/java/im/zhaojun/zfile/home/chain/command/FolderPasswordVerifyCommand.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/chain/command/FolderPasswordVerifyCommand.java @@ -1,10 +1,10 @@ -package im.zhaojun.zfile.home.chain.command; +package im.zhaojun.zfile.module.storage.chain.command; -import im.zhaojun.zfile.home.chain.FileContext; -import im.zhaojun.zfile.common.exception.PasswordVerifyException; -import im.zhaojun.zfile.home.model.request.FileListRequest; -import im.zhaojun.zfile.admin.model.verify.VerifyResult; -import im.zhaojun.zfile.admin.service.PasswordConfigService; +import im.zhaojun.zfile.module.password.model.dto.VerifyResultDTO; +import im.zhaojun.zfile.module.password.service.PasswordConfigService; +import im.zhaojun.zfile.core.exception.PasswordVerifyException; +import im.zhaojun.zfile.module.storage.chain.FileContext; +import im.zhaojun.zfile.module.storage.model.request.base.FileListRequest; import org.apache.commons.chain.Command; import org.apache.commons.chain.Context; import org.springframework.stereotype.Service; @@ -22,7 +22,7 @@ public class FolderPasswordVerifyCommand implements Command { @Resource private PasswordConfigService passwordConfigService; - + /** * 校验当前文件是否需要密码. * @@ -34,20 +34,20 @@ public class FolderPasswordVerifyCommand implements Command { @Override public boolean execute(Context context) throws Exception { FileContext fileContext = (FileContext) context; - FileListRequest fileListRequest = fileContext.getFileListRequest(); Integer storageId = fileContext.getStorageId(); - + + FileListRequest fileListRequest = fileContext.getFileListRequest(); String path = fileListRequest.getPath(); String password = fileListRequest.getPassword(); - + // 校验密码, 如果校验不通过, 则返回错误消息 - VerifyResult verifyResult = passwordConfigService.verifyPassword(storageId, path, password); - if (!verifyResult.isPassed()) { - throw new PasswordVerifyException(verifyResult.getCode(), verifyResult.getMsg()); + VerifyResultDTO verifyResultDTO = passwordConfigService.verifyPassword(storageId, path, password); + if (!verifyResultDTO.isPassed()) { + throw new PasswordVerifyException(verifyResultDTO.getCode(), verifyResultDTO.getMsg()); } // 设置当前文件夹所对应的文件夹路径表达式. - fileContext.setPasswordPattern(verifyResult.getPattern());; + fileContext.setPasswordPattern(verifyResultDTO.getPattern());; return false; } diff --git a/src/main/java/im/zhaojun/zfile/admin/constant/StorageConfigConstant.java b/src/main/java/im/zhaojun/zfile/module/storage/constant/StorageConfigConstant.java similarity index 82% rename from src/main/java/im/zhaojun/zfile/admin/constant/StorageConfigConstant.java rename to src/main/java/im/zhaojun/zfile/module/storage/constant/StorageConfigConstant.java index 0225ccd..0d2295f 100644 --- a/src/main/java/im/zhaojun/zfile/admin/constant/StorageConfigConstant.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/constant/StorageConfigConstant.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.constant; +package im.zhaojun.zfile.module.storage.constant; /** * 存储源设置字段常量. diff --git a/src/main/java/im/zhaojun/zfile/common/context/StorageSourceContext.java b/src/main/java/im/zhaojun/zfile/module/storage/context/StorageSourceContext.java similarity index 66% rename from src/main/java/im/zhaojun/zfile/common/context/StorageSourceContext.java rename to src/main/java/im/zhaojun/zfile/module/storage/context/StorageSourceContext.java index 7e6d759..f80ff01 100644 --- a/src/main/java/im/zhaojun/zfile/common/context/StorageSourceContext.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/context/StorageSourceContext.java @@ -1,22 +1,23 @@ -package im.zhaojun.zfile.common.context; +package im.zhaojun.zfile.module.storage.context; import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.spring.SpringUtil; -import com.alibaba.fastjson.JSON; -import im.zhaojun.zfile.admin.annotation.StorageParamItem; -import im.zhaojun.zfile.admin.annotation.model.StorageSourceParamDef; -import im.zhaojun.zfile.admin.model.entity.StorageSource; -import im.zhaojun.zfile.admin.model.entity.StorageSourceConfig; -import im.zhaojun.zfile.admin.model.param.IStorageParam; -import im.zhaojun.zfile.admin.service.StorageSourceConfigService; -import im.zhaojun.zfile.admin.service.StorageSourceService; -import im.zhaojun.zfile.common.config.FlywayDbInitializer; -import im.zhaojun.zfile.common.exception.InvalidStorageSourceException; -import im.zhaojun.zfile.common.util.ClassUtils; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; -import im.zhaojun.zfile.home.service.base.AbstractBaseFileService; -import im.zhaojun.zfile.home.service.base.RefreshTokenService; +import im.zhaojun.zfile.module.storage.annotation.StorageParamItem; +import im.zhaojun.zfile.module.storage.model.bo.StorageSourceParamDef; +import im.zhaojun.zfile.module.storage.model.entity.StorageSource; +import im.zhaojun.zfile.module.storage.model.entity.StorageSourceConfig; +import im.zhaojun.zfile.module.storage.model.param.IStorageParam; +import im.zhaojun.zfile.module.storage.service.StorageSourceConfigService; +import im.zhaojun.zfile.module.storage.service.StorageSourceService; +import im.zhaojun.zfile.core.config.FlywayDbInitializer; +import im.zhaojun.zfile.core.exception.file.init.InitializeStorageSourceException; +import im.zhaojun.zfile.core.exception.file.InvalidStorageSourceException; +import im.zhaojun.zfile.core.util.ClassUtils; +import im.zhaojun.zfile.core.util.CodeMsg; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService; +import im.zhaojun.zfile.module.storage.service.base.RefreshTokenService; import lombok.extern.slf4j.Slf4j; import org.springframework.aop.support.AopUtils; import org.springframework.beans.BeansException; @@ -33,11 +34,12 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; /** * 每个存储源对应一个 Service, 其中初始化好了与对象存储的配置信息. * 此存储源上下文环境用户缓存每个 Service, 避免重复初始化. - * + *
      * 依赖 {@link FlywayDbInitializer} 初始化数据库后执行. * * @author zhaojun @@ -51,17 +53,19 @@ public class StorageSourceContext implements ApplicationContextAware { * Map * Map<存储源 ID, 存储源 Service> */ - private static final Map DRIVES_SERVICE_MAP = new ConcurrentHashMap<>(); + private static final Map> DRIVES_SERVICE_MAP = new ConcurrentHashMap<>(); + + + /** + * Map<存储源类型, 存储源 Service> + */ + private static Map storageTypeEnumFileServiceMap; /** * 缓存每个存储源参数的字段列表. */ - Map, Map> PARAM_CLASS_FIELD_NAME_MAP_CACHE = new HashMap<>(); + private final Map, Map> PARAM_CLASS_FIELD_NAME_MAP_CACHE = new HashMap<>(); - /** - * Map<存储源类型, 存储源 Service> - */ - private static Map storageTypeEnumFileServiceMap; @Resource private StorageSourceService storageSourceService; @@ -81,103 +85,16 @@ public class StorageSourceContext implements ApplicationContextAware { for (StorageSource storageSource : list) { try { init(storageSource.getId()); - log.info("启动时初始化存储源成功, 存储源信息: {}", JSON.toJSONString(storageSource)); + log.info("启动时初始化存储源成功, 存储源 id: {}, 存储源类型: {}, 存储源名称: {}", + storageSource.getId(), storageSource.getType().getDescription(), storageSource.getName()); } catch (Exception e) { - log.error("启动时初始化存储源失败, 存储源信息: {}", JSON.toJSONString(storageSource), e); + log.error("启动时初始化存储源失败, 存储源 id: {}, 存储源类型: {}, 存储源名称: {}", + storageSource.getId(), storageSource.getType().getDescription(), storageSource.getName(), e); } } } - - - /** - * 初始化指定存储源的 Service, 添加到上下文环境中. - * - * @param storageId - * 存储源 ID. - */ - public void init(Integer storageId) { - AbstractBaseFileService baseFileService = getInitStorageBeanByStorageId(storageId); - if (baseFileService != null) { - if (log.isDebugEnabled()) { - log.debug("尝试初始化存储源, storageId: {}", storageId); - } - - baseFileService.setStorageId(storageId); - IStorageParam initParam = getInitParam(storageId, baseFileService); - baseFileService.setParam(initParam); - - baseFileService.init(); - - baseFileService.testConnection(); - if (log.isDebugEnabled()) { - log.debug("初始化存储源成功, storageId: {}", storageId); - } - DRIVES_SERVICE_MAP.put(storageId, baseFileService); - } - } - - /** - * 获取指定存储源的初始化参数. - * - * @param storageId - * 存储源 ID - * - * @return 存储源初始化参数 - */ - private IStorageParam getInitParam(Integer storageId, AbstractBaseFileService baseFileService) { - List storageSourceConfigList = storageSourceConfigService.selectStorageConfigByStorageId(storageId); - - // 获取存储源实现类的实际 Class - Class beanTargetClass = AopUtils.getTargetClass(baseFileService); - // 获取存储源实现类的实际 Class 的泛型参数类型 - Class paramClass = ClassUtils.getClassFirstGenericsParam(beanTargetClass); - String paramClassName = paramClass.getName(); - - IStorageParam iStorageParam = ReflectUtil.newInstance(paramClassName); - - - // 获取存储器参数 key -> 存储器 field 对照关系,如果缓存中有,则从缓存中取. - Map fieldMap = new HashMap<>(); - if (PARAM_CLASS_FIELD_NAME_MAP_CACHE.containsKey(paramClass)) { - fieldMap = PARAM_CLASS_FIELD_NAME_MAP_CACHE.get(paramClass); - } else { - Field[] fields = ReflectUtil.getFieldsDirectly(paramClass, true); - for (Field field : fields) { - String key; - - StorageParamItem storageParamItem = field.getDeclaredAnnotation(StorageParamItem.class); - // 没有注解或注解中没有配置 key 则使用字段名. - if (storageParamItem == null || StrUtil.isEmpty(storageParamItem.key())) { - key = field.getName(); - } else { - key = storageParamItem.key(); - } - - // 如果 map 中包含此 key, 则是父类的, 跳过. - if (fieldMap.containsKey(key)) { - continue; - } - - fieldMap.put(key, field); - } - PARAM_CLASS_FIELD_NAME_MAP_CACHE.put(paramClass, fieldMap); - } - - for (StorageSourceConfig storageSourceConfig : storageSourceConfigList) { - String name = storageSourceConfig.getName(); - String value = storageSourceConfig.getValue(); - try { - Field field = fieldMap.get(name); - ReflectUtil.setFieldValue(iStorageParam, field, value); - } catch (Exception e) { - log.error("初始化存储源参数失败, storageId: {}, name: {}, value: {}", storageId, name, value, e); - } - } - - return iStorageParam; - } - - + + /** * 根据存储源 id 获取对应的 Service. * @@ -186,15 +103,15 @@ public class StorageSourceContext implements ApplicationContextAware { * * @return 存储源对应的 Service */ - public AbstractBaseFileService get(Integer storageId) { + public AbstractBaseFileService getByStorageId(Integer storageId) { AbstractBaseFileService abstractBaseFileService = DRIVES_SERVICE_MAP.get(storageId); if (abstractBaseFileService == null) { - throw new InvalidStorageSourceException("无效的存储源, storageId: " + storageId); + throw new InvalidStorageSourceException(storageId); } return abstractBaseFileService; } - - + + /** * 根据存储源 key 获取对应的 Service. * @@ -203,26 +120,12 @@ public class StorageSourceContext implements ApplicationContextAware { * * @return 存储源对应的 Service */ - public AbstractBaseFileService getByKey(String key) { + public AbstractBaseFileService getByStorageKey(String key) { Integer storageId = storageSourceService.findIdByKey(key); if (storageId == null) { return null; } - return get(storageId); - } - - - /** - * 销毁指定存储源的 Service. - * - * @param storageId - * 存储源 ID - */ - public void destroy(Integer storageId) { - if (log.isDebugEnabled()) { - log.debug("清理存储源上下文对象, storageId: {}", storageId); - } - DRIVES_SERVICE_MAP.remove(storageId); + return getByStorageId(storageId); } @@ -235,20 +138,42 @@ public class StorageSourceContext implements ApplicationContextAware { * @return 指定类型存储源的参数列表. {@link AbstractBaseFileService#getStorageSourceParamList()} */ public static List getStorageSourceParamListByType(StorageTypeEnum type) { - AbstractBaseFileService service = null; - for (AbstractBaseFileService fileService : storageTypeEnumFileServiceMap.values()) { - if (fileService.getStorageTypeEnum() == type) { - service = fileService; - break; - } - } - if (service != null) { - return service.getStorageSourceParamList(); - } - return Collections.emptyList(); + return storageTypeEnumFileServiceMap.values().stream() + // 根据存储源类型找到第一个匹配的 Service + .filter(fileService -> fileService.getStorageTypeEnum() == type) + .findFirst() + // 获取该 Service 的参数列表 + .map((Function>) AbstractBaseFileService::getStorageSourceParamList) + // 如果没有找到, 则返回空列表 + .orElse(Collections.emptyList()); } - - + + + /** + * 初始化指定存储源的 Service, 添加到上下文环境中. + * + * @param storageId + * 存储源 ID. + */ + public void init(Integer storageId) { + AbstractBaseFileService baseFileService = getInitStorageBeanByStorageId(storageId); + if (baseFileService == null) { + throw new InvalidStorageSourceException(storageId); + } + + // 填充初始化参数 + baseFileService.setStorageId(storageId); + IStorageParam initParam = getInitParam(storageId, baseFileService); + baseFileService.setParam(initParam); + + // 进行初始化并测试连接 + baseFileService.init(); + baseFileService.testConnection(); + + DRIVES_SERVICE_MAP.put(storageId, baseFileService); + } + + /** * 获取指定存储源初始状态的 Service. * @@ -257,7 +182,7 @@ public class StorageSourceContext implements ApplicationContextAware { * * @return 存储源对应未初始化的 Service */ - private AbstractBaseFileService getInitStorageBeanByStorageId(Integer storageId) { + private AbstractBaseFileService getInitStorageBeanByStorageId(Integer storageId) { StorageTypeEnum storageTypeEnum = storageSourceService.findStorageTypeById(storageId); for (AbstractBaseFileService value : storageTypeEnumFileServiceMap.values()) { if (Objects.equals(value.getStorageTypeEnum(), storageTypeEnum)) { @@ -266,8 +191,70 @@ public class StorageSourceContext implements ApplicationContextAware { } return null; } + + + /** + * 获取指定存储源的初始化参数. + * + * @param storageId + * 存储源 ID + * + * @return 存储源初始化参数 + */ + private IStorageParam getInitParam(Integer storageId, AbstractBaseFileService baseFileService) { + // 获取存储源实现类的实际 Class + Class beanTargetClass = AopUtils.getTargetClass(baseFileService); + // 获取存储源实现类的实际 Class 的泛型参数类型 + Class paramClass = ClassUtils.getClassFirstGenericsParam(beanTargetClass); + + // 获取存储器参数 key -> 存储器 field 对照关系,如果缓存中有,则从缓存中取. + Map fieldMap = new HashMap<>(); + if (PARAM_CLASS_FIELD_NAME_MAP_CACHE.containsKey(paramClass)) { + fieldMap = PARAM_CLASS_FIELD_NAME_MAP_CACHE.get(paramClass); + } else { + Field[] fields = ReflectUtil.getFieldsDirectly(paramClass, true); + for (Field field : fields) { + String key; + + StorageParamItem storageParamItem = field.getDeclaredAnnotation(StorageParamItem.class); + // 没有注解或注解中没有配置 key 则使用字段名. + if (storageParamItem == null || StrUtil.isEmpty(storageParamItem.key())) { + key = field.getName(); + } else { + key = storageParamItem.key(); + } + + // 如果 map 中包含此 key, 则是父类的, 跳过. + if (fieldMap.containsKey(key)) { + continue; + } + + fieldMap.put(key, field); + } + PARAM_CLASS_FIELD_NAME_MAP_CACHE.put(paramClass, fieldMap); + } + + // 实例化参数对象 + IStorageParam iStorageParam = ReflectUtil.newInstance(paramClass.getName()); + + // 给所有字段填充值 + List storageSourceConfigList = storageSourceConfigService.selectStorageConfigByStorageId(storageId); + for (StorageSourceConfig storageSourceConfig : storageSourceConfigList) { + String name = storageSourceConfig.getName(); + String value = storageSourceConfig.getValue(); + try { + Field field = fieldMap.get(name); + ReflectUtil.setFieldValue(iStorageParam, field, value); + } catch (Exception e) { + String errMsg = StrUtil.format("为字段 {} 初始化值 {} 失败", name, value); + throw new InitializeStorageSourceException(CodeMsg.STORAGE_SOURCE_INIT_STORAGE_PARAM_FIELD_FAIL, storageId, errMsg, e).setResponseExceptionMessage(true); + } + } + + return iStorageParam; + } - + /** * 获取所有 AccessToken 机制的存储源, 这些存储源都继承类 {@link RefreshTokenService}. * @@ -276,7 +263,7 @@ public class StorageSourceContext implements ApplicationContextAware { public Map getAllRefreshTokenStorageSource() { Map result = new HashMap<>(); - for (Map.Entry baseFileServiceEntry : DRIVES_SERVICE_MAP.entrySet()) { + for (Map.Entry> baseFileServiceEntry : DRIVES_SERVICE_MAP.entrySet()) { Integer storageId = baseFileServiceEntry.getKey(); AbstractBaseFileService baseFileService = baseFileServiceEntry.getValue(); // 如果未初始化成功, 则直接跳过 @@ -291,5 +278,18 @@ public class StorageSourceContext implements ApplicationContextAware { return result; } - + + + /** + * 销毁指定存储源的 Service. + * + * @param storageId + * 存储源 ID + */ + public void destroy(Integer storageId) { + log.info("清理存储源上下文对象, storageId: {}", storageId); + DRIVES_SERVICE_MAP.remove(storageId); + } + + } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/controller/stroage/StorageMetaDataController.java b/src/main/java/im/zhaojun/zfile/module/storage/controller/base/StorageMetaDataController.java similarity index 83% rename from src/main/java/im/zhaojun/zfile/admin/controller/stroage/StorageMetaDataController.java rename to src/main/java/im/zhaojun/zfile/module/storage/controller/base/StorageMetaDataController.java index f3e2bb2..474a977 100644 --- a/src/main/java/im/zhaojun/zfile/admin/controller/stroage/StorageMetaDataController.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/controller/base/StorageMetaDataController.java @@ -1,11 +1,11 @@ -package im.zhaojun.zfile.admin.controller.stroage; +package im.zhaojun.zfile.module.storage.controller.base; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiSort; -import im.zhaojun.zfile.common.context.StorageSourceContext; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; -import im.zhaojun.zfile.admin.annotation.model.StorageSourceParamDef; -import im.zhaojun.zfile.common.util.AjaxJson; +import im.zhaojun.zfile.module.storage.context.StorageSourceContext; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.model.bo.StorageSourceParamDef; +import im.zhaojun.zfile.core.util.AjaxJson; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.GetMapping; diff --git a/src/main/java/im/zhaojun/zfile/admin/controller/stroage/StorageSourceController.java b/src/main/java/im/zhaojun/zfile/module/storage/controller/base/StorageSourceController.java similarity index 77% rename from src/main/java/im/zhaojun/zfile/admin/controller/stroage/StorageSourceController.java rename to src/main/java/im/zhaojun/zfile/module/storage/controller/base/StorageSourceController.java index 8616b90..b6896bb 100644 --- a/src/main/java/im/zhaojun/zfile/admin/controller/stroage/StorageSourceController.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/controller/base/StorageSourceController.java @@ -1,16 +1,16 @@ -package im.zhaojun.zfile.admin.controller.stroage; +package im.zhaojun.zfile.module.storage.controller.base; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiSort; -import im.zhaojun.zfile.admin.model.entity.StorageSource; -import im.zhaojun.zfile.admin.model.request.SaveStorageSourceRequest; -import im.zhaojun.zfile.admin.model.result.storage.StorageSourceAdminResult; -import im.zhaojun.zfile.admin.service.StorageSourceService; -import im.zhaojun.zfile.common.cache.RefreshTokenCache; -import im.zhaojun.zfile.common.util.AjaxJson; -import im.zhaojun.zfile.home.convert.StorageSourceConvert; -import im.zhaojun.zfile.home.model.dto.StorageSourceDTO; -import im.zhaojun.zfile.home.model.request.UpdateStorageSortRequest; +import im.zhaojun.zfile.module.storage.model.entity.StorageSource; +import im.zhaojun.zfile.module.storage.model.request.base.SaveStorageSourceRequest; +import im.zhaojun.zfile.module.storage.model.result.StorageSourceAdminResult; +import im.zhaojun.zfile.module.storage.service.StorageSourceService; +import im.zhaojun.zfile.module.storage.model.bo.RefreshTokenCacheBO; +import im.zhaojun.zfile.core.util.AjaxJson; +import im.zhaojun.zfile.module.storage.convert.StorageSourceConvert; +import im.zhaojun.zfile.module.storage.model.dto.StorageSourceDTO; +import im.zhaojun.zfile.module.storage.model.request.admin.UpdateStorageSortRequest; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; @@ -53,7 +53,7 @@ public class StorageSourceController { List storageSourceAdminResults = storageSourceConvert.entityToAdminResultList(list); storageSourceAdminResults.forEach(storageSourceAdminResult -> { - RefreshTokenCache.RefreshTokenInfo refreshTokenInfo = RefreshTokenCache.getRefreshTokenInfo(storageSourceAdminResult.getId()); + RefreshTokenCacheBO.RefreshTokenInfo refreshTokenInfo = RefreshTokenCacheBO.getRefreshTokenInfo(storageSourceAdminResult.getId()); storageSourceAdminResult.setRefreshTokenInfo(refreshTokenInfo); }); @@ -63,10 +63,10 @@ public class StorageSourceController { @ApiOperationSupport(order = 2) @ApiOperation(value = "获取指定存储源参数", notes = "获取指定存储源基本信息及其参数") - @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true) + @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true, dataTypeClass = Integer.class) @GetMapping("/storage/{storageId}") public AjaxJson storageItem(@PathVariable Integer storageId) { - StorageSourceDTO storageSourceDTO = storageSourceService.findStorageSourceDTOById(storageId); + StorageSourceDTO storageSourceDTO = storageSourceService.findDTOById(storageId); return AjaxJson.getSuccessData(storageSourceDTO); } @@ -74,15 +74,15 @@ public class StorageSourceController { @ApiOperationSupport(order = 3) @ApiOperation(value = "保存存储源参数", notes = "保存存储源的所有参数") @PostMapping("/storage") - public AjaxJson saveStorageItem(@RequestBody SaveStorageSourceRequest saveStorageSourceRequest) { - storageSourceService.saveStorageSource(saveStorageSourceRequest); - return AjaxJson.getSuccess(); + public AjaxJson saveStorageItem(@RequestBody SaveStorageSourceRequest saveStorageSourceRequest) { + Integer id = storageSourceService.saveStorageSource(saveStorageSourceRequest); + return AjaxJson.getSuccessData(id); } @ApiOperationSupport(order = 4) @ApiOperation(value = "删除存储源", notes = "删除存储源基本设置和拓展设置") - @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true) + @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true, dataTypeClass = Integer.class) @DeleteMapping("/storage/{storageId}") public AjaxJson deleteStorageItem(@PathVariable Integer storageId) { storageSourceService.deleteById(storageId); @@ -92,7 +92,7 @@ public class StorageSourceController { @ApiOperationSupport(order = 5) @ApiOperation(value = "启用存储源", notes = "开启存储源后可在前台显示") - @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true) + @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true, dataTypeClass = Integer.class) @PostMapping("/storage/{storageId}/enable") public AjaxJson enable(@PathVariable Integer storageId) { StorageSource storageSource = storageSourceService.findById(storageId); @@ -104,7 +104,7 @@ public class StorageSourceController { @ApiOperationSupport(order = 6) @ApiOperation(value = "停止存储源", notes = "停用存储源后不在前台显示") - @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true) + @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true, dataTypeClass = Integer.class) @PostMapping("/storage/{storageId}/disable") public AjaxJson disable(@PathVariable Integer storageId) { StorageSource storageSource = storageSourceService.findById(storageId); @@ -125,18 +125,19 @@ public class StorageSourceController { @ApiOperationSupport(order = 8) @ApiOperation(value = "校验存储源 key 是否重复") - @ApiImplicitParam(paramType = "query", name = "storageKey", value = "存储源 key", required = true) + @ApiImplicitParam(paramType = "query", name = "storageKey", value = "存储源 key", required = true, dataTypeClass = String.class) @GetMapping("/storage/exist/key") public AjaxJson existKey(String storageKey) { boolean exist = storageSourceService.existByStorageKey(storageKey); return AjaxJson.getSuccessData(exist); } - + + @ApiOperationSupport(order = 9) @ApiOperation(value = "修改 readme 兼容模式", notes = "修改 readme 兼容模式是否启用") @ApiImplicitParams({ - @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true), - @ApiImplicitParam(paramType = "path", name = "status", value = "存储源兼容模式状态", required = true) + @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true, dataTypeClass = Integer.class), + @ApiImplicitParam(paramType = "path", name = "status", value = "存储源兼容模式状态", required = true, dataTypeClass = Boolean.class) }) @PostMapping("/storage/{storageId}/compatibility_readme/{status}") public AjaxJson changeCompatibilityReadme(@PathVariable Integer storageId, @PathVariable Boolean status) { diff --git a/src/main/java/im/zhaojun/zfile/common/controller/callback/GdCallbackController.java b/src/main/java/im/zhaojun/zfile/module/storage/controller/callback/GoogleDriveCallbackController.java similarity index 89% rename from src/main/java/im/zhaojun/zfile/common/controller/callback/GdCallbackController.java rename to src/main/java/im/zhaojun/zfile/module/storage/controller/callback/GoogleDriveCallbackController.java index a63fa51..f6aac5d 100644 --- a/src/main/java/im/zhaojun/zfile/common/controller/callback/GdCallbackController.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/controller/callback/GoogleDriveCallbackController.java @@ -1,10 +1,10 @@ -package im.zhaojun.zfile.common.controller.callback; +package im.zhaojun.zfile.module.storage.controller.callback; import cn.hutool.core.codec.Base64; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSONObject; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; -import im.zhaojun.zfile.admin.model.dto.OAuth2Token; +import im.zhaojun.zfile.module.storage.model.dto.OAuth2TokenDTO; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; @@ -34,7 +34,7 @@ import java.net.HttpURLConnection; @Controller @Slf4j @RequestMapping(value = {"/gd"}) -public class GdCallbackController { +public class GoogleDriveCallbackController { @Value("${zfile.gd.clientId}") private String clientId; @@ -74,7 +74,7 @@ public class GdCallbackController { } @GetMapping("/callback") - public String gdCallback(String code, String state, Model model) { + public String googleDriveCallback(String code, String state, Model model) { log.info("gd 授权回调参数信息: code: {}, state: {}", code, state); String clientId, clientSecret, redirectUri; @@ -111,18 +111,18 @@ public class GdCallbackController { String body = response.getBody(); log.info("{} 根据授权回调 code 获取令牌结果:body: {}", this, body); - OAuth2Token oAuth2Token ; + OAuth2TokenDTO oAuth2TokenDTO; if (response.getStatusCode() != HttpStatus.OK) { - oAuth2Token = OAuth2Token.fail(clientId, clientSecret, redirectUri, body); + oAuth2TokenDTO = OAuth2TokenDTO.fail(clientId, clientSecret, redirectUri, body); } else { JSONObject jsonBody = JSONObject.parseObject(body); String accessToken = jsonBody.getString("access_token"); String refreshToken = jsonBody.getString("refresh_token"); - oAuth2Token = - OAuth2Token.success(clientId, clientSecret, redirectUri, accessToken, refreshToken, body); + oAuth2TokenDTO = + OAuth2TokenDTO.success(clientId, clientSecret, redirectUri, accessToken, refreshToken, body); } - model.addAttribute("oauth2Token", oAuth2Token); + model.addAttribute("oauth2Token", oAuth2TokenDTO); model.addAttribute("type", "Google Drive"); return "callback"; } diff --git a/src/main/java/im/zhaojun/zfile/common/controller/callback/OneDriveCallbackController.java b/src/main/java/im/zhaojun/zfile/module/storage/controller/callback/OneDriveCallbackController.java similarity index 89% rename from src/main/java/im/zhaojun/zfile/common/controller/callback/OneDriveCallbackController.java rename to src/main/java/im/zhaojun/zfile/module/storage/controller/callback/OneDriveCallbackController.java index dbbc26e..d0c187a 100644 --- a/src/main/java/im/zhaojun/zfile/common/controller/callback/OneDriveCallbackController.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/controller/callback/OneDriveCallbackController.java @@ -1,11 +1,11 @@ -package im.zhaojun.zfile.common.controller.callback; +package im.zhaojun.zfile.module.storage.controller.callback; import cn.hutool.core.codec.Base64; import cn.hutool.core.util.StrUtil; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; -import im.zhaojun.zfile.admin.model.dto.OAuth2Token; -import im.zhaojun.zfile.home.service.impl.OneDriveChinaServiceImpl; -import im.zhaojun.zfile.home.service.impl.OneDriveServiceImpl; +import im.zhaojun.zfile.module.storage.model.dto.OAuth2TokenDTO; +import im.zhaojun.zfile.module.storage.service.impl.OneDriveChinaServiceImpl; +import im.zhaojun.zfile.module.storage.service.impl.OneDriveServiceImpl; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; @@ -80,10 +80,10 @@ public class OneDriveCallbackController { redirectUri = stateArr[2]; } - OAuth2Token OAuth2Token = oneDriveServiceImpl.getToken(code, clientId, clientSecret, redirectUri); - log.info("onedrive 国际版授权回调获取令牌结果: {}", OAuth2Token); + OAuth2TokenDTO Oauth2TokenDTO = oneDriveServiceImpl.getToken(code, clientId, clientSecret, redirectUri); + log.info("onedrive 国际版授权回调获取令牌结果: {}", Oauth2TokenDTO); - model.addAttribute("oauth2Token", OAuth2Token); + model.addAttribute("oauth2Token", Oauth2TokenDTO); model.addAttribute("type", "OneDrive 国际版"); return "callback"; } @@ -135,10 +135,10 @@ public class OneDriveCallbackController { redirectUri = stateArr[2]; } - OAuth2Token OAuth2Token = oneDriveChinaServiceImpl.getToken(code, clientId, clientSecret, redirectUri); - log.info("onedrive 世纪互联版授权回调获取令牌结果: {}", OAuth2Token); + OAuth2TokenDTO OAuth2TokenDTO = oneDriveChinaServiceImpl.getToken(code, clientId, clientSecret, redirectUri); + log.info("onedrive 世纪互联版授权回调获取令牌结果: {}", OAuth2TokenDTO); - model.addAttribute("oauth2Token", OAuth2Token); + model.addAttribute("oauth2Token", OAuth2TokenDTO); model.addAttribute("type", "OneDrive 世纪互联"); return "callback"; } diff --git a/src/main/java/im/zhaojun/zfile/module/storage/controller/file/FileController.java b/src/main/java/im/zhaojun/zfile/module/storage/controller/file/FileController.java new file mode 100644 index 0000000..f15d1e3 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/storage/controller/file/FileController.java @@ -0,0 +1 @@ +package im.zhaojun.zfile.module.storage.controller.file; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiSort; import im.zhaojun.zfile.module.storage.model.entity.StorageSource; import im.zhaojun.zfile.module.storage.service.StorageSourceService; import im.zhaojun.zfile.module.storage.context.StorageSourceContext; import im.zhaojun.zfile.core.exception.file.InvalidStorageSourceException; import im.zhaojun.zfile.core.util.AjaxJson; import im.zhaojun.zfile.module.storage.annotation.CheckPassword; import im.zhaojun.zfile.module.storage.chain.FileChain; import im.zhaojun.zfile.module.storage.chain.FileContext; import im.zhaojun.zfile.module.storage.convert.StorageSourceConvert; import im.zhaojun.zfile.module.storage.model.request.base.FileItemRequest; import im.zhaojun.zfile.module.storage.model.request.base.FileListRequest; import im.zhaojun.zfile.module.storage.model.result.FileInfoResult; import im.zhaojun.zfile.module.storage.model.result.FileItemResult; import im.zhaojun.zfile.module.storage.model.result.StorageSourceResult; import im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import javax.validation.Valid; import java.util.List; /** * 文件列表相关接口, 如展示存储源列表, 展示文件列表, 搜索文件列表等. * * @author zhaojun */ @Api(tags = "文件列表模块") @ApiSort(2) @Slf4j @RequestMapping("/api/storage") @RestController public class FileController { @Resource private StorageSourceContext storageSourceContext; @Resource private StorageSourceService storageSourceService; @Resource private FileChain fileChain; @Resource private StorageSourceConvert storageSourceConvert; @ApiOperationSupport(order = 1) @ApiOperation(value = "获取存储源列表", notes = "获取所有已启用的存储源, 并且按照后台顺序排序") @GetMapping("/list") public AjaxJson> storageList() { List storageList = storageSourceService.findAllEnableOrderByOrderNum(); List storageSourceResultList = storageSourceConvert.entityToResultList(storageList); return AjaxJson.getSuccessData(storageSourceResultList); } @ApiOperationSupport(order = 2) @ApiOperation(value = "获取文件列表", notes = "获取某个存储源下, 指定路径的文件&文件夹列表") @PostMapping("/files") public AjaxJson list(@Valid @RequestBody FileListRequest fileListRequest) throws Exception { String storageKey = fileListRequest.getStorageKey(); Integer storageId = storageSourceService.findIdByKey(storageKey); if (storageId == null) { throw new InvalidStorageSourceException("通过存储源 key 未找到存储源, key: " + storageKey); } // 处理请求参数默认值 fileListRequest.handleDefaultValue(); // 获取文件列表 AbstractBaseFileService fileService = storageSourceContext.getByStorageId(storageId); List fileItemList = fileService.fileList(fileListRequest.getPath()); // 执行责任链 FileContext fileContext = FileContext.builder() .storageId(storageId) .fileListRequest(fileListRequest) .fileItemList(fileItemList).build(); fileChain.execute(fileContext); return AjaxJson.getSuccessData(new FileInfoResult(fileContext.getFileItemList(), fileContext.getPasswordPattern())); } @ApiOperationSupport(order = 3) @ApiOperation(value = "获取单个文件信息", notes = "获取某个存储源下, 单个文件的信息") @PostMapping("/file/item") @CheckPassword(storageKeyFieldExpression = "[0].storageKey", pathFieldExpression = "[0].path", pathIsDirectory = false, passwordFieldExpression = "[0].password") public AjaxJson fileItem(@Valid @RequestBody FileItemRequest fileItemRequest) { String storageKey = fileItemRequest.getStorageKey(); Integer storageId = storageSourceService.findIdByKey(storageKey); if (storageId == null) { throw new InvalidStorageSourceException("通过存储源 key 未找到存储源, key: " + storageKey); } // 处理请求参数默认值 fileItemRequest.handleDefaultValue(); // 获取文件列表 AbstractBaseFileService fileService = storageSourceContext.getByStorageId(storageId); FileItemResult fileItemResult; try { fileItemResult = fileService.getFileItem(fileItemRequest.getPath()); } catch (Exception e) { return AjaxJson.getError("获取文件信息失败: " + e.getMessage()); } return AjaxJson.getSuccessData(fileItemResult); } } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/controller/FileOperatorController.java b/src/main/java/im/zhaojun/zfile/module/storage/controller/file/FileOperatorController.java similarity index 51% rename from src/main/java/im/zhaojun/zfile/home/controller/FileOperatorController.java rename to src/main/java/im/zhaojun/zfile/module/storage/controller/file/FileOperatorController.java index 5113deb..b4f4649 100644 --- a/src/main/java/im/zhaojun/zfile/home/controller/FileOperatorController.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/controller/file/FileOperatorController.java @@ -1,17 +1,21 @@ -package im.zhaojun.zfile.home.controller; +package im.zhaojun.zfile.module.storage.controller.file; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.BooleanUtil; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiSort; -import im.zhaojun.zfile.common.context.StorageSourceContext; -import im.zhaojun.zfile.home.model.enums.FileTypeEnum; -import im.zhaojun.zfile.home.model.request.operator.BatchDeleteRequest; -import im.zhaojun.zfile.home.model.request.operator.NewFolderRequest; -import im.zhaojun.zfile.home.model.request.operator.RenameFileRequest; -import im.zhaojun.zfile.home.model.request.operator.RenameFolderRequest; -import im.zhaojun.zfile.home.model.request.operator.UploadFileRequest; -import im.zhaojun.zfile.home.service.base.AbstractBaseFileService; -import im.zhaojun.zfile.common.util.AjaxJson; +import im.zhaojun.zfile.core.util.AjaxJson; +import im.zhaojun.zfile.module.password.model.dto.VerifyResultDTO; +import im.zhaojun.zfile.module.password.service.PasswordConfigService; +import im.zhaojun.zfile.module.storage.annotation.CheckPassword; +import im.zhaojun.zfile.module.storage.context.StorageSourceContext; +import im.zhaojun.zfile.module.storage.model.enums.FileTypeEnum; +import im.zhaojun.zfile.module.storage.model.request.operator.BatchDeleteRequest; +import im.zhaojun.zfile.module.storage.model.request.operator.NewFolderRequest; +import im.zhaojun.zfile.module.storage.model.request.operator.RenameFileRequest; +import im.zhaojun.zfile.module.storage.model.request.operator.RenameFolderRequest; +import im.zhaojun.zfile.module.storage.model.request.operator.UploadFileRequest; +import im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; @@ -22,7 +26,9 @@ import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import javax.validation.Valid; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * 文件操作相关接口, 如新建文件夹, 上传文件, 删除文件, 移动文件等. @@ -38,12 +44,18 @@ public class FileOperatorController { @Resource private StorageSourceContext storageSourceContext; + + @Resource + private PasswordConfigService passwordConfigService; @ApiOperationSupport(order = 1) @ApiOperation(value = "创建文件夹") @PostMapping("/mkdir") + @CheckPassword(storageKeyFieldExpression = "[0].storageKey", + pathFieldExpression = "[0].path", + passwordFieldExpression = "[0].password") public AjaxJson mkdir(@Valid @RequestBody NewFolderRequest newFolderRequest) { - AbstractBaseFileService fileService = storageSourceContext.getByKey(newFolderRequest.getStorageKey()); + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey()); boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName()); if (flag) { return AjaxJson.getSuccess("创建成功"); @@ -57,22 +69,52 @@ public class FileOperatorController { @ApiOperation(value = "批量删除文件/文件夹") @PostMapping("/delete/batch") public AjaxJson deleteFile(@Valid @RequestBody BatchDeleteRequest batchDeleteRequest) { - AbstractBaseFileService fileService = storageSourceContext.getByKey(batchDeleteRequest.getStorageKey()); + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey()); List deleteItems = batchDeleteRequest.getDeleteItems(); int deleteSuccessCount = 0, deleteFailCount = 0, totalCount = CollUtil.size(deleteItems); + Map pathCheckCache = new HashMap<>(); + + for (BatchDeleteRequest.DeleteItem deleteItem : deleteItems) { - boolean flag = false; - if (deleteItem.getType() == FileTypeEnum.FILE) { - flag = fileService.deleteFile(deleteItem.getPath(), deleteItem.getName()); - } else if (deleteItem.getType() == FileTypeEnum.FOLDER) { - flag = fileService.deleteFile(deleteItem.getPath(), deleteItem.getName()); + // 检查权限 + Boolean pathCheckResult = pathCheckCache.get(deleteItem.getPath()); + + // 缓存值为 false, 则即为失败, 直接跳过此删除的文件 + if (BooleanUtil.isFalse(pathCheckResult)) { + deleteFailCount++; + continue; } - if (flag) { - deleteSuccessCount++; - } else { + // 缓存没有, 则进行校验 + if (pathCheckResult == null) { + VerifyResultDTO verifyResultDTO = passwordConfigService.verifyPassword(fileService.getStorageId(), deleteItem.getPath(), deleteItem.getPassword()); + // 校验不通过, 则跳过此删除的文件 + if (!verifyResultDTO.isPassed()) { + log.warn("因密码原因删除失败, 类型: {}, 路径: {}, 名称: {}, 原因: {}", deleteItem.getType(), deleteItem.getPath(), deleteItem.getName(), verifyResultDTO.getMsg()); + pathCheckCache.put(deleteItem.getPath(), false); + deleteFailCount++; + continue; + } + pathCheckCache.put(deleteItem.getPath(), true); + } + + boolean flag = false; + try { + if (deleteItem.getType() == FileTypeEnum.FILE) { + flag = fileService.deleteFile(deleteItem.getPath(), deleteItem.getName()); + } else if (deleteItem.getType() == FileTypeEnum.FOLDER) { + flag = fileService.deleteFolder(deleteItem.getPath(), deleteItem.getName()); + } + + if (flag) { + deleteSuccessCount++; + } else { + deleteFailCount++; + } + } catch (Exception e) { + log.error("删除文件/文件夹失败, 文件路径: {}, 文件名称: {}", deleteItem.getPath(), deleteItem.getName(), e); deleteFailCount++; } } @@ -85,11 +127,14 @@ public class FileOperatorController { } - @ApiOperationSupport(order = 4) + @ApiOperationSupport(order = 3) @ApiOperation(value = "重命名文件") @PostMapping("/rename/file") + @CheckPassword(storageKeyFieldExpression = "[0].storageKey", + pathFieldExpression = "[0].path", + passwordFieldExpression = "[0].password") public AjaxJson rename(@Valid @RequestBody RenameFileRequest renameFileRequest) { - AbstractBaseFileService fileService = storageSourceContext.getByKey(renameFileRequest.getStorageKey()); + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(renameFileRequest.getStorageKey()); boolean flag = fileService.renameFile(renameFileRequest.getPath(), renameFileRequest.getName(), renameFileRequest.getNewName()); if (flag) { return AjaxJson.getSuccess("重命名成功"); @@ -99,11 +144,14 @@ public class FileOperatorController { } - @ApiOperationSupport(order = 5) + @ApiOperationSupport(order = 4) @ApiOperation(value = "重命名文件夹") @PostMapping("/rename/folder") + @CheckPassword(storageKeyFieldExpression = "[0].storageKey", + pathFieldExpression = "[0].path", + passwordFieldExpression = "[0].password") public AjaxJson deleteFile(@Valid @RequestBody RenameFolderRequest renameFolderRequest) { - AbstractBaseFileService fileService = storageSourceContext.getByKey(renameFolderRequest.getStorageKey()); + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(renameFolderRequest.getStorageKey()); boolean flag = fileService.renameFolder(renameFolderRequest.getPath(), renameFolderRequest.getName(), renameFolderRequest.getNewName()); if (flag) { return AjaxJson.getSuccess("重命名成功"); @@ -113,11 +161,14 @@ public class FileOperatorController { } - @ApiOperationSupport(order = 6) + @ApiOperationSupport(order = 5) @ApiOperation(value = "上传文件") @PostMapping("/upload/file") - public AjaxJson uploadFile(@Valid @RequestBody UploadFileRequest uploadFileRequest) { - AbstractBaseFileService fileService = storageSourceContext.getByKey(uploadFileRequest.getStorageKey()); + @CheckPassword(storageKeyFieldExpression = "[0].storageKey", + pathFieldExpression = "[0].path", + passwordFieldExpression = "[0].password") + public AjaxJson getUploadFileUrl(@Valid @RequestBody UploadFileRequest uploadFileRequest) { + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(uploadFileRequest.getStorageKey()); String uploadUrl = fileService.getUploadUrl(uploadFileRequest.getPath(), uploadFileRequest.getName(), uploadFileRequest.getSize()); return AjaxJson.getSuccessData(uploadUrl); diff --git a/src/main/java/im/zhaojun/zfile/home/controller/FileParseController.java b/src/main/java/im/zhaojun/zfile/module/storage/controller/file/FileParseController.java similarity index 57% rename from src/main/java/im/zhaojun/zfile/home/controller/FileParseController.java rename to src/main/java/im/zhaojun/zfile/module/storage/controller/file/FileParseController.java index 0a096a4..5d754e9 100644 --- a/src/main/java/im/zhaojun/zfile/home/controller/FileParseController.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/controller/file/FileParseController.java @@ -1,11 +1,9 @@ -package im.zhaojun.zfile.home.controller; +package im.zhaojun.zfile.module.storage.controller.file; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiSort; -import com.github.xiaoymin.knife4j.annotations.DynamicParameter; -import com.github.xiaoymin.knife4j.annotations.DynamicResponseParameters; -import im.zhaojun.zfile.common.util.AjaxJson; -import im.zhaojun.zfile.common.util.HttpUtil; +import im.zhaojun.zfile.core.util.AjaxJson; +import im.zhaojun.zfile.core.util.HttpUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; @@ -27,12 +25,7 @@ public class FileParseController { @GetMapping("/content") @ApiOperationSupport(order = 1) @ApiOperation(value = "获取文本内容", notes = "获取文本文件的文件内容,一般用于 txt, md, ini 等普通文本文件") - @ApiImplicitParam(paramType = "query", name = "url", value = "文本文件下载地址", required = true) - @DynamicResponseParameters(name = "AjaxJson",properties = { - @DynamicParameter(name = "msg", value = "响应消息", example = "ok"), - @DynamicParameter(name = "code", value = "业务状态码,0 为正常,其他值均为异常,异常情况下见响应消息", example = "0"), - @DynamicParameter(name = "data", value = "文本内容", example = "这是一段 txt 中的文字") - }) + @ApiImplicitParam(paramType = "query", name = "url", value = "文本文件下载地址", required = true, dataTypeClass = String.class) public AjaxJson getContent(String url) { return AjaxJson.getSuccessData(HttpUtil.getTextContent(url)); } diff --git a/src/main/java/im/zhaojun/zfile/common/controller/gd/GDHelperController.java b/src/main/java/im/zhaojun/zfile/module/storage/controller/helper/GoogleDriveHelperController.java similarity index 71% rename from src/main/java/im/zhaojun/zfile/common/controller/gd/GDHelperController.java rename to src/main/java/im/zhaojun/zfile/module/storage/controller/helper/GoogleDriveHelperController.java index fca54e2..feaff0f 100644 --- a/src/main/java/im/zhaojun/zfile/common/controller/gd/GDHelperController.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/controller/helper/GoogleDriveHelperController.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.common.controller.gd; +package im.zhaojun.zfile.module.storage.controller.helper; import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpResponse; @@ -7,9 +7,9 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; -import im.zhaojun.zfile.admin.model.request.gd.GetGdDriveListRequest; -import im.zhaojun.zfile.admin.model.result.gd.GdDriveInfoResult; -import im.zhaojun.zfile.common.util.AjaxJson; +import im.zhaojun.zfile.module.storage.model.request.GetGoogleDriveListRequest; +import im.zhaojun.zfile.module.storage.model.result.GoogleDriveInfoResult; +import im.zhaojun.zfile.core.util.AjaxJson; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.stereotype.Controller; @@ -28,15 +28,15 @@ import java.util.List; @Api(tags = "gd 工具辅助模块") @Controller @RequestMapping("/gd") -public class GDHelperController { +public class GoogleDriveHelperController { @PostMapping("/drives") @ResponseBody @ApiOperationSupport(order = 1) @ApiOperation(value = "获取 gd drives 列表") - public AjaxJson> getDrives(@Valid @RequestBody GetGdDriveListRequest gdDriveListRequest) { - List bucketNameList = new ArrayList<>(); - String accessToken = gdDriveListRequest.getAccessToken(); + public AjaxJson> getDrives(@Valid @RequestBody GetGoogleDriveListRequest googleDriveListRequest) { + List bucketNameList = new ArrayList<>(); + String accessToken = googleDriveListRequest.getAccessToken(); HttpRequest httpRequest = HttpUtil.createGet("https://www.googleapis.com/drive/v3/drives"); httpRequest.header("Authorization", "Bearer " + accessToken); @@ -51,7 +51,7 @@ public class GDHelperController { JSONObject drive = drives.getJSONObject(i); String id = drive.getString("id"); String name = drive.getString("name"); - bucketNameList.add(new GdDriveInfoResult(id, name)); + bucketNameList.add(new GoogleDriveInfoResult(id, name)); } return AjaxJson.getSuccessData(bucketNameList); diff --git a/src/main/java/im/zhaojun/zfile/common/controller/s3/S3HelperController.java b/src/main/java/im/zhaojun/zfile/module/storage/controller/helper/S3HelperController.java similarity index 90% rename from src/main/java/im/zhaojun/zfile/common/controller/s3/S3HelperController.java rename to src/main/java/im/zhaojun/zfile/module/storage/controller/helper/S3HelperController.java index 11729f5..52cc8f7 100644 --- a/src/main/java/im/zhaojun/zfile/common/controller/s3/S3HelperController.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/controller/helper/S3HelperController.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.common.controller.s3; +package im.zhaojun.zfile.module.storage.controller.helper; import cn.hutool.core.util.StrUtil; import com.amazonaws.auth.AWSStaticCredentialsProvider; @@ -8,9 +8,9 @@ import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; import com.amazonaws.services.s3.model.Bucket; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; -import im.zhaojun.zfile.common.util.AjaxJson; -import im.zhaojun.zfile.admin.model.request.s3.GetS3BucketListRequest; -import im.zhaojun.zfile.admin.model.result.s3.S3BucketNameResult; +import im.zhaojun.zfile.core.util.AjaxJson; +import im.zhaojun.zfile.module.storage.model.request.GetS3BucketListRequest; +import im.zhaojun.zfile.module.storage.model.result.S3BucketNameResult; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.stereotype.Controller; diff --git a/src/main/java/im/zhaojun/zfile/common/controller/onedrive/SharePointHelperController.java b/src/main/java/im/zhaojun/zfile/module/storage/controller/helper/SharePointHelperController.java similarity index 87% rename from src/main/java/im/zhaojun/zfile/common/controller/onedrive/SharePointHelperController.java rename to src/main/java/im/zhaojun/zfile/module/storage/controller/helper/SharePointHelperController.java index b22a339..f8058fe 100644 --- a/src/main/java/im/zhaojun/zfile/common/controller/onedrive/SharePointHelperController.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/controller/helper/SharePointHelperController.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.common.controller.onedrive; +package im.zhaojun.zfile.module.storage.controller.helper; import cn.hutool.core.util.StrUtil; import cn.hutool.http.HttpRequest; @@ -7,12 +7,12 @@ import cn.hutool.http.HttpUtil; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; -import im.zhaojun.zfile.home.model.request.sharepoint.SharePointSearchSitesRequest; -import im.zhaojun.zfile.home.model.request.sharepoint.SharePointSiteListsRequest; -import im.zhaojun.zfile.admin.model.result.sharepoint.SharepointSite; -import im.zhaojun.zfile.admin.model.result.sharepoint.SharepointSiteList; -import im.zhaojun.zfile.home.model.request.SharePointInfoRequest; -import im.zhaojun.zfile.common.util.AjaxJson; +import im.zhaojun.zfile.module.storage.model.request.SharePointSearchSitesRequest; +import im.zhaojun.zfile.module.storage.model.request.SharePointSiteListsRequest; +import im.zhaojun.zfile.module.storage.model.result.SharepointSiteResult; +import im.zhaojun.zfile.module.storage.model.result.SharepointSiteListResult; +import im.zhaojun.zfile.module.storage.model.request.SharePointInfoRequest; +import im.zhaojun.zfile.core.util.AjaxJson; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.http.HttpStatus; @@ -48,8 +48,8 @@ public class SharePointHelperController { @ResponseBody @ApiOperationSupport(order = 1) @ApiOperation(value = "获取网站列表") - public AjaxJson> getSites(@Valid @RequestBody SharePointSearchSitesRequest searchSitesRequest) { - List sites = new ArrayList<>(); + public AjaxJson> getSites(@Valid @RequestBody SharePointSearchSitesRequest searchSitesRequest) { + List sites = new ArrayList<>(); String requestUrl = getSearchSiteUrlByType(searchSitesRequest.getType()); @@ -71,8 +71,8 @@ public class SharePointHelperController { JSONObject rootObject = JSONObject.parseObject(body); JSONArray valueArray = rootObject.getJSONArray("value"); for (int i = 0; i < valueArray.size(); i++) { - SharepointSite sharepointSite = valueArray.getObject(i, SharepointSite.class); - sites.add(sharepointSite); + SharepointSiteResult sharepointSiteResult = valueArray.getObject(i, SharepointSiteResult.class); + sites.add(sharepointSiteResult); } return AjaxJson.getSuccessData(sites); @@ -83,8 +83,8 @@ public class SharePointHelperController { @ResponseBody @ApiOperationSupport(order = 2) @ApiOperation(value = "获取网站下的子目录") - public AjaxJson> getSites(@Valid @RequestBody SharePointSiteListsRequest sharePointSiteListsRequest) { - List sites = new ArrayList<>(); + public AjaxJson> getSites(@Valid @RequestBody SharePointSiteListsRequest sharePointSiteListsRequest) { + List sites = new ArrayList<>(); String siteId = sharePointSiteListsRequest.getSiteId(); @@ -112,19 +112,19 @@ public class SharePointHelperController { JSONObject rootObject = JSONObject.parseObject(body); JSONArray valueArray = rootObject.getJSONArray("value"); for (int i = 0; i < valueArray.size(); i++) { - SharepointSiteList sharepointSiteList = valueArray.getObject(i, SharepointSiteList.class); + SharepointSiteListResult sharepointSiteListResult = valueArray.getObject(i, SharepointSiteListResult.class); // 如果是事件目录,则跳过 - if (Objects.equals(SHAREPOINT_LIST_TYPE_EVENT, sharepointSiteList.getDisplayName())) { + if (Objects.equals(SHAREPOINT_LIST_TYPE_EVENT, sharepointSiteListResult.getDisplayName())) { continue; } // 如果是文档类型,则改名为"默认文档" - if (Objects.equals(SHAREPOINT_LIST_TYPE_DOCUMENT, sharepointSiteList.getDisplayName())) { - sharepointSiteList.setDisplayName("默认文档"); + if (Objects.equals(SHAREPOINT_LIST_TYPE_DOCUMENT, sharepointSiteListResult.getDisplayName())) { + sharepointSiteListResult.setDisplayName("默认文档"); } - sites.add(sharepointSiteList); + sites.add(sharepointSiteListResult); } - sites.sort(Comparator.comparing(SharepointSiteList::getCreatedDateTime)); + sites.sort(Comparator.comparing(SharepointSiteListResult::getCreatedDateTime)); return AjaxJson.getSuccessData(sites); } diff --git a/src/main/java/im/zhaojun/zfile/common/controller/download/ProxyDownloadController.java b/src/main/java/im/zhaojun/zfile/module/storage/controller/proxy/ProxyDownloadController.java similarity index 78% rename from src/main/java/im/zhaojun/zfile/common/controller/download/ProxyDownloadController.java rename to src/main/java/im/zhaojun/zfile/module/storage/controller/proxy/ProxyDownloadController.java index a902035..92ce858 100644 --- a/src/main/java/im/zhaojun/zfile/common/controller/download/ProxyDownloadController.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/controller/proxy/ProxyDownloadController.java @@ -1,12 +1,12 @@ -package im.zhaojun.zfile.common.controller.download; +package im.zhaojun.zfile.module.storage.controller.proxy; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiSort; -import im.zhaojun.zfile.common.context.StorageSourceContext; -import im.zhaojun.zfile.common.exception.StorageSourceNotSupportProxyUploadException; -import im.zhaojun.zfile.common.util.ProxyDownloadUrlUtils; -import im.zhaojun.zfile.home.service.base.AbstractBaseFileService; -import im.zhaojun.zfile.home.service.base.ProxyTransferService; +import im.zhaojun.zfile.module.storage.context.StorageSourceContext; +import im.zhaojun.zfile.core.exception.StorageSourceNotSupportProxyUploadException; +import im.zhaojun.zfile.core.util.ProxyDownloadUrlUtils; +import im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService; +import im.zhaojun.zfile.module.storage.service.base.AbstractProxyTransferService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; @@ -22,6 +22,7 @@ import org.springframework.web.servlet.HandlerMapping; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.beans.Beans; +import java.io.IOException; /** * 服务端代理下载 Controller @@ -44,29 +45,29 @@ public class ProxyDownloadController { @ApiOperationSupport(order = 1) @ApiOperation(value = "下载本地存储源的文件", notes = "因第三方存储源都有下载地址,本接口提供本地存储的下载地址的处理, 返回文件流进行下载.") @ApiImplicitParams({ - @ApiImplicitParam(paramType = "path", name = "storageKey", value = "存储源 id"), + @ApiImplicitParam(paramType = "path", name = "storageKey", value = "存储源 key", dataTypeClass = String.class), @ApiImplicitParam(paramType = "query", name = "type", value = "下载类型: download(不论什么格式的文件都进行下载操作), " + "default(使用浏览器默认处理,浏览器支持预览的格式,则进行预览,不支持的则进行下载)", - example = "download") + example = "download", dataTypeClass = String.class) }) @ResponseBody - public ResponseEntity downAttachment(@PathVariable("storageKey") String storageKey, String signature) { + public ResponseEntity downAttachment(@PathVariable("storageKey") String storageKey, String signature) throws IOException { // 获取下载文件路径 String path = (String) httpServletRequest.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE); String bestMatchPattern = (String) httpServletRequest.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE); AntPathMatcher apm = new AntPathMatcher(); String filePath = apm.extractPathWithinPattern(bestMatchPattern, path); - AbstractBaseFileService storageServiceByKey = storageSourceContext.getByKey(storageKey); + AbstractBaseFileService storageServiceByKey = storageSourceContext.getByStorageKey(storageKey); // 如果不是 ProxyTransferService, 则返回错误信息. - if (!Beans.isInstanceOf(storageServiceByKey, ProxyTransferService.class)) { + if (!Beans.isInstanceOf(storageServiceByKey, AbstractProxyTransferService.class)) { throw new StorageSourceNotSupportProxyUploadException("存储类型异常,不支持上传."); } // 进行上传. - ProxyTransferService proxyDownloadService = (ProxyTransferService) storageServiceByKey; + AbstractProxyTransferService proxyDownloadService = (AbstractProxyTransferService) storageServiceByKey; // 如果是私有空间才校验签名. boolean privateStorage = proxyDownloadService.getParam().isPrivate(); diff --git a/src/main/java/im/zhaojun/zfile/common/controller/upload/ProxyUploadController.java b/src/main/java/im/zhaojun/zfile/module/storage/controller/proxy/ProxyUploadController.java similarity index 74% rename from src/main/java/im/zhaojun/zfile/common/controller/upload/ProxyUploadController.java rename to src/main/java/im/zhaojun/zfile/module/storage/controller/proxy/ProxyUploadController.java index b36c80c..2a768b8 100644 --- a/src/main/java/im/zhaojun/zfile/common/controller/upload/ProxyUploadController.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/controller/proxy/ProxyUploadController.java @@ -1,9 +1,10 @@ -package im.zhaojun.zfile.common.controller.upload; +package im.zhaojun.zfile.module.storage.controller.proxy; -import im.zhaojun.zfile.common.context.StorageSourceContext; -import im.zhaojun.zfile.common.util.AjaxJson; -import im.zhaojun.zfile.home.service.base.AbstractBaseFileService; -import im.zhaojun.zfile.home.service.base.ProxyTransferService; +import im.zhaojun.zfile.module.storage.context.StorageSourceContext; +import im.zhaojun.zfile.core.util.AjaxJson; +import im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService; +import im.zhaojun.zfile.module.storage.service.base.AbstractProxyTransferService; +import io.swagger.annotations.Api; import org.springframework.util.AntPathMatcher; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -23,6 +24,7 @@ import java.io.IOException; * * @author zhaojun */ +@Api(tags = "服务端代理上传") @RestController public class ProxyUploadController { @@ -46,16 +48,16 @@ public class ProxyUploadController { AntPathMatcher apm = new AntPathMatcher(); String filePath = apm.extractPathWithinPattern(bestMatchPattern, path); - AbstractBaseFileService storageServiceByKey = storageSourceContext.getByKey(storageKey); + AbstractBaseFileService storageServiceByKey = storageSourceContext.getByStorageKey(storageKey); // 如果不是 ProxyTransferService, 则返回错误信息. - if (!Beans.isInstanceOf(storageServiceByKey, ProxyTransferService.class)) { + if (!Beans.isInstanceOf(storageServiceByKey, AbstractProxyTransferService.class)) { return AjaxJson.getError("存储类型异常,不支持上传."); } // 进行上传. - ProxyTransferService proxyUploadService = (ProxyTransferService) storageServiceByKey; + AbstractProxyTransferService proxyUploadService = (AbstractProxyTransferService) storageServiceByKey; proxyUploadService.uploadFile(filePath, file.getInputStream()); return AjaxJson.getSuccess(); } diff --git a/src/main/java/im/zhaojun/zfile/module/storage/convert/StorageSourceConvert.java b/src/main/java/im/zhaojun/zfile/module/storage/convert/StorageSourceConvert.java new file mode 100644 index 0000000..e93f61d --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/storage/convert/StorageSourceConvert.java @@ -0,0 +1,75 @@ +package im.zhaojun.zfile.module.storage.convert; + +import im.zhaojun.zfile.module.readme.model.entity.ReadmeConfig; +import im.zhaojun.zfile.module.storage.model.request.base.SaveStorageSourceRequest; +import im.zhaojun.zfile.module.storage.model.result.StorageSourceAdminResult; +import im.zhaojun.zfile.module.storage.model.dto.StorageSourceAllParamDTO; +import im.zhaojun.zfile.module.storage.model.dto.StorageSourceDTO; +import im.zhaojun.zfile.module.storage.model.result.StorageSourceConfigResult; +import im.zhaojun.zfile.module.storage.model.result.StorageSourceResult; +import im.zhaojun.zfile.module.storage.model.entity.StorageSource; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * StorageSource 转换器 + * + * @author zhaojun + */ +@Component +@Mapper(componentModel = "spring") +public interface StorageSourceConvert { + + + /** + * 将 StorageSource 转换为 StorageSourceResult + * + * @param list + * StorageSource 列表 + * + * @return StorageSourceResult 列表 + */ + List entityToResultList(List list); + + + /** + * 将 StorageSource 转换为 StorageSourceConfigResult + * + * @param storageSource + * StorageSource 实体 + * + * @return StorageSourceConfigResult 实体 + */ + @Mapping(source = "readmeConfig.displayMode", target = "readmeDisplayMode") + @Mapping(source = "storageSource.allowOperator", target = "enableFileOperator") + StorageSourceConfigResult entityToConfigResult(StorageSource storageSource, ReadmeConfig readmeConfig); + + + /** + * 将 StorageSource 转换为 StorageSourceAdminResult + * + * @param list + * StorageSource 列表 + * + * @return StorageSourceAdminResult 列表 + */ + List entityToAdminResultList(List list); + + + StorageSourceDTO entityToDTO(StorageSource storageSource, StorageSourceAllParamDTO storageSourceAllParam); + + + /** + * 将 SaveStorageSourceRequest 转换为 StorageSource + * + * @param saveStorageSourceRequest + * SaveStorageSourceRequest 实体 + * + * @return StorageSource 实体 + */ + StorageSource saveRequestToEntity(SaveStorageSourceRequest saveStorageSourceRequest); + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/filter/DownloadLinkFilter.java b/src/main/java/im/zhaojun/zfile/module/storage/filter/DownloadLinkFilter.java similarity index 77% rename from src/main/java/im/zhaojun/zfile/home/filter/DownloadLinkFilter.java rename to src/main/java/im/zhaojun/zfile/module/storage/filter/DownloadLinkFilter.java index 4d49b91..34c99ea 100644 --- a/src/main/java/im/zhaojun/zfile/home/filter/DownloadLinkFilter.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/filter/DownloadLinkFilter.java @@ -1,20 +1,20 @@ -package im.zhaojun.zfile.home.filter; +package im.zhaojun.zfile.module.storage.filter; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.BooleanUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.spring.SpringUtil; -import im.zhaojun.zfile.admin.model.entity.ShortLink; -import im.zhaojun.zfile.admin.model.entity.StorageSource; -import im.zhaojun.zfile.admin.service.DownloadLogService; -import im.zhaojun.zfile.admin.service.FilterConfigService; -import im.zhaojun.zfile.admin.service.ShortLinkService; -import im.zhaojun.zfile.admin.service.StorageSourceService; -import im.zhaojun.zfile.admin.service.SystemConfigService; -import im.zhaojun.zfile.common.constant.ZFileConstant; -import im.zhaojun.zfile.common.context.StorageSourceContext; -import im.zhaojun.zfile.common.util.StringUtils; -import im.zhaojun.zfile.home.model.dto.SystemConfigDTO; +import im.zhaojun.zfile.module.link.model.entity.ShortLink; +import im.zhaojun.zfile.module.storage.model.entity.StorageSource; +import im.zhaojun.zfile.module.log.service.DownloadLogService; +import im.zhaojun.zfile.module.filter.service.FilterConfigService; +import im.zhaojun.zfile.module.link.service.ShortLinkService; +import im.zhaojun.zfile.module.storage.service.StorageSourceService; +import im.zhaojun.zfile.module.config.service.SystemConfigService; +import im.zhaojun.zfile.core.constant.ZFileConstant; +import im.zhaojun.zfile.module.storage.context.StorageSourceContext; +import im.zhaojun.zfile.core.util.StringUtils; +import im.zhaojun.zfile.module.config.model.dto.SystemConfigDTO; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpHeaders; @@ -98,7 +98,7 @@ public class DownloadLinkFilter implements Filter { SystemConfigDTO systemConfig = systemConfigService.getSystemConfig(); String directLinkPrefix = systemConfig.getDirectLinkPrefix(); if (StrUtil.equalsIgnoreCase(currentRequestPrefix, directLinkPrefix)) { - + if (BooleanUtil.isFalse(systemConfig.getShowPathLink())) { httpServletResponse.setHeader(HttpHeaders.CONTENT_TYPE, "text/plain;charset=utf-8"); httpServletResponse.getWriter().write("当前系统不允许使用直链."); @@ -110,7 +110,7 @@ public class DownloadLinkFilter implements Filter { // 根据存储源 key 获取存储源 id. Integer storageId = storageSourceService.findIdByKey(currentStorageKey); - if (filterConfigService.filterResultIsDisableDownload(storageId, decodeFilePath)) { + if (filterConfigService.checkFileIsDisableDownload(storageId, decodeFilePath)) { // 获取 Forbidden 页面地址 String forbiddenUrl = systemConfigService.getForbiddenUrl(); httpServletResponse.sendRedirect(forbiddenUrl); @@ -141,7 +141,7 @@ public class DownloadLinkFilter implements Filter { StorageSource storageSource = storageSourceService.findByStorageKey(storageKey); Boolean enable = storageSource.getEnable(); if (!enable) { - log.error("存储源当前状态为未启用,仍然请求下载,存储源 key {}, 文件路径 {}", storageKey, filePath); + log.warn("存储源当前状态为未启用,仍然请求下载,存储源 key {}, 文件路径 {}", storageKey, filePath); response.setHeader(HttpHeaders.CONTENT_TYPE, "text/plain;charset=utf-8"); response.getWriter().write("当前存储源未启用, 无法下载,请联系管理员!"); return; @@ -152,8 +152,17 @@ public class DownloadLinkFilter implements Filter { } ShortLink shortLink = shortLinkService.findByStorageIdAndUrl(storageId, filePath); + SystemConfigDTO systemConfig = systemConfigService.getSystemConfig(); + // 如果没有短链,则生成短链 if (shortLink == null) { + if (BooleanUtil.isFalse(systemConfig.getAllowPathLinkAnonAccess())) { + log.warn("存储源「{}」未启用 \"允许路径直链可直接访问\" 功能,仍然进行了访问路径直链: {}", storageKey, filePath); + response.setHeader(HttpHeaders.CONTENT_TYPE, "text/plain;charset=utf-8"); + response.getWriter().write("该文件未生成直链, 无法下载,请联系管理员!"); + return; + } + shortLink = shortLinkService.generatorShortLink(storageId, filePath); } diff --git a/src/main/java/im/zhaojun/zfile/admin/mapper/StorageSourceConfigMapper.java b/src/main/java/im/zhaojun/zfile/module/storage/mapper/StorageSourceConfigMapper.java similarity index 71% rename from src/main/java/im/zhaojun/zfile/admin/mapper/StorageSourceConfigMapper.java rename to src/main/java/im/zhaojun/zfile/module/storage/mapper/StorageSourceConfigMapper.java index 9549f04..fea1dc0 100644 --- a/src/main/java/im/zhaojun/zfile/admin/mapper/StorageSourceConfigMapper.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/mapper/StorageSourceConfigMapper.java @@ -1,7 +1,7 @@ -package im.zhaojun.zfile.admin.mapper; +package im.zhaojun.zfile.module.storage.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import im.zhaojun.zfile.admin.model.entity.StorageSourceConfig; +import im.zhaojun.zfile.module.storage.model.entity.StorageSourceConfig; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -25,21 +25,7 @@ public interface StorageSourceConfigMapper extends BaseMapper findByStorageIdOrderById(@Param("storageId") Integer storageId); - - - /** - * 获取指定存储源的指定参数名称 - * - * @param storageId - * 存储源 id - * - * @param name - * 参数名 - * - * @return 参数信息 - */ - StorageSourceConfig findByStorageIdAndName(@Param("storageId") Integer storageId, @Param("name") String name); - + /** * 根据存储源 ID 删除存储源拓展配置 diff --git a/src/main/java/im/zhaojun/zfile/admin/mapper/StorageSourceMapper.java b/src/main/java/im/zhaojun/zfile/module/storage/mapper/StorageSourceMapper.java similarity index 91% rename from src/main/java/im/zhaojun/zfile/admin/mapper/StorageSourceMapper.java rename to src/main/java/im/zhaojun/zfile/module/storage/mapper/StorageSourceMapper.java index 0e6c677..1fc8992 100644 --- a/src/main/java/im/zhaojun/zfile/admin/mapper/StorageSourceMapper.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/mapper/StorageSourceMapper.java @@ -1,8 +1,8 @@ -package im.zhaojun.zfile.admin.mapper; +package im.zhaojun.zfile.module.storage.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import im.zhaojun.zfile.admin.model.entity.StorageSource; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.model.entity.StorageSource; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; diff --git a/src/main/java/im/zhaojun/zfile/home/model/upyun/AuthModel.java b/src/main/java/im/zhaojun/zfile/module/storage/model/bo/AuthModel.java similarity index 88% rename from src/main/java/im/zhaojun/zfile/home/model/upyun/AuthModel.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/bo/AuthModel.java index e30bf60..f6532e7 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/upyun/AuthModel.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/bo/AuthModel.java @@ -1,5 +1,5 @@ -package im.zhaojun.zfile.home.model.upyun; +package im.zhaojun.zfile.module.storage.model.bo; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/src/main/java/im/zhaojun/zfile/common/cache/RefreshTokenCache.java b/src/main/java/im/zhaojun/zfile/module/storage/model/bo/RefreshTokenCacheBO.java similarity index 72% rename from src/main/java/im/zhaojun/zfile/common/cache/RefreshTokenCache.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/bo/RefreshTokenCacheBO.java index bec239e..81716d6 100644 --- a/src/main/java/im/zhaojun/zfile/common/cache/RefreshTokenCache.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/bo/RefreshTokenCacheBO.java @@ -1,8 +1,9 @@ -package im.zhaojun.zfile.common.cache; +package im.zhaojun.zfile.module.storage.model.bo; import cn.hutool.cache.Cache; import cn.hutool.cache.CacheUtil; import lombok.Data; +import lombok.ToString; import java.util.Date; @@ -11,16 +12,17 @@ import java.util.Date; * * @author zhaojun */ -public class RefreshTokenCache { +@ToString +public class RefreshTokenCacheBO { - private static final Cache cache = CacheUtil.newFIFOCache(100); + private static final Cache REFRESH_TOKEN_INFO_CACHE = CacheUtil.newFIFOCache(100); public static void putRefreshTokenInfo(Integer storageId, RefreshTokenInfo lastRefreshTime) { - cache.put(storageId, lastRefreshTime); + REFRESH_TOKEN_INFO_CACHE.put(storageId, lastRefreshTime); } public static RefreshTokenInfo getRefreshTokenInfo(Integer storageId) { - return cache.get(storageId); + return REFRESH_TOKEN_INFO_CACHE.get(storageId); } @Data diff --git a/src/main/java/im/zhaojun/zfile/admin/annotation/model/StorageSourceParamDef.java b/src/main/java/im/zhaojun/zfile/module/storage/model/bo/StorageSourceParamDef.java similarity index 87% rename from src/main/java/im/zhaojun/zfile/admin/annotation/model/StorageSourceParamDef.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/bo/StorageSourceParamDef.java index cd9278c..7425979 100644 --- a/src/main/java/im/zhaojun/zfile/admin/annotation/model/StorageSourceParamDef.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/bo/StorageSourceParamDef.java @@ -1,7 +1,7 @@ -package im.zhaojun.zfile.admin.annotation.model; +package im.zhaojun.zfile.module.storage.model.bo; -import im.zhaojun.zfile.admin.annotation.StorageParamSelectOption; -import im.zhaojun.zfile.admin.model.enums.StorageParamTypeEnum; +import im.zhaojun.zfile.module.storage.annotation.StorageParamSelectOption; +import im.zhaojun.zfile.module.storage.model.enums.StorageParamTypeEnum; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/im/zhaojun/zfile/home/model/upyun/UploadSignParam.java b/src/main/java/im/zhaojun/zfile/module/storage/model/bo/UploadSignParam.java similarity index 84% rename from src/main/java/im/zhaojun/zfile/home/model/upyun/UploadSignParam.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/bo/UploadSignParam.java index 51238d1..cd739ef 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/upyun/UploadSignParam.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/bo/UploadSignParam.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.home.model.upyun; +package im.zhaojun.zfile.module.storage.model.bo; import lombok.Data; diff --git a/src/main/java/im/zhaojun/zfile/module/storage/model/dto/FileOperatorTypeDefaultValueDTO.java b/src/main/java/im/zhaojun/zfile/module/storage/model/dto/FileOperatorTypeDefaultValueDTO.java new file mode 100644 index 0000000..8eaa0a5 --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/dto/FileOperatorTypeDefaultValueDTO.java @@ -0,0 +1,19 @@ +package im.zhaojun.zfile.module.storage.model.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * 文件操作类型默认结果 + * + * @author zhaojun + */ +@Data +@AllArgsConstructor +public class FileOperatorTypeDefaultValueDTO { + + private boolean allowAdmin; + + private boolean allowAnonymous; + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/model/dto/OAuth2Token.java b/src/main/java/im/zhaojun/zfile/module/storage/model/dto/OAuth2TokenDTO.java similarity index 65% rename from src/main/java/im/zhaojun/zfile/admin/model/dto/OAuth2Token.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/dto/OAuth2TokenDTO.java index bf800d5..8c112e7 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/dto/OAuth2Token.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/dto/OAuth2TokenDTO.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.dto; +package im.zhaojun.zfile.module.storage.model.dto; import lombok.Data; @@ -8,7 +8,7 @@ import lombok.Data; * @author zhaojun */ @Data -public class OAuth2Token { +public class OAuth2TokenDTO { private String clientId; @@ -24,8 +24,8 @@ public class OAuth2Token { private String body; - public static OAuth2Token success(String clientId, String clientSecret, String redirectUri, String accessToken, String refreshToken, String body) { - OAuth2Token token = new OAuth2Token(); + public static OAuth2TokenDTO success(String clientId, String clientSecret, String redirectUri, String accessToken, String refreshToken, String body) { + OAuth2TokenDTO token = new OAuth2TokenDTO(); token.setClientId(clientId); token.setClientSecret(clientSecret); token.setRedirectUri(redirectUri); @@ -36,8 +36,8 @@ public class OAuth2Token { return token; } - public static OAuth2Token fail(String clientId, String clientSecret, String redirectUri, String body) { - OAuth2Token token = new OAuth2Token(); + public static OAuth2TokenDTO fail(String clientId, String clientSecret, String redirectUri, String body) { + OAuth2TokenDTO token = new OAuth2TokenDTO(); token.setClientId(clientId); token.setClientSecret(clientSecret); token.setRedirectUri(redirectUri); diff --git a/src/main/java/im/zhaojun/zfile/home/model/dto/StorageSourceAllParam.java b/src/main/java/im/zhaojun/zfile/module/storage/model/dto/StorageSourceAllParamDTO.java similarity index 97% rename from src/main/java/im/zhaojun/zfile/home/model/dto/StorageSourceAllParam.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/dto/StorageSourceAllParamDTO.java index 62754e8..40a8b4f 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/dto/StorageSourceAllParam.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/dto/StorageSourceAllParamDTO.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.home.model.dto; +package im.zhaojun.zfile.module.storage.model.dto; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -11,7 +11,7 @@ import lombok.Data; */ @Data @ApiModel(description = "存储源所有拓展参数") -public class StorageSourceAllParam { +public class StorageSourceAllParamDTO { @ApiModelProperty(value = "Endpoint 接入点", example = "oss-cn-beijing.aliyuncs.com") private String endPoint; diff --git a/src/main/java/im/zhaojun/zfile/home/model/dto/StorageSourceDTO.java b/src/main/java/im/zhaojun/zfile/module/storage/model/dto/StorageSourceDTO.java similarity index 91% rename from src/main/java/im/zhaojun/zfile/home/model/dto/StorageSourceDTO.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/dto/StorageSourceDTO.java index f5af590..db1939c 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/dto/StorageSourceDTO.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/dto/StorageSourceDTO.java @@ -1,8 +1,8 @@ -package im.zhaojun.zfile.home.model.dto; +package im.zhaojun.zfile.module.storage.model.dto; import com.baomidou.mybatisplus.annotation.TableField; -import im.zhaojun.zfile.admin.model.enums.SearchModeEnum; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.model.enums.SearchModeEnum; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -58,7 +58,7 @@ public class StorageSourceDTO { private Integer orderNum; @ApiModelProperty(value = "存储源拓展属性") - private StorageSourceAllParam storageSourceAllParam; + private StorageSourceAllParamDTO storageSourceAllParam; @ApiModelProperty(value = "是否默认开启图片模式", example = "true") private boolean defaultSwitchToImgMode; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/entity/StorageSource.java b/src/main/java/im/zhaojun/zfile/module/storage/model/entity/StorageSource.java similarity index 93% rename from src/main/java/im/zhaojun/zfile/admin/model/entity/StorageSource.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/entity/StorageSource.java index ef47a70..3253c44 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/entity/StorageSource.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/entity/StorageSource.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.entity; +package im.zhaojun.zfile.module.storage.model.entity; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.util.BooleanUtil; @@ -6,8 +6,8 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import im.zhaojun.zfile.admin.model.enums.SearchModeEnum; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.model.enums.SearchModeEnum; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -16,6 +16,8 @@ import java.io.Serializable; /** * 存储源基本属性 entity + * + * @author zhaojun */ @Data @ApiModel(description = "存储源基本属性") @@ -98,11 +100,12 @@ public class StorageSource implements Serializable { @ApiModelProperty(value = "是否默认开启图片模式", example = "true") private Boolean defaultSwitchToImgMode; + @TableField(value = "compatibility_readme") @ApiModelProperty(value = "兼容 readme 模式", example = "true", notes = "兼容模式, 目录文档读取 readme.md 文件") private Boolean compatibilityReadme; - public boolean allowOperator() { + public boolean getAllowOperator() { // 允许文件操作,且允许匿名操作或者当前登录用户是管理员 return BooleanUtil.isTrue(enableFileOperator) && (BooleanUtil.isTrue(enableFileAnnoOperator) || StpUtil.isLogin()); } diff --git a/src/main/java/im/zhaojun/zfile/admin/model/entity/StorageSourceConfig.java b/src/main/java/im/zhaojun/zfile/module/storage/model/entity/StorageSourceConfig.java similarity index 90% rename from src/main/java/im/zhaojun/zfile/admin/model/entity/StorageSourceConfig.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/entity/StorageSourceConfig.java index 59f5c34..2b99559 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/entity/StorageSourceConfig.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/entity/StorageSourceConfig.java @@ -1,10 +1,10 @@ -package im.zhaojun.zfile.admin.model.entity; +package im.zhaojun.zfile.module.storage.model.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -13,6 +13,8 @@ import java.io.Serializable; /** * 存储源拓展属性 entity + * + * @author zhaojun */ @Data @ApiModel(description = "存储源拓展属性") diff --git a/src/main/java/im/zhaojun/zfile/admin/model/enums/FileOperatorTypeEnum.java b/src/main/java/im/zhaojun/zfile/module/storage/model/enums/FileOperatorTypeEnum.java similarity index 91% rename from src/main/java/im/zhaojun/zfile/admin/model/enums/FileOperatorTypeEnum.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/enums/FileOperatorTypeEnum.java index 32dbbfe..1509993 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/enums/FileOperatorTypeEnum.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/enums/FileOperatorTypeEnum.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.enums; +package im.zhaojun.zfile.module.storage.model.enums; import com.baomidou.mybatisplus.annotation.EnumValue; import com.fasterxml.jackson.annotation.JsonValue; @@ -13,41 +13,41 @@ import lombok.Getter; @Getter @AllArgsConstructor public enum FileOperatorTypeEnum { - + /** * 获取文件上传链接操作 */ UPLOAD("上传", "upload"), - + /** * 新建文件夹操作 */ NEW_FOLDER("新建文件夹", "new_folder"), - + /** * 删除文件&文件夹操作 */ DELETE("删除", "delete"), - + /** * 重命名文件&文件夹操作 */ RENAME("重命名", "rename"), - + /** * 复制文件&文件夹操作 */ COPY("复制", "copy"), - + /** * 移动文件&文件夹操作 */ MOVE("移动", "move"); - + private final String name; - + @EnumValue @JsonValue private final String value; - + } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/model/enums/FileTypeEnum.java b/src/main/java/im/zhaojun/zfile/module/storage/model/enums/FileTypeEnum.java similarity index 89% rename from src/main/java/im/zhaojun/zfile/home/model/enums/FileTypeEnum.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/enums/FileTypeEnum.java index ead59d4..1373c4c 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/enums/FileTypeEnum.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/enums/FileTypeEnum.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.home.model.enums; +package im.zhaojun.zfile.module.storage.model.enums; import com.baomidou.mybatisplus.annotation.EnumValue; import com.fasterxml.jackson.annotation.JsonValue; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/enums/SearchModeEnum.java b/src/main/java/im/zhaojun/zfile/module/storage/model/enums/SearchModeEnum.java similarity index 89% rename from src/main/java/im/zhaojun/zfile/admin/model/enums/SearchModeEnum.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/enums/SearchModeEnum.java index 65d67e2..9577774 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/enums/SearchModeEnum.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/enums/SearchModeEnum.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.enums; +package im.zhaojun.zfile.module.storage.model.enums; import com.baomidou.mybatisplus.annotation.EnumValue; import com.fasterxml.jackson.annotation.JsonValue; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/enums/StorageParamTypeEnum.java b/src/main/java/im/zhaojun/zfile/module/storage/model/enums/StorageParamTypeEnum.java similarity index 89% rename from src/main/java/im/zhaojun/zfile/admin/model/enums/StorageParamTypeEnum.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/enums/StorageParamTypeEnum.java index 9423cab..6985f76 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/enums/StorageParamTypeEnum.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/enums/StorageParamTypeEnum.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.enums; +package im.zhaojun.zfile.module.storage.model.enums; import com.baomidou.mybatisplus.annotation.EnumValue; import com.fasterxml.jackson.annotation.JsonValue; diff --git a/src/main/java/im/zhaojun/zfile/home/model/enums/StorageTypeEnum.java b/src/main/java/im/zhaojun/zfile/module/storage/model/enums/StorageTypeEnum.java similarity index 97% rename from src/main/java/im/zhaojun/zfile/home/model/enums/StorageTypeEnum.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/enums/StorageTypeEnum.java index 9d2e396..e28b63a 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/enums/StorageTypeEnum.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/enums/StorageTypeEnum.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.home.model.enums; +package im.zhaojun.zfile.module.storage.model.enums; import com.baomidou.mybatisplus.annotation.EnumValue; import com.baomidou.mybatisplus.annotation.IEnum; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/param/AliyunParam.java b/src/main/java/im/zhaojun/zfile/module/storage/model/param/AliyunParam.java similarity index 72% rename from src/main/java/im/zhaojun/zfile/admin/model/param/AliyunParam.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/param/AliyunParam.java index 47b1e68..2c37e72 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/param/AliyunParam.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/param/AliyunParam.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.param; +package im.zhaojun.zfile.module.storage.model.param; import lombok.Getter; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/param/FtpParam.java b/src/main/java/im/zhaojun/zfile/module/storage/model/param/FtpParam.java similarity index 80% rename from src/main/java/im/zhaojun/zfile/admin/model/param/FtpParam.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/param/FtpParam.java index 79622fd..5e311a3 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/param/FtpParam.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/param/FtpParam.java @@ -1,8 +1,8 @@ -package im.zhaojun.zfile.admin.model.param; +package im.zhaojun.zfile.module.storage.model.param; -import im.zhaojun.zfile.admin.annotation.StorageParamItem; -import im.zhaojun.zfile.admin.annotation.select.impl.EncodingStorageParamSelect; -import im.zhaojun.zfile.admin.model.enums.StorageParamTypeEnum; +import im.zhaojun.zfile.module.storage.annotation.StorageParamItem; +import im.zhaojun.zfile.module.storage.annotation.impl.EncodingStorageParamSelect; +import im.zhaojun.zfile.module.storage.model.enums.StorageParamTypeEnum; import lombok.Getter; /** diff --git a/src/main/java/im/zhaojun/zfile/admin/model/param/GoogleDriveParam.java b/src/main/java/im/zhaojun/zfile/module/storage/model/param/GoogleDriveParam.java similarity index 93% rename from src/main/java/im/zhaojun/zfile/admin/model/param/GoogleDriveParam.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/param/GoogleDriveParam.java index 55fd43b..60b9022 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/param/GoogleDriveParam.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/param/GoogleDriveParam.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.admin.model.param; +package im.zhaojun.zfile.module.storage.model.param; -import im.zhaojun.zfile.admin.annotation.StorageParamItem; +import im.zhaojun.zfile.module.storage.annotation.StorageParamItem; import lombok.Getter; import lombok.Setter; import lombok.ToString; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/param/HuaweiParam.java b/src/main/java/im/zhaojun/zfile/module/storage/model/param/HuaweiParam.java similarity index 72% rename from src/main/java/im/zhaojun/zfile/admin/model/param/HuaweiParam.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/param/HuaweiParam.java index 5e59efb..440ad51 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/param/HuaweiParam.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/param/HuaweiParam.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.param; +package im.zhaojun.zfile.module.storage.model.param; import lombok.Getter; diff --git a/src/main/java/im/zhaojun/zfile/module/storage/model/param/IStorageParam.java b/src/main/java/im/zhaojun/zfile/module/storage/model/param/IStorageParam.java new file mode 100644 index 0000000..3a0706d --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/param/IStorageParam.java @@ -0,0 +1,7 @@ +package im.zhaojun.zfile.module.storage.model.param; + +/** + * @author zhaojun + */ +public interface IStorageParam { +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/model/param/LocalParam.java b/src/main/java/im/zhaojun/zfile/module/storage/model/param/LocalParam.java similarity index 79% rename from src/main/java/im/zhaojun/zfile/admin/model/param/LocalParam.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/param/LocalParam.java index c2a8850..7454004 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/param/LocalParam.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/param/LocalParam.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.admin.model.param; +package im.zhaojun.zfile.module.storage.model.param; -import im.zhaojun.zfile.admin.annotation.StorageParamItem; +import im.zhaojun.zfile.module.storage.annotation.StorageParamItem; import lombok.Getter; /** diff --git a/src/main/java/im/zhaojun/zfile/admin/model/param/MicrosoftDriveParam.java b/src/main/java/im/zhaojun/zfile/module/storage/model/param/MicrosoftDriveParam.java similarity index 92% rename from src/main/java/im/zhaojun/zfile/admin/model/param/MicrosoftDriveParam.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/param/MicrosoftDriveParam.java index 828e9fe..a577f1a 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/param/MicrosoftDriveParam.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/param/MicrosoftDriveParam.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.admin.model.param; +package im.zhaojun.zfile.module.storage.model.param; -import im.zhaojun.zfile.admin.annotation.StorageParamItem; +import im.zhaojun.zfile.module.storage.annotation.StorageParamItem; import lombok.Getter; /** diff --git a/src/main/java/im/zhaojun/zfile/admin/model/param/MinIOParam.java b/src/main/java/im/zhaojun/zfile/module/storage/model/param/MinIOParam.java similarity index 83% rename from src/main/java/im/zhaojun/zfile/admin/model/param/MinIOParam.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/param/MinIOParam.java index 47a03aa..61b5151 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/param/MinIOParam.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/param/MinIOParam.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.admin.model.param; +package im.zhaojun.zfile.module.storage.model.param; -import im.zhaojun.zfile.admin.annotation.StorageParamItem; +import im.zhaojun.zfile.module.storage.annotation.StorageParamItem; import lombok.Getter; /** diff --git a/src/main/java/im/zhaojun/zfile/admin/model/param/OneDriveChinaParam.java b/src/main/java/im/zhaojun/zfile/module/storage/model/param/OneDriveChinaParam.java similarity index 87% rename from src/main/java/im/zhaojun/zfile/admin/model/param/OneDriveChinaParam.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/param/OneDriveChinaParam.java index f00f8fc..9d540c3 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/param/OneDriveChinaParam.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/param/OneDriveChinaParam.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.admin.model.param; +package im.zhaojun.zfile.module.storage.model.param; -import im.zhaojun.zfile.admin.annotation.StorageParamItem; +import im.zhaojun.zfile.module.storage.annotation.StorageParamItem; import lombok.Getter; /** diff --git a/src/main/java/im/zhaojun/zfile/admin/model/param/OneDriveParam.java b/src/main/java/im/zhaojun/zfile/module/storage/model/param/OneDriveParam.java similarity index 73% rename from src/main/java/im/zhaojun/zfile/admin/model/param/OneDriveParam.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/param/OneDriveParam.java index 16f71b6..6e676e9 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/param/OneDriveParam.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/param/OneDriveParam.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.param; +package im.zhaojun.zfile.module.storage.model.param; import lombok.Getter; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/param/ProxyDownloadParam.java b/src/main/java/im/zhaojun/zfile/module/storage/model/param/ProxyDownloadParam.java similarity index 73% rename from src/main/java/im/zhaojun/zfile/admin/model/param/ProxyDownloadParam.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/param/ProxyDownloadParam.java index 9c72f87..ea60861 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/param/ProxyDownloadParam.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/param/ProxyDownloadParam.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.param; +package im.zhaojun.zfile.module.storage.model.param; import lombok.Getter; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/param/ProxyTransferParam.java b/src/main/java/im/zhaojun/zfile/module/storage/model/param/ProxyTransferParam.java similarity index 80% rename from src/main/java/im/zhaojun/zfile/admin/model/param/ProxyTransferParam.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/param/ProxyTransferParam.java index d4889b0..9c5ab14 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/param/ProxyTransferParam.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/param/ProxyTransferParam.java @@ -1,7 +1,7 @@ -package im.zhaojun.zfile.admin.model.param; +package im.zhaojun.zfile.module.storage.model.param; -import im.zhaojun.zfile.admin.annotation.StorageParamItem; -import im.zhaojun.zfile.admin.model.enums.StorageParamTypeEnum; +import im.zhaojun.zfile.module.storage.annotation.StorageParamItem; +import im.zhaojun.zfile.module.storage.model.enums.StorageParamTypeEnum; import lombok.Getter; /** diff --git a/src/main/java/im/zhaojun/zfile/admin/model/param/ProxyUploadParam.java b/src/main/java/im/zhaojun/zfile/module/storage/model/param/ProxyUploadParam.java similarity index 68% rename from src/main/java/im/zhaojun/zfile/admin/model/param/ProxyUploadParam.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/param/ProxyUploadParam.java index 6ea447d..fe3567a 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/param/ProxyUploadParam.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/param/ProxyUploadParam.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.param; +package im.zhaojun.zfile.module.storage.model.param; /** * 代理上传参数 diff --git a/src/main/java/im/zhaojun/zfile/admin/model/param/QiniuParam.java b/src/main/java/im/zhaojun/zfile/module/storage/model/param/QiniuParam.java similarity index 72% rename from src/main/java/im/zhaojun/zfile/admin/model/param/QiniuParam.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/param/QiniuParam.java index bf25916..f6683dd 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/param/QiniuParam.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/param/QiniuParam.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.param; +package im.zhaojun.zfile.module.storage.model.param; import lombok.Getter; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/param/S3BaseParam.java b/src/main/java/im/zhaojun/zfile/module/storage/model/param/S3BaseParam.java similarity index 79% rename from src/main/java/im/zhaojun/zfile/admin/model/param/S3BaseParam.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/param/S3BaseParam.java index e547767..f3a2502 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/param/S3BaseParam.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/param/S3BaseParam.java @@ -1,7 +1,7 @@ -package im.zhaojun.zfile.admin.model.param; +package im.zhaojun.zfile.module.storage.model.param; -import im.zhaojun.zfile.admin.annotation.StorageParamItem; -import im.zhaojun.zfile.admin.model.enums.StorageParamTypeEnum; +import im.zhaojun.zfile.module.storage.annotation.StorageParamItem; +import im.zhaojun.zfile.module.storage.model.enums.StorageParamTypeEnum; import lombok.Getter; /** @@ -36,7 +36,8 @@ public class S3BaseParam implements IStorageParam { @StorageParamItem(name = "下载签名有效期", required = false, defaultValue = "1800", description = "当为私有空间时, 用于下载签名的有效期, 单位为秒, 如不配置则默认为 1800 秒.") private Integer tokenTime; - @StorageParamItem(name = "是否自动配置 CORS 跨域设置", order = 100, type = StorageParamTypeEnum.SWITCH, defaultValue = "true", description = "如不配置跨域设置,可能会无法导致无法上传,或上传后看不到文件") + @StorageParamItem(name = "是否自动配置 CORS 跨域设置", order = 100, type = StorageParamTypeEnum.SWITCH, defaultValue = "true", + description = "如不配置跨域设置,可能会无法导致无法上传,或上传后看不到文件(某些 S3 存储无需配置此选项,如 Cloudflare R2、Oracle 对象存储)") private boolean autoConfigCors; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/param/S3Param.java b/src/main/java/im/zhaojun/zfile/module/storage/model/param/S3Param.java similarity index 65% rename from src/main/java/im/zhaojun/zfile/admin/model/param/S3Param.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/param/S3Param.java index dcc8482..c581357 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/param/S3Param.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/param/S3Param.java @@ -1,8 +1,8 @@ -package im.zhaojun.zfile.admin.model.param; +package im.zhaojun.zfile.module.storage.model.param; -import im.zhaojun.zfile.admin.annotation.StorageParamItem; -import im.zhaojun.zfile.admin.annotation.StorageParamSelectOption; -import im.zhaojun.zfile.admin.model.enums.StorageParamTypeEnum; +import im.zhaojun.zfile.module.storage.annotation.StorageParamItem; +import im.zhaojun.zfile.module.storage.annotation.StorageParamSelectOption; +import im.zhaojun.zfile.module.storage.model.enums.StorageParamTypeEnum; import lombok.Getter; /** @@ -19,9 +19,9 @@ public class S3Param extends S3BaseParam { @StorageParamItem(name = "地域", order = 3) private String region; - @StorageParamItem(name = "域名风格", type = StorageParamTypeEnum.SWITCH, - options = { @StorageParamSelectOption(value = "path-style", label = "path-style"), - @StorageParamSelectOption(value = "bucket-virtual-hosting", label = "bucket-virtual-hosting")}, + @StorageParamItem(name = "域名风格", type = StorageParamTypeEnum.SELECT, + options = { @StorageParamSelectOption(value = "path-style", label = "路径风格"), + @StorageParamSelectOption(value = "bucket-virtual-hosting", label = "虚拟主机风格") }, linkName = "查看 S3 API 说明文档", link = "https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/userguide/VirtualHosting.html#path-style-access") private String pathStyle; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/param/SftpParam.java b/src/main/java/im/zhaojun/zfile/module/storage/model/param/SftpParam.java similarity index 71% rename from src/main/java/im/zhaojun/zfile/admin/model/param/SftpParam.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/param/SftpParam.java index 3bb94ef..ec207c2 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/param/SftpParam.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/param/SftpParam.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.param; +package im.zhaojun.zfile.module.storage.model.param; import lombok.Getter; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/param/SharePointChinaParam.java b/src/main/java/im/zhaojun/zfile/module/storage/model/param/SharePointChinaParam.java similarity index 87% rename from src/main/java/im/zhaojun/zfile/admin/model/param/SharePointChinaParam.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/param/SharePointChinaParam.java index 99dca3a..0b7138e 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/param/SharePointChinaParam.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/param/SharePointChinaParam.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.admin.model.param; +package im.zhaojun.zfile.module.storage.model.param; -import im.zhaojun.zfile.admin.annotation.StorageParamItem; +import im.zhaojun.zfile.module.storage.annotation.StorageParamItem; import lombok.Getter; /** diff --git a/src/main/java/im/zhaojun/zfile/admin/model/param/SharePointParam.java b/src/main/java/im/zhaojun/zfile/module/storage/model/param/SharePointParam.java similarity index 84% rename from src/main/java/im/zhaojun/zfile/admin/model/param/SharePointParam.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/param/SharePointParam.java index 1046125..aa27d2b 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/param/SharePointParam.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/param/SharePointParam.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.admin.model.param; +package im.zhaojun.zfile.module.storage.model.param; -import im.zhaojun.zfile.admin.annotation.StorageParamItem; +import im.zhaojun.zfile.module.storage.annotation.StorageParamItem; import lombok.Getter; /** diff --git a/src/main/java/im/zhaojun/zfile/admin/model/param/TencentParam.java b/src/main/java/im/zhaojun/zfile/module/storage/model/param/TencentParam.java similarity index 66% rename from src/main/java/im/zhaojun/zfile/admin/model/param/TencentParam.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/param/TencentParam.java index 0f7eb9a..daa617d 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/param/TencentParam.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/param/TencentParam.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.admin.model.param; +package im.zhaojun.zfile.module.storage.model.param; -import im.zhaojun.zfile.admin.annotation.StorageParamItem; +import im.zhaojun.zfile.module.storage.annotation.StorageParamItem; import lombok.Getter; /** diff --git a/src/main/java/im/zhaojun/zfile/admin/model/param/UpYunParam.java b/src/main/java/im/zhaojun/zfile/module/storage/model/param/UpYunParam.java similarity index 90% rename from src/main/java/im/zhaojun/zfile/admin/model/param/UpYunParam.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/param/UpYunParam.java index 225dc38..6924be7 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/param/UpYunParam.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/param/UpYunParam.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.admin.model.param; +package im.zhaojun.zfile.module.storage.model.param; -import im.zhaojun.zfile.admin.annotation.StorageParamItem; +import im.zhaojun.zfile.module.storage.annotation.StorageParamItem; import lombok.Getter; /** diff --git a/src/main/java/im/zhaojun/zfile/admin/model/param/WebdavParam.java b/src/main/java/im/zhaojun/zfile/module/storage/model/param/WebdavParam.java similarity index 77% rename from src/main/java/im/zhaojun/zfile/admin/model/param/WebdavParam.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/param/WebdavParam.java index c493760..16e2225 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/param/WebdavParam.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/param/WebdavParam.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.admin.model.param; +package im.zhaojun.zfile.module.storage.model.param; -import im.zhaojun.zfile.admin.annotation.StorageParamItem; +import im.zhaojun.zfile.module.storage.annotation.StorageParamItem; import lombok.Getter; /** diff --git a/src/main/java/im/zhaojun/zfile/admin/model/request/gd/GetGdDriveListRequest.java b/src/main/java/im/zhaojun/zfile/module/storage/model/request/GetGoogleDriveListRequest.java similarity index 85% rename from src/main/java/im/zhaojun/zfile/admin/model/request/gd/GetGdDriveListRequest.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/request/GetGoogleDriveListRequest.java index 77cb251..d1b5753 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/request/gd/GetGdDriveListRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/request/GetGoogleDriveListRequest.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.request.gd; +package im.zhaojun.zfile.module.storage.model.request; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -11,7 +11,7 @@ import javax.validation.constraints.NotBlank; */ @Data @ApiModel(value="gd drive 列表请求类") -public class GetGdDriveListRequest { +public class GetGoogleDriveListRequest { @NotBlank(message = "accessToken 不能为空") @ApiModelProperty(value = "accessToken", required = true, example = "v7LtfjIbnxLCTj0R3riwhyxcbv4KVH5HuPWHWrrewHMEwjJyUlYXV6D4m1MLJ2dP__GX_7CKCc-HudUetPXWS2wwbfkNs6ydLq3xrk1gHA7wcD_pmt6oNuRXw5mnFzfdLkH5wIG1suQp3p0eHJurzIaCgYKATASATASFQE65dr8hO725r41QtZc9RJVUg12cA0163") diff --git a/src/main/java/im/zhaojun/zfile/admin/model/request/s3/GetS3BucketListRequest.java b/src/main/java/im/zhaojun/zfile/module/storage/model/request/GetS3BucketListRequest.java similarity index 94% rename from src/main/java/im/zhaojun/zfile/admin/model/request/s3/GetS3BucketListRequest.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/request/GetS3BucketListRequest.java index 179e3ef..2136aba 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/request/s3/GetS3BucketListRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/request/GetS3BucketListRequest.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.request.s3; +package im.zhaojun.zfile.module.storage.model.request; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; diff --git a/src/main/java/im/zhaojun/zfile/home/model/request/SharePointInfoRequest.java b/src/main/java/im/zhaojun/zfile/module/storage/model/request/SharePointInfoRequest.java similarity index 95% rename from src/main/java/im/zhaojun/zfile/home/model/request/SharePointInfoRequest.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/request/SharePointInfoRequest.java index 187bac5..dfba542 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/request/SharePointInfoRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/request/SharePointInfoRequest.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.home.model.request; +package im.zhaojun.zfile.module.storage.model.request; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; diff --git a/src/main/java/im/zhaojun/zfile/home/model/request/sharepoint/SharePointSearchSitesRequest.java b/src/main/java/im/zhaojun/zfile/module/storage/model/request/SharePointSearchSitesRequest.java similarity index 83% rename from src/main/java/im/zhaojun/zfile/home/model/request/sharepoint/SharePointSearchSitesRequest.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/request/SharePointSearchSitesRequest.java index 860d3dc..dd57ad8 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/request/sharepoint/SharePointSearchSitesRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/request/SharePointSearchSitesRequest.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.home.model.request.sharepoint; +package im.zhaojun.zfile.module.storage.model.request; -import im.zhaojun.zfile.common.validation.StringListValue; +import im.zhaojun.zfile.core.validation.StringListValue; import io.swagger.annotations.ApiModelProperty; import lombok.Data; diff --git a/src/main/java/im/zhaojun/zfile/home/model/request/sharepoint/SharePointSiteListsRequest.java b/src/main/java/im/zhaojun/zfile/module/storage/model/request/SharePointSiteListsRequest.java similarity index 89% rename from src/main/java/im/zhaojun/zfile/home/model/request/sharepoint/SharePointSiteListsRequest.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/request/SharePointSiteListsRequest.java index a86eafc..de100da 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/request/sharepoint/SharePointSiteListsRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/request/SharePointSiteListsRequest.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.home.model.request.sharepoint; +package im.zhaojun.zfile.module.storage.model.request; -import im.zhaojun.zfile.common.validation.StringListValue; +import im.zhaojun.zfile.core.validation.StringListValue; import io.swagger.annotations.ApiModelProperty; import lombok.Data; diff --git a/src/main/java/im/zhaojun/zfile/home/model/request/UpdateStorageIdRequest.java b/src/main/java/im/zhaojun/zfile/module/storage/model/request/admin/UpdateStorageIdRequest.java similarity index 91% rename from src/main/java/im/zhaojun/zfile/home/model/request/UpdateStorageIdRequest.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/request/admin/UpdateStorageIdRequest.java index 690cc93..946fec6 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/request/UpdateStorageIdRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/request/admin/UpdateStorageIdRequest.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.home.model.request; +package im.zhaojun.zfile.module.storage.model.request.admin; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; diff --git a/src/main/java/im/zhaojun/zfile/home/model/request/UpdateStorageSortRequest.java b/src/main/java/im/zhaojun/zfile/module/storage/model/request/admin/UpdateStorageSortRequest.java similarity index 91% rename from src/main/java/im/zhaojun/zfile/home/model/request/UpdateStorageSortRequest.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/request/admin/UpdateStorageSortRequest.java index 6a202ef..3ea6e32 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/request/UpdateStorageSortRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/request/admin/UpdateStorageSortRequest.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.home.model.request; +package im.zhaojun.zfile.module.storage.model.request.admin; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; diff --git a/src/main/java/im/zhaojun/zfile/home/model/request/FileItemRequest.java b/src/main/java/im/zhaojun/zfile/module/storage/model/request/base/FileItemRequest.java similarity index 90% rename from src/main/java/im/zhaojun/zfile/home/model/request/FileItemRequest.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/request/base/FileItemRequest.java index 45e4212..304c55f 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/request/FileItemRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/request/base/FileItemRequest.java @@ -1,7 +1,7 @@ -package im.zhaojun.zfile.home.model.request; +package im.zhaojun.zfile.module.storage.model.request.base; import cn.hutool.core.util.StrUtil; -import im.zhaojun.zfile.common.util.StringUtils; +import im.zhaojun.zfile.core.util.StringUtils; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; diff --git a/src/main/java/im/zhaojun/zfile/home/model/request/FileListConfigRequest.java b/src/main/java/im/zhaojun/zfile/module/storage/model/request/base/FileListConfigRequest.java similarity index 86% rename from src/main/java/im/zhaojun/zfile/home/model/request/FileListConfigRequest.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/request/base/FileListConfigRequest.java index 602e6d2..5b3801e 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/request/FileListConfigRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/request/base/FileListConfigRequest.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.home.model.request; +package im.zhaojun.zfile.module.storage.model.request.base; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -20,6 +20,6 @@ public class FileListConfigRequest { private String storageKey; @ApiModelProperty(value = "请求路径", example = "/") - private String path; + private String path = "/"; } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/model/request/FileListRequest.java b/src/main/java/im/zhaojun/zfile/module/storage/model/request/base/FileListRequest.java similarity index 89% rename from src/main/java/im/zhaojun/zfile/home/model/request/FileListRequest.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/request/base/FileListRequest.java index 97aeb20..f6796ca 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/request/FileListRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/request/base/FileListRequest.java @@ -1,8 +1,8 @@ -package im.zhaojun.zfile.home.model.request; +package im.zhaojun.zfile.module.storage.model.request.base; import cn.hutool.core.util.StrUtil; -import im.zhaojun.zfile.common.validation.StringListValue; -import im.zhaojun.zfile.common.util.StringUtils; +import im.zhaojun.zfile.core.validation.StringListValue; +import im.zhaojun.zfile.core.util.StringUtils; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/request/SaveStorageSourceRequest.java b/src/main/java/im/zhaojun/zfile/module/storage/model/request/base/SaveStorageSourceRequest.java similarity index 88% rename from src/main/java/im/zhaojun/zfile/admin/model/request/SaveStorageSourceRequest.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/request/base/SaveStorageSourceRequest.java index b207bc0..0d08c8f 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/request/SaveStorageSourceRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/request/base/SaveStorageSourceRequest.java @@ -1,9 +1,9 @@ -package im.zhaojun.zfile.admin.model.request; +package im.zhaojun.zfile.module.storage.model.request.base; import com.baomidou.mybatisplus.annotation.TableField; -import im.zhaojun.zfile.admin.model.enums.SearchModeEnum; -import im.zhaojun.zfile.home.model.dto.StorageSourceAllParam; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.model.enums.SearchModeEnum; +import im.zhaojun.zfile.module.storage.model.dto.StorageSourceAllParamDTO; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -61,7 +61,7 @@ public class SaveStorageSourceRequest { private Integer orderNum; @ApiModelProperty(value = "存储源拓展属性") - private StorageSourceAllParam storageSourceAllParam; + private StorageSourceAllParamDTO storageSourceAllParam; @ApiModelProperty(value = "是否默认开启图片模式", example = "true") private boolean defaultSwitchToImgMode; diff --git a/src/main/java/im/zhaojun/zfile/home/model/request/operator/BatchDeleteRequest.java b/src/main/java/im/zhaojun/zfile/module/storage/model/request/operator/BatchDeleteRequest.java similarity index 83% rename from src/main/java/im/zhaojun/zfile/home/model/request/operator/BatchDeleteRequest.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/request/operator/BatchDeleteRequest.java index 95b7bce..5ab602e 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/request/operator/BatchDeleteRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/request/operator/BatchDeleteRequest.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.home.model.request.operator; +package im.zhaojun.zfile.module.storage.model.request.operator; -import im.zhaojun.zfile.home.model.enums.FileTypeEnum; +import im.zhaojun.zfile.module.storage.model.enums.FileTypeEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -34,6 +34,9 @@ public class BatchDeleteRequest { private String path; private FileTypeEnum type; + + private String password; + } } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/model/request/operator/NewFolderRequest.java b/src/main/java/im/zhaojun/zfile/module/storage/model/request/operator/NewFolderRequest.java similarity index 75% rename from src/main/java/im/zhaojun/zfile/home/model/request/operator/NewFolderRequest.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/request/operator/NewFolderRequest.java index 79de8af..7d236fd 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/request/operator/NewFolderRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/request/operator/NewFolderRequest.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.home.model.request.operator; +package im.zhaojun.zfile.module.storage.model.request.operator; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -20,11 +20,13 @@ public class NewFolderRequest { private String storageKey; @ApiModelProperty(value = "请求路径", example = "/", notes = "表示在哪个文件夹下创建文件夹") - @NotBlank(message = "请求路径不能为空") - private String path; + private String path = "/"; @ApiModelProperty(value = "新建的文件夹名称", example = "/a/b/c", notes = "文件夹名称支持多级,如:/a/b/c") @NotBlank(message = "新建的文件夹名称不能为空") private String name; + + @ApiModelProperty(value = "文件夹密码, 如果文件夹需要密码才能访问,则支持请求密码", example = "123456") + private String password; } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/model/request/operator/RenameFileRequest.java b/src/main/java/im/zhaojun/zfile/module/storage/model/request/operator/RenameFileRequest.java similarity index 77% rename from src/main/java/im/zhaojun/zfile/home/model/request/operator/RenameFileRequest.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/request/operator/RenameFileRequest.java index 8c1b9ba..acb99bc 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/request/operator/RenameFileRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/request/operator/RenameFileRequest.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.home.model.request.operator; +package im.zhaojun.zfile.module.storage.model.request.operator; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -20,8 +20,7 @@ public class RenameFileRequest { private String storageKey; @ApiModelProperty(value = "请求路径", example = "/", notes = "表示在哪个文件夹下重命名文件") - @NotBlank(message = "请求路径不能为空") - private String path; + private String path = "/"; @ApiModelProperty(value = "重命名的原文件名称", example = "test.txt") @NotBlank(message = "原文件名不能为空") @@ -30,5 +29,8 @@ public class RenameFileRequest { @ApiModelProperty(value = "重命名后的文件名称", example = "text-1.txt") @NotBlank(message = "新文件名不能为空") private String newName; + + @ApiModelProperty(value = "文件夹密码, 如果文件夹需要密码才能访问,则支持请求密码", example = "123456") + private String password; } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/model/request/operator/RenameFolderRequest.java b/src/main/java/im/zhaojun/zfile/module/storage/model/request/operator/RenameFolderRequest.java similarity index 78% rename from src/main/java/im/zhaojun/zfile/home/model/request/operator/RenameFolderRequest.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/request/operator/RenameFolderRequest.java index d0a87cd..4f3c667 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/request/operator/RenameFolderRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/request/operator/RenameFolderRequest.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.home.model.request.operator; +package im.zhaojun.zfile.module.storage.model.request.operator; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -20,8 +20,7 @@ public class RenameFolderRequest { private String storageKey; @ApiModelProperty(value = "请求路径", example = "/", notes = "表示在哪个文件夹下重命名文件夹") - @NotBlank(message = "请求路径不能为空") - private String path; + private String path = "/"; @ApiModelProperty(value = "重命名的原文件夹名称", example = "movie") @NotBlank(message = "原文件夹名称不能为空") @@ -30,5 +29,8 @@ public class RenameFolderRequest { @ApiModelProperty(value = "重命名后的文件名称", example = "music") @NotBlank(message = "新文件夹名称不能为空") private String newName; + + @ApiModelProperty(value = "文件夹密码, 如果文件夹需要密码才能访问,则支持请求密码", example = "123456") + private String password; } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/model/request/operator/UploadFileRequest.java b/src/main/java/im/zhaojun/zfile/module/storage/model/request/operator/UploadFileRequest.java similarity index 76% rename from src/main/java/im/zhaojun/zfile/home/model/request/operator/UploadFileRequest.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/request/operator/UploadFileRequest.java index 8e620bf..82c4c73 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/request/operator/UploadFileRequest.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/request/operator/UploadFileRequest.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.home.model.request.operator; +package im.zhaojun.zfile.module.storage.model.request.operator; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -20,8 +20,7 @@ public class UploadFileRequest { private String storageKey; @ApiModelProperty(value = "上传路径", example = "/movie", notes = "表示上传文件到哪个路径") - @NotBlank(message = "上传路径不能为空") - private String path; + private String path = "/"; @ApiModelProperty(value = "上传的文件名", example = "test.mp4") @NotBlank(message = "上传的文件名不能为空") @@ -29,5 +28,8 @@ public class UploadFileRequest { @ApiModelProperty(value = "文件大小", example = "129102") private Long size; + + @ApiModelProperty(value = "文件夹密码, 如果文件夹需要密码才能访问,则支持请求密码", example = "123456") + private String password; } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/model/result/FileInfoResult.java b/src/main/java/im/zhaojun/zfile/module/storage/model/result/FileInfoResult.java similarity index 90% rename from src/main/java/im/zhaojun/zfile/home/model/result/FileInfoResult.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/result/FileInfoResult.java index 292fe0b..de697be 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/result/FileInfoResult.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/result/FileInfoResult.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.home.model.result; +package im.zhaojun.zfile.module.storage.model.result; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; diff --git a/src/main/java/im/zhaojun/zfile/home/model/result/FileItemResult.java b/src/main/java/im/zhaojun/zfile/module/storage/model/result/FileItemResult.java similarity index 66% rename from src/main/java/im/zhaojun/zfile/home/model/result/FileItemResult.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/result/FileItemResult.java index 03c836e..aa3c2fb 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/result/FileItemResult.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/result/FileItemResult.java @@ -1,6 +1,8 @@ -package im.zhaojun.zfile.home.model.result; +package im.zhaojun.zfile.module.storage.model.result; -import im.zhaojun.zfile.home.model.enums.FileTypeEnum; +import com.fasterxml.jackson.annotation.JsonIgnore; +import im.zhaojun.zfile.core.util.StringUtils; +import im.zhaojun.zfile.module.storage.model.enums.FileTypeEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -34,5 +36,15 @@ public class FileItemResult implements Serializable { @ApiModelProperty(value = "下载地址", example = "http://www.example.com/a.mp4") private String url; + + /** + * 获取路径和名称的组合, 并移除重复的路径分隔符 /. + * + * @return 路径和名称的组合 + */ + @JsonIgnore + public String getFullPath() { + return StringUtils.concat(path, name); + } } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/admin/model/result/gd/GdDriveInfoResult.java b/src/main/java/im/zhaojun/zfile/module/storage/model/result/GoogleDriveInfoResult.java similarity index 83% rename from src/main/java/im/zhaojun/zfile/admin/model/result/gd/GdDriveInfoResult.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/result/GoogleDriveInfoResult.java index d63331f..8f662c7 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/result/gd/GdDriveInfoResult.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/result/GoogleDriveInfoResult.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.result.gd; +package im.zhaojun.zfile.module.storage.model.result; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -13,7 +13,7 @@ import lombok.Data; @Data @AllArgsConstructor @ApiModel(value="gd drive 基本信息结果类") -public class GdDriveInfoResult { +public class GoogleDriveInfoResult { @ApiModelProperty(value = "drive id", example = "0AGrY0xF1D7PEUk9PVB") private String id; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/result/s3/S3BucketNameResult.java b/src/main/java/im/zhaojun/zfile/module/storage/model/result/S3BucketNameResult.java similarity index 90% rename from src/main/java/im/zhaojun/zfile/admin/model/result/s3/S3BucketNameResult.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/result/S3BucketNameResult.java index 0285f99..cccfcf1 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/result/s3/S3BucketNameResult.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/result/S3BucketNameResult.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.result.s3; +package im.zhaojun.zfile.module.storage.model.result; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/result/sharepoint/SharepointSiteList.java b/src/main/java/im/zhaojun/zfile/module/storage/model/result/SharepointSiteListResult.java similarity index 85% rename from src/main/java/im/zhaojun/zfile/admin/model/result/sharepoint/SharepointSiteList.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/result/SharepointSiteListResult.java index 39c5fa5..b4c4191 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/result/sharepoint/SharepointSiteList.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/result/SharepointSiteListResult.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.result.sharepoint; +package im.zhaojun.zfile.module.storage.model.result; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -13,7 +13,7 @@ import java.util.Date; */ @Data @ApiModel(description = "Sharepoint 网站 list 列表") -public class SharepointSiteList { +public class SharepointSiteListResult { @ApiModelProperty(value="站点目录 id") private String id; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/result/sharepoint/SharepointSite.java b/src/main/java/im/zhaojun/zfile/module/storage/model/result/SharepointSiteResult.java similarity index 82% rename from src/main/java/im/zhaojun/zfile/admin/model/result/sharepoint/SharepointSite.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/result/SharepointSiteResult.java index 87966bc..426a602 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/result/sharepoint/SharepointSite.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/result/SharepointSiteResult.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.admin.model.result.sharepoint; +package im.zhaojun.zfile.module.storage.model.result; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -11,7 +11,7 @@ import lombok.Data; */ @Data @ApiModel(description = "SharePoint 站点结果类") -public class SharepointSite { +public class SharepointSiteResult { @ApiModelProperty(value="站点 id") private String id; diff --git a/src/main/java/im/zhaojun/zfile/admin/model/result/storage/StorageSourceAdminResult.java b/src/main/java/im/zhaojun/zfile/module/storage/model/result/StorageSourceAdminResult.java similarity index 88% rename from src/main/java/im/zhaojun/zfile/admin/model/result/storage/StorageSourceAdminResult.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/result/StorageSourceAdminResult.java index eebd0a0..f196b63 100644 --- a/src/main/java/im/zhaojun/zfile/admin/model/result/storage/StorageSourceAdminResult.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/result/StorageSourceAdminResult.java @@ -1,8 +1,8 @@ -package im.zhaojun.zfile.admin.model.result.storage; +package im.zhaojun.zfile.module.storage.model.result; -import im.zhaojun.zfile.admin.model.enums.SearchModeEnum; -import im.zhaojun.zfile.common.cache.RefreshTokenCache; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.model.enums.SearchModeEnum; +import im.zhaojun.zfile.module.storage.model.bo.RefreshTokenCacheBO; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -76,7 +76,7 @@ public class StorageSourceAdminResult { @ApiModelProperty(value = "存储源刷新信息") - private RefreshTokenCache.RefreshTokenInfo refreshTokenInfo; + private RefreshTokenCacheBO.RefreshTokenInfo refreshTokenInfo; @ApiModelProperty(value = "兼容 readme 模式", example = "true", notes = "兼容模式, 目录文档读取 readme.md 文件") diff --git a/src/main/java/im/zhaojun/zfile/home/model/result/StorageSourceConfigResult.java b/src/main/java/im/zhaojun/zfile/module/storage/model/result/StorageSourceConfigResult.java similarity index 87% rename from src/main/java/im/zhaojun/zfile/home/model/result/StorageSourceConfigResult.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/result/StorageSourceConfigResult.java index f989747..3da2778 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/result/StorageSourceConfigResult.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/result/StorageSourceConfigResult.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.home.model.result; +package im.zhaojun.zfile.module.storage.model.result; -import im.zhaojun.zfile.admin.model.enums.ReadmeDisplayModeEnum; +import im.zhaojun.zfile.module.readme.model.enums.ReadmeDisplayModeEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; diff --git a/src/main/java/im/zhaojun/zfile/home/model/result/StorageSourceResult.java b/src/main/java/im/zhaojun/zfile/module/storage/model/result/StorageSourceResult.java similarity index 88% rename from src/main/java/im/zhaojun/zfile/home/model/result/StorageSourceResult.java rename to src/main/java/im/zhaojun/zfile/module/storage/model/result/StorageSourceResult.java index 90f6abf..7e887b8 100644 --- a/src/main/java/im/zhaojun/zfile/home/model/result/StorageSourceResult.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/model/result/StorageSourceResult.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.home.model.result; +package im.zhaojun.zfile.module.storage.model.result; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; diff --git a/src/main/java/im/zhaojun/zfile/common/schedule/AccessTokenRefreshSchedule.java b/src/main/java/im/zhaojun/zfile/module/storage/schedule/AccessTokenRefreshSchedule.java similarity index 73% rename from src/main/java/im/zhaojun/zfile/common/schedule/AccessTokenRefreshSchedule.java rename to src/main/java/im/zhaojun/zfile/module/storage/schedule/AccessTokenRefreshSchedule.java index d03573a..e655d43 100644 --- a/src/main/java/im/zhaojun/zfile/common/schedule/AccessTokenRefreshSchedule.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/schedule/AccessTokenRefreshSchedule.java @@ -1,7 +1,7 @@ -package im.zhaojun.zfile.common.schedule; +package im.zhaojun.zfile.module.storage.schedule; -import im.zhaojun.zfile.common.context.StorageSourceContext; -import im.zhaojun.zfile.home.service.base.RefreshTokenService; +import im.zhaojun.zfile.module.storage.context.StorageSourceContext; +import im.zhaojun.zfile.module.storage.service.base.RefreshTokenService; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; @@ -37,11 +37,14 @@ public class AccessTokenRefreshSchedule { RefreshTokenService refreshTokenService = refreshTokenServiceEntry.getValue(); try { refreshTokenService.refreshAccessToken(); - log.info("尝试刷新存储源 {} AccessToken, 刷新成功", storageId); + log.info("成功刷新存储源 AccessToken, 存储源 id: {}, 存储源类型: {}", + storageId, refreshTokenService.getStorageTypeEnum().getDescription()); } catch (Exception e) { - log.error("尝试刷新存储源 {} AccessToken, 刷新失败", storageId); + log.error("刷新存储源 AccessToken 失败, 存储源 id: {}, 存储源类型: {}", + storageId, refreshTokenService.getStorageTypeEnum().getDescription(), e); } } + log.info("执行需要定期刷新 AccessToken 存储源的定时任务完成"); } diff --git a/src/main/java/im/zhaojun/zfile/module/storage/service/StorageSourceConfigService.java b/src/main/java/im/zhaojun/zfile/module/storage/service/StorageSourceConfigService.java new file mode 100644 index 0000000..b4e8fbb --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/StorageSourceConfigService.java @@ -0,0 +1,192 @@ +package im.zhaojun.zfile.module.storage.service; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; +import im.zhaojun.zfile.module.storage.model.bo.StorageSourceParamDef; +import im.zhaojun.zfile.module.storage.mapper.StorageSourceConfigMapper; +import im.zhaojun.zfile.module.storage.model.entity.StorageSourceConfig; +import im.zhaojun.zfile.module.storage.context.StorageSourceContext; +import im.zhaojun.zfile.core.exception.file.init.InitializeStorageSourceException; +import im.zhaojun.zfile.core.util.CodeMsg; +import im.zhaojun.zfile.module.storage.model.dto.StorageSourceAllParamDTO; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * 存储源拓展配置 Service + * + * @author zhaojun + */ +@Service +@Slf4j +@CacheConfig(cacheNames = "storageSourceConfig") +public class StorageSourceConfigService { + + @Resource + private StorageSourceConfigMapper storageSourceConfigMapper; + + @Resource + private StorageSourceConfigService storageSourceConfigService; + + /** + * 根据存储源 ID 查询存储源拓展配置, 并按照存储源 id 排序 + * + * @param storageId + * 存储源 ID + * + * @return 存储源拓展配置列表 + */ + @Cacheable(key = "#storageId", unless = "#result == null or #result.size() == 0") + public List selectStorageConfigByStorageId(Integer storageId) { + return storageSourceConfigMapper.findByStorageIdOrderById(storageId); + } + + + /** + * 获取指定存储源的指定参数名称 + * + * @param storageId + * 存储源 id + * + * @param name + * 参数名 + * + * @return 参数信息 + */ + public StorageSourceConfig findByStorageIdAndName(Integer storageId, String name) { + return storageSourceConfigService + .selectStorageConfigByStorageId(storageId) + .stream() + .filter(storageSourceConfig -> StrUtil.equals(name, storageSourceConfig.getName())) + .findFirst() + .orElse(null); + } + + + /** + * 根据存储源 id 删除所有设置 + * + * @param storageId + * 存储源 ID + */ + @CacheEvict(key = "#storageId") + public int deleteByStorageId(Integer storageId) { + int deleteSize = storageSourceConfigMapper.deleteByStorageId(storageId); + log.info("删除存储源 ID 为 {} 的参数配置 {} 条", storageId, deleteSize); + return deleteSize; + } + + + /** + * 批量保存 + * + * @param storageId + * 存储源 ID + * + * @param configList + * 实体对象集合 + */ + @Transactional(rollbackFor = Exception.class) + public void saveBatch(Integer storageId, Collection configList) { + storageSourceConfigService.deleteByStorageId(storageId); + + log.info("更新存储源 ID 为 {} 的参数配置 {} 条", storageId, configList.size()); + + configList.forEach(storageSourceConfig -> { + storageSourceConfig.setStorageId(storageId); + storageSourceConfigMapper.insert(storageSourceConfig); + + if (log.isDebugEnabled()) { + log.debug("新增存储源参数配置, 存储源 ID: {}, 存储源类型: {}, 参数名: {}", + storageSourceConfig.getStorageId(), storageSourceConfig.getType().getDescription(), + storageSourceConfig.getName()); + } + }); + } + + /** + * 批量更新存储源设置 + * + * @param storageSourceConfigList + * 存储源设置列表 + */ + @Transactional(rollbackFor = Exception.class) + @CacheEvict(key = "#storageId") + public void updateBatch(Integer storageId, List storageSourceConfigList) { + storageSourceConfigList.forEach(storageSourceConfig -> { + storageSourceConfig.setStorageId(storageId); + storageSourceConfigMapper.updateById(storageSourceConfig); + + if (log.isDebugEnabled()) { + log.debug("更新存储源参数配置, 存储源 ID: {}, 存储源类型: {}, 参数名: {}", + storageSourceConfig.getStorageId(), storageSourceConfig.getType().getDescription(), + storageSourceConfig.getName()); + } + }); + } + + + /** + * 将存储源所有参数转换成指定存储类型的参数对象列表 + * + * @param storageId + * 存储源 ID + * + * @param storageType + * 存储源类型 + * + * @param storageSourceAllParam + * 存储源所有参数 + */ + public List toStorageSourceConfigList(Integer storageId, StorageTypeEnum storageType, StorageSourceAllParamDTO storageSourceAllParam) { + // 返回结果 + List result = new ArrayList<>(); + + // 获取该存储源类型需要的参数列表 + List storageSourceParamList = StorageSourceContext.getStorageSourceParamListByType(storageType); + + // 遍历参数列表, 将参数转换成存储源参数对象 + for (StorageSourceParamDef storageSourceParam : storageSourceParamList) { + // 根据字段名称获取字段值 + Object fieldValue = ReflectUtil.getFieldValue(storageSourceAllParam, storageSourceParam.getKey()); + String fieldStrValue = Convert.toStr(fieldValue); + + // 校验是否必填, 如果不符合则抛出异常 + boolean paramRequired = storageSourceParam.isRequired(); + if (paramRequired && StrUtil.isEmpty(fieldStrValue)) { + String errMsg = StrUtil.format("参数「{}」不能为空", storageSourceParam.getName()); + throw new InitializeStorageSourceException(CodeMsg.STORAGE_SOURCE_INIT_STORAGE_CONFIG_FAIL, + storageId, errMsg).setResponseExceptionMessage(true); + } + + // 校验如果有默认值,则填充默认值 + String paramDefaultValue = storageSourceParam.getDefaultValue(); + if (StrUtil.isNotEmpty(paramDefaultValue) && StrUtil.isEmpty(fieldStrValue)) { + fieldStrValue = paramDefaultValue; + } + + // 添加到结果列表 + StorageSourceConfig storageSourceConfig = new StorageSourceConfig(); + storageSourceConfig.setTitle(storageSourceParam.getName()); + storageSourceConfig.setName(storageSourceParam.getKey()); + storageSourceConfig.setValue(fieldStrValue); + storageSourceConfig.setType(storageType); + storageSourceConfig.setStorageId(storageId); + result.add(storageSourceConfig); + } + + return result; + } + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/module/storage/service/StorageSourceService.java b/src/main/java/im/zhaojun/zfile/module/storage/service/StorageSourceService.java new file mode 100644 index 0000000..5edf42e --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/StorageSourceService.java @@ -0,0 +1,369 @@ +package im.zhaojun.zfile.module.storage.service; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; +import im.zhaojun.zfile.core.exception.StorageSourceException; +import im.zhaojun.zfile.core.exception.file.InvalidStorageSourceException; +import im.zhaojun.zfile.core.util.CodeMsg; +import im.zhaojun.zfile.module.filter.service.FilterConfigService; +import im.zhaojun.zfile.module.link.service.ShortLinkService; +import im.zhaojun.zfile.module.log.service.DownloadLogService; +import im.zhaojun.zfile.module.password.service.PasswordConfigService; +import im.zhaojun.zfile.module.readme.model.entity.ReadmeConfig; +import im.zhaojun.zfile.module.readme.service.ReadmeConfigService; +import im.zhaojun.zfile.module.storage.context.StorageSourceContext; +import im.zhaojun.zfile.module.storage.convert.StorageSourceConvert; +import im.zhaojun.zfile.module.storage.mapper.StorageSourceMapper; +import im.zhaojun.zfile.module.storage.model.dto.StorageSourceAllParamDTO; +import im.zhaojun.zfile.module.storage.model.dto.StorageSourceDTO; +import im.zhaojun.zfile.module.storage.model.entity.StorageSource; +import im.zhaojun.zfile.module.storage.model.entity.StorageSourceConfig; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.model.request.admin.UpdateStorageSortRequest; +import im.zhaojun.zfile.module.storage.model.request.base.FileListConfigRequest; +import im.zhaojun.zfile.module.storage.model.request.base.SaveStorageSourceRequest; +import im.zhaojun.zfile.module.storage.model.result.StorageSourceConfigResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +/** + * 存储源基本信息 Service + * + * @author zhaojun + */ +@Slf4j +@Service +@CacheConfig(cacheNames = "storageSource") +public class StorageSourceService { + + @Resource + private StorageSourceMapper storageSourceMapper; + + @Resource + private StorageSourceService storageSourceService; + + @Resource + private StorageSourceContext storageSourceContext; + + @Resource + private StorageSourceConvert storageSourceConvert; + + @Resource + private StorageSourceConfigService storageSourceConfigService; + + @Resource + private FilterConfigService filterConfigService; + + @Resource + private PasswordConfigService passwordConfigService; + + @Resource + private ReadmeConfigService readmeConfigService; + + @Resource + private ShortLinkService shortLinkService; + + @Resource + private DownloadLogService downloadLogService; + + + /** + * 获取所有存储源列表 + * + * @return 存储源列表 + */ + public List findAllOrderByOrderNum() { + return storageSourceMapper.findAllOrderByOrderNum(); + } + + + /** + * 获取所有已启用的存储源列表,按照存储源的排序号排序 + * + * @return 已启用的存储源列表 + */ + public List findAllEnableOrderByOrderNum() { + return storageSourceMapper.findListByEnableOrderByOrderNum(); + } + + + /** + * 获取指定存储源设置 + * + * @param id + * 存储源 ID + * + * @return 存储源设置 + */ + @Cacheable(key = "#id", unless = "#result == null") + public StorageSource findById(Integer id) { + return storageSourceMapper.selectById(id); + } + + + /** + * 根据存储源 key 获取存储源 + * + * @param storageKey + * 存储源 key + * + * @throws InvalidStorageSourceException 存储源不存在时, 抛出异常. + * + * @return 存储源信息 + */ + @Cacheable(key = "#storageKey", unless = "#result == null") + public StorageSource findByStorageKey(String storageKey) { + return storageSourceMapper.findByStorageKey(storageKey); + } + + + /** + * 根据存储源 key 获取存储源 id + * + * @param storageKey + * 存储源 key + * + * @return 存储源信息 + */ + public Integer findIdByKey(String storageKey) { + return Optional.ofNullable(storageSourceService.findByStorageKey(storageKey)).map(StorageSource::getId).orElse(null); + } + + + /** + * 根据存储源 id 获取存储源 key + * + * @param id + * 存储源 id + * + * @return 存储源 key + */ + public String findStorageKeyById(Integer id){ + return Optional.ofNullable(storageSourceService.findById(id)).map(StorageSource::getKey).orElse(null); + } + + + /** + * 根据 id 获取指定存储源的类型. + * + * @param id + * 存储源 ID + * + * @return 存储源对应的类型. + */ + public StorageTypeEnum findStorageTypeById(Integer id) { + return Optional.ofNullable(storageSourceService.findById(id)).map(StorageSource::getType).orElse(null); + } + + + /** + * 获取指定存储源 DTO 对象, 此对象包含详细的参数设置. + * + * @param id + * 存储源 ID + * + * @return 存储源 DTO + */ + @Cacheable(key = "'dto-' + #id", unless = "#result == null") + public StorageSourceDTO findDTOById(Integer id) { + // 将参数列表通过反射写入到 StorageSourceAllParam 中. + StorageSourceAllParamDTO storageSourceAllParam = new StorageSourceAllParamDTO(); + storageSourceConfigService.selectStorageConfigByStorageId(id) + .forEach(storageSourceConfig -> + ReflectUtil.setFieldValue(storageSourceAllParam, storageSourceConfig.getName(), storageSourceConfig.getValue()) + ); + + // 获取数据库对象,转为 dto 对象返回 + StorageSource storageSource = findById(id); + return storageSourceConvert.entityToDTO(storageSource, storageSourceAllParam); + } + + + /** + * 判断存储源 key 是否已存在 (不读取缓存) + * + * @param storageKey + * 存储源 key + * + * @return 是否已存在 + */ + public boolean existByStorageKey(String storageKey) { + return storageSourceService.findByStorageKey(storageKey) != null; + } + + + /** + * 删除指定存储源设置, 会级联删除其参数设置 + * + * @param id + * 存储源 ID + */ + @Transactional(rollbackFor = Exception.class) + @Caching(evict = { + @CacheEvict(key = "#id"), + @CacheEvict(key = "'dto-' + #id"), + @CacheEvict(key = "#result.key", condition = "#result != null") + }) + public StorageSource deleteById(Integer id) { + log.info("删除 id 为 {} 的存储源", id); + StorageSource storageSource = findById(id); + + if (storageSource == null) { + String msg = StrUtil.format("删除存储源时检测到 id 为 {} 的存储源不存在", id); + throw new StorageSourceException(CodeMsg.STORAGE_SOURCE_NOT_FOUND, id, msg); + } + + String storageKey = storageSource.getKey(); + + int deleteEntitySize = storageSourceMapper.deleteById(id); + int deleteConfigSize = storageSourceConfigService.deleteByStorageId(id); + + int clearPasswordSize = passwordConfigService.deleteByStorageId(id); + int clearFilterSize = filterConfigService.deleteByStorageId(id); + int clearReadmeSize = readmeConfigService.deleteByStorageId(id); + + int clearShortLinkSize = shortLinkService.deleteByStorageId(id); + int clearDownloadLogSize = downloadLogService.deleteByStorageKey(storageKey); + + storageSourceContext.destroy(id); + log.info("尝试删除存储源 {} 成功, 已清理相关数据及上下文环境(存储源 {} 条、存储源设置 {} 条、" + + "密码规则 {} 条、过滤规则 {} 条,目录文档 {} 条、直链 {} 条、直链下载日志 {} 条)", + id, deleteEntitySize, deleteConfigSize, + clearPasswordSize, clearFilterSize, clearReadmeSize, clearShortLinkSize, clearDownloadLogSize); + return storageSource; + } + + + /** + * 交换存储源排序 + * + * @param updateStorageSortRequestList + * 更新排序的存储源 id 及排序值列表 + */ + @Transactional(rollbackFor = Exception.class) + @CacheEvict(allEntries = true) + public void updateStorageSort(List updateStorageSortRequestList) { + for (int i = 0; i < updateStorageSortRequestList.size(); i++) { + UpdateStorageSortRequest item = updateStorageSortRequestList.get(i); + if (!Objects.equals(i, item.getOrderNum())) { + log.info("变更存储源 {} 顺序号为 {}", item.getId(), i); + storageSourceMapper.updateSetOrderNumById(i, item.getId()); + } + } + } + + + @Caching(evict = { + @CacheEvict(key = "#entity.id"), + @CacheEvict(key = "#entity.key"), + @CacheEvict(key = "'dto-' + #entity.id") + }) + public void updateById(StorageSource entity) { + storageSourceMapper.updateById(entity); + } + + + /** + * 保存存储源基本信息及其对应的参数设置 + * + * @param saveStorageSourceRequest + * 存储源 DTO 对象 + */ + @Transactional(rollbackFor = Exception.class) + public Integer saveStorageSource(SaveStorageSourceRequest saveStorageSourceRequest) { + log.info("尝试保存存储源, id: {}, name: {}, key: {}, type: {}", + saveStorageSourceRequest.getId(), saveStorageSourceRequest.getName(), + saveStorageSourceRequest.getKey(), saveStorageSourceRequest.getType().getDescription()); + + // 转换为存储源 entity 对象 + StorageSource storageSource = storageSourceConvert.saveRequestToEntity(saveStorageSourceRequest); + + // 保存或更新存储源 + StorageSource dbSaveResult = storageSourceService.saveOrUpdate(storageSource); + + log.info("保存存储源成功, id: {}, name: {}, key: {}, type: {}", + dbSaveResult.getId(), dbSaveResult.getName(), + dbSaveResult.getKey(), dbSaveResult.getType().getDescription()); + + // 存储源 ID + Integer storageId = dbSaveResult.getId(); + + // 保存存储源参数 + List storageSourceConfigList = + storageSourceConfigService.toStorageSourceConfigList(storageId, + dbSaveResult.getType(), + saveStorageSourceRequest.getStorageSourceAllParam()); + storageSourceConfigService.saveBatch(storageId, storageSourceConfigList); + log.info("保存存储源参数成功,尝试根据参数初始化存储源, id: {}, name: {}, config size: {}", + dbSaveResult.getId(), dbSaveResult.getName(), storageSourceConfigList.size()); + + // 初始化并检查是否可用 + storageSourceContext.init(storageId); + log.info("根据参数初始化存储源成功, id: {}, name: {}, config size: {}", + dbSaveResult.getId(), dbSaveResult.getName(), storageSourceConfigList.size()); + + return storageId; + } + + + /** + * 保存或修改存储源设置,如果没有 id 则新增,有则更新,且会检测是否填写 key,如果没写,则自动将 id 设置为 key 并保存。 + * + * @param storageSource + * 存储源对象 + * + * @return 保存后对象 + */ + @Caching(evict = { + @CacheEvict(key = "#result.id"), + @CacheEvict(key = "'dto-' + #result.id"), + @CacheEvict(key = "#result.key") + }) + public StorageSource saveOrUpdate(StorageSource storageSource) { + // 保存存储源基本信息 + if (storageSource.getId() == null) { + storageSourceMapper.insert(storageSource); + } else { + storageSourceMapper.updateById(storageSource); + } + + // 如果没输入存储源 key, 则自动将 id 设置为 key + if (StrUtil.isEmpty(storageSource.getKey()) && !StrUtil.equals(storageSource.getId().toString(), storageSource.getKey())) { + storageSource.setKey(Convert.toStr(storageSource.getId())); + storageSourceMapper.updateById(storageSource); + } + return storageSource; + } + + + public StorageSourceConfigResult getStorageConfigSource(FileListConfigRequest fileListConfigRequest) { + String storageKey = fileListConfigRequest.getStorageKey(); + String path = fileListConfigRequest.getPath(); + + // 判断存储源是否存在. + StorageSource storageSource = findByStorageKey(storageKey); + if (storageSource == null) { + throw new InvalidStorageSourceException("通过存储源 key 未找到存储源, key: " + storageKey); + } + + // 根据存储源 key 获取存储源 id + Integer storageId = storageSource.getId(); + + // 获取指定存储源路径下的 readme 信息 + ReadmeConfig readmeByPath = readmeConfigService.getByStorageAndPath(storageId, path, storageSource.getCompatibilityReadme()); + return storageSourceConvert.entityToConfigResult(storageSource, readmeByPath); + } + + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/service/base/AbstractBaseFileService.java b/src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractBaseFileService.java similarity index 83% rename from src/main/java/im/zhaojun/zfile/home/service/base/AbstractBaseFileService.java rename to src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractBaseFileService.java index 8234c1e..c75a783 100644 --- a/src/main/java/im/zhaojun/zfile/home/service/base/AbstractBaseFileService.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractBaseFileService.java @@ -1,23 +1,22 @@ -package im.zhaojun.zfile.home.service.base; +package im.zhaojun.zfile.module.storage.service.base; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.StrUtil; -import im.zhaojun.zfile.admin.annotation.StorageParamItem; -import im.zhaojun.zfile.admin.annotation.StorageParamSelect; -import im.zhaojun.zfile.admin.annotation.StorageParamSelectOption; -import im.zhaojun.zfile.admin.annotation.model.StorageSourceParamDef; -import im.zhaojun.zfile.admin.model.enums.StorageParamTypeEnum; -import im.zhaojun.zfile.admin.model.param.IStorageParam; -import im.zhaojun.zfile.admin.service.SystemConfigService; -import im.zhaojun.zfile.common.cache.ZFileCache; -import im.zhaojun.zfile.common.exception.InitializeStorageSourceException; -import im.zhaojun.zfile.common.util.ClassUtils; -import im.zhaojun.zfile.common.util.PlaceholderUtils; -import im.zhaojun.zfile.common.util.StringUtils; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; -import im.zhaojun.zfile.home.model.result.FileItemResult; +import im.zhaojun.zfile.core.exception.file.init.InitializeStorageSourceException; +import im.zhaojun.zfile.core.util.ClassUtils; +import im.zhaojun.zfile.core.util.CodeMsg; +import im.zhaojun.zfile.core.util.PlaceholderUtils; +import im.zhaojun.zfile.core.util.StringUtils; +import im.zhaojun.zfile.module.config.service.SystemConfigService; +import im.zhaojun.zfile.module.storage.annotation.StorageParamItem; +import im.zhaojun.zfile.module.storage.annotation.StorageParamSelect; +import im.zhaojun.zfile.module.storage.annotation.StorageParamSelectOption; +import im.zhaojun.zfile.module.storage.model.bo.StorageSourceParamDef; +import im.zhaojun.zfile.module.storage.model.enums.StorageParamTypeEnum; +import im.zhaojun.zfile.module.storage.model.param.IStorageParam; +import im.zhaojun.zfile.module.storage.model.result.FileItemResult; import lombok.extern.slf4j.Slf4j; import javax.annotation.Resource; @@ -34,9 +33,6 @@ import java.util.concurrent.ConcurrentHashMap; @Slf4j public abstract class AbstractBaseFileService

      implements BaseFileService { - @Resource - private ZFileCache zFileCache; - @Resource private SystemConfigService systemConfigService; @@ -84,7 +80,7 @@ public abstract class AbstractBaseFileService

      implement fileList("/"); isInitialized = true; } catch (Exception e) { - throw new InitializeStorageSourceException("初始化异常, 错误信息为: " + e.getMessage(), e); + throw new InitializeStorageSourceException(CodeMsg.STORAGE_SOURCE_INIT_FAIL, storageId, "初始化异常, 错误信息为: " + e.getMessage(), e).setResponseExceptionMessage(true); } } @@ -163,7 +159,7 @@ public abstract class AbstractBaseFileService

      implement // 从实现类中通过反射获取 options Class storageParamSelectClass = annotation.optionsClass(); if (ObjectUtil.isNotEmpty(storageParamSelectClass) - && ObjectUtil.notEqual(storageParamSelectClass.getName(), "im.zhaojun.zfile.admin.annotation.StorageParamSelect")) { + && ObjectUtil.notEqual(storageParamSelectClass.getName(), "im.zhaojun.zfile.module.storage.annotation.StorageParamSelect")) { StorageParamSelect storageParamSelect = ReflectUtil.newInstance(storageParamSelectClass); List storageParamSelectOptions = storageParamSelect.getOptions(annotation, param); optionsList.addAll(storageParamSelectOptions); @@ -219,14 +215,14 @@ public abstract class AbstractBaseFileService

      implement public void setStorageId(Integer storageId) { if (this.storageId != null) { - throw new RuntimeException("请勿重复初始化存储源"); + throw new IllegalStateException("请勿重复初始化存储源"); } this.storageId = storageId; } public void setParam(P param) { if (this.param != null) { - throw new RuntimeException("请勿重复初始化存储源"); + throw new IllegalStateException("请勿重复初始化存储源"); } this.param = param; } @@ -251,14 +247,6 @@ public abstract class AbstractBaseFileService

      implement } - /** - * 获取当前实现类的存储源类型 - * - * @return 存储源类型枚举对象 - */ - public abstract StorageTypeEnum getStorageTypeEnum(); - - public P getParam() { return param; } diff --git a/src/main/java/im/zhaojun/zfile/home/service/base/MicrosoftDriveServiceBase.java b/src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractMicrosoftDriveService.java similarity index 72% rename from src/main/java/im/zhaojun/zfile/home/service/base/MicrosoftDriveServiceBase.java rename to src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractMicrosoftDriveService.java index c4302ff..5e8f5c2 100644 --- a/src/main/java/im/zhaojun/zfile/home/service/base/MicrosoftDriveServiceBase.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractMicrosoftDriveService.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.home.service.base; +package im.zhaojun.zfile.module.storage.service.base; import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.URLUtil; @@ -7,17 +7,17 @@ import cn.hutool.http.HttpResponse; import cn.hutool.http.HttpUtil; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; -import im.zhaojun.zfile.admin.constant.StorageConfigConstant; -import im.zhaojun.zfile.admin.model.dto.OAuth2Token; -import im.zhaojun.zfile.admin.model.entity.StorageSourceConfig; -import im.zhaojun.zfile.admin.model.param.MicrosoftDriveParam; -import im.zhaojun.zfile.admin.service.StorageSourceConfigService; -import im.zhaojun.zfile.common.cache.RefreshTokenCache; -import im.zhaojun.zfile.common.constant.ZFileConstant; -import im.zhaojun.zfile.common.exception.StorageSourceRefreshTokenException; -import im.zhaojun.zfile.common.util.StringUtils; -import im.zhaojun.zfile.home.model.enums.FileTypeEnum; -import im.zhaojun.zfile.home.model.result.FileItemResult; +import im.zhaojun.zfile.module.storage.constant.StorageConfigConstant; +import im.zhaojun.zfile.module.storage.model.dto.OAuth2TokenDTO; +import im.zhaojun.zfile.module.storage.model.entity.StorageSourceConfig; +import im.zhaojun.zfile.module.storage.model.param.MicrosoftDriveParam; +import im.zhaojun.zfile.module.storage.service.StorageSourceConfigService; +import im.zhaojun.zfile.module.storage.model.bo.RefreshTokenCacheBO; +import im.zhaojun.zfile.core.constant.ZFileConstant; +import im.zhaojun.zfile.core.exception.StorageSourceRefreshTokenException; +import im.zhaojun.zfile.core.util.StringUtils; +import im.zhaojun.zfile.module.storage.model.enums.FileTypeEnum; +import im.zhaojun.zfile.module.storage.model.result.FileItemResult; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Lazy; import org.springframework.http.HttpEntity; @@ -35,8 +35,11 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; +/** + * @author zhaojun + */ @Slf4j -public abstract class MicrosoftDriveServiceBase

      extends AbstractBaseFileService

      implements RefreshTokenService { +public abstract class AbstractMicrosoftDriveService

      extends AbstractBaseFileService

      implements RefreshTokenService { /** * 获取根文件 API URI @@ -90,7 +93,7 @@ public abstract class MicrosoftDriveServiceBase

      e * * @return 刷新后的 Token */ - public OAuth2Token getRefreshToken() { + public OAuth2TokenDTO getRefreshToken() { StorageSourceConfig refreshStorageSourceConfig = storageSourceConfigService.findByStorageIdAndName(storageId, StorageConfigConstant.REFRESH_TOKEN_KEY); @@ -100,25 +103,34 @@ public abstract class MicrosoftDriveServiceBase

      e "&refresh_token=" + refreshStorageSourceConfig.getValue() + "&grant_type=refresh_token"; - log.info("{} 尝试刷新令牌, 参数信息为: {}", this, param); + log.info("存储源 {}({}) 尝试刷新令牌", storageId, this.getStorageTypeEnum().getDescription()); + + if (log.isDebugEnabled()) { + log.debug("存储源 {}({}) 尝试刷新令牌, 参数信息为: {}", storageId, this.getStorageTypeEnum().getDescription(), param); + } String fullAuthenticateUrl = AUTHENTICATE_URL.replace("{authenticateEndPoint}", getAuthenticateEndPoint()); HttpRequest post = HttpUtil.createPost(fullAuthenticateUrl); post.body(param, "application/x-www-form-urlencoded"); HttpResponse response = post.execute(); - String body = response.body(); - log.info("{} 尝试刷新令牌成功, 响应信息为: {}", this, body); + String responseBody = response.body(); - JSONObject jsonBody = JSONObject.parseObject(body); + log.info("存储源 {}({}) 刷新令牌完成, 响应信息为: httpStatus: {}", storageId, this.getStorageTypeEnum().getDescription(), response.getStatus()); + + if (log.isDebugEnabled()) { + log.debug("存储源 {}({}) 刷新令牌完成, 响应信息为: {}", storageId, this.getStorageTypeEnum().getDescription(), responseBody); + } + + JSONObject jsonBody = JSONObject.parseObject(responseBody); if (response.getStatus() != HttpStatus.OK.value()) { - return OAuth2Token.fail(getClientId(), getClientSecret(), getRedirectUri(), body); + return OAuth2TokenDTO.fail(getClientId(), getClientSecret(), getRedirectUri(), responseBody); } String accessToken = jsonBody.getString("access_token"); String refreshToken = jsonBody.getString("refresh_token"); - return OAuth2Token.success(getClientId(), getClientSecret(), getRedirectUri(), accessToken, refreshToken, body); + return OAuth2TokenDTO.success(getClientId(), getClientSecret(), getRedirectUri(), accessToken, refreshToken, responseBody); } /** @@ -129,31 +141,42 @@ public abstract class MicrosoftDriveServiceBase

      e * * @return 获取的 Token 信息. */ - public OAuth2Token getToken(String code, String clientId, String clientSecret, String redirectUri) { - log.info("{} 根据授权回调 code 获取令牌:code: {}, clientId: {}, clientSecret: {}, redirectUri: {}", this, code, clientId, clientSecret, redirectUri); + public OAuth2TokenDTO getToken(String code, String clientId, String clientSecret, String redirectUri) { String param = "client_id=" + clientId + "&redirect_uri=" + redirectUri + "&client_secret=" + clientSecret + "&code=" + code + "&scope=" + getScope() + "&grant_type=authorization_code"; - + + log.info("根据授权回调 code 获取存储源类型为 {} 的令牌, code: {}", this.getStorageTypeEnum().getDescription(), code); + + if (log.isDebugEnabled()) { + log.debug("根据授权回调 code 获取存储源类型为 {} 的令牌, 参数信息为: {}", this.getStorageTypeEnum().getDescription(), param); + } + String fullAuthenticateUrl = AUTHENTICATE_URL.replace("{authenticateEndPoint}", getAuthenticateEndPoint()); HttpRequest post = HttpUtil.createPost(fullAuthenticateUrl); post.body(param, "application/x-www-form-urlencoded"); HttpResponse response = post.execute(); - String body = response.body(); - log.info("{} 根据授权回调 code 获取令牌结果:body: {}", this, body); - JSONObject jsonBody = JSONObject.parseObject(body); + String responseBody = response.body(); + + log.info("根据授权回调 code 获取存储源类型为 {} 的令牌完成, 响应信息为: httpStatus: {}", this.getStorageTypeEnum().getDescription(), response.getStatus()); + + if (log.isDebugEnabled()) { + log.debug("根据授权回调 code 获取存储源类型为 {} 的令牌完成, 响应信息为: {}", this.getStorageTypeEnum().getDescription(), responseBody); + } + + JSONObject jsonBody = JSONObject.parseObject(responseBody); if (response.getStatus() != HttpStatus.OK.value()) { - return OAuth2Token.fail(clientId, clientSecret, redirectUri, body); + return OAuth2TokenDTO.fail(clientId, clientSecret, redirectUri, responseBody); } String accessToken = jsonBody.getString("access_token"); String refreshToken = jsonBody.getString("refresh_token"); - return OAuth2Token.success(clientId, clientSecret, redirectUri, accessToken, refreshToken, body); + return OAuth2TokenDTO.success(clientId, clientSecret, redirectUri, accessToken, refreshToken, responseBody); } @Override @@ -186,7 +209,7 @@ public abstract class MicrosoftDriveServiceBase

      e try { root = oneDriveRestTemplate.exchange(requestUrl, HttpMethod.GET, entity, JSONObject.class, getGraphEndPoint(), getType(), fullPath).getBody(); } catch (HttpClientErrorException e) { - log.debug("调用 OneDrive 时出现了网络异常, 响应信息: {}, 已尝试重新刷新 token 后再试.", e.getResponseBodyAsString()); + log.error("调用 OneDrive 时出现了网络异常, 响应信息: {}, 已尝试重新刷新 token 后再试.", e.getResponseBodyAsString(), e); refreshAccessToken(); root = oneDriveRestTemplate.exchange(requestUrl, HttpMethod.GET, entity, JSONObject.class, getGraphEndPoint(), getType(), fullPath).getBody(); } @@ -208,7 +231,7 @@ public abstract class MicrosoftDriveServiceBase

      e return result; } - + @Override public FileItemResult getFileItem(String pathAndName) { String fullPath = StringUtils.concat(param.getBasePath(), pathAndName); @@ -222,7 +245,7 @@ public abstract class MicrosoftDriveServiceBase

      e try { fileItem = oneDriveRestTemplate.exchange(DRIVER_ITEM_URL, HttpMethod.GET, entity, JSONObject.class, getGraphEndPoint(), getType(), fullPath).getBody(); } catch (HttpClientErrorException e) { - log.debug("调用 OneDrive 时出现了网络异常, 响应信息: {}, 已尝试重新刷新 token 后再试.", e.getResponseBodyAsString()); + log.error("调用 OneDrive 时出现了网络异常, 响应信息: {}, 已尝试重新刷新 token 后再试.", e.getResponseBodyAsString(), e); refreshAccessToken(); fileItem = oneDriveRestTemplate.exchange(DRIVER_ITEM_URL, HttpMethod.GET, entity, JSONObject.class, getGraphEndPoint(), getType(), fullPath).getBody(); } @@ -251,8 +274,6 @@ public abstract class MicrosoftDriveServiceBase

      e fullPath = StringUtils.trimEndSlashes(fullPath); - JSONObject result = null; - HttpHeaders headers = new HttpHeaders(); headers.set("storageId", storageId.toString()); HashMap data = new HashMap<>(); @@ -260,14 +281,9 @@ public abstract class MicrosoftDriveServiceBase

      e data.put("folder", new HashMap<>()); data.put("@microsoft.graph.conflictBehavior", "replace"); HttpEntity entity = new HttpEntity<>(data, headers); - - try { - result = oneDriveRestTemplate.exchange(requestUrl, HttpMethod.POST, entity, JSONObject.class, getGraphEndPoint(), getType(), fullPath).getBody(); - } catch (Exception e) { - log.error("存储源 {} 新建文件 {} 失败", storageId, fullPath, e); - } - - return result != null; + + ResponseEntity responseEntity = oneDriveRestTemplate.exchange(requestUrl, HttpMethod.POST, entity, JSONObject.class, getGraphEndPoint(), getType(), fullPath); + return responseEntity.getStatusCode().is2xxSuccessful(); } @Override @@ -282,14 +298,9 @@ public abstract class MicrosoftDriveServiceBase

      e HttpHeaders headers = new HttpHeaders(); headers.set("storageId", storageId.toString()); HttpEntity entity = new HttpEntity<>(headers); - - try { - oneDriveRestTemplate.exchange(DRIVER_ITEM_OPERATOR_URL, HttpMethod.DELETE, entity, JSONObject.class, getGraphEndPoint(), getType(), fullPath).getBody(); - } catch (Exception e) { - log.error("存储源 {} 删除文件 {} 失败", storageId, fullPath, e); - return false; - } - return true; + + ResponseEntity responseEntity = oneDriveRestTemplate.exchange(DRIVER_ITEM_OPERATOR_URL, HttpMethod.DELETE, entity, JSONObject.class, getGraphEndPoint(), getType(), fullPath); + return responseEntity.getStatusCode().is2xxSuccessful(); } @Override @@ -301,14 +312,9 @@ public abstract class MicrosoftDriveServiceBase

      e JSONObject jsonObject = new JSONObject(); jsonObject.put("name", newName); HttpEntity entity = new HttpEntity<>(jsonObject, headers); - - try { - oneDriveRestTemplate.exchange(DRIVER_ITEM_OPERATOR_URL, HttpMethod.PATCH, entity, JSONObject.class, getGraphEndPoint(), getType(), fullPath).getBody(); - } catch (Exception e) { - log.error("存储源 {} 重命名文件 {} 至 {} 失败", storageId, fullPath, newName, e); - return false; - } - return true; + + ResponseEntity responseEntity = oneDriveRestTemplate.exchange(DRIVER_ITEM_OPERATOR_URL, HttpMethod.PATCH, entity, JSONObject.class, getGraphEndPoint(), getType(), fullPath); + return responseEntity.getStatusCode().is2xxSuccessful(); } @Override @@ -316,7 +322,6 @@ public abstract class MicrosoftDriveServiceBase

      e return renameFile(path, name, newName); } - @Override public String getUploadUrl(String path, String name, Long size) { String fullPath = StringUtils.concat(param.getBasePath(), path, name); @@ -324,12 +329,12 @@ public abstract class MicrosoftDriveServiceBase

      e HttpHeaders headers = new HttpHeaders(); headers.set("storageId", storageId.toString()); HttpEntity entity = new HttpEntity<>(headers); - + ResponseEntity responseEntity = oneDriveRestTemplate.exchange(CREATE_UPLOAD_SESSION_URL, - HttpMethod.POST, entity, JSONObject.class, - getGraphEndPoint(), getType(), fullPath); + HttpMethod.POST, entity, JSONObject.class, + getGraphEndPoint(), getType(), fullPath); + JSONObject responseEntityBody = responseEntity.getBody(); - return responseEntityBody.getString("uploadUrl"); } @@ -383,10 +388,10 @@ public abstract class MicrosoftDriveServiceBase

      e @Override public void refreshAccessToken() { try { - OAuth2Token refreshToken = getRefreshToken(); + OAuth2TokenDTO refreshToken = getRefreshToken(); if (refreshToken.getAccessToken() == null || refreshToken.getRefreshToken() == null) { - throw new StorageSourceRefreshTokenException("获取或刷新 AccessToken 失败, 获取到的令牌为空, 相关诊断信息为: " + refreshToken, storageId); + throw new StorageSourceRefreshTokenException("存储源刷新令牌失败, 获取到令牌为空.", storageId); } StorageSourceConfig accessTokenConfig = @@ -396,12 +401,12 @@ public abstract class MicrosoftDriveServiceBase

      e accessTokenConfig.setValue(refreshToken.getAccessToken()); refreshTokenConfig.setValue(refreshToken.getRefreshToken()); - storageSourceConfigService.updateStorageConfig(Arrays.asList(accessTokenConfig, refreshTokenConfig)); - RefreshTokenCache.putRefreshTokenInfo(storageId, RefreshTokenCache.RefreshTokenInfo.success()); + storageSourceConfigService.updateBatch(storageId, Arrays.asList(accessTokenConfig, refreshTokenConfig)); + RefreshTokenCacheBO.putRefreshTokenInfo(storageId, RefreshTokenCacheBO.RefreshTokenInfo.success()); log.info("存储源 {} 刷新 AccessToken 成功", storageId); } catch (Exception e) { - RefreshTokenCache.putRefreshTokenInfo(storageId, RefreshTokenCache.RefreshTokenInfo.fail(getStorageTypeEnum().getDescription() + " AccessToken 刷新失败: " + e.getMessage())); - throw new StorageSourceRefreshTokenException("存储源 ID: [{}] 刷新 AccessToken 失败", e, storageId); + RefreshTokenCacheBO.putRefreshTokenInfo(storageId, RefreshTokenCacheBO.RefreshTokenInfo.fail(getStorageTypeEnum().getDescription() + " AccessToken 刷新失败: " + e.getMessage())); + throw new StorageSourceRefreshTokenException("存储源刷新令牌失败,获取时发生异常", e, storageId); } } diff --git a/src/main/java/im/zhaojun/zfile/home/service/base/AbstractOneDriveServiceBase.java b/src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractOneDriveServiceBase.java similarity index 71% rename from src/main/java/im/zhaojun/zfile/home/service/base/AbstractOneDriveServiceBase.java rename to src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractOneDriveServiceBase.java index ab5e6de..ce77c8a 100644 --- a/src/main/java/im/zhaojun/zfile/home/service/base/AbstractOneDriveServiceBase.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractOneDriveServiceBase.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.home.service.base; +package im.zhaojun.zfile.module.storage.service.base; -import im.zhaojun.zfile.admin.model.param.OneDriveParam; +import im.zhaojun.zfile.module.storage.model.param.OneDriveParam; import lombok.extern.slf4j.Slf4j; /** @@ -10,7 +10,7 @@ import lombok.extern.slf4j.Slf4j; * @author zhaojun */ @Slf4j -public abstract class AbstractOneDriveServiceBase

      extends MicrosoftDriveServiceBase { +public abstract class AbstractOneDriveServiceBase

      extends AbstractMicrosoftDriveService

      { @Override public void init() { diff --git a/src/main/java/im/zhaojun/zfile/home/service/base/ProxyDownloadService.java b/src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractProxyDownloadService.java similarity index 50% rename from src/main/java/im/zhaojun/zfile/home/service/base/ProxyDownloadService.java rename to src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractProxyDownloadService.java index 2a800e8..9670e59 100644 --- a/src/main/java/im/zhaojun/zfile/home/service/base/ProxyDownloadService.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractProxyDownloadService.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.home.service.base; +package im.zhaojun.zfile.module.storage.service.base; -import im.zhaojun.zfile.admin.model.param.ProxyDownloadParam; +import im.zhaojun.zfile.module.storage.model.param.ProxyDownloadParam; import java.io.InputStream; @@ -9,7 +9,7 @@ import java.io.InputStream; * @author zhaojun */ -public abstract class ProxyDownloadService

      extends ProxyTransferService

      { +public abstract class AbstractProxyDownloadService

      extends AbstractProxyTransferService

      { /** * 空实现. diff --git a/src/main/java/im/zhaojun/zfile/home/service/base/ProxyTransferService.java b/src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractProxyTransferService.java similarity index 77% rename from src/main/java/im/zhaojun/zfile/home/service/base/ProxyTransferService.java rename to src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractProxyTransferService.java index 01ea202..00f9545 100644 --- a/src/main/java/im/zhaojun/zfile/home/service/base/ProxyTransferService.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractProxyTransferService.java @@ -1,14 +1,15 @@ -package im.zhaojun.zfile.home.service.base; +package im.zhaojun.zfile.module.storage.service.base; import cn.hutool.core.util.StrUtil; -import im.zhaojun.zfile.admin.model.param.ProxyTransferParam; -import im.zhaojun.zfile.admin.service.StorageSourceService; -import im.zhaojun.zfile.admin.service.SystemConfigService; -import im.zhaojun.zfile.common.util.ProxyDownloadUrlUtils; -import im.zhaojun.zfile.common.util.StringUtils; +import im.zhaojun.zfile.module.storage.model.param.ProxyTransferParam; +import im.zhaojun.zfile.module.storage.service.StorageSourceService; +import im.zhaojun.zfile.module.config.service.SystemConfigService; +import im.zhaojun.zfile.core.util.ProxyDownloadUrlUtils; +import im.zhaojun.zfile.core.util.StringUtils; import org.springframework.core.io.Resource; import org.springframework.http.ResponseEntity; +import java.io.IOException; import java.io.InputStream; /** @@ -16,7 +17,7 @@ import java.io.InputStream; * * @author zhaojun */ -public abstract class ProxyTransferService

      extends AbstractBaseFileService

      { +public abstract class AbstractProxyTransferService

      extends AbstractBaseFileService

      { /** @@ -56,7 +57,7 @@ public abstract class ProxyTransferService

      extends // 如果未填写下载域名,则默认使用带来下载地址. if (StrUtil.isEmpty(param.getDomain())) { String domain = systemConfigService.getDomain(); - String storageKey = storageSourceService.findKeyById(storageId); + String storageKey = storageSourceService.findStorageKeyById(storageId); return StringUtils.concat(domain, PROXY_DOWNLOAD_LINK_PREFIX, storageKey, StringUtils.encodeAllIgnoreSlashes(pathAndName)) + signature; } else { return StringUtils.concat(param.getDomain(), StringUtils.encodeAllIgnoreSlashes(pathAndName)) + signature; @@ -81,7 +82,7 @@ public abstract class ProxyTransferService

      extends @Override public String getUploadUrl(String path, String name, Long size) { String domain = systemConfigService.getDomain(); - String storageKey = storageSourceService.findKeyById(storageId); + String storageKey = storageSourceService.findStorageKeyById(storageId); String pathAndName = StringUtils.concat(true, path, name); return StringUtils.concat(domain, PROXY_UPLOAD_LINK_PREFIX, storageKey, pathAndName); } @@ -107,6 +108,6 @@ public abstract class ProxyTransferService

      extends * * @return 文件响应. */ - public abstract ResponseEntity downloadToStream(String pathAndName); + public abstract ResponseEntity downloadToStream(String pathAndName) throws IOException; } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/service/base/ProxyUploadService.java b/src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractProxyUploadService.java similarity index 57% rename from src/main/java/im/zhaojun/zfile/home/service/base/ProxyUploadService.java rename to src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractProxyUploadService.java index 625064b..f1cbef8 100644 --- a/src/main/java/im/zhaojun/zfile/home/service/base/ProxyUploadService.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractProxyUploadService.java @@ -1,6 +1,6 @@ -package im.zhaojun.zfile.home.service.base; +package im.zhaojun.zfile.module.storage.service.base; -import im.zhaojun.zfile.admin.model.param.ProxyUploadParam; +import im.zhaojun.zfile.module.storage.model.param.ProxyUploadParam; import org.springframework.core.io.Resource; import org.springframework.http.ResponseEntity; @@ -9,7 +9,7 @@ import org.springframework.http.ResponseEntity; * * @author zhaojun */ -public abstract class ProxyUploadService

      extends ProxyTransferService

      { +public abstract class AbstractProxyUploadService

      extends AbstractProxyTransferService

      { /** * 空实现. diff --git a/src/main/java/im/zhaojun/zfile/home/service/base/AbstractS3BaseFileService.java b/src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractS3BaseFileService.java similarity index 62% rename from src/main/java/im/zhaojun/zfile/home/service/base/AbstractS3BaseFileService.java rename to src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractS3BaseFileService.java index e3e43e9..7dfa38d 100644 --- a/src/main/java/im/zhaojun/zfile/home/service/base/AbstractS3BaseFileService.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractS3BaseFileService.java @@ -1,4 +1,4 @@ -package im.zhaojun.zfile.home.service.base; +package im.zhaojun.zfile.module.storage.service.base; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.BooleanUtil; @@ -15,14 +15,13 @@ import com.amazonaws.services.s3.model.PutObjectRequest; import com.amazonaws.services.s3.model.PutObjectResult; import com.amazonaws.services.s3.model.S3ObjectSummary; import com.amazonaws.services.s3.model.SetBucketCrossOriginConfigurationRequest; -import im.zhaojun.zfile.admin.exception.StorageSourceAutoConfigCorsException; -import im.zhaojun.zfile.admin.model.param.S3BaseParam; -import im.zhaojun.zfile.admin.service.SystemConfigService; -import im.zhaojun.zfile.common.constant.ZFileConstant; -import im.zhaojun.zfile.common.exception.file.operator.GetFileInfoException; -import im.zhaojun.zfile.common.util.StringUtils; -import im.zhaojun.zfile.home.model.enums.FileTypeEnum; -import im.zhaojun.zfile.home.model.result.FileItemResult; +import im.zhaojun.zfile.core.constant.ZFileConstant; +import im.zhaojun.zfile.core.exception.StorageSourceAutoConfigCorsException; +import im.zhaojun.zfile.core.util.StringUtils; +import im.zhaojun.zfile.module.config.service.SystemConfigService; +import im.zhaojun.zfile.module.storage.model.enums.FileTypeEnum; +import im.zhaojun.zfile.module.storage.model.param.S3BaseParam; +import im.zhaojun.zfile.module.storage.model.result.FileItemResult; import lombok.extern.slf4j.Slf4j; import javax.annotation.Resource; @@ -43,6 +42,8 @@ public abstract class AbstractS3BaseFileService

      extends A protected AmazonS3 s3Client; + public static final InputStream EMPTY_INPUT_STREAM = new ByteArrayInputStream(new byte[0]); + @Resource private SystemConfigService systemConfigService; @@ -96,127 +97,116 @@ public abstract class AbstractS3BaseFileService

      extends A String bucketName = param.getBucketName(); path = StringUtils.trimStartSlashes(path); String fullPath = StringUtils.trimStartSlashes(StringUtils.concat(param.getBasePath(), path, ZFileConstant.PATH_SEPARATOR)); + List fileItemList = new ArrayList<>(); - ObjectListing objectListing = s3Client.listObjects(new ListObjectsRequest(bucketName, fullPath, "", "/", 1000)); + + ListObjectsRequest listObjectsRequest = new ListObjectsRequest() + .withBucketName(bucketName) + .withPrefix(fullPath) + .withMaxKeys(1000) + .withDelimiter("/"); + ObjectListing objectListing = s3Client.listObjects(listObjectsRequest); - for (S3ObjectSummary s : objectListing.getObjectSummaries()) { - FileItemResult fileItemResult = new FileItemResult(); - if (s.getKey().equals(fullPath)) { - continue; - } - fileItemResult.setName(s.getKey().substring(fullPath.length())); - fileItemResult.setSize(s.getSize()); - fileItemResult.setTime(s.getLastModified()); - fileItemResult.setType(FileTypeEnum.FILE); - fileItemResult.setPath(path); - - String fullPathAndName = StringUtils.concat(path, fileItemResult.getName()); - fileItemResult.setUrl(getDownloadUrl(fullPathAndName)); - - fileItemList.add(fileItemResult); - } + boolean isFirstWhile = true; - for (String commonPrefix : objectListing.getCommonPrefixes()) { - FileItemResult fileItemResult = new FileItemResult(); - fileItemResult.setName(commonPrefix.substring(fullPath.length(), commonPrefix.length() - 1)); - String name = fileItemResult.getName(); - if (StrUtil.isEmpty(name) || StrUtil.equals(name, StringUtils.DELIMITER_STR)) { - continue; + do { + if (!isFirstWhile) { + objectListing = s3Client.listNextBatchOfObjects(objectListing); } - - fileItemResult.setType(FileTypeEnum.FOLDER); - fileItemResult.setPath(path); - fileItemList.add(fileItemResult); - } + + for (S3ObjectSummary s : objectListing.getObjectSummaries()) { + FileItemResult fileItemResult = new FileItemResult(); + if (s.getKey().equals(fullPath)) { + continue; + } + fileItemResult.setName(s.getKey().substring(fullPath.length())); + fileItemResult.setSize(s.getSize()); + fileItemResult.setTime(s.getLastModified()); + fileItemResult.setType(FileTypeEnum.FILE); + fileItemResult.setPath(path); + + String fullPathAndName = StringUtils.concat(path, fileItemResult.getName()); + fileItemResult.setUrl(getDownloadUrl(fullPathAndName)); + + fileItemList.add(fileItemResult); + } + + for (String commonPrefix : objectListing.getCommonPrefixes()) { + FileItemResult fileItemResult = new FileItemResult(); + fileItemResult.setName(commonPrefix.substring(fullPath.length(), commonPrefix.length() - 1)); + String name = fileItemResult.getName(); + if (StrUtil.isEmpty(name) || StrUtil.equals(name, StringUtils.DELIMITER_STR)) { + continue; + } + + fileItemResult.setType(FileTypeEnum.FOLDER); + fileItemResult.setPath(path); + fileItemList.add(fileItemResult); + } + isFirstWhile = false; + } while (objectListing.isTruncated()); return fileItemList; } @Override public FileItemResult getFileItem(String pathAndName) { - try { - String fileName = FileUtil.getName(pathAndName); - String parentPath = StringUtils.getParentPath(pathAndName); - - String trimStartPath = StringUtils.concatTrimStartSlashes(param.getBasePath(), pathAndName); - ObjectMetadata objectMetadata = s3Client.getObjectMetadata(param.getBucketName(), trimStartPath); - - FileItemResult fileItemResult = new FileItemResult(); - fileItemResult.setName(fileName); - fileItemResult.setSize(objectMetadata.getInstanceLength()); - fileItemResult.setTime(objectMetadata.getLastModified()); - fileItemResult.setType(FileTypeEnum.FILE); - fileItemResult.setPath(parentPath); - fileItemResult.setUrl(getDownloadUrl(pathAndName)); - return fileItemResult; - } catch (Exception e) { - throw new GetFileInfoException(storageId, pathAndName, e); - } + String fileName = FileUtil.getName(pathAndName); + String parentPath = StringUtils.getParentPath(pathAndName); + + String trimStartPath = StringUtils.concatTrimStartSlashes(param.getBasePath(), pathAndName); + ObjectMetadata objectMetadata = s3Client.getObjectMetadata(param.getBucketName(), trimStartPath); + + FileItemResult fileItemResult = new FileItemResult(); + fileItemResult.setName(fileName); + fileItemResult.setSize(objectMetadata.getInstanceLength()); + fileItemResult.setTime(objectMetadata.getLastModified()); + fileItemResult.setType(FileTypeEnum.FILE); + fileItemResult.setPath(parentPath); + fileItemResult.setUrl(getDownloadUrl(pathAndName)); + return fileItemResult; } @Override public boolean newFolder(String path, String name) { - String bucketName = param.getBucketName(); name = StringUtils.trimSlashes(name); String fullPath = StringUtils.concat(param.getBasePath(), path, name, ZFileConstant.PATH_SEPARATOR); fullPath = StringUtils.trimStartSlashes(fullPath); - InputStream emptyContent = new ByteArrayInputStream(new byte[0]); - PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fullPath, emptyContent, null); + PutObjectRequest putObjectRequest = new PutObjectRequest(param.getBucketName(), fullPath, EMPTY_INPUT_STREAM, null); PutObjectResult putObjectResult = s3Client.putObject(putObjectRequest); return putObjectResult != null; } @Override public boolean deleteFile(String path, String name) { - String bucketName = param.getBucketName(); String fullPath = StringUtils.concat(param.getBasePath(), path, name); fullPath = StringUtils.trimStartSlashes(fullPath); - try { - s3Client.deleteObject(bucketName, fullPath); - return true; - } catch (Exception e) { - log.error("存储源 {} 删除文件 {} 失败", storageId, fullPath, e); - } - return false; + s3Client.deleteObject(param.getBucketName(), fullPath); + return true; } @Override public boolean deleteFolder(String path, String name) { - String bucketName = param.getBucketName(); String fullPath = StringUtils.concat(param.getBasePath(), path, name); fullPath = StringUtils.trimStartSlashes(fullPath); - try { - s3Client.deleteObject(bucketName, fullPath + '/'); - return true; - } catch (Exception e) { - log.error("存储源 {} 删除文件夹 {} 失败", storageId, fullPath, e); - } - return false; + s3Client.deleteObject(param.getBucketName(), fullPath + '/'); + return true; } @Override public boolean renameFile(String path, String name, String newName) { + String srcPath = StringUtils.concatTrimStartSlashes(param.getBasePath(), path, name); + String distPath = StringUtils.concatTrimStartSlashes(param.getBasePath(), path, newName); + String bucketName = param.getBucketName(); - String srcPath = StringUtils.concat(param.getBasePath(), path, name); - srcPath = StringUtils.trimStartSlashes(srcPath); - - String distPath = StringUtils.concat(param.getBasePath(), path, newName); - distPath = StringUtils.trimStartSlashes(distPath); - - try { - s3Client.copyObject(bucketName, srcPath, bucketName, distPath); - deleteFile(path, name); - return true; - } catch (Exception e) { - log.error("存储源 {} 重命名文件 {} 至 {} 失败", storageId, srcPath, distPath, e); - } - - return false; + s3Client.copyObject(bucketName, srcPath, bucketName, distPath); + deleteFile(path, name); + return true; } @Override public boolean renameFolder(String path, String name, String newName) { - throw new UnsupportedOperationException("不支持重命名文件夹"); + throw new UnsupportedOperationException("该存储类型不支持此操作"); } @Override @@ -262,7 +252,7 @@ public abstract class AbstractS3BaseFileService

      extends A CORSRule corsRule = new CORSRule(); corsRule.setAllowedMethods(CORSRule.AllowedMethods.PUT, CORSRule.AllowedMethods.GET); - corsRule.setAllowedOrigins("*", systemConfigService.getDomain(), systemConfigService.getFrontDomain()); + corsRule.setAllowedOrigins(allowOrigins); corsRules.add(corsRule); bucketCrossOriginConfiguration.setRules(corsRules); @@ -270,7 +260,7 @@ public abstract class AbstractS3BaseFileService

      extends A new SetBucketCrossOriginConfigurationRequest(param.getBucketName(), bucketCrossOriginConfiguration); s3Client.setBucketCrossOriginConfiguration(setBucketCrossOriginConfigurationRequest); } catch (Exception e) { - throw new StorageSourceAutoConfigCorsException("设置跨域失败,请检查 API 密钥是否有权限设置跨域", e, param); + throw new StorageSourceAutoConfigCorsException("设置跨域失败,请检查 API 密钥、地域、存储器名称是否正确,或 API 是否有权限设置跨域", e, param); } } } diff --git a/src/main/java/im/zhaojun/zfile/home/service/base/AbstractSharePointServiceBase.java b/src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractSharePointServiceBase.java similarity index 62% rename from src/main/java/im/zhaojun/zfile/home/service/base/AbstractSharePointServiceBase.java rename to src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractSharePointServiceBase.java index 7def0dc..79d5c23 100644 --- a/src/main/java/im/zhaojun/zfile/home/service/base/AbstractSharePointServiceBase.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/base/AbstractSharePointServiceBase.java @@ -1,8 +1,11 @@ -package im.zhaojun.zfile.home.service.base; +package im.zhaojun.zfile.module.storage.service.base; -import im.zhaojun.zfile.admin.model.param.SharePointParam; +import im.zhaojun.zfile.module.storage.model.param.SharePointParam; -public abstract class AbstractSharePointServiceBase

      extends MicrosoftDriveServiceBase { +/** + * @author zhaojun + */ +public abstract class AbstractSharePointServiceBase

      extends AbstractMicrosoftDriveService { @Override public void init() { diff --git a/src/main/java/im/zhaojun/zfile/home/service/base/BaseFileService.java b/src/main/java/im/zhaojun/zfile/module/storage/service/base/BaseFileService.java similarity index 66% rename from src/main/java/im/zhaojun/zfile/home/service/base/BaseFileService.java rename to src/main/java/im/zhaojun/zfile/module/storage/service/base/BaseFileService.java index 889e69c..1271914 100644 --- a/src/main/java/im/zhaojun/zfile/home/service/base/BaseFileService.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/base/BaseFileService.java @@ -1,6 +1,7 @@ -package im.zhaojun.zfile.home.service.base; +package im.zhaojun.zfile.module.storage.service.base; -import im.zhaojun.zfile.home.model.result.FileItemResult; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.model.result.FileItemResult; import java.util.List; @@ -31,5 +32,13 @@ public interface BaseFileService { * @return 文件下载地址 */ String getDownloadUrl(String pathAndName); - + + + /** + * 获取存储源类型 + * + * @return 存储源类型 + */ + StorageTypeEnum getStorageTypeEnum(); + } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/module/storage/service/base/RefreshTokenService.java b/src/main/java/im/zhaojun/zfile/module/storage/service/base/RefreshTokenService.java new file mode 100644 index 0000000..b8e010b --- /dev/null +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/base/RefreshTokenService.java @@ -0,0 +1,17 @@ +package im.zhaojun.zfile.module.storage.service.base; + +/** + * 需要刷新 Token 服务的存储源 + * + * @author zhaojun + */ +public interface RefreshTokenService extends BaseFileService { + + /** + * 刷新存储源 AccessToken 或者其他需要定时刷新的 Token + * + * @throws Exception 刷新 Token 时出现的异常 + */ + void refreshAccessToken() throws Exception; + +} \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/service/impl/AliyunServiceImpl.java b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/AliyunServiceImpl.java similarity index 80% rename from src/main/java/im/zhaojun/zfile/home/service/impl/AliyunServiceImpl.java rename to src/main/java/im/zhaojun/zfile/module/storage/service/impl/AliyunServiceImpl.java index 57568d8..1c71713 100644 --- a/src/main/java/im/zhaojun/zfile/home/service/impl/AliyunServiceImpl.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/AliyunServiceImpl.java @@ -1,12 +1,12 @@ -package im.zhaojun.zfile.home.service.impl; +package im.zhaojun.zfile.module.storage.service.impl; import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.client.builder.AwsClientBuilder; import com.amazonaws.services.s3.AmazonS3ClientBuilder; -import im.zhaojun.zfile.admin.model.param.AliyunParam; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; -import im.zhaojun.zfile.home.service.base.AbstractS3BaseFileService; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.model.param.AliyunParam; +import im.zhaojun.zfile.module.storage.service.base.AbstractS3BaseFileService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; @@ -19,7 +19,7 @@ import org.springframework.stereotype.Service; @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) @Slf4j public class AliyunServiceImpl extends AbstractS3BaseFileService { - + @Override public void init() { BasicAWSCredentials credentials = new BasicAWSCredentials(param.getAccessKey(), param.getSecretKey()); @@ -35,5 +35,5 @@ public class AliyunServiceImpl extends AbstractS3BaseFileService { public StorageTypeEnum getStorageTypeEnum() { return StorageTypeEnum.ALIYUN; } - + } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/service/impl/FtpServiceImpl.java b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/FtpServiceImpl.java similarity index 74% rename from src/main/java/im/zhaojun/zfile/home/service/impl/FtpServiceImpl.java rename to src/main/java/im/zhaojun/zfile/module/storage/service/impl/FtpServiceImpl.java index ec7d64a..8575d7c 100644 --- a/src/main/java/im/zhaojun/zfile/home/service/impl/FtpServiceImpl.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/FtpServiceImpl.java @@ -1,20 +1,20 @@ -package im.zhaojun.zfile.home.service.impl; +package im.zhaojun.zfile.module.storage.service.impl; +import cn.hutool.core.exceptions.ExceptionUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.ftp.Ftp; import cn.hutool.extra.ftp.FtpMode; -import im.zhaojun.zfile.admin.model.param.FtpParam; -import im.zhaojun.zfile.common.exception.DisableProxyDownloadException; -import im.zhaojun.zfile.common.exception.file.operator.DownloadFileException; -import im.zhaojun.zfile.common.exception.file.operator.GetFileInfoException; -import im.zhaojun.zfile.common.util.RequestHolder; -import im.zhaojun.zfile.common.util.StringUtils; -import im.zhaojun.zfile.home.model.enums.FileTypeEnum; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; -import im.zhaojun.zfile.home.model.result.FileItemResult; -import im.zhaojun.zfile.home.service.base.ProxyTransferService; +import im.zhaojun.zfile.core.exception.file.operator.DisableProxyDownloadException; +import im.zhaojun.zfile.core.util.CodeMsg; +import im.zhaojun.zfile.core.util.RequestHolder; +import im.zhaojun.zfile.core.util.StringUtils; +import im.zhaojun.zfile.module.storage.model.enums.FileTypeEnum; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.model.param.FtpParam; +import im.zhaojun.zfile.module.storage.model.result.FileItemResult; +import im.zhaojun.zfile.module.storage.service.base.AbstractProxyTransferService; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.net.ftp.FTP; @@ -28,6 +28,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletResponse; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -42,7 +43,7 @@ import java.util.List; @Service @Slf4j @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) -public class FtpServiceImpl extends ProxyTransferService { +public class FtpServiceImpl extends AbstractProxyTransferService { private Ftp ftp; @@ -62,12 +63,12 @@ public class FtpServiceImpl extends ProxyTransferService { ftp.reconnectIfTimeout(); String fullPath = StringUtils.concat(param.getBasePath(), folderPath); ftp.cd(fullPath); - FTPFile[] ftpFiles = new FTPFile[]{}; + FTPFile[] ftpFiles; try { ftp.getClient().changeWorkingDirectory("/"); ftpFiles = ftp.getClient().listFiles(fullPath); } catch (Exception e) { - e.printStackTrace(); + throw ExceptionUtil.wrapRuntime(e); } List fileItemList = new ArrayList<>(); @@ -96,11 +97,11 @@ public class FtpServiceImpl extends ProxyTransferService { try { ftpFiles = ftp.getClient().listFiles(pathAndName); } catch (IOException e) { - throw new GetFileInfoException(storageId, pathAndName, e); + throw ExceptionUtil.wrapRuntime(e); } - + if (ArrayUtil.isEmpty(ftpFiles)) { - throw new GetFileInfoException(storageId, pathAndName); + throw ExceptionUtil.wrapRuntime(new FileNotFoundException()); } FTPFile ftpFile = ftpFiles[0]; @@ -136,13 +137,12 @@ public class FtpServiceImpl extends ProxyTransferService { ftp.reconnectIfTimeout(); String srcPath = StringUtils.concat(param.getBasePath(), path, name); String distPath = StringUtils.concat(param.getBasePath(), path, newName); + try { return ftp.getClient().rename(srcPath, distPath); } catch (IOException e) { - log.error("存储源 {} 重命名文件 {} 至 {} 失败", storageId, srcPath, distPath, e); + throw ExceptionUtil.wrapRuntime(e); } - - return false; } @@ -153,29 +153,24 @@ public class FtpServiceImpl extends ProxyTransferService { @Override - public synchronized ResponseEntity downloadToStream(String pathAndName) { + public synchronized ResponseEntity downloadToStream(String pathAndName) throws IOException { // 如果配置了域名,还访问代理下载 URL, 则抛出异常进行提示. if (StrUtil.isNotEmpty(param.getDomain())) { - throw new DisableProxyDownloadException(); + throw new DisableProxyDownloadException(CodeMsg.STORAGE_SOURCE_FILE_DISABLE_PROXY_DOWNLOAD, storageId); } ftp.reconnectIfTimeout(); HttpServletResponse response = RequestHolder.getResponse(); - try { - pathAndName = StringUtils.concat(param.getBasePath(), pathAndName); - String fileName = FileUtil.getName(pathAndName); - String folderName = FileUtil.getParent(pathAndName, 1); - - OutputStream outputStream = response.getOutputStream(); + pathAndName = StringUtils.concat(param.getBasePath(), pathAndName); + String fileName = FileUtil.getName(pathAndName); + String folderName = FileUtil.getParent(pathAndName, 1); + + OutputStream outputStream = response.getOutputStream(); + + response.setContentType(MediaType.APPLICATION_OCTET_STREAM.getType()); + response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + StringUtils.encodeAllIgnoreSlashes(fileName)); - response.setContentType(MediaType.APPLICATION_OCTET_STREAM.getType()); - response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + StringUtils.encodeAllIgnoreSlashes(fileName)); - - - ftp.download(folderName, fileName, outputStream); - } catch (Exception e) { - throw new DownloadFileException(storageId, "下载文件失败", e); - } + ftp.download(folderName, fileName, outputStream); return null; } diff --git a/src/main/java/im/zhaojun/zfile/home/service/impl/GoogleDriveServiceImpl.java b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/GoogleDriveServiceImpl.java similarity index 74% rename from src/main/java/im/zhaojun/zfile/home/service/impl/GoogleDriveServiceImpl.java rename to src/main/java/im/zhaojun/zfile/module/storage/service/impl/GoogleDriveServiceImpl.java index c4c3ef2..7b187ee 100644 --- a/src/main/java/im/zhaojun/zfile/home/service/impl/GoogleDriveServiceImpl.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/GoogleDriveServiceImpl.java @@ -1,5 +1,6 @@ -package im.zhaojun.zfile.home.service.impl; +package im.zhaojun.zfile.module.storage.service.impl; +import cn.hutool.core.exceptions.ExceptionUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjectUtil; @@ -11,26 +12,25 @@ import cn.hutool.http.HttpUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; -import im.zhaojun.zfile.admin.constant.StorageConfigConstant; -import im.zhaojun.zfile.admin.model.dto.OAuth2Token; -import im.zhaojun.zfile.admin.model.entity.StorageSourceConfig; -import im.zhaojun.zfile.admin.model.param.GoogleDriveParam; -import im.zhaojun.zfile.admin.service.StorageSourceConfigService; -import im.zhaojun.zfile.common.cache.RefreshTokenCache; -import im.zhaojun.zfile.common.exception.StorageSourceRefreshTokenException; -import im.zhaojun.zfile.common.exception.file.StorageSourceException; -import im.zhaojun.zfile.common.util.RequestHolder; -import im.zhaojun.zfile.common.util.StringUtils; -import im.zhaojun.zfile.home.model.enums.FileTypeEnum; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; -import im.zhaojun.zfile.home.model.result.FileItemResult; -import im.zhaojun.zfile.home.service.base.ProxyTransferService; -import im.zhaojun.zfile.home.service.base.RefreshTokenService; +import im.zhaojun.zfile.core.exception.StorageSourceRefreshTokenException; +import im.zhaojun.zfile.core.exception.http.HttpResponseStatusErrorException; +import im.zhaojun.zfile.core.util.RequestHolder; +import im.zhaojun.zfile.core.util.StringUtils; +import im.zhaojun.zfile.module.storage.constant.StorageConfigConstant; +import im.zhaojun.zfile.module.storage.model.bo.RefreshTokenCacheBO; +import im.zhaojun.zfile.module.storage.model.dto.OAuth2TokenDTO; +import im.zhaojun.zfile.module.storage.model.entity.StorageSourceConfig; +import im.zhaojun.zfile.module.storage.model.enums.FileTypeEnum; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.model.param.GoogleDriveParam; +import im.zhaojun.zfile.module.storage.model.result.FileItemResult; +import im.zhaojun.zfile.module.storage.service.StorageSourceConfigService; +import im.zhaojun.zfile.module.storage.service.base.AbstractProxyTransferService; +import im.zhaojun.zfile.module.storage.service.base.RefreshTokenService; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.apache.http.HttpEntity; import org.apache.http.HttpHeaders; -import org.apache.http.StatusLine; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.RequestBuilder; @@ -48,6 +48,7 @@ import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -63,7 +64,7 @@ import java.util.List; @Service @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) @Slf4j -public class GoogleDriveServiceImpl extends ProxyTransferService implements RefreshTokenService { +public class GoogleDriveServiceImpl extends AbstractProxyTransferService implements RefreshTokenService { /** * 文件类型:文件夹 @@ -109,7 +110,7 @@ public class GoogleDriveServiceImpl extends ProxyTransferService { +public class LocalServiceImpl extends AbstractProxyTransferService { + + private static final String PREVIEW_PARAM_NAME = "preview"; @Override public void init() { @@ -50,7 +56,9 @@ public class LocalServiceImpl extends ProxyTransferService { File file = new File(param.getFilePath()); // 校验文件夹是否存在 if (!file.exists()) { - throw new InitializeStorageSourceException("文件路径: \"" + file.getAbsolutePath() + "\"不存在, 请检查是否填写正确."); + String errMsg = StrUtil.format("文件路径:「{}」不存在, 请检查是否填写正确.", file.getAbsolutePath()); + throw new InitializeStorageSourceException(CodeMsg.STORAGE_SOURCE_INIT_FAIL, + storageId, errMsg).setResponseExceptionMessage(true); } } @@ -92,7 +100,7 @@ public class LocalServiceImpl extends ProxyTransferService { File file = new File(fullPath); if (!file.exists()) { - throw new GetFileInfoException(storageId, pathAndName, new NotExistFileException("文件不存在.")); + throw ExceptionUtil.wrapRuntime(new FileNotFoundException("文件不存在")); } String folderPath = StringUtils.getParentPath(pathAndName); @@ -109,6 +117,10 @@ public class LocalServiceImpl extends ProxyTransferService { @Override public boolean deleteFile(String path, String name) { + log.error("删除文件: {}", path + name); + if (RandomUtil.randomBoolean()) { + throw new RuntimeException("模拟删除失败"); + } String fullPath = StringUtils.concat(param.getFilePath(), path, name); return FileUtil.del(fullPath); } @@ -129,17 +141,14 @@ public class LocalServiceImpl extends ProxyTransferService { String srcPath = StringUtils.concat(param.getFilePath(), path, name); File file = new File(srcPath); - try { - boolean srcExists = file.exists(); - if (!srcExists) { - throw new StorageSourceException(storageId, "文件夹不存在."); - } - FileUtil.rename(file, newName, true); - return true; - } catch (Exception e) { - log.error("存储源 {} 重命名文件 {} 至 {} 失败", storageId, srcPath, newName, e); + + boolean srcExists = file.exists(); + if (!srcExists) { + throw ExceptionUtil.wrapRuntime(new FileNotFoundException("文件夹不存在.")); } - return false; + + FileUtil.rename(file, newName, true); + return true; } @@ -156,9 +165,9 @@ public class LocalServiceImpl extends ProxyTransferService { @Override - public void uploadFile(String path, InputStream inputStream) { + public void uploadFile(String pathAndName, InputStream inputStream) { String baseFilePath = param.getFilePath(); - String uploadPath = StringUtils.removeDuplicateSlashes(baseFilePath + ZFileConstant.PATH_SEPARATOR + path); + String uploadPath = StringUtils.removeDuplicateSlashes(baseFilePath + ZFileConstant.PATH_SEPARATOR + pathAndName); // 如果目录不存在则创建 String parentPath = FileUtil.getParent(uploadPath, 1); if (!FileUtil.exist(parentPath)) { @@ -181,16 +190,26 @@ public class LocalServiceImpl extends ProxyTransferService { .body(byteArrayResource); } + HttpServletRequest request = RequestHolder.getRequest(); + String type = request.getParameter("type"); + + MediaType mimeType = MediaType.APPLICATION_OCTET_STREAM; + if (StrUtil.equals(type, PREVIEW_PARAM_NAME)) { + mimeType = MediaTypeFactory.getMediaType(file.getName()).orElse(MediaType.APPLICATION_OCTET_STREAM); + } + HttpHeaders headers = new HttpHeaders(); - - String fileName = file.getName(); - headers.setContentDispositionFormData("attachment", StringUtils.encodeAllIgnoreSlashes(fileName)); + + if (ObjectUtil.equals(mimeType, MediaType.APPLICATION_OCTET_STREAM)) { + String fileName = file.getName(); + headers.setContentDispositionFormData("attachment", StringUtils.encodeAllIgnoreSlashes(fileName)); + } return ResponseEntity .ok() .headers(headers) .contentLength(file.length()) - .contentType(MediaType.APPLICATION_OCTET_STREAM) + .contentType(mimeType) .body(new FileSystemResource(file)); } diff --git a/src/main/java/im/zhaojun/zfile/home/service/impl/MinIOServiceImpl.java b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/MinIOServiceImpl.java similarity index 81% rename from src/main/java/im/zhaojun/zfile/home/service/impl/MinIOServiceImpl.java rename to src/main/java/im/zhaojun/zfile/module/storage/service/impl/MinIOServiceImpl.java index 459ea6f..c92fc35 100644 --- a/src/main/java/im/zhaojun/zfile/home/service/impl/MinIOServiceImpl.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/MinIOServiceImpl.java @@ -1,12 +1,12 @@ -package im.zhaojun.zfile.home.service.impl; +package im.zhaojun.zfile.module.storage.service.impl; import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.client.builder.AwsClientBuilder; import com.amazonaws.services.s3.AmazonS3ClientBuilder; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; -import im.zhaojun.zfile.admin.model.param.MinIOParam; -import im.zhaojun.zfile.home.service.base.AbstractS3BaseFileService; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.model.param.MinIOParam; +import im.zhaojun.zfile.module.storage.service.base.AbstractS3BaseFileService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; diff --git a/src/main/java/im/zhaojun/zfile/home/service/impl/OneDriveChinaServiceImpl.java b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/OneDriveChinaServiceImpl.java similarity index 86% rename from src/main/java/im/zhaojun/zfile/home/service/impl/OneDriveChinaServiceImpl.java rename to src/main/java/im/zhaojun/zfile/module/storage/service/impl/OneDriveChinaServiceImpl.java index a5f2380..418a17c 100644 --- a/src/main/java/im/zhaojun/zfile/home/service/impl/OneDriveChinaServiceImpl.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/OneDriveChinaServiceImpl.java @@ -1,8 +1,8 @@ -package im.zhaojun.zfile.home.service.impl; +package im.zhaojun.zfile.module.storage.service.impl; -import im.zhaojun.zfile.admin.model.param.OneDriveChinaParam; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; -import im.zhaojun.zfile.home.service.base.AbstractOneDriveServiceBase; +import im.zhaojun.zfile.module.storage.model.param.OneDriveChinaParam; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.service.base.AbstractOneDriveServiceBase; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.ConfigurableBeanFactory; diff --git a/src/main/java/im/zhaojun/zfile/home/service/impl/OneDriveServiceImpl.java b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/OneDriveServiceImpl.java similarity index 86% rename from src/main/java/im/zhaojun/zfile/home/service/impl/OneDriveServiceImpl.java rename to src/main/java/im/zhaojun/zfile/module/storage/service/impl/OneDriveServiceImpl.java index a59a112..348b0d8 100644 --- a/src/main/java/im/zhaojun/zfile/home/service/impl/OneDriveServiceImpl.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/OneDriveServiceImpl.java @@ -1,8 +1,8 @@ -package im.zhaojun.zfile.home.service.impl; +package im.zhaojun.zfile.module.storage.service.impl; -import im.zhaojun.zfile.admin.model.param.OneDriveParam; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; -import im.zhaojun.zfile.home.service.base.AbstractOneDriveServiceBase; +import im.zhaojun.zfile.module.storage.model.param.OneDriveParam; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.service.base.AbstractOneDriveServiceBase; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.ConfigurableBeanFactory; diff --git a/src/main/java/im/zhaojun/zfile/home/service/impl/QiniuServiceImpl.java b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/QiniuServiceImpl.java similarity index 83% rename from src/main/java/im/zhaojun/zfile/home/service/impl/QiniuServiceImpl.java rename to src/main/java/im/zhaojun/zfile/module/storage/service/impl/QiniuServiceImpl.java index 3619314..a2a6599 100644 --- a/src/main/java/im/zhaojun/zfile/home/service/impl/QiniuServiceImpl.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/QiniuServiceImpl.java @@ -1,5 +1,6 @@ -package im.zhaojun.zfile.home.service.impl; +package im.zhaojun.zfile.module.storage.service.impl; +import cn.hutool.core.exceptions.ExceptionUtil; import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.client.builder.AwsClientBuilder; @@ -9,10 +10,10 @@ import com.qiniu.storage.BucketManager; import com.qiniu.storage.Configuration; import com.qiniu.storage.Region; import com.qiniu.util.Auth; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; -import im.zhaojun.zfile.admin.model.param.QiniuParam; -import im.zhaojun.zfile.home.service.base.AbstractS3BaseFileService; -import im.zhaojun.zfile.common.util.StringUtils; +import im.zhaojun.zfile.core.util.StringUtils; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.model.param.QiniuParam; +import im.zhaojun.zfile.module.storage.service.base.AbstractS3BaseFileService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; @@ -62,10 +63,9 @@ public class QiniuServiceImpl extends AbstractS3BaseFileService { bucketManager.move(bucketName, srcPath, bucketName, distPath); return true; } catch (QiniuException e) { - log.error("存储源 {} 重命名文件 {} 至 {} 失败", storageId, srcPath, distPath, e); + throw ExceptionUtil.wrapRuntime(e); } - - return false; + } } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/home/service/impl/S3ServiceImpl.java b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/S3ServiceImpl.java similarity index 80% rename from src/main/java/im/zhaojun/zfile/home/service/impl/S3ServiceImpl.java rename to src/main/java/im/zhaojun/zfile/module/storage/service/impl/S3ServiceImpl.java index dbd1967..596cef3 100644 --- a/src/main/java/im/zhaojun/zfile/home/service/impl/S3ServiceImpl.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/S3ServiceImpl.java @@ -1,13 +1,13 @@ -package im.zhaojun.zfile.home.service.impl; +package im.zhaojun.zfile.module.storage.service.impl; import cn.hutool.core.util.StrUtil; import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.client.builder.AwsClientBuilder; import com.amazonaws.services.s3.AmazonS3ClientBuilder; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; -import im.zhaojun.zfile.admin.model.param.S3Param; -import im.zhaojun.zfile.home.service.base.AbstractS3BaseFileService; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.model.param.S3Param; +import im.zhaojun.zfile.module.storage.service.base.AbstractS3BaseFileService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; @@ -25,7 +25,7 @@ public class S3ServiceImpl extends AbstractS3BaseFileService { public void init() { boolean isPathStyle = "path-style".equals(param.getPathStyle()); String region = param.getRegion(); - if (StrUtil.isNotEmpty(param.getEndPoint())) { + if (StrUtil.isEmpty(param.getRegion()) && StrUtil.isNotEmpty(param.getEndPoint())) { region = param.getEndPoint().split("\\.")[1]; } BasicAWSCredentials credentials = new BasicAWSCredentials(param.getAccessKey(), param.getSecretKey()); diff --git a/src/main/java/im/zhaojun/zfile/home/service/impl/SftpServiceImpl.java b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/SftpServiceImpl.java similarity index 82% rename from src/main/java/im/zhaojun/zfile/home/service/impl/SftpServiceImpl.java rename to src/main/java/im/zhaojun/zfile/module/storage/service/impl/SftpServiceImpl.java index 52bde53..ea49729 100644 --- a/src/main/java/im/zhaojun/zfile/home/service/impl/SftpServiceImpl.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/SftpServiceImpl.java @@ -1,22 +1,22 @@ -package im.zhaojun.zfile.home.service.impl; +package im.zhaojun.zfile.module.storage.service.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; +import cn.hutool.core.exceptions.ExceptionUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.ssh.Sftp; import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.SftpException; -import im.zhaojun.zfile.admin.model.param.SftpParam; -import im.zhaojun.zfile.common.exception.DisableProxyDownloadException; -import im.zhaojun.zfile.common.exception.NotExistFileException; -import im.zhaojun.zfile.common.exception.file.operator.GetFileInfoException; -import im.zhaojun.zfile.common.util.RequestHolder; -import im.zhaojun.zfile.common.util.StringUtils; -import im.zhaojun.zfile.home.model.enums.FileTypeEnum; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; -import im.zhaojun.zfile.home.model.result.FileItemResult; -import im.zhaojun.zfile.home.service.base.ProxyTransferService; +import im.zhaojun.zfile.core.exception.file.operator.DisableProxyDownloadException; +import im.zhaojun.zfile.core.util.CodeMsg; +import im.zhaojun.zfile.core.util.RequestHolder; +import im.zhaojun.zfile.core.util.StringUtils; +import im.zhaojun.zfile.module.storage.model.enums.FileTypeEnum; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.model.param.SftpParam; +import im.zhaojun.zfile.module.storage.model.result.FileItemResult; +import im.zhaojun.zfile.module.storage.service.base.AbstractProxyTransferService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; @@ -27,6 +27,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletResponse; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -40,7 +41,7 @@ import java.util.List; @Service @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) @Slf4j -public class SftpServiceImpl extends ProxyTransferService { +public class SftpServiceImpl extends AbstractProxyTransferService { private Sftp sftp; @@ -80,7 +81,7 @@ public class SftpServiceImpl extends ProxyTransferService { List entryList = sftp.lsEntries(fullPath); if (CollUtil.isEmpty(entryList)) { - throw new GetFileInfoException(storageId, pathAndName, new NotExistFileException("文件不存在.")); + throw ExceptionUtil.wrapRuntime(new FileNotFoundException()); } ChannelSftp.LsEntry sftpEntry = CollUtil.getFirst(entryList); @@ -117,10 +118,8 @@ public class SftpServiceImpl extends ProxyTransferService { sftp.getClient().rename(srcPath, distPath); return true; } catch (SftpException e) { - log.error("存储源 {} 重命名文件 {} 至 {} 失败", storageId, srcPath, distPath, e); + throw ExceptionUtil.wrapRuntime(e); } - - return false; } @@ -134,7 +133,7 @@ public class SftpServiceImpl extends ProxyTransferService { public synchronized ResponseEntity downloadToStream(String pathAndName) { // 如果配置了域名,还访问代理下载 URL, 则抛出异常进行提示. if (StrUtil.isNotEmpty(param.getDomain())) { - throw new DisableProxyDownloadException(); + throw new DisableProxyDownloadException(CodeMsg.STORAGE_SOURCE_FILE_DISABLE_PROXY_DOWNLOAD, storageId); } HttpServletResponse response = RequestHolder.getResponse(); @@ -150,7 +149,7 @@ public class SftpServiceImpl extends ProxyTransferService { sftp.download(pathAndName, outputStream); return null; } catch (IOException e) { - throw new RuntimeException("下载文件失败", e); + throw ExceptionUtil.wrapRuntime(e); } } diff --git a/src/main/java/im/zhaojun/zfile/home/service/impl/SharePointChinaServiceImpl.java b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/SharePointChinaServiceImpl.java similarity index 86% rename from src/main/java/im/zhaojun/zfile/home/service/impl/SharePointChinaServiceImpl.java rename to src/main/java/im/zhaojun/zfile/module/storage/service/impl/SharePointChinaServiceImpl.java index 28c1b63..27db3e1 100644 --- a/src/main/java/im/zhaojun/zfile/home/service/impl/SharePointChinaServiceImpl.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/SharePointChinaServiceImpl.java @@ -1,8 +1,8 @@ -package im.zhaojun.zfile.home.service.impl; +package im.zhaojun.zfile.module.storage.service.impl; -import im.zhaojun.zfile.admin.model.param.SharePointChinaParam; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; -import im.zhaojun.zfile.home.service.base.AbstractSharePointServiceBase; +import im.zhaojun.zfile.module.storage.model.param.SharePointChinaParam; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.service.base.AbstractSharePointServiceBase; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.ConfigurableBeanFactory; diff --git a/src/main/java/im/zhaojun/zfile/home/service/impl/SharePointServiceImpl.java b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/SharePointServiceImpl.java similarity index 86% rename from src/main/java/im/zhaojun/zfile/home/service/impl/SharePointServiceImpl.java rename to src/main/java/im/zhaojun/zfile/module/storage/service/impl/SharePointServiceImpl.java index 0750804..2e3cc13 100644 --- a/src/main/java/im/zhaojun/zfile/home/service/impl/SharePointServiceImpl.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/SharePointServiceImpl.java @@ -1,8 +1,8 @@ -package im.zhaojun.zfile.home.service.impl; +package im.zhaojun.zfile.module.storage.service.impl; -import im.zhaojun.zfile.admin.model.param.SharePointParam; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; -import im.zhaojun.zfile.home.service.base.AbstractSharePointServiceBase; +import im.zhaojun.zfile.module.storage.model.param.SharePointParam; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.service.base.AbstractSharePointServiceBase; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.ConfigurableBeanFactory; diff --git a/src/main/java/im/zhaojun/zfile/home/service/impl/TencentServiceImpl.java b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/TencentServiceImpl.java similarity index 81% rename from src/main/java/im/zhaojun/zfile/home/service/impl/TencentServiceImpl.java rename to src/main/java/im/zhaojun/zfile/module/storage/service/impl/TencentServiceImpl.java index d4ef91f..37052ad 100644 --- a/src/main/java/im/zhaojun/zfile/home/service/impl/TencentServiceImpl.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/TencentServiceImpl.java @@ -1,12 +1,12 @@ -package im.zhaojun.zfile.home.service.impl; +package im.zhaojun.zfile.module.storage.service.impl; import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.client.builder.AwsClientBuilder; import com.amazonaws.services.s3.AmazonS3ClientBuilder; -import im.zhaojun.zfile.admin.model.param.TencentParam; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; -import im.zhaojun.zfile.home.service.base.AbstractS3BaseFileService; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.model.param.TencentParam; +import im.zhaojun.zfile.module.storage.service.base.AbstractS3BaseFileService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; diff --git a/src/main/java/im/zhaojun/zfile/home/service/impl/UpYunServiceImpl.java b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/UpYunServiceImpl.java similarity index 77% rename from src/main/java/im/zhaojun/zfile/home/service/impl/UpYunServiceImpl.java rename to src/main/java/im/zhaojun/zfile/module/storage/service/impl/UpYunServiceImpl.java index bd246b7..dc78332 100644 --- a/src/main/java/im/zhaojun/zfile/home/service/impl/UpYunServiceImpl.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/UpYunServiceImpl.java @@ -1,5 +1,6 @@ -package im.zhaojun.zfile.home.service.impl; +package im.zhaojun.zfile.module.storage.service.impl; +import cn.hutool.core.exceptions.ExceptionUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; @@ -8,21 +9,20 @@ import com.alibaba.fastjson.JSON; import com.upyun.Params; import com.upyun.UpException; import com.upyun.UpYunUtils; -import im.zhaojun.zfile.admin.model.param.UpYunParam; -import im.zhaojun.zfile.common.exception.NotExistFileException; -import im.zhaojun.zfile.common.exception.UnSupportedOperation; -import im.zhaojun.zfile.common.util.StringUtils; -import im.zhaojun.zfile.home.model.enums.FileTypeEnum; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; -import im.zhaojun.zfile.home.model.result.FileItemResult; -import im.zhaojun.zfile.home.model.upyun.AuthModel; -import im.zhaojun.zfile.home.model.upyun.UploadSignParam; -import im.zhaojun.zfile.home.service.base.AbstractBaseFileService; +import im.zhaojun.zfile.core.util.StringUtils; +import im.zhaojun.zfile.module.storage.model.bo.AuthModel; +import im.zhaojun.zfile.module.storage.model.bo.UploadSignParam; +import im.zhaojun.zfile.module.storage.model.enums.FileTypeEnum; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.model.param.UpYunParam; +import im.zhaojun.zfile.module.storage.model.result.FileItemResult; +import im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Service; +import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.Base64; @@ -104,34 +104,33 @@ public class UpYunServiceImpl extends AbstractBaseFileService { @Override public FileItemResult getFileItem(String pathAndName) { + String encodeFullUrl = StringUtils.concat(true, param.getBasePath() + pathAndName); + Map fileInfo; try { - String encodeFullUrl = StringUtils.concat(true, param.getBasePath() + pathAndName); - Map fileInfo = upYun.getFileInfo(encodeFullUrl); - - if (fileInfo == null) { - throw new NotExistFileException(); - } - - String name = FileUtil.getName(pathAndName); - String folderPath = StringUtils.getParentPath(pathAndName); - FileItemResult fileItemResult = new FileItemResult(); - fileItemResult.setName(name); - fileItemResult.setSize(Long.valueOf(fileInfo.get("size"))); - fileItemResult.setTime(new Date(Long.parseLong(fileInfo.get("date")) * 1000)); - fileItemResult.setPath(folderPath); - - if ("folder".equals(fileInfo.get("type"))) { - fileItemResult.setType(FileTypeEnum.FOLDER); - } else { - fileItemResult.setType(FileTypeEnum.FILE); - fileItemResult.setUrl(getDownloadUrl(pathAndName)); - } - return fileItemResult; + fileInfo = upYun.getFileInfo(encodeFullUrl); } catch (IOException | UpException e) { - e.printStackTrace(); + throw ExceptionUtil.wrapRuntime(e); + } + + if (fileInfo == null) { + throw ExceptionUtil.wrapRuntime(new FileNotFoundException()); } - throw new NotExistFileException(); + String name = FileUtil.getName(pathAndName); + String folderPath = StringUtils.getParentPath(pathAndName); + FileItemResult fileItemResult = new FileItemResult(); + fileItemResult.setName(name); + fileItemResult.setSize(Long.valueOf(fileInfo.get("size"))); + fileItemResult.setTime(new Date(Long.parseLong(fileInfo.get("date")) * 1000)); + fileItemResult.setPath(folderPath); + + if ("folder".equals(fileInfo.get("type"))) { + fileItemResult.setType(FileTypeEnum.FOLDER); + } else { + fileItemResult.setType(FileTypeEnum.FILE); + fileItemResult.setUrl(getDownloadUrl(pathAndName)); + } + return fileItemResult; } @Override @@ -140,9 +139,8 @@ public class UpYunServiceImpl extends AbstractBaseFileService { try { return upYun.mkDir(fullPath, true); } catch (IOException | UpException e) { - log.error("存储源 {} 创建文件夹 {} 失败.", storageId, fullPath, e); + throw ExceptionUtil.wrapRuntime(e); } - return false; } @Override @@ -157,9 +155,8 @@ public class UpYunServiceImpl extends AbstractBaseFileService { throw new RuntimeException("非空文件夹不允许删除"); } } - log.error("存储源 {} 删除文件 {} 异常.", storageId, fullPath, e); + throw ExceptionUtil.wrapRuntime(e); } - return false; } @Override @@ -175,15 +172,13 @@ public class UpYunServiceImpl extends AbstractBaseFileService { try { return upYun.moveFile(distPath, srcPath); } catch (IOException | UpException e) { - log.error("存储源 {} 重命名文件 {} 至 {} 失败", storageId, srcPath, distPath, e); + throw ExceptionUtil.wrapRuntime(e); } - - return false; } @Override public boolean renameFolder(String path, String name, String newName) { - throw new UnSupportedOperation("该存储类型不支持此操作"); + throw new UnsupportedOperationException("该存储类型不支持此操作"); } @Override @@ -234,7 +229,6 @@ public class UpYunServiceImpl extends AbstractBaseFileService { String bucketName = param.getBucketName(); HashMap params = new HashMap<>(); params.put(Params.BUCKET, bucketName); - // params.put(Params.SAVE_KEY, "/{filename}{.suffix}"); params.put(Params.SAVE_KEY, StringUtils.concat(uploadSignParam.getPath(), uploadSignParam.getName())); params.put(Params.EXPIRATION, System.currentTimeMillis() / 1000 + UPLOAD_SESSION_EXPIRATION); params.put("content-length", uploadSignParam.getSize()); diff --git a/src/main/java/im/zhaojun/zfile/home/service/impl/WebdavServiceImpl.java b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/WebdavServiceImpl.java similarity index 78% rename from src/main/java/im/zhaojun/zfile/home/service/impl/WebdavServiceImpl.java rename to src/main/java/im/zhaojun/zfile/module/storage/service/impl/WebdavServiceImpl.java index 134a7c0..d95ef54 100644 --- a/src/main/java/im/zhaojun/zfile/home/service/impl/WebdavServiceImpl.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/service/impl/WebdavServiceImpl.java @@ -1,21 +1,20 @@ -package im.zhaojun.zfile.home.service.impl; +package im.zhaojun.zfile.module.storage.service.impl; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.exceptions.ExceptionUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.URLUtil; import com.github.sardine.DavResource; import com.github.sardine.Sardine; import com.github.sardine.SardineFactory; -import im.zhaojun.zfile.admin.model.param.WebdavParam; -import im.zhaojun.zfile.common.constant.ZFileConstant; -import im.zhaojun.zfile.common.exception.FileUploadException; -import im.zhaojun.zfile.common.exception.file.operator.GetFileInfoException; -import im.zhaojun.zfile.common.util.RequestHolder; -import im.zhaojun.zfile.common.util.StringUtils; -import im.zhaojun.zfile.home.model.enums.FileTypeEnum; -import im.zhaojun.zfile.home.model.enums.StorageTypeEnum; -import im.zhaojun.zfile.home.model.result.FileItemResult; -import im.zhaojun.zfile.home.service.base.ProxyTransferService; +import im.zhaojun.zfile.core.constant.ZFileConstant; +import im.zhaojun.zfile.core.util.RequestHolder; +import im.zhaojun.zfile.core.util.StringUtils; +import im.zhaojun.zfile.module.storage.model.enums.FileTypeEnum; +import im.zhaojun.zfile.module.storage.model.enums.StorageTypeEnum; +import im.zhaojun.zfile.module.storage.model.param.WebdavParam; +import im.zhaojun.zfile.module.storage.model.result.FileItemResult; +import im.zhaojun.zfile.module.storage.service.base.AbstractProxyTransferService; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.config.ConfigurableBeanFactory; @@ -37,7 +36,7 @@ import java.util.Objects; @Service @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) @Slf4j -public class WebdavServiceImpl extends ProxyTransferService { +public class WebdavServiceImpl extends AbstractProxyTransferService { private Sardine sardine; @@ -99,7 +98,7 @@ public class WebdavServiceImpl extends ProxyTransferService { DavResource davResource = CollUtil.getLast(resources); return davResourceToFileItem(davResource, folderPath); } catch (Exception e) { - throw new GetFileInfoException(storageId, pathAndName, e); + throw ExceptionUtil.wrapRuntime(e); } } @@ -107,11 +106,10 @@ public class WebdavServiceImpl extends ProxyTransferService { public boolean newFolder(String path, String name) { try { sardine.createDirectory(getRequestPath(path, name)); + return true; } catch (Exception e) { - log.error("webdav newFolder error, path: {}, name: {}", path, name, e); - return false; + throw ExceptionUtil.wrapRuntime(e); } - return true; } @Override @@ -120,8 +118,7 @@ public class WebdavServiceImpl extends ProxyTransferService { sardine.delete(getRequestPath(path, name)); return true; } catch (IOException e) { - log.error("webdav deleteFile error, path: {}, name: {}", path, name, e); - return false; + throw ExceptionUtil.wrapRuntime(e); } } @@ -139,11 +136,10 @@ public class WebdavServiceImpl extends ProxyTransferService { public boolean renameFile(String path, String name, String newName) { try { sardine.move(getRequestPath(path, name), getRequestPath(path, newName)); + return true; } catch (IOException e) { - log.error("webdav renameFile error, path: {}, name: {}, newName: {}", path, name, newName, e); - return false; + throw ExceptionUtil.wrapRuntime(e); } - return true; } @Override @@ -152,7 +148,7 @@ public class WebdavServiceImpl extends ProxyTransferService { try { return sardine.get(getRequestPath(pathAndName)); } catch (IOException e) { - throw new RuntimeException(e); + throw ExceptionUtil.wrapRuntime(e); } }, pathAndName); return null; @@ -164,7 +160,7 @@ public class WebdavServiceImpl extends ProxyTransferService { pathAndName = getRequestPath(pathAndName); sardine.put(pathAndName, inputStream); } catch (IOException e) { - throw new FileUploadException(getStorageTypeEnum(), storageId, pathAndName, e); + throw ExceptionUtil.wrapRuntime(e); } } diff --git a/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 1dece3f..94514ee 100644 --- a/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,27 +1,5 @@ { "properties": [ - { - "name": "zfile.cache.timeout", - "type": "java.lang.Long", - "description": "目录缓存过期时间 和 下载地址过期时间. 单位为秒." - }, - { - "name": "zfile.cache.auto-refresh.interval", - "type": "java.lang.Long", - "description": "任务间隔时间, 每隔多长时间检测一次到期的缓存 KEY 并自动刷新, 单位为秒." - }, - { - "name": "zfile.constant.readme", - "type": "java.lang.String", - "defaultValue": "readme.md", - "description": "文档文件 文件名." - }, - { - "name": "zfile.constant.password", - "type": "java.lang.String", - "defaultValue": "password.txt", - "description": "密码文件 文件名." - }, { "name": "zfile.onedrive.clientId", "type": "java.lang.String", @@ -62,11 +40,6 @@ "type": "java.lang.String", "description": "OneDrive China 认证权限." }, - { - "name": "zfile.preview.audio.maxFileSizeMb", - "type": "java.lang.Long", - "description": "允许在线解析封面, 专辑, 歌手信息的音频文件大小, 单位为 KB." - }, { "name": "zfile.preview.text.maxFileSizeKb", "type": "java.lang.Long", @@ -82,11 +55,6 @@ "type": "java.lang.String", "description": "数据库文件路径." }, - { - "name": "zfile.tmp.path", - "type": "java.lang.String", - "description": "临时文件路径." - }, { "name": "zfile.debug", "type": "java.lang.Boolean", diff --git a/src/main/resources/application-default.properties b/src/main/resources/application-default.properties index 835d175..bcec975 100644 --- a/src/main/resources/application-default.properties +++ b/src/main/resources/application-default.properties @@ -1 +1 @@ -# onedrive config zfile.onedrive.clientId=09939809-c617-43c8-a220-a93c1513c5d4 zfile.onedrive.clientSecret=_l:zI-_yrW75lV8M61K@z.I2K@B/On6Q zfile.onedrive.redirectUri=https://zfile.jun6.net/onedrive/callback zfile.onedrive.scope=offline_access User.Read Files.ReadWrite.All Sites.Read.All Sites.ReadWrite.All # onedrive china config zfile.onedrive-china.clientId=4a72d927-1907-488d-9eb2-1b465c53c1c5 zfile.onedrive-china.clientSecret=Y9CEA=82da5n-y_]KAWAgLH3?R9xf7Uw zfile.onedrive-china.redirectUri=https://zfile.jun6.net/onedrive/china-callback zfile.onedrive-china.scope=offline_access User.Read Files.ReadWrite.All Sites.Read.All Sites.ReadWrite.All # gd config zfile.gd.clientId=659016983345-vlp413rgrl2spe5d53ml16p2btslfa44.apps.googleusercontent.com zfile.gd.clientSecret=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 zfile.gd.redirectUri=http://localhost:8080/gd/callback zfile.gd.scope=https://www.googleapis.com/auth/drive # result config spring.jackson.date-format=yyyy-MM-dd HH:mm spring.jackson.time-zone=GMT+8 spring.web.resources.chain.compressed=true ## mybatis config mybatis-plus.configuration.map-underscore-to-camel-case=true mybatis-plus.mapper-locations=classpath*:mapper/*.xml,classpath*:com/gitee/sunchenbin/mybatis/actable/mapping/*/*.xml ## flyway config spring.flyway.clean-disabled=true spring.flyway.enabled=false # knife4j config knife4j.enable=true knife4j.setting.enableSwaggerModels=true # sa-token config sa-token.is-print=false sa-token.token-name=zfile-token spring.main.allow-circular-references=true spring.servlet.multipart.max-request-size=-1 spring.servlet.multipart.max-file-size=-1 mybatis-plus.configuration.default-enum-type-handler=im.zhaojun.zfile.common.config.MybatisEnumTypeHandler spring.mvc.pathmatch.matching-strategy=ant_path_matcher server.compression.enabled=true \ No newline at end of file +# onedrive config zfile.onedrive.clientId=09939809-c617-43c8-a220-a93c1513c5d4 zfile.onedrive.clientSecret=_l:zI-_yrW75lV8M61K@z.I2K@B/On6Q zfile.onedrive.redirectUri=https://zfile.jun6.net/onedrive/callback zfile.onedrive.scope=offline_access User.Read Files.ReadWrite.All Sites.Read.All Sites.ReadWrite.All # onedrive china config zfile.onedrive-china.clientId=4a72d927-1907-488d-9eb2-1b465c53c1c5 zfile.onedrive-china.clientSecret=Y9CEA=82da5n-y_]KAWAgLH3?R9xf7Uw zfile.onedrive-china.redirectUri=https://zfile.jun6.net/onedrive/china-callback zfile.onedrive-china.scope=offline_access User.Read Files.ReadWrite.All Sites.Read.All Sites.ReadWrite.All # gd config zfile.gd.clientId=659016983345-vlp413rgrl2spe5d53ml16p2btslfa44.apps.googleusercontent.com zfile.gd.clientSecret=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 zfile.gd.redirectUri=http://localhost:8080/gd/callback zfile.gd.scope=https://www.googleapis.com/auth/drive # result config spring.jackson.date-format=yyyy-MM-dd HH:mm spring.jackson.time-zone=GMT+8 spring.web.resources.chain.compressed=true ## mybatis config mybatis-plus.configuration.map-underscore-to-camel-case=true mybatis-plus.mapper-locations=classpath*:mapper/*.xml,classpath*:com/gitee/sunchenbin/mybatis/actable/mapping/*/*.xml ## flyway config spring.flyway.clean-disabled=true spring.flyway.enabled=false # knife4j config knife4j.enable=true knife4j.setting.enableSwaggerModels=true # sa-token config sa-token.is-print=false sa-token.token-name=zfile-token spring.main.allow-circular-references=true spring.servlet.multipart.max-request-size=-1 spring.servlet.multipart.max-file-size=-1 mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.nologging.NoLoggingImpl spring.mvc.pathmatch.matching-strategy=ant_path_matcher server.compression.enabled=true zfile.log.encoder=UTF-8 \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 543c49c..972b36f 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -4,11 +4,7 @@ zfile.debug=false zfile.log.path=${user.home}/.zfile-v4/logs zfile.db.path=${user.home}/.zfile-v4/db/zfile -zfile.temp.path=${user.home}/.zfile-v4/temp -zfile.cache.auto-refresh.interval=1 -zfile.cache.timeout=1800 -zfile.preview.audio.maxFileSizeMb=5 zfile.preview.text.maxFileSizeKb=512 server.port=8080 diff --git a/src/main/resources/db/migration-mysql/V13__system_config_add_field_allow_path_link_anon_access.sql b/src/main/resources/db/migration-mysql/V13__system_config_add_field_allow_path_link_anon_access.sql new file mode 100644 index 0000000..c139589 --- /dev/null +++ b/src/main/resources/db/migration-mysql/V13__system_config_add_field_allow_path_link_anon_access.sql @@ -0,0 +1 @@ +INSERT INTO system_config (`name`, `title`, `value`) VALUES ('allowPathLinkAnonAccess', '是否允许路径直链可直接访问', 'false'); \ No newline at end of file diff --git a/src/main/resources/db/migration-sqlite/V13__system_config_add_field_allow_path_link_anon_access.sql b/src/main/resources/db/migration-sqlite/V13__system_config_add_field_allow_path_link_anon_access.sql new file mode 100644 index 0000000..c139589 --- /dev/null +++ b/src/main/resources/db/migration-sqlite/V13__system_config_add_field_allow_path_link_anon_access.sql @@ -0,0 +1 @@ +INSERT INTO system_config (`name`, `title`, `value`) VALUES ('allowPathLinkAnonAccess', '是否允许路径直链可直接访问', 'false'); \ No newline at end of file diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml index 4dda046..b9477ef 100644 --- a/src/main/resources/logback-spring.xml +++ b/src/main/resources/logback-spring.xml @@ -13,93 +13,155 @@ - + + + + + + + + + + + + - + + INFO - - %clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(%-6L){yellow} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx} - + + %clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} [%36.36X{traceId}] [%10.10X{user}] [%15.15X{ip}] %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(%-6L){yellow} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx} + ${LOG_ENCODER} + - - + + - ${LOG_HOME}/${appName}.log + ${LOG_HOME}/${appName}-debug.log - - - ${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.gz - - 30 - + ${LOG_HOME}/${appName}-debug-%d{yyyy-MM-dd}-%i.gz + ${debugMaxHistory} - 10MB + ${maxFileSize} - - - %d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx} - + + + ${log-file-pattern} + + + + DEBUG + ACCEPT + DENY + - + + + + ${LOG_HOME}/${appName}-info.log - - + + ${LOG_HOME}/${appName}-info-%d{yyyy-MM-dd}-%i.gz + ${maxHistory} + + ${maxFileSize} + + - - + + ${log-file-pattern} + - - - - - - + + INFO + ACCEPT + DENY + + - - - + + + + ${LOG_HOME}/${appName}-warn.log - - - - + + ${LOG_HOME}/${appName}-warn-%d{yyyy-MM-dd}-%i.gz + ${maxHistory} + + ${maxFileSize} + + + + + ${log-file-pattern} + + + + WARN + ACCEPT + DENY + + + + + + + ${LOG_HOME}/${appName}-error.log + + + ${LOG_HOME}/${appName}-error-%d{yyyy-MM-dd}-%i.gz + ${maxHistory} + + ${maxFileSize} + + + + + ${log-file-pattern} + + + + ERROR + ACCEPT + DENY + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/DownloadLogMapper.xml b/src/main/resources/mapper/DownloadLogMapper.xml index 01099e3..4e81ee7 100644 --- a/src/main/resources/mapper/DownloadLogMapper.xml +++ b/src/main/resources/mapper/DownloadLogMapper.xml @@ -1,7 +1,7 @@ - - + + @@ -18,4 +18,51 @@ `id`, `path`, `storage_key`, `create_time`, `ip`, `user_agent`, `referer`, `short_key` + + + + + + + + + + delete from download_log where storage_key = #{storageKey} + \ No newline at end of file diff --git a/src/main/resources/mapper/FilterConfigMapper.xml b/src/main/resources/mapper/FilterConfigMapper.xml index caa1e4f..e8520a7 100644 --- a/src/main/resources/mapper/FilterConfigMapper.xml +++ b/src/main/resources/mapper/FilterConfigMapper.xml @@ -1,7 +1,7 @@ - - + + diff --git a/src/main/resources/mapper/PasswordConfigMapper.xml b/src/main/resources/mapper/PasswordConfigMapper.xml index 0b3a562..6e227f5 100644 --- a/src/main/resources/mapper/PasswordConfigMapper.xml +++ b/src/main/resources/mapper/PasswordConfigMapper.xml @@ -1,7 +1,7 @@ - - + + diff --git a/src/main/resources/mapper/ReadmeConfigMapper.xml b/src/main/resources/mapper/ReadmeConfigMapper.xml index 5088fe8..0779951 100644 --- a/src/main/resources/mapper/ReadmeConfigMapper.xml +++ b/src/main/resources/mapper/ReadmeConfigMapper.xml @@ -1,7 +1,7 @@ - - + + diff --git a/src/main/resources/mapper/ShortLinkMapper.xml b/src/main/resources/mapper/ShortLinkMapper.xml index de78b49..bd53643 100644 --- a/src/main/resources/mapper/ShortLinkMapper.xml +++ b/src/main/resources/mapper/ShortLinkMapper.xml @@ -1,7 +1,7 @@ - - + + @@ -34,4 +34,9 @@ from short_link where url=#{url,jdbcType=LONGVARCHAR} and storage_id=#{storageId,jdbcType=INTEGER} + + + delete from short_link where storage_id = #{storageId} + + \ No newline at end of file diff --git a/src/main/resources/mapper/StorageConfigMapper.xml b/src/main/resources/mapper/StorageConfigMapper.xml index 8f98092..d70cdbb 100644 --- a/src/main/resources/mapper/StorageConfigMapper.xml +++ b/src/main/resources/mapper/StorageConfigMapper.xml @@ -1,7 +1,7 @@ - - + + @@ -32,14 +32,6 @@ where storage_id=#{storageId,jdbcType=INTEGER} order by id - - - delete from storage_source_config diff --git a/src/main/resources/mapper/StorageSourceMapper.xml b/src/main/resources/mapper/StorageSourceMapper.xml index 4662b61..5434e83 100644 --- a/src/main/resources/mapper/StorageSourceMapper.xml +++ b/src/main/resources/mapper/StorageSourceMapper.xml @@ -1,7 +1,7 @@ - - + + @@ -29,14 +29,14 @@