mirror of
https://github.com/zfile-dev/zfile.git
synced 2025-04-19 05:34:52 +00:00
🔨 重构代码,将捐赠版已验证的功能合并
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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<Void> 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<Void> 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<CacheInfoDTO> 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<Void> 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<Void> 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<Void> 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<Void> clearCache(@PathVariable("storageId") Integer storageId) {
|
||||
storageSourceService.clearCache(storageId);
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<DownloadLog> pages = Page.of(queryDownloadLogRequest.getPage(), queryDownloadLogRequest.getLimit());
|
||||
boolean asc = Objects.equals(orderDirection, "asc");
|
||||
pages.addOrder(new OrderItem(orderBy, asc));
|
||||
|
||||
DownloadLog downloadLog = new DownloadLog();
|
||||
QueryWrapper<DownloadLog> 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<DownloadLog> selectResult = downloadLogService.page(pages, queryWrapper);
|
||||
|
||||
long total = selectResult.getTotal();
|
||||
List<DownloadLog> records = selectResult.getRecords();
|
||||
|
||||
Map<String, StorageSource> cache = new HashMap<>();
|
||||
|
||||
Stream<DownloadLogResult> 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<Void> 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<Void> batchDelete(@RequestBody BatchDeleteRequest batchDeleteRequest) {
|
||||
List<Integer> ids = batchDeleteRequest.getIds();
|
||||
downloadLogService.removeBatchByIds(ids);
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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<ShortLink> pages = Page.of(page, limit);
|
||||
boolean asc = Objects.equals(orderDirection, "asc");
|
||||
pages.addOrder(new OrderItem(orderBy, asc));
|
||||
QueryWrapper<ShortLink> 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<ShortLink> selectResult = shortLinkService.page(pages, queryWrapper);
|
||||
|
||||
long total = selectResult.getTotal();
|
||||
List<ShortLink> records = selectResult.getRecords();
|
||||
|
||||
Map<Integer, StorageSource> cache = new HashMap<>();
|
||||
|
||||
Stream<ShortLinkResult> 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<Void> 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<Void> batchDelete(@RequestBody BatchDeleteRequest batchDeleteRequest) {
|
||||
shortLinkService.removeBatchByIds(batchDeleteRequest.getIds());
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<DownloadLog> {
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package im.zhaojun.zfile.admin.model.param;
|
||||
|
||||
|
||||
public interface IStorageParam {
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<DownloadLogMapper, DownloadLog> {
|
||||
|
||||
|
||||
}
|
||||
@@ -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<FilterConfigMapper, FilterConfig> {
|
||||
|
||||
@Resource
|
||||
private FilterConfigMapper filterConfigMapper;
|
||||
|
||||
|
||||
/**
|
||||
* 存储源 ID -> 过滤器列表(全部)缓存.
|
||||
*/
|
||||
private final Map<Integer, List<FilterConfig>> baseCache = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 存储源 ID -> 过滤器列表(禁止访问)缓存.
|
||||
*/
|
||||
private final Map<Integer, List<FilterConfig>> inaccessibleCache = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 存储源 ID -> 过滤器列表(禁止下载)缓存.
|
||||
*/
|
||||
private final Map<Integer, List<FilterConfig>> disableDownloadCache = new HashMap<>();
|
||||
|
||||
|
||||
/**
|
||||
* 根据存储源 ID 获取存储源配置列表
|
||||
*
|
||||
* @param storageId
|
||||
* 存储源 ID
|
||||
*
|
||||
* @return 存储源过滤器配置列表
|
||||
*/
|
||||
public List<FilterConfig> findByStorageId(Integer storageId){
|
||||
if (baseCache.get(storageId) != null) {
|
||||
return baseCache.get(storageId);
|
||||
} else {
|
||||
List<FilterConfig> 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<FilterConfig> 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<FilterConfig> filterConfigList = findByStorageIdAndInaccessible(storageId);
|
||||
if (testPattern(filterConfigList, path)) {
|
||||
throw new FileAccessException("您没有权限访问该路径");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取所有类型为禁止访问的过滤规则
|
||||
*
|
||||
* @param storageId
|
||||
* 存储 ID
|
||||
*
|
||||
* @return 禁止访问的过滤规则列表
|
||||
*/
|
||||
public List<FilterConfig> findByStorageIdAndInaccessible(Integer storageId){
|
||||
if (inaccessibleCache.get(storageId) != null) {
|
||||
return inaccessibleCache.get(storageId);
|
||||
} else {
|
||||
List<FilterConfig> dbResult = filterConfigMapper.findByStorageIdAndInaccessible(storageId);
|
||||
inaccessibleCache.put(storageId, dbResult);
|
||||
return dbResult;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取所有类型为禁止下载的过滤规则
|
||||
*
|
||||
* @param storageId
|
||||
* 存储 ID
|
||||
*
|
||||
* @return 禁止下载的过滤规则列表
|
||||
*/
|
||||
public List<FilterConfig> findByStorageIdAndDisableDownload(Integer storageId){
|
||||
if (disableDownloadCache.get(storageId) != null) {
|
||||
return disableDownloadCache.get(storageId);
|
||||
} else {
|
||||
List<FilterConfig> 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<FilterConfig> filterConfigList = findByStorageId(storageId);
|
||||
return testPattern(filterConfigList, fileName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 指定存储源下的文件名称, 根据过滤表达式判断文件名和所在路径是否禁止下载, 如果符合任意一条表达式, 则返回 true, 反之则返回 false.
|
||||
*
|
||||
* @param storageId
|
||||
* 存储源 ID
|
||||
*
|
||||
* @param fileName
|
||||
* 文件名
|
||||
*
|
||||
* @return 是否显示
|
||||
*/
|
||||
public boolean filterResultIsDisableDownload(Integer storageId, String fileName) {
|
||||
List<FilterConfig> 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<FilterConfig> 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<PasswordConfigMapper, PasswordConfig> {
|
||||
|
||||
@Resource
|
||||
private PasswordConfigMapper passwordConfigMapper;
|
||||
|
||||
|
||||
/**
|
||||
* 存储源 ID -> 密码规则列表(全部)缓存.
|
||||
*/
|
||||
private final Map<Integer, List<PasswordConfig>> baseCache = new HashMap<>();
|
||||
|
||||
|
||||
/**
|
||||
* 根据存储源 ID 查询密码规则列表
|
||||
*
|
||||
* @param storageId
|
||||
* 存储源 ID
|
||||
*
|
||||
* @return 密码规则列表
|
||||
*/
|
||||
public List<PasswordConfig> findByStorageId(Integer storageId) {
|
||||
if (baseCache.get(storageId) != null) {
|
||||
return baseCache.get(storageId);
|
||||
} else {
|
||||
List<PasswordConfig> 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<PasswordConfig> 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<PasswordConfig> 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<ReadmeConfigMapper, ReadmeConfig> {
|
||||
|
||||
@Resource
|
||||
private ReadmeConfigMapper readmeConfigMapper;
|
||||
|
||||
|
||||
/**
|
||||
* 根据存储源 ID 查询文档配置
|
||||
*
|
||||
* @param storageId
|
||||
* 存储源ID
|
||||
*
|
||||
* @return 存储源文档配置列表
|
||||
*/
|
||||
public List<ReadmeConfig> findByStorageId(Integer storageId){
|
||||
return readmeConfigMapper.findByStorageId(storageId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 批量保存存储源 readme 配置, 会先删除之前的所有配置(在事务中运行)
|
||||
*
|
||||
* @param storageId
|
||||
* 存储源 ID
|
||||
*
|
||||
* @param filterConfigList
|
||||
* 存储源 readme 配置列表
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void batchSave(Integer storageId, List<ReadmeConfig> filterConfigList) {
|
||||
readmeConfigMapper.deleteByStorageId(storageId);
|
||||
super.saveBatch(filterConfigList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 根据存储源指定路径下的 readme 配置
|
||||
*
|
||||
* @param storageId
|
||||
* 存储源ID
|
||||
*
|
||||
* @param path
|
||||
* 文件夹路径
|
||||
*
|
||||
* @return 存储源 readme 配置列表
|
||||
*/
|
||||
public ReadmeConfig findReadmeByPath(Integer storageId, String path) {
|
||||
List<ReadmeConfig> readmeConfigList = readmeConfigMapper.findByStorageId(storageId);
|
||||
return getReadmeByTestPattern(readmeConfigList, path);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据规则表达式和测试字符串进行匹配,如测试字符串和其中一个规则匹配上,则返回 true,反之返回 false。
|
||||
*
|
||||
* @param patternList
|
||||
* 规则列表
|
||||
*
|
||||
* @param test
|
||||
* 测试字符串
|
||||
*
|
||||
* @return 是否显示
|
||||
*/
|
||||
private ReadmeConfig getReadmeByTestPattern(List<ReadmeConfig> 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<StorageSourceConfigMapper, StorageSourceConfig> implements IService<StorageSourceConfig> {
|
||||
|
||||
@Resource
|
||||
private StorageSourceConfigMapper storageSourceConfigMapper;
|
||||
|
||||
/**
|
||||
* 存储源 ID -> 存储源参数列表对象缓存
|
||||
*/
|
||||
private final Map<Integer, List<StorageSourceConfig>> sourceConfigConfigMapCache = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 根据存储源 ID 查询存储源拓展配置, 并按照存储源 id 排序
|
||||
*
|
||||
* @param storageId
|
||||
* 存储源 ID
|
||||
*
|
||||
* @return 存储源拓展配置列表
|
||||
*/
|
||||
public List<StorageSourceConfig> selectStorageConfigByStorageId(Integer storageId) {
|
||||
if (sourceConfigConfigMapCache.containsKey(storageId)) {
|
||||
return sourceConfigConfigMapCache.get(storageId);
|
||||
} else {
|
||||
List<StorageSourceConfig> 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<StorageSourceConfig> 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<StorageSourceConfig> 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<StorageSourceMapper, StorageSource> implements IService<StorageSource> {
|
||||
|
||||
@Resource
|
||||
private StorageSourceMapper storageSourceMapper;
|
||||
|
||||
@Resource
|
||||
private StorageSourceConfigService storageSourceConfigService;
|
||||
|
||||
@Resource
|
||||
private StorageSourceContext storageSourceContext;
|
||||
|
||||
@Resource
|
||||
private ZFileCache zFileCache;
|
||||
|
||||
public static final Class<StorageSourceAllParam> STORAGE_SOURCE_ALL_PARAM_CLASS = StorageSourceAllParam.class;
|
||||
|
||||
|
||||
/**
|
||||
* 存储源 ID -> 存储源对象缓存
|
||||
*/
|
||||
private final Map<Integer, StorageSource> storageIdMapCache = new HashMap<>();
|
||||
|
||||
|
||||
/**
|
||||
* 存储源 KEY -> 存储源对象缓存
|
||||
*/
|
||||
private final Map<String, StorageSource> storageKeyMapCache = new HashMap<>();
|
||||
|
||||
|
||||
/**
|
||||
* 获取所有存储源列表
|
||||
*
|
||||
* @return 存储源列表
|
||||
*/
|
||||
public List<StorageSource> findAllOrderByOrderNum() {
|
||||
return storageSourceMapper.findAllOrderByOrderNum();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取所有已启用的存储源列表,按照存储源的排序号排序
|
||||
*
|
||||
* @return 已启用的存储源列表
|
||||
*/
|
||||
public List<StorageSource> 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<StorageSourceConfig> 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<StorageSourceParamDef> storageSourceParamList = StorageSourceContext.getStorageSourceParamListByType(storageType);
|
||||
|
||||
List<StorageSourceConfig> 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<IStorageParam> 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<String> 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<UpdateStorageSortRequest> 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<K, V> extends TimedCache<K, V> {
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<Integer, ConcurrentHashMap<String, List<FileItemDTO>>>
|
||||
* ConcurrentMap<storageId, ConcurrentHashMap<key, value>>
|
||||
*
|
||||
* storageId: 存储源 ID
|
||||
* key: 文件夹路径
|
||||
* value: 文件夹中内容
|
||||
*/
|
||||
private final ConcurrentMap<Integer, MyTimedCache<StorageSourceCacheKey, List<FileItemResult>>> storageSourcesCache = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 系统设置缓存
|
||||
*/
|
||||
private SystemConfigDTO systemConfigCache;
|
||||
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
*
|
||||
* @param storageId
|
||||
* 存储源 ID
|
||||
*
|
||||
* @param key
|
||||
* 文件夹路径
|
||||
*
|
||||
* @param value
|
||||
* 文件夹中列表
|
||||
*/
|
||||
public synchronized void put(Integer storageId, String key, List<FileItemResult> value) {
|
||||
getCacheByStorageId(storageId).put(new StorageSourceCacheKey(storageId, key), value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取指定存储源, 某个文件夹的名称
|
||||
*
|
||||
* @param storageId
|
||||
* 存储源 ID
|
||||
*
|
||||
* @param key
|
||||
* 文件夹路径
|
||||
*
|
||||
* @return 存储源中文件夹的内容
|
||||
*/
|
||||
public List<FileItemResult> 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<String> keySet(Integer storageId) {
|
||||
Iterator<CacheObj<StorageSourceCacheKey, List<FileItemResult>>> cacheObjIterator = getCacheByStorageId(storageId).cacheObjIterator();
|
||||
Set<String> 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<StorageSourceCacheKey, List<FileItemResult>> getCacheByStorageId(Integer storageId) {
|
||||
MyTimedCache<StorageSourceCacheKey, List<FileItemResult>> 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<StorageSourceCacheKey, List<FileItemResult>> 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<StorageSourceCacheKey, List<FileItemResult>> driveCache = storageSourcesCache.get(storageId);
|
||||
if (driveCache != null) {
|
||||
driveCache.cancelPruneSchedule();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package im.zhaojun.zfile.common.config;
|
||||
@@ -1 +0,0 @@
|
||||
package im.zhaojun.zfile.common.config;
|
||||
@@ -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<E extends Enum<E>> extends BaseTypeHandler<E> {
|
||||
|
||||
private static final Map<String, String> TABLE_METHOD_OF_ENUM_TYPES = new ConcurrentHashMap<>();
|
||||
private static final ReflectorFactory REFLECTOR_FACTORY = new DefaultReflectorFactory();
|
||||
private final Class<E> enumClassType;
|
||||
private final Class<?> propertyType;
|
||||
private final Invoker getInvoker;
|
||||
|
||||
public MybatisEnumTypeHandler(Class<E> 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<String> 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<Field> fieldOptional = findEnumValueAnnotationField(clazz);
|
||||
return fieldOptional.map(Field::getName).orElse(null);
|
||||
}));
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private static Optional<Field> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package im.zhaojun.zfile.common.config;
|
||||
@@ -1,10 +0,0 @@
|
||||
package im.zhaojun.zfile.common.exception;
|
||||
|
||||
/**
|
||||
* 禁止服务器代理下载异常
|
||||
*
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class DisableProxyDownloadException extends RuntimeException {
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package im.zhaojun.zfile.common.util;
|
||||
@@ -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<Object> {
|
||||
|
||||
@Override
|
||||
public boolean supports(MethodParameter returnType,
|
||||
@NonNull Class<? extends HttpMessageConverter<?>> converterType) {
|
||||
return AbstractJackson2HttpMessageConverter.class.isAssignableFrom(converterType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public final Object beforeBodyWrite(@Nullable Object body,
|
||||
@NonNull MethodParameter returnType,
|
||||
@NonNull MediaType contentType,
|
||||
@NonNull Class<? extends HttpMessageConverter<?>> 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"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package im.zhaojun.zfile.core.config;
|
||||
@@ -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;
|
||||
@@ -0,0 +1 @@
|
||||
package im.zhaojun.zfile.core.config;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -0,0 +1 @@
|
||||
package im.zhaojun.zfile.core.config;
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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";
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -0,0 +1,14 @@
|
||||
package im.zhaojun.zfile.core.exception;
|
||||
|
||||
/**
|
||||
* 非法使用下载链接异常.
|
||||
*
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class IllegalDownloadLinkException extends ZFileRuntimeException {
|
||||
|
||||
public IllegalDownloadLinkException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package im.zhaojun.zfile.core.exception;
|
||||
|
||||
/**
|
||||
* 系统初始化异常
|
||||
*
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class InstallSystemException extends ZFileRuntimeException {
|
||||
|
||||
public InstallSystemException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package im.zhaojun.zfile.core.exception;
|
||||
|
||||
/**
|
||||
* 无效的直链异常
|
||||
*
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class InvalidShortLinkException extends ZFileRuntimeException {
|
||||
|
||||
public InvalidShortLinkException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
@@ -1,4 +1,4 @@
|
||||
package im.zhaojun.zfile.common.exception;
|
||||
package im.zhaojun.zfile.core.exception;
|
||||
|
||||
|
||||
/**
|
||||
@@ -0,0 +1,14 @@
|
||||
package im.zhaojun.zfile.core.exception;
|
||||
|
||||
/**
|
||||
* 文件预览异常类
|
||||
*
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class PreviewException extends ZFileRuntimeException {
|
||||
|
||||
public PreviewException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
41
src/main/java/im/zhaojun/zfile/core/filter/MDCFilter.java
Normal file
41
src/main/java/im/zhaojun/zfile/core/filter/MDCFilter.java
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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";
|
||||
|
||||
}
|
||||
1
src/main/java/im/zhaojun/zfile/core/util/AjaxJson.java
Normal file
1
src/main/java/im/zhaojun/zfile/core/util/AjaxJson.java
Normal file
@@ -0,0 +1 @@
|
||||
package im.zhaojun.zfile.core.util;
|
||||
@@ -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;
|
||||
76
src/main/java/im/zhaojun/zfile/core/util/CodeMsg.java
Normal file
76
src/main/java/im/zhaojun/zfile/core/util/CodeMsg.java
Normal file
@@ -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 {
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
* <p>
|
||||
* 均为 5 位数, 如 00000, 10100, 20105 等.
|
||||
* <br>
|
||||
* 第一位表示错误类型, 4 为用户请求输入错误, 5 为服务端处理错误, 6 为警告信息
|
||||
* <br>
|
||||
* 第二位到第三位为二级类型
|
||||
* <br>
|
||||
* 第四位到第五位为具体错误代码, 根据业务场景自行定义
|
||||
* <p>
|
||||
* 以上三种类型均不允许重复, 且都需保持递增.
|
||||
*/
|
||||
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", "非法操作, 当前文件不支持此类下载方式");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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 <natorder@paour.com>
|
||||
@@ -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<String, PathMatcher> PATH_MATCHER_MAP = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 兼容模式的 glob 表达式匹配.
|
||||
* 默认的 glob 表达式是不支持以下情况的:<br>
|
||||
* <ul>
|
||||
* <li>pattern: /a/**</li>
|
||||
* <li>test1: /a</li>
|
||||
* <li>test2: /a/</li>
|
||||
* <ul>
|
||||
* <p>test1 和 test 2 均无法匹配这种情况, 此方法兼容了这种情况, 即对 test 内容后拼接 "/xx", 使其可以匹配上 pattern.
|
||||
* <p><strong>注意:</strong>但此方法对包含文件名的情况无效, 仅支持 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
@@ -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<String> 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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -1,4 +1,4 @@
|
||||
package im.zhaojun.zfile.common.util;
|
||||
package im.zhaojun.zfile.core.util;
|
||||
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
34
src/main/java/im/zhaojun/zfile/core/util/UrlUtils.java
Normal file
34
src/main/java/im/zhaojun/zfile/core/util/UrlUtils.java
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package im.zhaojun.zfile.common.validation;
|
||||
package im.zhaojun.zfile.core.validation;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
@@ -1,4 +1,4 @@
|
||||
package im.zhaojun.zfile.common.validation;
|
||||
package im.zhaojun.zfile.core.validation;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
@@ -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<FileItemResult> 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<FileItemResult> cacheFileList = zFileCache.get(storageId, path);
|
||||
if (cacheFileList == null) {
|
||||
result = Collections.unmodifiableList((List<FileItemResult>) point.proceed());
|
||||
zFileCache.put(storageId, path, result);
|
||||
} else {
|
||||
result = cacheFileList;
|
||||
}
|
||||
} else {
|
||||
result = (List<FileItemResult>) point.proceed();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package im.zhaojun.zfile.home.controller;
|
||||
@@ -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<SiteConfigResult> 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<StorageSourceConfigResult> 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<IStorageParam> 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 模式,不允许进行此操作。");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user