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);
}
/**
*
* - 根据存放规则和文件名生成存放的URI
* - 支持
* - {yyyy}/{MM}/{dd}/{HH}/{mm}/{ss} 年月日时分秒
* - {UUID} 32位的唯一标志
* - {i} 自增id
* - {id} 当日int类型的唯一id,防止重复建议+年月日路径
* - {id16} 当日int类型的唯一id16进制表示,防止重复建议+年月日路径
* - {id36} 当日int类型的唯一id36进制表示,防止重复建议+年月日路径
* - {filename} 文件基础名称
* - {ext} 扩展名
*
*
* @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;
}
}