ids, Boolean isValid);
+
+
+ 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 * maxWidth / 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);
+
+ ByteArrayInputStream pin = new ByteArrayInputStream(pout.toByteArray());
+ pout.close();
+ pout = null;
+ return pin;
+ } catch (Exception e) {
+ throw new RuntimeException("处理图片错误", e);
+ }
+ }
+
+
+
+ /**
+ *
+ * - 根据存放规则和文件名生成存放的URI
+ * - 支持
+ * - {yyyy}/{MM}/{dd}/{HH}/{mm}/{ss} 年月日时分秒
+ * - {UUID} 32位的唯一标志
+ * - {id} int类型的唯一id,防止重复建议+年月日路径
+ * - {id16} int类型的唯一id16进制表示,防止重复建议+年月日路径
+ * - {id36} int类型的唯一id36进制表示,防止重复建议+年月日路径
+ * - {filename} 文件基础名称
+ * - {ext} 扩展名
+ *
+ *
+ * @param rule
+ * @param filename
+ * @return
+ */
+ default String generateURI(String rule, String filename) {
+ Calendar c = Calendar.getInstance();
+ if (rule.contains("{yyyy}")) {
+ rule = rule.replace("{yyyy}", "" + c.get(Calendar.YEAR));
+ }
+ if (rule.contains("{MM}")) {
+ rule = rule.replace("{MM}", "" + (c.get(Calendar.MONTH) + 1));
+ }
+ if (rule.contains("{dd}")) {
+ rule = rule.replace("{dd}", "" + c.get(Calendar.DATE));
+ }
+ if (rule.contains("{HH}")) {
+ rule = rule.replace("{HH}", "" + c.get(Calendar.HOUR_OF_DAY));
+ }
+ if (rule.contains("{mm}")) {
+ rule = rule.replace("{mm}", "" + c.get(Calendar.MINUTE));
+ }
+ if (rule.contains("{ss}")) {
+ rule = rule.replace("{ss}", "" + c.get(Calendar.SECOND));
+ }
+ if (rule.contains("{UUID}")) {
+ rule = rule.replace("{UUID}", UUID.fastUUID().toString(true));
+ }
+ if (rule.contains("{id}")) {
+ rule = rule.replace("{id}", Integer.toString(id.nextId()));
+ }
+ if (rule.contains("{id16}")) {
+ rule = rule.replace("{id16}", Integer.toString(id.nextId(), 16));
+ }
+ if (rule.contains("{id36}")) {
+ rule = rule.replace("{id36}", Integer.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 rule;
+ }
+ Id id = new Id();
+
+ static class Id {
+ private long lastTimestamp = 0;
+ private int sequence = 0;
+
+ public synchronized int nextId() {
+ long timestamp = System.currentTimeMillis();
+ if (lastTimestamp == timestamp) {
+ sequence = (sequence + 1) & 0xF;
+ if (sequence == 0) {
+ while (timestamp <= lastTimestamp) {
+ timestamp = System.currentTimeMillis();
+ }
+ }
+ } else {
+ sequence = 0;
+ }
+ lastTimestamp = timestamp;
+ return (int) (timestamp & 0xFFFF) << 8 | sequence;
+ }
+ }
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java
index 932753b..1403e2a 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java
@@ -2,6 +2,8 @@ package com.ruoyi.system.service.impl;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.http.HttpUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -18,10 +20,13 @@ import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.mapper.SysConfigMapper;
import com.ruoyi.system.service.ISysConfigService;
import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -33,6 +38,7 @@ import java.util.Map;
*/
@RequiredArgsConstructor
@Service
+@Slf4j
public class SysConfigServiceImpl implements ISysConfigService, ConfigService {
private final SysConfigMapper baseMapper;
@@ -224,4 +230,24 @@ public class SysConfigServiceImpl implements ISysConfigService, ConfigService {
return SpringUtils.getAopProxy(this).selectConfigByKey(configKey);
}
+
+
+ private BufferedImage img;
+
+ @Override
+ public synchronized BufferedImage getWatermark() {
+ if (img == null) {
+ try{
+ HttpResponse response = HttpUtil.createGet(selectConfigByKey("image.watermark")).execute();
+ if(response.isOk()){
+ img = ImageIO.read(response.bodyStream());
+ }
+ log.info("下载默认水印图片成功");
+ }catch (Exception e) {
+ log.warn("下载水印图片失败",e);
+ }
+ }
+ return img;
+ }
+
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssServiceImpl.java
index c36bfa2..68beae3 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssServiceImpl.java
@@ -3,6 +3,7 @@ package com.ruoyi.system.service.impl;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -23,6 +24,7 @@ import com.ruoyi.system.domain.SysOss;
import com.ruoyi.system.domain.bo.SysOssBo;
import com.ruoyi.system.domain.vo.SysOssVo;
import com.ruoyi.system.mapper.SysOssMapper;
+import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysOssService;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.Cacheable;
@@ -31,6 +33,7 @@ import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
+import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
@@ -45,6 +48,7 @@ import java.util.stream.Collectors;
@Service
public class SysOssServiceImpl implements ISysOssService, OssService {
+ private final ISysConfigService configService;
private final SysOssMapper baseMapper;
@Override
@@ -120,12 +124,65 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
@Override
public SysOssVo upload(MultipartFile file) {
- String originalfileName = file.getOriginalFilename();
- String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length());
+ return upload(file,null);
+ }
+
+ @Override
+ public SysOssVo upload(MultipartFile file, String pre) {
+ String originalFileName = file.getOriginalFilename();
+ String suffix = StringUtils.substring(originalFileName, originalFileName.lastIndexOf("."), originalFileName.length());
OssClient storage = OssFactory.instance();
UploadResult uploadResult;
try {
- uploadResult = storage.uploadSuffix(file.getBytes(), suffix, file.getContentType());
+ String path = "";
+ if(StrUtil.isNotBlank(storage.getProperties().getPrefix())){
+ path += storage.getProperties().getPrefix()+"/";
+ }
+ if(StrUtil.isNotBlank(pre)) {
+ path += pre+"/";
+ }
+ path += generateURI("{yyyy}/{MM}/{dd}/{id36}.{ext}",originalFileName);
+ uploadResult = storage.upload(file.getInputStream(),path,file.getContentType());
+ } catch (IOException e) {
+ throw new ServiceException(e.getMessage());
+ }
+ // 保存文件信息
+ SysOss oss = new SysOss();
+ oss.setUrl(uploadResult.getUrl());
+ oss.setFileSuffix(suffix);
+ oss.setFileName(uploadResult.getFilename());
+ oss.setOriginalName(originalFileName);
+ oss.setService(storage.getConfigKey());
+ baseMapper.insert(oss);
+ SysOssVo sysOssVo = new SysOssVo();
+ BeanCopyUtils.copy(oss, sysOssVo);
+ return this.matchingUrl(sysOssVo);
+ }
+
+ @Override
+ public SysOssVo uploadImgs(MultipartFile file, String pre) {
+ return uploadImgs(file,pre,Integer.valueOf(configService.selectConfigByKey("image.maxWidth")),Integer.valueOf(configService.selectConfigByKey("image.maxHeight")),configService.getWatermark());
+ }
+
+ @Override
+ public SysOssVo uploadImgs(MultipartFile file, String pre, int maxWidth, int maxHeight, BufferedImage watermark) {
+ String originalFileName = file.getOriginalFilename();
+ String suffix = StringUtils.substring(originalFileName, originalFileName.lastIndexOf("."), originalFileName.length());
+ OssClient storage = OssFactory.instance();
+ UploadResult uploadResult;
+ try (
+ InputStream in = formatImage(file,maxWidth,maxWidth,watermark)
+ ){
+ String path = "";
+ if(StrUtil.isNotBlank(storage.getProperties().getPrefix())){
+ path += storage.getProperties().getPrefix()+"/";
+ }
+ if(StrUtil.isNotBlank(pre)) {
+ path += pre+"/";
+ }
+ path += generateURI("{yyyy}/{MM}/{dd}/{id36}.webp","a.webp");
+
+ uploadResult = storage.upload(in,path,"image/webp");
} catch (IOException e) {
throw new ServiceException(e.getMessage());
}
@@ -134,7 +191,7 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
oss.setUrl(uploadResult.getUrl());
oss.setFileSuffix(suffix);
oss.setFileName(uploadResult.getFilename());
- oss.setOriginalName(originalfileName);
+ oss.setOriginalName(originalFileName);
oss.setService(storage.getConfigKey());
baseMapper.insert(oss);
SysOssVo sysOssVo = new SysOssVo();