|
|
package com.ruoyi.file;
|
|
|
|
|
|
import cn.hutool.core.date.DateUtil;
|
|
|
import cn.hutool.core.img.Img;
|
|
|
import cn.hutool.core.img.ImgUtil;
|
|
|
import cn.hutool.core.lang.UUID;
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
import cn.hutool.crypto.SecureUtil;
|
|
|
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
|
|
|
import cn.hutool.crypto.symmetric.SymmetricCrypto;
|
|
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
|
|
import com.ruoyi.common.utils.IdUtils;
|
|
|
import lombok.Data;
|
|
|
import lombok.SneakyThrows;
|
|
|
import org.apache.tika.Tika;
|
|
|
import org.dromara.x.file.storage.core.Downloader;
|
|
|
import org.dromara.x.file.storage.core.FileInfo;
|
|
|
import org.dromara.x.file.storage.core.hash.HashInfo;
|
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
|
|
|
|
import javax.imageio.ImageIO;
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
import java.awt.*;
|
|
|
import java.awt.image.BufferedImage;
|
|
|
import java.io.ByteArrayInputStream;
|
|
|
import java.io.ByteArrayOutputStream;
|
|
|
import java.io.IOException;
|
|
|
import java.io.InputStream;
|
|
|
import java.nio.ByteBuffer;
|
|
|
import java.time.Duration;
|
|
|
import java.time.LocalDateTime;
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
|
public interface FileService {
|
|
|
|
|
|
/**
|
|
|
* 生成保留文件名的规则
|
|
|
*/
|
|
|
String RULE_KEEP_FILENAME = "/{yyyy}/{MM}/{dd}/{id36}/{filename}.{ext}";
|
|
|
|
|
|
/**
|
|
|
* 生成随机文件名的规则
|
|
|
*/
|
|
|
String RULE_RANDOM_FILENAME = "/{yyyy}/{MM}/{dd}/{id36}.{ext}";
|
|
|
|
|
|
/**
|
|
|
* 默认前缀
|
|
|
*/
|
|
|
String DEFAULT_PREFIX = "default";
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 默认图片文件名
|
|
|
*/
|
|
|
String DEFAULT_IMAGE_FILENAME = "a.webp";
|
|
|
|
|
|
/**
|
|
|
* 缩略图的扩展名
|
|
|
*/
|
|
|
String THUMBNAIL_EXT = ".min.webp";
|
|
|
|
|
|
/**
|
|
|
* 源文件的扩展名
|
|
|
*/
|
|
|
String SRC_EXT = ".zip";
|
|
|
|
|
|
/**
|
|
|
* webp图片格式扩展名
|
|
|
*/
|
|
|
String IMAGE_WEBP = "webp";
|
|
|
|
|
|
|
|
|
ThreadLocal<Param> paramThreadLocal = ThreadLocal.withInitial(() -> new Param());
|
|
|
ThreadLocal<HashInfo> hashInfoThreadLocal = new ThreadLocal<>();
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 获取文件上传完成后计算的md5值
|
|
|
* @return
|
|
|
*/
|
|
|
default String getMd5() {
|
|
|
return hashInfoThreadLocal.get()==null?null:hashInfoThreadLocal.get().getMd5();
|
|
|
}
|
|
|
/**
|
|
|
* 获取文件上传完成后计算的sha256值
|
|
|
* @return
|
|
|
*/
|
|
|
default String getSha256() {
|
|
|
return hashInfoThreadLocal.get()==null?null:hashInfoThreadLocal.get().getSha256();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 初始化分片上传
|
|
|
*
|
|
|
* @return 分配上传编号
|
|
|
*/
|
|
|
String multipartUploadInit();
|
|
|
|
|
|
/**
|
|
|
* 分片上传
|
|
|
*
|
|
|
* @param uploadId
|
|
|
* @param partNumber
|
|
|
* @param inputStream
|
|
|
*/
|
|
|
void multipartUpload(String uploadId, Integer partNumber, InputStream inputStream);
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 分片上传完成
|
|
|
*
|
|
|
* @param uploadId
|
|
|
* @return
|
|
|
*/
|
|
|
String multipartUploadComplete(String uploadId);
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 分片上传取消
|
|
|
*
|
|
|
* @param uploadId
|
|
|
*/
|
|
|
void multipartUploadAbort(String uploadId);
|
|
|
|
|
|
List<Integer> multipartUploadListParts(String uploadId);
|
|
|
|
|
|
/**
|
|
|
* 删除
|
|
|
*
|
|
|
* @param url
|
|
|
*/
|
|
|
void delete(String url);
|
|
|
|
|
|
/**
|
|
|
* 下载
|
|
|
*
|
|
|
* @param url
|
|
|
* @return
|
|
|
*/
|
|
|
Downloader download(String url);
|
|
|
|
|
|
/**
|
|
|
* 下载文件
|
|
|
* 1.支持预签名的跳转
|
|
|
* 2.本地模式的读取下载
|
|
|
* 3.否则,直接读取下载
|
|
|
*
|
|
|
* @param url url
|
|
|
* @param exp 过期时间
|
|
|
* @param request 请求
|
|
|
* @param response 响应
|
|
|
*/
|
|
|
void download(String url, Duration exp, HttpServletRequest request, HttpServletResponse response);
|
|
|
|
|
|
/**
|
|
|
* 生成预签名URL
|
|
|
*
|
|
|
* @param url 原始URL
|
|
|
* @param exp 过期时间
|
|
|
* @return
|
|
|
*/
|
|
|
String generatePresignedUrl(String url, Duration exp);
|
|
|
|
|
|
/**
|
|
|
* 在保存方法之前执行
|
|
|
* 设置平台
|
|
|
*
|
|
|
* @param platform 平台
|
|
|
* @return
|
|
|
*/
|
|
|
default FileService setPlatform(String platform) {
|
|
|
paramThreadLocal.get().setPlatform(platform);
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 设置计算md5
|
|
|
* @return
|
|
|
*/
|
|
|
default FileService setMd5() {
|
|
|
paramThreadLocal.get().setMd5(true);
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 设置是否计算md5
|
|
|
* @param md5
|
|
|
* @return
|
|
|
*/
|
|
|
default FileService setMd5(boolean md5) {
|
|
|
paramThreadLocal.get().setMd5(md5);
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 设置计算Sha256
|
|
|
* @return
|
|
|
*/
|
|
|
default FileService setSha256() {
|
|
|
paramThreadLocal.get().setSha256(true);
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 设置是否计算Sha256
|
|
|
* @return
|
|
|
*/
|
|
|
default FileService setSha256(boolean sha256) {
|
|
|
paramThreadLocal.get().setSha256(sha256);
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 在保存方法之前执行
|
|
|
* 设置路径前缀
|
|
|
*
|
|
|
* @param prefix 前缀
|
|
|
* @return
|
|
|
*/
|
|
|
default FileService setPrefix(String prefix) {
|
|
|
if (StrUtil.isBlank(prefix)) {
|
|
|
return this;
|
|
|
}
|
|
|
if (!prefix.matches("^[\\w\\-]+$")) {
|
|
|
throw new RuntimeException("路径前缀规则错误");
|
|
|
}
|
|
|
paramThreadLocal.get().setPrefix(prefix);
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 在保存方法之前执行
|
|
|
* 设置文件名
|
|
|
* 保存inputstream流需要设置
|
|
|
*
|
|
|
* @param filename
|
|
|
* @return
|
|
|
*/
|
|
|
default FileService setFilename(String filename) {
|
|
|
paramThreadLocal.get().setFilename(filename);
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 在保存方法之前执行
|
|
|
* 使用RULE_KEEP_FILENAME规则生成保存路径
|
|
|
* 不执行使用RULE_RANDOM_FILENAME规则生成保存路径
|
|
|
*
|
|
|
* @return
|
|
|
*/
|
|
|
default FileService setKeepFilename() {
|
|
|
return setKeepFilename(true);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 在保存方法之前执行
|
|
|
* 使用RULE_KEEP_FILENAME规则生成保存路径
|
|
|
* 不执行使用RULE_RANDOM_FILENAME规则生成保存路径
|
|
|
*
|
|
|
* @return
|
|
|
*/
|
|
|
default FileService setKeepFilename(Boolean keepFilename) {
|
|
|
paramThreadLocal.get().setKeepFilename(keepFilename);
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 在保存方法之前执行
|
|
|
* 设置保存路径,执行该方法后,setKeepFilename,setFilename,setRule将无效
|
|
|
*
|
|
|
* @param uri 保存路径
|
|
|
* @return
|
|
|
*/
|
|
|
default FileService setUri(String uri) {
|
|
|
paramThreadLocal.get().setUri(uri);
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 在保存方法之前执行
|
|
|
* 使用rule规则生成保存路径
|
|
|
*
|
|
|
* @param rule
|
|
|
* @return
|
|
|
*/
|
|
|
default FileService setRule(String rule) {
|
|
|
paramThreadLocal.get().setRule(rule);
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 在saveImage方法之前执行
|
|
|
* 调整图片大小
|
|
|
*
|
|
|
* @param maxWidth
|
|
|
* @param maxHeight
|
|
|
* @return
|
|
|
*/
|
|
|
default FileService setSize(int maxWidth, int maxHeight) {
|
|
|
paramThreadLocal.get().setMaxWidth(maxWidth);
|
|
|
paramThreadLocal.get().setMaxHeight(maxHeight);
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 在saveImage方法之前执行
|
|
|
* 调整图片大小(默认值)
|
|
|
*
|
|
|
* @return
|
|
|
*/
|
|
|
FileService setSize();
|
|
|
|
|
|
/**
|
|
|
* 在saveImage方法之前执行
|
|
|
* 设置水印
|
|
|
*
|
|
|
* @param watermark
|
|
|
* @return
|
|
|
*/
|
|
|
default FileService setWatermark(BufferedImage watermark) {
|
|
|
paramThreadLocal.get().setWatermark(watermark);
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 是否添加默认水印
|
|
|
*
|
|
|
* @param watermark
|
|
|
* @return
|
|
|
*/
|
|
|
default FileService setWatermark(Boolean watermark) {
|
|
|
if (watermark) {
|
|
|
this.setWatermark();
|
|
|
} else {
|
|
|
paramThreadLocal.get().setWatermark(null);
|
|
|
}
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 在saveImage方法之前执行
|
|
|
* 设置默认水印
|
|
|
*
|
|
|
* @return
|
|
|
*/
|
|
|
FileService setWatermark();
|
|
|
|
|
|
/**
|
|
|
* 在saveImage方法之前执行
|
|
|
* 设置同时生成缩略图
|
|
|
*
|
|
|
* @return
|
|
|
*/
|
|
|
default FileService setThumbnail() {
|
|
|
return setThumbnail(true);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 在saveImage方法之前执行
|
|
|
* 设置是否同时生成缩略图
|
|
|
*
|
|
|
* @return
|
|
|
*/
|
|
|
FileService setThumbnail(boolean thumbnail);
|
|
|
|
|
|
default FileService setSaveSrc() {
|
|
|
return setSaveSrc(true);
|
|
|
}
|
|
|
|
|
|
default FileService setSaveSrc(boolean saveSrc) {
|
|
|
paramThreadLocal.get().setSaveSrc(saveSrc);
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 在saveImage方法之前执行
|
|
|
* 设置同时生成缩略图,并指定尺寸
|
|
|
*
|
|
|
* @param width
|
|
|
* @param height
|
|
|
* @return
|
|
|
*/
|
|
|
default FileService setThumbnail(int width, int height) {
|
|
|
paramThreadLocal.get().setThWidth(width);
|
|
|
paramThreadLocal.get().setThHeight(height);
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 保存文件
|
|
|
*
|
|
|
* @param in
|
|
|
* @return
|
|
|
*/
|
|
|
String save(InputStream in);
|
|
|
|
|
|
/**
|
|
|
* 保存文件
|
|
|
*
|
|
|
* @param file
|
|
|
* @return
|
|
|
*/
|
|
|
@SneakyThrows
|
|
|
default String save(MultipartFile file) {
|
|
|
if (file == null || file.isEmpty()) {
|
|
|
throw new RuntimeException("文件不能为空");
|
|
|
}
|
|
|
return setFilename(file.getOriginalFilename()).save(file.getInputStream());
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 保存图片
|
|
|
*
|
|
|
* @param in
|
|
|
* @return
|
|
|
*/
|
|
|
String saveImage(InputStream in);
|
|
|
|
|
|
/**
|
|
|
* 保存图片
|
|
|
*
|
|
|
* @param image 图片
|
|
|
* @return
|
|
|
*/
|
|
|
default String saveImage(Image image) {
|
|
|
return saveImage(ImgUtil.toStream(image, "png"));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 保存图片
|
|
|
*
|
|
|
* @param file
|
|
|
* @return
|
|
|
*/
|
|
|
@SneakyThrows
|
|
|
default String saveImage(MultipartFile file) {
|
|
|
if (file == null || file.isEmpty()) {
|
|
|
throw new RuntimeException("文件不能为空");
|
|
|
}
|
|
|
return setFilename(file.getOriginalFilename()).saveImage(file.getInputStream());
|
|
|
}
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 获取类型提取工具
|
|
|
*
|
|
|
* @return
|
|
|
*/
|
|
|
Tika getTika();
|
|
|
|
|
|
/**
|
|
|
* 获取文件类型
|
|
|
*
|
|
|
* @param in
|
|
|
* @return
|
|
|
*/
|
|
|
@SneakyThrows
|
|
|
default String getContentType(InputStream in) {
|
|
|
return getTika().detect(in);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 是否是图片文件
|
|
|
*
|
|
|
* @param in
|
|
|
* @return
|
|
|
*/
|
|
|
@SneakyThrows
|
|
|
default boolean isImage(InputStream in) {
|
|
|
return getContentType(in).startsWith("image/");
|
|
|
}
|
|
|
|
|
|
|
|
|
default InputStream formatImage(MultipartFile file, int maxWidth, int maxHeight,
|
|
|
BufferedImage watermark) {
|
|
|
try {
|
|
|
if (file == null || file.isEmpty()) {
|
|
|
throw new RuntimeException("上传图片不能为空");
|
|
|
}
|
|
|
if (!file.getContentType().startsWith("image/")) {
|
|
|
throw new RuntimeException("上传的文件不是图片");
|
|
|
}
|
|
|
return formatImage(file.getInputStream(), maxWidth, maxHeight, watermark);
|
|
|
} catch (IOException e) {
|
|
|
throw new RuntimeException("处理图片错误", e);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
default InputStream formatImage(Image img, int maxWidth, int maxHeight, BufferedImage watermark) {
|
|
|
if (img == null) {
|
|
|
throw new RuntimeException("图片不能为空");
|
|
|
}
|
|
|
return formatImage(Img.from(img), maxWidth, maxHeight, watermark);
|
|
|
}
|
|
|
|
|
|
default InputStream formatImage(InputStream in, int maxWidth, int maxHeight, BufferedImage watermark) {
|
|
|
return formatImage(Img.from(in), maxWidth, maxHeight, watermark);
|
|
|
}
|
|
|
|
|
|
default InputStream formatImage(Img img, int maxWidth, int maxHeight, BufferedImage watermark) {
|
|
|
try {
|
|
|
int w = img.getImg().getWidth(null);
|
|
|
int h = img.getImg().getHeight(null);
|
|
|
if (maxWidth > 0 && maxHeight > 0) {
|
|
|
if (w > maxWidth || h > maxHeight) {
|
|
|
int outWidth = 0;
|
|
|
int outHeight = 0;
|
|
|
outHeight = maxWidth * h / w;
|
|
|
if (outHeight > maxHeight) {
|
|
|
outHeight = maxHeight;
|
|
|
outWidth = outHeight * w / h;
|
|
|
} else {
|
|
|
outWidth = maxWidth;
|
|
|
}
|
|
|
img = img.scale(outWidth, outHeight);
|
|
|
w = outWidth;
|
|
|
h = outHeight;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
if (watermark != null) {
|
|
|
int ww = watermark.getWidth(null);
|
|
|
int wh = watermark.getHeight(null);
|
|
|
if (w > ww && h > wh) {
|
|
|
img = img.pressImage(watermark, 0, 0, 1f);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
ByteArrayOutputStream pout = new ByteArrayOutputStream();
|
|
|
|
|
|
// img.setTargetImageType(IMAGE_WEBP).write(pout);
|
|
|
ImageIO.write(ImgUtil.toBufferedImage(img.getImg()), IMAGE_WEBP, pout);
|
|
|
|
|
|
ByteArrayInputStream pin = new ByteArrayInputStream(pout.toByteArray());
|
|
|
pout.close();
|
|
|
pout = null;
|
|
|
return pin;
|
|
|
} catch (Exception e) {
|
|
|
throw new RuntimeException("处理图片错误", e);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 生成存放的URI并保留文件名
|
|
|
*
|
|
|
* @param filename 文件名
|
|
|
* @param prefix 前缀
|
|
|
* @return
|
|
|
*/
|
|
|
default String generateURIKeepFilename(String prefix, String filename) {
|
|
|
return generateURI(prefix, RULE_KEEP_FILENAME, filename);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 生成存放的URI并保留文件名
|
|
|
*
|
|
|
* @param filename 文件名
|
|
|
* @return
|
|
|
*/
|
|
|
default String generateURIKeepFilename(String filename) {
|
|
|
return generateURI(DEFAULT_PREFIX, RULE_KEEP_FILENAME, filename);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 生成存放的URI并随机文件名
|
|
|
*
|
|
|
* @param filename 文件名
|
|
|
* @param prefix 前缀
|
|
|
* @return
|
|
|
*/
|
|
|
default String generateURIRandomFilename(String prefix, String filename) {
|
|
|
return generateURI(prefix, RULE_RANDOM_FILENAME, filename);
|
|
|
}
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 生成存放的URI并随机文件名
|
|
|
*
|
|
|
* @param filename 文件名
|
|
|
* @return
|
|
|
*/
|
|
|
default String generateURIRandomFilename(String filename) {
|
|
|
return generateURI(DEFAULT_PREFIX, RULE_RANDOM_FILENAME, filename);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* <pre>
|
|
|
* - 根据存放规则和文件名生成存放的URI
|
|
|
* - 支持
|
|
|
* - {yyyy}/{MM}/{dd}/{HH}/{mm}/{ss} 年月日时分秒
|
|
|
* - {UUID} 32位的唯一标志
|
|
|
* - {i} 自增id
|
|
|
* - {id} 当日int类型的唯一id,防止重复建议+年月日路径
|
|
|
* - {id16} 当日int类型的唯一id16进制表示,防止重复建议+年月日路径
|
|
|
* - {id36} 当日int类型的唯一id36进制表示,防止重复建议+年月日路径
|
|
|
* - {filename} 文件基础名称
|
|
|
* - {ext} 扩展名
|
|
|
* </pre>
|
|
|
*
|
|
|
* @param prefix 前缀
|
|
|
* @param rule 规则
|
|
|
* @param filename 文件名
|
|
|
* @return
|
|
|
*/
|
|
|
default String generateURI(String prefix, String rule, String filename) {
|
|
|
if (StrUtil.isBlank(prefix)) {
|
|
|
prefix = DEFAULT_PREFIX;
|
|
|
}
|
|
|
LocalDateTime now = LocalDateTime.now();
|
|
|
if (rule.contains("{yyyy}")) {
|
|
|
rule = rule.replace("{yyyy}", "" + now.getYear());
|
|
|
}
|
|
|
if (rule.contains("{MM}")) {
|
|
|
rule = rule.replace("{MM}", String.format("%02d", now.getMonthValue()));
|
|
|
}
|
|
|
if (rule.contains("{dd}")) {
|
|
|
rule = rule.replace("{dd}", String.format("%02d", now.getDayOfMonth()));
|
|
|
}
|
|
|
if (rule.contains("{HH}")) {
|
|
|
rule = rule.replace("{HH}", String.format("%02d", now.getHour()));
|
|
|
}
|
|
|
if (rule.contains("{mm}")) {
|
|
|
rule = rule.replace("{mm}", String.format("%02d", now.getMinute()));
|
|
|
}
|
|
|
if (rule.contains("{ss}")) {
|
|
|
rule = rule.replace("{ss}", String.format("%02d", now.getSecond()));
|
|
|
}
|
|
|
if (rule.contains("{UUID}")) {
|
|
|
rule = rule.replace("{UUID}", UUID.fastUUID().toString(true));
|
|
|
}
|
|
|
if (rule.contains("{i}")) {
|
|
|
rule = rule.replace("{i}", IdUtils.nextId(Id.groupName).toString());
|
|
|
}
|
|
|
if (rule.contains("{id}")) {
|
|
|
rule = rule.replace("{id}", Long.toString(id.nextId()));
|
|
|
}
|
|
|
if (rule.contains("{id16}")) {
|
|
|
rule = rule.replace("{id16}", Long.toString(id.nextId(), 16));
|
|
|
}
|
|
|
if (rule.contains("{id36}")) {
|
|
|
rule = rule.replace("{id36}", Long.toString(id.nextId(), 36));
|
|
|
}
|
|
|
if (rule.contains("{filename}")) {
|
|
|
String temp = null;
|
|
|
if (filename.contains(".")) {
|
|
|
temp = filename.substring(0, filename.lastIndexOf("."));
|
|
|
} else {
|
|
|
temp = filename;
|
|
|
}
|
|
|
rule = rule.replace("{filename}", temp);
|
|
|
}
|
|
|
|
|
|
if (rule.contains("{ext}")) {
|
|
|
String temp = null;
|
|
|
if (filename.contains(".")) {
|
|
|
temp = filename.substring(filename.lastIndexOf(".") + 1);
|
|
|
} else {
|
|
|
temp = "";
|
|
|
}
|
|
|
rule = rule.replace("{ext}", temp.toLowerCase());
|
|
|
}
|
|
|
return prefix + rule;
|
|
|
}
|
|
|
|
|
|
Id id = new Id();
|
|
|
|
|
|
static class Id {
|
|
|
|
|
|
private static final String groupName = "file:id";
|
|
|
|
|
|
private SymmetricCrypto crypto;
|
|
|
|
|
|
private String today = DateUtil.today();
|
|
|
|
|
|
public synchronized Long nextId() {
|
|
|
if (crypto == null || !today.equals(DateUtil.today())) {
|
|
|
today = DateUtil.today();
|
|
|
byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.DES.getValue(), today.getBytes()).getEncoded();
|
|
|
crypto = new SymmetricCrypto(SymmetricAlgorithm.DES, key);
|
|
|
}
|
|
|
ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES);
|
|
|
buffer.putInt(IdUtils.nextDayId(groupName).intValue());
|
|
|
return Math.abs(ByteBuffer.wrap(crypto.encrypt(buffer.array())).getLong());
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
@Data
|
|
|
public static class Param {
|
|
|
private String platform;
|
|
|
private String prefix = FileService.DEFAULT_PREFIX;
|
|
|
private String filename;
|
|
|
private boolean keepFilename = false;
|
|
|
private boolean saveSrc = false;
|
|
|
private String rule;
|
|
|
private String uri;
|
|
|
private int maxWidth = 0;
|
|
|
private int maxHeight = 0;
|
|
|
@JsonIgnore
|
|
|
private BufferedImage watermark;
|
|
|
private int thWidth = 0;
|
|
|
private int thHeight = 0;
|
|
|
|
|
|
private boolean md5 = false;
|
|
|
|
|
|
private boolean sha256 = false;
|
|
|
|
|
|
}
|
|
|
}
|