diff --git a/admin-ui/src/store/modules/user.js b/admin-ui/src/store/modules/user.js index 1f932e8..03b096c 100644 --- a/admin-ui/src/store/modules/user.js +++ b/admin-ui/src/store/modules/user.js @@ -9,6 +9,7 @@ const useUserStore = defineStore( { state: () => ({ token: getToken(), + user: {}, name: '', avatar: '', roles: [], @@ -45,8 +46,9 @@ const useUserStore = defineStore( } else { this.roles = ['ROLE_DEFAULT'] } - this.name = user.userName + this.name = user.userName; this.avatar = avatar; + this.user = user; resolve(res) }).catch(error => { reject(error) diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/event/QaEvent.java b/ruoyi-common/src/main/java/com/ruoyi/common/event/QaEvent.java new file mode 100644 index 0000000..dec1825 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/event/QaEvent.java @@ -0,0 +1,26 @@ +package com.ruoyi.common.event; + +import org.springframework.context.ApplicationEvent; + +/** + * 需要触发QAnything知识库的增删改查事件 + */ +public class QaEvent extends ApplicationEvent { + + public static enum Type { + ALL, ADD, UPDATE, REMOVE; + } + + public QaEvent(Type source) { + super(source); + } + + public QaEvent() { + super(Type.ALL); + } + + @Override + public Type getSource() { + return (Type) super.getSource(); + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/MongoUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/MongoUtil.java index 35ca078..67e788e 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/MongoUtil.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/MongoUtil.java @@ -61,6 +61,7 @@ public class MongoUtil { } return c; } + public static Criteria or(Criteria... criterias) { Criteria c = new Criteria(); if (ArrayUtil.isNotEmpty(criterias)) { @@ -73,6 +74,7 @@ public class MongoUtil { /** * 非空字段完全匹配(is,eq)
* 字段名匹配字段值 + * * @param obj * @return */ @@ -81,7 +83,7 @@ public class MongoUtil { if (ObjUtil.isNull(obj)) { return c; } - for(PropDesc pd : BeanUtil.getBeanDesc(obj.getClass()).getProps()) { + for (PropDesc pd : BeanUtil.getBeanDesc(obj.getClass()).getProps()) { if (pd.getGetter() == null) { continue; } @@ -101,34 +103,44 @@ public class MongoUtil { } - /** age$gt + /** + * age$gt * 含操作符的字符名 * 字段命名:字段$操作符 + * * @param obj * @return */ public static Criteria criteria(Object obj) { - Map map = MapUtil.newHashMap(); - for(PropDesc pd : BeanUtil.getBeanDesc(obj.getClass()).getProps()){ - if(pd.getGetter()==null){ + Map map = MapUtil.newHashMap(); + for (PropDesc pd : BeanUtil.getBeanDesc(obj.getClass()).getProps()) { + if (pd.getGetter() == null) { continue; } Object val = pd.getValue(obj); - if(ObjUtil.isNull(val)){ + if (ObjUtil.isNull(val)) { continue; } - if(pd.getFieldClass()==String.class){ - String str = (String)val; - if(StrUtil.isBlank(str)) { + if (pd.getFieldClass() == String.class) { + String str = (String) val; + if (StrUtil.isBlank(str)) { continue; } } - map.put(pd.getFieldName(),val); + map.put(pd.getFieldName(), val); } return criteria(map); } + public static Criteria criteria() { + return new Criteria(); + } + + public static Criteria criteria(String key) { + return Criteria.where(key); + } + /** * 根据map的key(rule)生成条件,要求value非空 * rule:字段$(操作符) @@ -334,12 +346,12 @@ public class MongoUtil { return find(cls, new Query()); } - public static boolean findExists(Query query, Class entityClass){ + public static boolean findExists(Query query, Class entityClass) { return template.exists(query, entityClass); } - public static boolean findExists(Query query, String collectionName){ + public static boolean findExists(Query query, String collectionName) { return template.exists(query, collectionName); } @@ -461,11 +473,11 @@ public class MongoUtil { return this; } - public Criteria criteria(){ + public Criteria criteria() { return MongoUtil.criteria(this); } - public Query query(){ + public Query query() { return MongoUtil.query(this); } diff --git a/ruoyi-system-cron/src/main/java/com/ruoyi/cron/task/CronTaskLogCleanTask.java b/ruoyi-system-cron/src/main/java/com/ruoyi/cron/task/CronTaskLogCleanTask.java new file mode 100644 index 0000000..d2b91f6 --- /dev/null +++ b/ruoyi-system-cron/src/main/java/com/ruoyi/cron/task/CronTaskLogCleanTask.java @@ -0,0 +1,37 @@ +package com.ruoyi.cron.task; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.date.LocalDateTimeUtil; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.cron.TaskLog; +import com.ruoyi.cron.annotation.Cron; +import com.ruoyi.cron.annotation.CronComponent; +import com.ruoyi.cron.annotation.CronParam; +import com.ruoyi.cron.document.CronTaskLog; +import com.ruoyi.cron.runner.CronBeanPostProcessor; +import lombok.RequiredArgsConstructor; + +import java.time.LocalDate; +import java.util.Date; + +import static com.ruoyi.common.utils.MongoUtil.*; + +@CronComponent +@RequiredArgsConstructor +public class CronTaskLogCleanTask { + + private final TaskLog log; + private final CronBeanPostProcessor cronBeanPostProcessor; + + @Cron("日志清理任务") + public void clear(@CronParam("几天前") Integer day, @CronParam("清理的组(null全部)") Integer groupId, @CronParam("清理的任务(null全部)") String taskId) { + log.log("开始执行日志清理..."); + Date date = DateUtils.toDate(LocalDate.now().plusDays(-day)); + log.log("清理时间(之前):" + DateUtil.formatDateTime(date)); + log.log("清理的组编号:" + ((groupId == null) ? "全部" : groupId)); + log.log("清理的任务:" + ((taskId == null) ? "全部" : cronBeanPostProcessor.getList().stream().filter(a -> a.getId().equals(taskId)).findFirst().get().getName())); + long count = doRemove(CronTaskLog.class, conditions().put("startTime$lt", date).query()).getDeletedCount(); + log.log("日志清理完成,清理数量:" + count); + } + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOssService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOssService.java index 1f4180f..aae7bd8 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOssService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOssService.java @@ -38,307 +38,328 @@ import java.util.function.Supplier; */ public interface ISysOssService { - String IMAGE_WEBP = "webp"; + /** + * 服务商 + */ + public static enum Service { + minio, qiniu, aliyun, qcloud, image, upload; + } + + String IMAGE_WEBP = "webp"; + + /** + * 默认路径前缀 + */ + String PRE_DEFAULT = "default"; + + /** + * 设置指定服务商 + * + * @param handle + */ + void setService(Service service, Runnable handle); + + public T setService(Service service, Supplier handle); + + /** + * 只保存,不存放记录 + * + * @param handle 处理执行方法 + */ + void ignore(Runnable handle); + + + /** + * 只保存,不存放记录 + * + * @param handle 处理执行方法 + */ + public T ignore(Supplier handle); + + + TableDataInfo queryPageList(SysOssBo sysOss, PageQuery pageQuery); + + List listByIds(Collection ossIds); + + SysOssVo getById(Long ossId); + + default SysOssVo upload(MultipartFile file) { + return upload(file, PRE_DEFAULT); + } + + /** + * @param file + * @param pre - 图片保存路径前缀 + * @return + */ + default SysOssVo upload(MultipartFile file, String pre) { + if (file == null || file.isEmpty()) { + throw new RuntimeException("文件不能为空"); + } + try { + return save(file.getInputStream(), file.getOriginalFilename(), file.getContentType(), pre); + } catch (IOException e) { + throw new RuntimeException(e.getMessage(), e); + } + } + + + /** + * 保存文件, rule:{yyyy}/{MM}/{dd}/{id36}.{ext} + * + * @param in 输入流 + * @param filename 文件名 + * @param contentType 文件类型 + * @param pre 路径前缀 + * @return + */ + default SysOssVo save(InputStream in, String filename, String contentType, String pre) { + return save(in, filename, contentType, pre, "{yyyy}/{MM}/{dd}/{id36}.{ext}"); + } + + /** + * 保存文件,保留文件名,rule:{yyyy}/{MM}/{dd}/{id36}/{filename}.{ext} + * + * @param in 输入流 + * @param filename 文件名 + * @param contentType 文件类型 + * @param pre 路径前缀 + * @return + */ + default SysOssVo saveFilename(InputStream in, String filename, String contentType, String pre) { + return save(in, filename, contentType, pre, "{yyyy}/{MM}/{dd}/{id36}/{filename}.{ext}"); + } + + /** + * 保存文件,存放路径规则rule: + *
+   * - 根据存放规则和文件名生成存放的URI
+   * - 支持
+   * 	- {yyyy}/{MM}/{dd}/{HH}/{mm}/{ss} 年月日时分秒
+   * 	- {UUID} 32位的唯一标志
+   * 	- {i} 自增id
+   * 	- {id} 当日int类型的唯一id,防止重复建议+年月日路径
+   * 	- {id16} 当日int类型的唯一id16进制表示,防止重复建议+年月日路径
+   * 	- {id36} 当日int类型的唯一id36进制表示,防止重复建议+年月日路径
+   * 	- {filename} 文件基础名称
+   * 	- {ext} 扩展名
+   * 
+ * + * @param in 输入流 + * @param filename 文件名 + * @param contentType 文件类型 + * @param pre 路径前缀 + * @param rule 路径规则 + * @return + */ + SysOssVo save(InputStream in, String filename, String contentType, String pre, String rule); + + SysOssVo uploadImgs(MultipartFile file, String pre); + + default SysOssVo uploadImgs(MultipartFile file, String pre, int maxWidth, int maxHeight, BufferedImage watermark) { + if (file == null || file.isEmpty()) { + throw new RuntimeException("图片不能为空"); + } + try { + return uploadImgs(file.getInputStream(), pre, maxWidth, maxHeight, watermark); + } catch (IOException e) { + throw new RuntimeException(e.getMessage(), e); + } + } - /** - * 默认路径前缀 - */ - String PRE_DEFAULT = "default"; + /** + * @param in + * @param pre - 图片保存路径前缀 + * @param maxWidth - 缩放到指定的宽 小于1表示不缩放 + * @param maxHeight - 缩放到指定的高 小于1表示不缩放 + * @param watermark - 水印图片 null表示不加水印 + * @return + */ + SysOssVo uploadImgs(InputStream in, String pre, int maxWidth, int maxHeight, + BufferedImage watermark); + void download(Long ossId, HttpServletResponse response) throws IOException; - /** - * 只保存图片,不存放记录 - * - * @param handle 处理执行方法 - */ - void ignore(Runnable handle); + void download(String url, Service service, HttpServletResponse response) throws IOException; + InputStream download(Long ossId) throws IOException; - /** - * 只保存图片,不存放记录 - * - * @param handle 处理执行方法 - */ - public T ignore(Supplier handle); + InputStream download(SysOssVo sysOss) throws IOException; + InputStream download(String url, Service service) throws IOException; - TableDataInfo queryPageList(SysOssBo sysOss, PageQuery pageQuery); + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); - List listByIds(Collection ossIds); - SysOssVo getById(Long ossId); + 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 SysOssVo upload(MultipartFile file) { - return upload(file, PRE_DEFAULT); + 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; - /** - * @param file - * @param pre - 图片保存路径前缀 - * @return - */ - default SysOssVo upload(MultipartFile file, String pre) { - if (file == null || file.isEmpty()) { - throw new RuntimeException("文件不能为空"); } - try { - return save(file.getInputStream(), file.getOriginalFilename(), file.getContentType(), pre); - } catch (IOException e) { - throw new RuntimeException(e.getMessage(), e); + } + + + 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(); - /** - * 保存文件, rule:{yyyy}/{MM}/{dd}/{id36}.{ext} - * - * @param in 输入流 - * @param filename 文件名 - * @param contentType 文件类型 - * @param pre 路径前缀 - * @return - */ - default SysOssVo save(InputStream in, String filename, String contentType, String pre) { - return save(in, filename, contentType, pre, "{yyyy}/{MM}/{dd}/{id36}.{ext}"); - } + img.setTargetImageType(IMAGE_WEBP).write(pout); - /** - * 保存文件,保留文件名,rule:{yyyy}/{MM}/{dd}/{id36}/{filename}.{ext} - * - * @param in 输入流 - * @param filename 文件名 - * @param contentType 文件类型 - * @param pre 路径前缀 - * @return - */ - default SysOssVo saveFilename(InputStream in, String filename, String contentType, String pre) { - return save(in, filename, contentType, pre, "{yyyy}/{MM}/{dd}/{id36}/{filename}.{ext}"); + ByteArrayInputStream pin = new ByteArrayInputStream(pout.toByteArray()); + pout.close(); + pout = null; + return pin; + } catch (Exception e) { + throw new RuntimeException("处理图片错误", e); } - - /** - * 保存文件,存放路径规则rule: - *
-     * - 根据存放规则和文件名生成存放的URI
-     * - 支持
-     * 	- {yyyy}/{MM}/{dd}/{HH}/{mm}/{ss} 年月日时分秒
-     * 	- {UUID} 32位的唯一标志
-     * 	- {i} 自增id
-     * 	- {id} 当日int类型的唯一id,防止重复建议+年月日路径
-     * 	- {id16} 当日int类型的唯一id16进制表示,防止重复建议+年月日路径
-     * 	- {id36} 当日int类型的唯一id36进制表示,防止重复建议+年月日路径
-     * 	- {filename} 文件基础名称
-     * 	- {ext} 扩展名
-     * 
- * - * @param in 输入流 - * @param filename 文件名 - * @param contentType 文件类型 - * @param pre 路径前缀 - * @param rule 路径规则 - * @return - */ - SysOssVo save(InputStream in, String filename, String contentType, String pre, String rule); - - SysOssVo uploadImgs(MultipartFile file, String pre); - - default SysOssVo uploadImgs(MultipartFile file, String pre, int maxWidth, int maxHeight, BufferedImage watermark) { - if (file == null || file.isEmpty()) { - throw new RuntimeException("图片不能为空"); - } - try { - return uploadImgs(file.getInputStream(), pre, maxWidth, maxHeight, watermark); - } catch (IOException e) { - throw new RuntimeException(e.getMessage(), e); - } + } + + + /** + *
+   * - 根据存放规则和文件名生成存放的URI
+   * - 支持
+   * 	- {yyyy}/{MM}/{dd}/{HH}/{mm}/{ss} 年月日时分秒
+   * 	- {UUID} 32位的唯一标志
+   *  - {i} 自增id
+   * 	- {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)); } - - /** - * @param in - * @param pre - 图片保存路径前缀 - * @param maxWidth - 缩放到指定的宽 小于1表示不缩放 - * @param maxHeight - 缩放到指定的高 小于1表示不缩放 - * @param watermark - 水印图片 null表示不加水印 - * @return - */ - SysOssVo uploadImgs(InputStream in, String pre, int maxWidth, int maxHeight, - BufferedImage watermark); - - void download(Long ossId, HttpServletResponse response) throws IOException; - - void download(String url, String service, HttpServletResponse response) throws IOException; - - Boolean deleteWithValidByIds(Collection 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); - } + if (rule.contains("{MM}")) { + rule = rule.replace("{MM}", String.format("%02d", c.get(Calendar.MONTH) + 1)); } - - 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); + if (rule.contains("{dd}")) { + rule = rule.replace("{dd}", String.format("%02d", c.get(Calendar.DATE))); } - - default InputStream formatImage(InputStream in, int maxWidth, int maxHeight, BufferedImage watermark) { - return formatImage(Img.from(in), maxWidth, maxHeight, watermark); + if (rule.contains("{HH}")) { + rule = rule.replace("{HH}", String.format("%02d", c.get(Calendar.HOUR_OF_DAY))); } - - 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); - - ByteArrayInputStream pin = new ByteArrayInputStream(pout.toByteArray()); - pout.close(); - pout = null; - return pin; - } catch (Exception e) { - throw new RuntimeException("处理图片错误", e); - } + if (rule.contains("{mm}")) { + rule = rule.replace("{mm}", String.format("%02d", c.get(Calendar.MINUTE))); } - - - /** - *
-     * - 根据存放规则和文件名生成存放的URI
-     * - 支持
-     * 	- {yyyy}/{MM}/{dd}/{HH}/{mm}/{ss} 年月日时分秒
-     * 	- {UUID} 32位的唯一标志
-     *  - {i} 自增id
-     * 	- {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}", String.format("%02d", c.get(Calendar.MONTH) + 1)); - } - if (rule.contains("{dd}")) { - rule = rule.replace("{dd}", String.format("%02d", c.get(Calendar.DATE))); - } - if (rule.contains("{HH}")) { - rule = rule.replace("{HH}", String.format("%02d", c.get(Calendar.HOUR_OF_DAY))); - } - if (rule.contains("{mm}")) { - rule = rule.replace("{mm}", String.format("%02d", c.get(Calendar.MINUTE))); - } - if (rule.contains("{ss}")) { - rule = rule.replace("{ss}", String.format("%02d", c.get(Calendar.SECOND))); - } - 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 rule; + if (rule.contains("{ss}")) { + rule = rule.replace("{ss}", String.format("%02d", c.get(Calendar.SECOND))); + } + 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); } - Id id = new Id(); + 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; + } - static class Id { + Id id = new Id(); - private static final String groupName = "file:id"; + static class Id { - private SymmetricCrypto crypto; + private static final String groupName = "file:id"; - private String today = DateUtil.today(); + private SymmetricCrypto crypto; - 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()); - } + 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()); } + } + // public static void main(String[] args) { // byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.DES.getValue(),DateUtil.today().getBytes()).getEncoded(); // System.out.println(HexUtil.encodeHexStr(key)); @@ -361,4 +382,15 @@ public interface ISysOssService { // System.out.println(ByteBuffer.wrap(aes.encrypt(buffer.array())).getLong()); // } + SysOssVo url(SysOssVo oss, int second); + + default SysOssVo url(SysOssVo oss) { + return url(oss, 120); + } + + String url(Service service,String url,int second); + + default String url(Service service,String url) { + return url(service,url, 120); + } } 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 d291cf2..5878078 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 @@ -52,278 +52,337 @@ import java.util.stream.Collectors; @Service public class SysOssServiceImpl implements ISysOssService, OssService { - private static final String UPLOAD = "UPLOAD"; - private final ISysConfigService configService; - private final FileService fileService; - private final SysOssMapper baseMapper; - private static ThreadLocal IGNORE_THREAD_LOCAL = new ThreadLocal<>(); - - @Override - public void ignore(Runnable handle) { - IGNORE_THREAD_LOCAL.set(true); - try { - handle.run(); - } finally { - IGNORE_THREAD_LOCAL.remove(); - } + private static final String UPLOAD = "UPLOAD"; + private final ISysConfigService configService; + private final FileService fileService; + private final SysOssMapper baseMapper; + private static ThreadLocal IGNORE_THREAD_LOCAL = new ThreadLocal<>(); + private static ThreadLocal SERVICE_THREAD_LOCAL = new ThreadLocal<>(); + + @Override + public void setService(Service service, Runnable handle) { + SERVICE_THREAD_LOCAL.set(service); + try { + handle.run(); + } finally { + SERVICE_THREAD_LOCAL.remove(); } + } - @Override - public T ignore(Supplier handle) { - IGNORE_THREAD_LOCAL.set(true); - try { - return handle.get(); - } finally { - IGNORE_THREAD_LOCAL.remove(); - } + @Override + public T setService(Service service, Supplier handle) { + SERVICE_THREAD_LOCAL.set(service); + try { + return handle.get(); + } finally { + SERVICE_THREAD_LOCAL.remove(); } + } - @Override - public TableDataInfo queryPageList(SysOssBo bo, PageQuery pageQuery) { - LambdaQueryWrapper lqw = buildQueryWrapper(bo); - Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); - List filterResult = result.getRecords().stream().map(this::matchingUrl).collect(Collectors.toList()); - result.setRecords(filterResult); - return TableDataInfo.build(result); + @Override + public void ignore(Runnable handle) { + IGNORE_THREAD_LOCAL.set(true); + try { + handle.run(); + } finally { + IGNORE_THREAD_LOCAL.remove(); } + } - @Override - public List listByIds(Collection ossIds) { - List list = new ArrayList<>(); - for (Long id : ossIds) { - SysOssVo vo = SpringUtils.getBean(ISysOssService.class).getById(id); - if (ObjectUtil.isNotNull(vo)) { - list.add(this.matchingUrl(vo)); - } - } - return list; + @Override + public T ignore(Supplier handle) { + IGNORE_THREAD_LOCAL.set(true); + try { + return handle.get(); + } finally { + IGNORE_THREAD_LOCAL.remove(); } + } - @Override - public String selectUrlByIds(String ossIds) { - List list = new ArrayList<>(); - for (Long id : StringUtils.splitTo(ossIds, Convert::toLong)) { - SysOssVo vo = SpringUtils.getBean(ISysOssService.class).getById(id); - if (ObjectUtil.isNotNull(vo)) { - list.add(this.matchingUrl(vo).getUrl()); - } - } - return String.join(StringUtils.SEPARATOR, list); + @Override + public TableDataInfo queryPageList(SysOssBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + List filterResult = result.getRecords().stream().map(this::url).collect(Collectors.toList()); + result.setRecords(filterResult); + return TableDataInfo.build(result); + } + + @Override + public List listByIds(Collection ossIds) { + List list = new ArrayList<>(); + for (Long id : ossIds) { + SysOssVo vo = SpringUtils.getBean(ISysOssService.class).getById(id); + if (ObjectUtil.isNotNull(vo)) { + list.add(this.url(vo)); + } + } + return list; + } + + @Override + public String selectUrlByIds(String ossIds) { + List list = new ArrayList<>(); + for (Long id : StringUtils.splitTo(ossIds, Convert::toLong)) { + SysOssVo vo = SpringUtils.getBean(ISysOssService.class).getById(id); + if (ObjectUtil.isNotNull(vo)) { + list.add(this.url(vo).getUrl()); + } } + return String.join(StringUtils.SEPARATOR, list); + } + + private LambdaQueryWrapper buildQueryWrapper(SysOssBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getFileName()), SysOss::getFileName, bo.getFileName()); + lqw.like(StringUtils.isNotBlank(bo.getOriginalName()), SysOss::getOriginalName, bo.getOriginalName()); + lqw.eq(StringUtils.isNotBlank(bo.getFileSuffix()), SysOss::getFileSuffix, bo.getFileSuffix()); + lqw.eq(StringUtils.isNotBlank(bo.getUrl()), SysOss::getUrl, bo.getUrl()); + lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null, + SysOss::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime")); + lqw.eq(StringUtils.isNotBlank(bo.getCreateBy()), SysOss::getCreateBy, bo.getCreateBy()); + lqw.eq(StringUtils.isNotBlank(bo.getService()), SysOss::getService, bo.getService()); + return lqw; + } - private LambdaQueryWrapper buildQueryWrapper(SysOssBo bo) { - Map params = bo.getParams(); - LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); - lqw.like(StringUtils.isNotBlank(bo.getFileName()), SysOss::getFileName, bo.getFileName()); - lqw.like(StringUtils.isNotBlank(bo.getOriginalName()), SysOss::getOriginalName, bo.getOriginalName()); - lqw.eq(StringUtils.isNotBlank(bo.getFileSuffix()), SysOss::getFileSuffix, bo.getFileSuffix()); - lqw.eq(StringUtils.isNotBlank(bo.getUrl()), SysOss::getUrl, bo.getUrl()); - lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null, - SysOss::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime")); - lqw.eq(StringUtils.isNotBlank(bo.getCreateBy()), SysOss::getCreateBy, bo.getCreateBy()); - lqw.eq(StringUtils.isNotBlank(bo.getService()), SysOss::getService, bo.getService()); - return lqw; + @Cacheable(cacheNames = CacheNames.SYS_OSS, key = "#ossId") + @Override + public SysOssVo getById(Long ossId) { + return baseMapper.selectVoById(ossId); + } + + @Override + public void download(Long ossId, HttpServletResponse response) throws IOException { + SysOssVo sysOss = SpringUtils.getBean(ISysOssService.class).getById(ossId); + if (ObjectUtil.isNull(sysOss)) { + throw new ServiceException("文件数据不存在!"); + } + FileUtils.setAttachmentResponseHeader(response, sysOss.getOriginalName()); + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8"); + if (UPLOAD.equals(sysOss.getService())) { + try (InputStream inputStream = new FileInputStream(fileService.getFile(sysOss.getUrl()))) { + int available = inputStream.available(); + IoUtil.copy(inputStream, response.getOutputStream()); + response.setContentLength(available); + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } + } else { + OssClient storage = OssFactory.instance(sysOss.getService()); + try (InputStream inputStream = storage.getObjectContent(sysOss.getUrl())) { + int available = inputStream.available(); + IoUtil.copy(inputStream, response.getOutputStream()); + response.setContentLength(available); + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } } + } - @Cacheable(cacheNames = CacheNames.SYS_OSS, key = "#ossId") - @Override - public SysOssVo getById(Long ossId) { - return baseMapper.selectVoById(ossId); + public void download(String url, Service service, HttpServletResponse response) throws IOException { + FileUtils.setAttachmentResponseHeader(response, FileNameUtil.getName(url)); + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8"); + if (UPLOAD.equalsIgnoreCase(service.name())) { + try (InputStream inputStream = new FileInputStream(fileService.getFile(url))) { + int available = inputStream.available(); + IoUtil.copy(inputStream, response.getOutputStream()); + response.setContentLength(available); + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } + } else { + OssClient storage = OssFactory.instance(service.name()); + try (InputStream inputStream = storage.getObjectContent(url)) { + int available = inputStream.available(); + IoUtil.copy(inputStream, response.getOutputStream()); + response.setContentLength(available); + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } } + } - @Override - public void download(Long ossId, HttpServletResponse response) throws IOException { - SysOssVo sysOss = SpringUtils.getBean(ISysOssService.class).getById(ossId); - if (ObjectUtil.isNull(sysOss)) { - throw new ServiceException("文件数据不存在!"); - } - FileUtils.setAttachmentResponseHeader(response, sysOss.getOriginalName()); - response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8"); - if (UPLOAD.equals(sysOss.getService())) { - try (InputStream inputStream = new FileInputStream(fileService.getFile(sysOss.getUrl()))) { - int available = inputStream.available(); - IoUtil.copy(inputStream, response.getOutputStream()); - response.setContentLength(available); - } catch (Exception e) { - throw new ServiceException(e.getMessage()); - } - } else { - OssClient storage = OssFactory.instance(sysOss.getService()); - try (InputStream inputStream = storage.getObjectContent(sysOss.getUrl())) { - int available = inputStream.available(); - IoUtil.copy(inputStream, response.getOutputStream()); - response.setContentLength(available); - } catch (Exception e) { - throw new ServiceException(e.getMessage()); - } - } + @Override + public InputStream download(Long ossId) throws IOException { + SysOssVo sysOss = SpringUtils.getBean(ISysOssService.class).getById(ossId); + return download(sysOss); + } + + @Override + public InputStream download(SysOssVo sysOss) throws IOException { + if (ObjectUtil.isNull(sysOss)) { + throw new ServiceException("文件数据不存在!"); } + if (UPLOAD.equals(sysOss.getService())) { + return new FileInputStream(fileService.getFile(sysOss.getUrl())); + } else { + OssClient storage = OssFactory.instance(sysOss.getService()); + return storage.getObjectContent(sysOss.getUrl()); + } + } - @Override - public void download(String url, String service, HttpServletResponse response) throws IOException { - FileUtils.setAttachmentResponseHeader(response, FileNameUtil.getName(url)); - response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8"); - if (UPLOAD.equalsIgnoreCase(service)) { - try (InputStream inputStream = new FileInputStream(fileService.getFile(url))) { - int available = inputStream.available(); - IoUtil.copy(inputStream, response.getOutputStream()); - response.setContentLength(available); - } catch (Exception e) { - throw new ServiceException(e.getMessage()); - } - } else { - OssClient storage = OssFactory.instance(service); - try (InputStream inputStream = storage.getObjectContent(url)) { - int available = inputStream.available(); - IoUtil.copy(inputStream, response.getOutputStream()); - response.setContentLength(available); - } catch (Exception e) { - throw new ServiceException(e.getMessage()); - } - } + @Override + public InputStream download(String url, Service service) throws IOException { + if (UPLOAD.equalsIgnoreCase(service.name())) { + return new FileInputStream(fileService.getFile(url)); + } else { + OssClient storage = OssFactory.instance(service.name()); + return storage.getObjectContent(url); } + } - @Override - public SysOssVo save(InputStream in, String originalFileName, String contentType, String pre, String rule) { - String suffix = StringUtils.substring(originalFileName, originalFileName.lastIndexOf("."), originalFileName.length()); - SysOss oss = new SysOss(); - oss.setOriginalName(originalFileName); - oss.setFileSuffix(suffix); - if (configService.selectOssEnabled()) { - OssClient storage = OssFactory.instance(); - UploadResult uploadResult; - try { - String path = ""; - if (StrUtil.isNotBlank(storage.getProperties().getPrefix())) { - path += storage.getProperties().getPrefix() + "/"; - - } - if (StrUtil.isBlank(pre)) { - pre = PRE_DEFAULT; - } - path += pre + "/" + generateURI(rule, originalFileName); - uploadResult = storage.upload(in, path, contentType); - } catch (Exception e) { - throw new RuntimeException(e.getMessage(), e); - } - // 保存文件信息 - - oss.setUrl(uploadResult.getUrl()); - oss.setFileName(uploadResult.getFilename()); - oss.setService(storage.getConfigKey()); - - } else { - try { - String url = fileService.save(in, originalFileName, pre); - oss.setUrl(url); - oss.setFileName(url); - oss.setService(UPLOAD); - } catch (Exception e) { - throw new RuntimeException("保存文件失败", e); - } + @Override + public SysOssVo save(InputStream in, String originalFileName, String contentType, String pre, String rule) { + String suffix = StringUtils.substring(originalFileName, originalFileName.lastIndexOf("."), originalFileName.length()); + SysOss oss = new SysOss(); + oss.setOriginalName(originalFileName); + oss.setFileSuffix(suffix); + if (configService.selectOssEnabled()) { + OssClient storage = SERVICE_THREAD_LOCAL.get() == null ? OssFactory.instance() : OssFactory.instance(SERVICE_THREAD_LOCAL.get().name()); + UploadResult uploadResult; + try { + String path = ""; + if (StrUtil.isNotBlank(storage.getProperties().getPrefix())) { + path += storage.getProperties().getPrefix() + "/"; + } - if (IGNORE_THREAD_LOCAL.get() == null) { - baseMapper.insert(oss); + if (StrUtil.isBlank(pre)) { + pre = PRE_DEFAULT; } + path += pre + "/" + generateURI(rule, originalFileName); + uploadResult = storage.upload(in, path, contentType); + } catch (Exception e) { + throw new RuntimeException(e.getMessage(), e); + } + // 保存文件信息 - SysOssVo sysOssVo = new SysOssVo(); - BeanCopyUtils.copy(oss, sysOssVo); - return this.matchingUrl(sysOssVo); - } + oss.setUrl(uploadResult.getUrl()); + oss.setFileName(uploadResult.getFilename()); + oss.setService(storage.getConfigKey()); - public SysOssVo uploadImgs(MultipartFile file, String pre) { - return uploadImgs(file, pre, configService.selectImageMaxWidth(), configService.selectImageMaxHeight(), configService.getWatermark()); + } else { + try { + String url = fileService.save(in, originalFileName, pre); + oss.setUrl(url); + oss.setFileName(url); + oss.setService(UPLOAD); + } catch (Exception e) { + throw new RuntimeException("保存文件失败", e); + } } + if (IGNORE_THREAD_LOCAL.get() == null) { + baseMapper.insert(oss); + } + + SysOssVo sysOssVo = new SysOssVo(); + BeanCopyUtils.copy(oss, sysOssVo); + return this.url(sysOssVo); + } + + public SysOssVo uploadImgs(MultipartFile file, String pre) { + return uploadImgs(file, pre, configService.selectImageMaxWidth(), configService.selectImageMaxHeight(), configService.getWatermark()); + } + + @Override + public SysOssVo uploadImgs(InputStream inputStream, String pre, int maxWidth, int maxHeight, BufferedImage watermark) { + String originalFileName = "temp.webp"; + String suffix = StringUtils.substring(originalFileName, originalFileName.lastIndexOf("."), originalFileName.length()); + SysOss oss = new SysOss(); + oss.setFileSuffix(suffix); + oss.setOriginalName(originalFileName); + if (configService.selectOssEnabled()) { + + OssClient storage = SERVICE_THREAD_LOCAL.get() == null ? OssFactory.instance() : OssFactory.instance(SERVICE_THREAD_LOCAL.get().name()); + UploadResult uploadResult; + + try ( + InputStream in = formatImage(inputStream, maxWidth, maxWidth, watermark) + ) { + String path = ""; + if (StrUtil.isNotBlank(storage.getProperties().getPrefix())) { + + path += storage.getProperties().getPrefix() + "/"; - @Override - public SysOssVo uploadImgs(InputStream inputStream, String pre, int maxWidth, int maxHeight, BufferedImage watermark) { - String originalFileName = "temp.webp"; - String suffix = StringUtils.substring(originalFileName, originalFileName.lastIndexOf("."), originalFileName.length()); - SysOss oss = new SysOss(); - oss.setFileSuffix(suffix); - oss.setOriginalName(originalFileName); - if (configService.selectOssEnabled()) { - - OssClient storage = OssFactory.instance(); - UploadResult uploadResult; - - try ( - InputStream in = formatImage(inputStream, 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 RuntimeException(e.getMessage(), e); - } - // 保存文件信息 - - oss.setUrl(uploadResult.getUrl()); - oss.setFileName(uploadResult.getFilename()); - oss.setService(storage.getConfigKey()); - } else { - try ( - InputStream in = formatImage(inputStream, maxWidth, maxWidth, watermark) - ) { - String url = fileService.save(in, originalFileName + ".webp", pre); - oss.setUrl(url); - oss.setFileName(url); - oss.setService(UPLOAD); - } catch (IOException e) { - throw new RuntimeException(e.getMessage(), e); - } } - if (IGNORE_THREAD_LOCAL.get() == null) { - baseMapper.insert(oss); + if (StrUtil.isNotBlank(pre)) { + path += pre + "/"; } - SysOssVo sysOssVo = new SysOssVo(); - BeanCopyUtils.copy(oss, sysOssVo); - return this.matchingUrl(sysOssVo); + path += generateURI("{yyyy}/{MM}/{dd}/{id36}.webp", "a.webp"); + + uploadResult = storage.upload(in, path, "image/webp"); + } catch (IOException e) { + throw new RuntimeException(e.getMessage(), e); + } + // 保存文件信息 + + oss.setUrl(uploadResult.getUrl()); + oss.setFileName(uploadResult.getFilename()); + oss.setService(storage.getConfigKey()); + } else { + try ( + InputStream in = formatImage(inputStream, maxWidth, maxWidth, watermark) + ) { + String url = fileService.save(in, originalFileName + ".webp", pre); + oss.setUrl(url); + oss.setFileName(url); + oss.setService(UPLOAD); + } catch (IOException e) { + throw new RuntimeException(e.getMessage(), e); + } } + if (IGNORE_THREAD_LOCAL.get() == null) { + baseMapper.insert(oss); + } + SysOssVo sysOssVo = new SysOssVo(); + BeanCopyUtils.copy(oss, sysOssVo); + return this.url(sysOssVo); + } - @Override - public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { - if (isValid) { - // 做一些业务上的校验,判断是否需要校验 - } - List list = baseMapper.selectBatchIds(ids); - for (SysOss sysOss : list) { - if (UPLOAD.equals(sysOss.getService())) { - fileService.delete(sysOss.getUrl()); - } else { - OssClient storage = OssFactory.instance(sysOss.getService()); - storage.delete(sysOss.getUrl()); - } - } - return baseMapper.deleteBatchIds(ids) > 0; + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + // 做一些业务上的校验,判断是否需要校验 + } + List list = baseMapper.selectBatchIds(ids); + for (SysOss sysOss : list) { + if (UPLOAD.equals(sysOss.getService())) { + fileService.delete(sysOss.getUrl()); + } else { + OssClient storage = OssFactory.instance(sysOss.getService()); + storage.delete(sysOss.getUrl()); + } } + return baseMapper.deleteBatchIds(ids) > 0; + } - /** - * 匹配Url - * - * @param oss OSS对象 - * @return oss 匹配Url的OSS对象 - */ - private SysOssVo matchingUrl(SysOssVo oss) { - if (UPLOAD.equals(oss.getService())) { - return oss; - } else { - OssClient storage = OssFactory.instance(oss.getService()); - // 仅修改桶类型为 private 的URL,临时URL时长为120s - if (AccessPolicyType.PRIVATE == storage.getAccessPolicy()) { - oss.setUrl(storage.getPrivateUrl(oss.getFileName(), 120)); - } - return oss; - } + @Override + public SysOssVo url(SysOssVo oss, int second) { + if (UPLOAD.equals(oss.getService())) { + return oss; + } else { + OssClient storage = OssFactory.instance(oss.getService()); + // 仅修改桶类型为 private 的URL,临时URL时长为120s + if (AccessPolicyType.PRIVATE == storage.getAccessPolicy()) { + oss.setUrl(storage.getPrivateUrl(oss.getFileName(), second)); + } + return oss; + } + } + + @Override + public String url(Service service, String url, int second) { + if (Service.upload.equals(service)) { + return url; + } else { + OssClient storage = OssFactory.instance(service.name()); + // 仅修改桶类型为 private 的URL,临时URL时长为120s + if (AccessPolicyType.PRIVATE == storage.getAccessPolicy()) { + return storage.getPrivateUrl(url, second); + } + return url; } + } + }