From fd45cdb882271ff39ba49a58494dfb222173030f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Mon, 29 Nov 2021 22:07:22 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E8=A1=A5=E5=85=A8=E6=BC=8F=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application-dev.yml | 14 ++ .../src/main/resources/application-prod.yml | 14 ++ ruoyi-ui/src/plugins/tab.js | 66 +++++++ .../common/core/service/ConfigService.java | 18 ++ .../common/core/service/DictService.java | 57 ++++++ .../common/core/service/UserService.java | 28 +++ .../common/excel/DefaultExcelListener.java | 108 +++++++++++ .../ruoyi/common/excel/DefautExcelResult.java | 73 +++++++ .../com/ruoyi/common/excel/ExcelListener.java | 14 ++ .../com/ruoyi/common/excel/ExcelResult.java | 26 +++ .../ruoyi/common/utils/TreeBuildUtils.java | 31 +++ .../ruoyi/common/utils/ValidatorUtils.java | 25 +++ .../demo/domain/bo/TestDemoImportVo.java | 61 ++++++ .../com/ruoyi/oss/constant/OssConstant.java | 38 ++++ .../java/com/ruoyi/oss/enumd/OssEnumd.java | 63 ++++++ .../ruoyi/oss/properties/OssProperties.java | 48 +++++ .../com/ruoyi/oss/service/IOssStrategy.java | 64 +++++++ .../abstractd/AbstractOssStrategy.java | 60 ++++++ .../oss/service/impl/AliyunOssStrategy.java | 113 +++++++++++ .../oss/service/impl/MinioOssStrategy.java | 181 ++++++++++++++++++ .../oss/service/impl/QcloudOssStrategy.java | 121 ++++++++++++ .../oss/service/impl/QiniuOssStrategy.java | 127 ++++++++++++ .../listener/SysUserImportListener.java | 109 +++++++++++ .../runner/SystemApplicationRunner.java | 42 ++++ .../service/impl/SysUserServiceImpl.java | 2 - .../src/main/resources/mapper/package-info.md | 3 + script/sql/ry_20210908.sql | 6 +- 27 files changed, 1507 insertions(+), 5 deletions(-) create mode 100644 ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-dev.yml create mode 100644 ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-prod.yml create mode 100644 ruoyi-ui/src/plugins/tab.js create mode 100644 ruoyi/src/main/java/com/ruoyi/common/core/service/ConfigService.java create mode 100644 ruoyi/src/main/java/com/ruoyi/common/core/service/DictService.java create mode 100644 ruoyi/src/main/java/com/ruoyi/common/core/service/UserService.java create mode 100644 ruoyi/src/main/java/com/ruoyi/common/excel/DefaultExcelListener.java create mode 100644 ruoyi/src/main/java/com/ruoyi/common/excel/DefautExcelResult.java create mode 100644 ruoyi/src/main/java/com/ruoyi/common/excel/ExcelListener.java create mode 100644 ruoyi/src/main/java/com/ruoyi/common/excel/ExcelResult.java create mode 100644 ruoyi/src/main/java/com/ruoyi/common/utils/TreeBuildUtils.java create mode 100644 ruoyi/src/main/java/com/ruoyi/common/utils/ValidatorUtils.java create mode 100644 ruoyi/src/main/java/com/ruoyi/demo/domain/bo/TestDemoImportVo.java create mode 100644 ruoyi/src/main/java/com/ruoyi/oss/constant/OssConstant.java create mode 100644 ruoyi/src/main/java/com/ruoyi/oss/enumd/OssEnumd.java create mode 100644 ruoyi/src/main/java/com/ruoyi/oss/properties/OssProperties.java create mode 100644 ruoyi/src/main/java/com/ruoyi/oss/service/IOssStrategy.java create mode 100644 ruoyi/src/main/java/com/ruoyi/oss/service/abstractd/AbstractOssStrategy.java create mode 100644 ruoyi/src/main/java/com/ruoyi/oss/service/impl/AliyunOssStrategy.java create mode 100644 ruoyi/src/main/java/com/ruoyi/oss/service/impl/MinioOssStrategy.java create mode 100644 ruoyi/src/main/java/com/ruoyi/oss/service/impl/QcloudOssStrategy.java create mode 100644 ruoyi/src/main/java/com/ruoyi/oss/service/impl/QiniuOssStrategy.java create mode 100644 ruoyi/src/main/java/com/ruoyi/system/listener/SysUserImportListener.java create mode 100644 ruoyi/src/main/java/com/ruoyi/system/runner/SystemApplicationRunner.java create mode 100644 ruoyi/src/main/resources/mapper/package-info.md diff --git a/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-dev.yml b/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-dev.yml new file mode 100644 index 000000000..829314b41 --- /dev/null +++ b/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-dev.yml @@ -0,0 +1,14 @@ +--- # 监控配置 +spring: + boot: + admin: + # Spring Boot Admin Client 客户端的相关配置 + client: + # 增加客户端开关 + enabled: true + # 设置 Spring Boot Admin Server 地址 + url: http://localhost:9090/admin + instance: + prefer-ip: true # 注册实例时,优先使用 IP + username: ruoyi + password: 123456 diff --git a/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-prod.yml b/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-prod.yml new file mode 100644 index 000000000..e8cac1369 --- /dev/null +++ b/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-prod.yml @@ -0,0 +1,14 @@ +--- # 监控配置 +spring: + boot: + admin: + # Spring Boot Admin Client 客户端的相关配置 + client: + # 增加客户端开关 + enabled: true + # 设置 Spring Boot Admin Server 地址 + url: http://172.30.0.90:9090/admin + instance: + prefer-ip: true # 注册实例时,优先使用 IP + username: ruoyi + password: 123456 diff --git a/ruoyi-ui/src/plugins/tab.js b/ruoyi-ui/src/plugins/tab.js new file mode 100644 index 000000000..011897c5f --- /dev/null +++ b/ruoyi-ui/src/plugins/tab.js @@ -0,0 +1,66 @@ +import store from '@/store' +import router from '@/router'; + +export default { + // 刷新当前tab页签 + refreshPage(obj) { + const { path, matched } = router.currentRoute; + if (obj === undefined) { + matched.forEach((m) => { + if (m.components && m.components.default && m.components.default.name) { + if (!['Layout', 'ParentView'].includes(m.components.default.name)) { + obj = { name: m.components.default.name, path: path }; + } + } + }); + } + return store.dispatch('tagsView/delCachedView', obj).then(() => { + const { path } = obj + router.replace({ + path: '/redirect' + path + }) + }) + }, + // 关闭当前tab页签,打开新页签 + closeOpenPage(obj) { + store.dispatch("tagsView/delView", router.currentRoute); + if (obj !== undefined) { + return router.push(obj); + } + }, + // 关闭指定tab页签 + closePage(obj) { + if (obj === undefined) { + return store.dispatch('tagsView/delView', router.currentRoute).then(({ lastPath }) => { + return router.push(lastPath || '/'); + }); + } + return store.dispatch('tagsView/delView', obj); + }, + // 关闭所有tab页签 + closeAllPage() { + return store.dispatch('tagsView/delAllViews'); + }, + // 关闭左侧tab页签 + closeLeftPage(obj) { + return store.dispatch('tagsView/delLeftTags', obj || router.currentRoute); + }, + // 关闭右侧tab页签 + closeRightPage(obj) { + return store.dispatch('tagsView/delRightTags', obj || router.currentRoute); + }, + // 关闭其他tab页签 + closeOtherPage(obj) { + return store.dispatch('tagsView/delOthersViews', obj || router.currentRoute); + }, + // 添加tab页签 + openPage(title, url) { + var obj = { path: url, meta: { title: title } } + store.dispatch('tagsView/addView', obj); + return router.push(url); + }, + // 修改tab页签 + updatePage(obj) { + return store.dispatch('tagsView/updateVisitedView', obj); + } +} diff --git a/ruoyi/src/main/java/com/ruoyi/common/core/service/ConfigService.java b/ruoyi/src/main/java/com/ruoyi/common/core/service/ConfigService.java new file mode 100644 index 000000000..c6badf65c --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/common/core/service/ConfigService.java @@ -0,0 +1,18 @@ +package com.ruoyi.common.core.service; + +/** + * 通用 参数配置服务 + * + * @author Lion Li + */ +public interface ConfigService { + + /** + * 根据参数 key 获取参数值 + * + * @param configKey 参数 key + * @return 参数值 + */ + String getConfigValue(String configKey); + +} diff --git a/ruoyi/src/main/java/com/ruoyi/common/core/service/DictService.java b/ruoyi/src/main/java/com/ruoyi/common/core/service/DictService.java new file mode 100644 index 000000000..b334c82af --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/common/core/service/DictService.java @@ -0,0 +1,57 @@ +package com.ruoyi.common.core.service; + +/** + * 通用 字典服务 + * + * @author Lion Li + */ +public interface DictService { + + /** + * 分隔符 + */ + String SEPARATOR = ","; + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @return 字典标签 + */ + default String getDictLabel(String dictType, String dictValue) { + return getDictLabel(dictType, dictValue, SEPARATOR); + } + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @return 字典值 + */ + default String getDictValue(String dictType, String dictLabel) { + return getDictValue(dictType, dictLabel, SEPARATOR); + } + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @param separator 分隔符 + * @return 字典标签 + */ + String getDictLabel(String dictType, String dictValue, String separator); + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @param separator 分隔符 + * @return 字典值 + */ + String getDictValue(String dictType, String dictLabel, String separator); + +} diff --git a/ruoyi/src/main/java/com/ruoyi/common/core/service/UserService.java b/ruoyi/src/main/java/com/ruoyi/common/core/service/UserService.java new file mode 100644 index 000000000..e637f4731 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/common/core/service/UserService.java @@ -0,0 +1,28 @@ +package com.ruoyi.common.core.service; + +import com.ruoyi.common.core.domain.entity.SysUser; + +/** + * 通用 用户业务 + * + * @author Lion Li + */ +public interface UserService { + + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + SysUser selectUserByUserName(String userName); + + /** + * 通过用户ID查询用户 + * + * @param userId 用户ID + * @return 用户对象信息 + */ + SysUser selectUserById(Long userId); + +} diff --git a/ruoyi/src/main/java/com/ruoyi/common/excel/DefaultExcelListener.java b/ruoyi/src/main/java/com/ruoyi/common/excel/DefaultExcelListener.java new file mode 100644 index 000000000..f626a5e11 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/common/excel/DefaultExcelListener.java @@ -0,0 +1,108 @@ +package com.ruoyi.common.excel; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.exception.ExcelDataConvertException; +import com.alibaba.fastjson.JSON; +import com.ruoyi.common.utils.ValidatorUtils; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Excel 导入监听 + * + * @author Yjoioooo + * @author Lion Li + */ +@Slf4j +@NoArgsConstructor +public class DefaultExcelListener extends AnalysisEventListener implements ExcelListener { + + /** + * 是否Validator检验,默认为是 + */ + private Boolean isValidate = Boolean.TRUE; + + /** + * excel 表头数据 + */ + private Map headMap; + + /** + * 导入回执 + */ + private ExcelResult excelResult; + + public DefaultExcelListener(boolean isValidate) { + this.excelResult = new DefautExcelResult<>(); + this.isValidate = isValidate; + } + + /** + * 处理异常 + * + * @param exception ExcelDataConvertException + * @param context Excel 上下文 + */ + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + String errMsg = null; + if (exception instanceof ExcelDataConvertException) { + // 如果是某一个单元格的转换异常 能获取到具体行号 + ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception; + Integer rowIndex = excelDataConvertException.getRowIndex(); + Integer columnIndex = excelDataConvertException.getColumnIndex(); + errMsg = StrUtil.format("第{}行-第{}列-表头{}: 解析异常
", + rowIndex + 1, columnIndex + 1, headMap.get(columnIndex)); + if (log.isDebugEnabled()) { + log.error(errMsg); + } + } + if (exception instanceof ConstraintViolationException) { + ConstraintViolationException constraintViolationException = (ConstraintViolationException) exception; + Set> constraintViolations = constraintViolationException.getConstraintViolations(); + String constraintViolationsMsg = constraintViolations.stream() + .map(ConstraintViolation::getMessage) + .collect(Collectors.joining(", ")); + errMsg = StrUtil.format("第{}行数据校验异常: {}", context.readRowHolder().getRowIndex() + 1, constraintViolationsMsg); + if (log.isDebugEnabled()) { + log.error(errMsg); + } + } + excelResult.getErrorList().add(errMsg); + throw new ExcelAnalysisException(errMsg); + } + + @Override + public void invokeHeadMap(Map headMap, AnalysisContext context) { + this.headMap = headMap; + log.debug("解析到一条表头数据: {}", JSON.toJSONString(headMap)); + } + + @Override + public void invoke(T data, AnalysisContext context) { + if (isValidate) { + ValidatorUtils.validate(data); + } + excelResult.getList().add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + log.debug("所有数据解析完成!"); + } + + @Override + public ExcelResult getExcelResult() { + return excelResult; + } + +} diff --git a/ruoyi/src/main/java/com/ruoyi/common/excel/DefautExcelResult.java b/ruoyi/src/main/java/com/ruoyi/common/excel/DefautExcelResult.java new file mode 100644 index 000000000..c852ce65f --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/common/excel/DefautExcelResult.java @@ -0,0 +1,73 @@ +package com.ruoyi.common.excel; + +import cn.hutool.core.util.StrUtil; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +/** + * 默认excel返回对象 + * + * @author Yjoioooo + * @author Lion Li + */ +public class DefautExcelResult implements ExcelResult { + + /** + * 数据对象list + */ + @Setter + private List list; + + /** + * 错误信息列表 + */ + @Setter + private List errorList; + + public DefautExcelResult() { + this.list = new ArrayList<>(); + this.errorList = new ArrayList<>(); + } + + public DefautExcelResult(List list, List errorList) { + this.list = list; + this.errorList = errorList; + } + + public DefautExcelResult(ExcelResult excelResult) { + this.list = excelResult.getList(); + this.errorList = excelResult.getErrorList(); + } + + @Override + public List getList() { + return list; + } + + @Override + public List getErrorList() { + return errorList; + } + + /** + * 获取导入回执 + * + * @return 导入回执 + */ + @Override + public String getAnalysis() { + int successCount = list.size(); + int errorCount = errorList.size(); + if (successCount == 0) { + return "读取失败,未解析到数据"; + } else { + if (errorCount == 0) { + return StrUtil.format("恭喜您,全部读取成功!共{}条", successCount); + } else { + return ""; + } + } + } +} diff --git a/ruoyi/src/main/java/com/ruoyi/common/excel/ExcelListener.java b/ruoyi/src/main/java/com/ruoyi/common/excel/ExcelListener.java new file mode 100644 index 000000000..2064cad36 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/common/excel/ExcelListener.java @@ -0,0 +1,14 @@ +package com.ruoyi.common.excel; + +import com.alibaba.excel.read.listener.ReadListener; + +/** + * Excel 导入监听 + * + * @author Lion Li + */ +public interface ExcelListener extends ReadListener { + + ExcelResult getExcelResult(); + +} diff --git a/ruoyi/src/main/java/com/ruoyi/common/excel/ExcelResult.java b/ruoyi/src/main/java/com/ruoyi/common/excel/ExcelResult.java new file mode 100644 index 000000000..63f8b8ac6 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/common/excel/ExcelResult.java @@ -0,0 +1,26 @@ +package com.ruoyi.common.excel; + +import java.util.List; + +/** + * excel返回对象 + * + * @author Lion Li + */ +public interface ExcelResult { + + /** + * 对象列表 + */ + List getList(); + + /** + * 错误列表 + */ + List getErrorList(); + + /** + * 导入回执 + */ + String getAnalysis(); +} diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/TreeBuildUtils.java b/ruoyi/src/main/java/com/ruoyi/common/utils/TreeBuildUtils.java new file mode 100644 index 000000000..a8380a287 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/common/utils/TreeBuildUtils.java @@ -0,0 +1,31 @@ +package com.ruoyi.common.utils; + +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.lang.tree.TreeNodeConfig; +import cn.hutool.core.lang.tree.TreeUtil; +import cn.hutool.core.lang.tree.parser.NodeParser; + +import java.util.List; + +/** + * 扩展 hutool TreeUtil 封装系统树构建 + * + * @author Lion Li + */ +public class TreeBuildUtils extends TreeUtil { + + /** + * 根据前端定制差异化字段 + */ + public static final TreeNodeConfig DEFAULT_CONFIG = TreeNodeConfig.DEFAULT_CONFIG.setNameKey("label"); + + /** + * 默认树父节点id + */ + public static final Long DEFAULT_PARENT_ID = 0L; + + public static List> build(List list, NodeParser nodeParser) { + return TreeUtil.build(list, DEFAULT_PARENT_ID, DEFAULT_CONFIG, nodeParser); + } + +} diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/ValidatorUtils.java b/ruoyi/src/main/java/com/ruoyi/common/utils/ValidatorUtils.java new file mode 100644 index 000000000..c28cf80fa --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/common/utils/ValidatorUtils.java @@ -0,0 +1,25 @@ +package com.ruoyi.common.utils; + +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import javax.validation.Validation; +import javax.validation.Validator; +import java.util.Set; + +/** + * Validator 校验框架工具 + * + * @author Lion Li + */ +public class ValidatorUtils { + + private static final Validator VALID = Validation.buildDefaultValidatorFactory().getValidator(); + + public static void validate(T object, Class... groups) { + Set> validate = VALID.validate(object, groups); + if (!validate.isEmpty()) { + throw new ConstraintViolationException("参数校验异常", validate); + } + } + +} diff --git a/ruoyi/src/main/java/com/ruoyi/demo/domain/bo/TestDemoImportVo.java b/ruoyi/src/main/java/com/ruoyi/demo/domain/bo/TestDemoImportVo.java new file mode 100644 index 000000000..7185514fd --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/demo/domain/bo/TestDemoImportVo.java @@ -0,0 +1,61 @@ +package com.ruoyi.demo.domain.bo; + +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 测试单表业务对象 test_demo + * + * @author Lion Li + * @date 2021-07-26 + */ +@Data +@ApiModel("测试单表业务对象") +public class TestDemoImportVo { + + /** + * 部门id + */ + @ApiModelProperty("部门id") + @NotNull(message = "部门id不能为空") + @ExcelProperty(value = "部门id") + private Long deptId; + + /** + * 用户id + */ + @ApiModelProperty("用户id") + @NotNull(message = "用户id不能为空") + @ExcelProperty(value = "用户id") + private Long userId; + + /** + * 排序号 + */ + @ApiModelProperty("排序号") + @NotNull(message = "排序号不能为空") + @ExcelProperty(value = "排序号") + private Long orderNum; + + /** + * key键 + */ + @ApiModelProperty("key键") + @NotBlank(message = "key键不能为空") + @ExcelProperty(value = "key键") + private String testKey; + + /** + * 值 + */ + @ApiModelProperty("值") + @NotBlank(message = "值不能为空") + @ExcelProperty(value = "值") + private String value; + +} diff --git a/ruoyi/src/main/java/com/ruoyi/oss/constant/OssConstant.java b/ruoyi/src/main/java/com/ruoyi/oss/constant/OssConstant.java new file mode 100644 index 000000000..b5236bfe7 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/oss/constant/OssConstant.java @@ -0,0 +1,38 @@ +package com.ruoyi.oss.constant; + +import java.util.Arrays; +import java.util.List; + +/** + * 对象存储常量 + * + * @author Lion Li + */ +public class OssConstant { + + /** + * OSS模块KEY + */ + public static final String SYS_OSS_KEY = "sys_oss:"; + + /** + * 对象存储配置KEY + */ + public static final String OSS_CONFIG_KEY = "OssConfig"; + + /** + * 缓存配置KEY + */ + public static final String CACHE_CONFIG_KEY = SYS_OSS_KEY + OSS_CONFIG_KEY; + + /** + * 预览列表资源开关Key + */ + public static final String PEREVIEW_LIST_RESOURCE_KEY = "sys.oss.previewListResource"; + + /** + * 系统数据ids + */ + public static final List SYSTEM_DATA_IDS = Arrays.asList(1, 2, 3, 4); + +} diff --git a/ruoyi/src/main/java/com/ruoyi/oss/enumd/OssEnumd.java b/ruoyi/src/main/java/com/ruoyi/oss/enumd/OssEnumd.java new file mode 100644 index 000000000..4defca40e --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/oss/enumd/OssEnumd.java @@ -0,0 +1,63 @@ +package com.ruoyi.oss.enumd; + +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.oss.service.impl.AliyunOssStrategy; +import com.ruoyi.oss.service.impl.MinioOssStrategy; +import com.ruoyi.oss.service.impl.QcloudOssStrategy; +import com.ruoyi.oss.service.impl.QiniuOssStrategy; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 对象存储服务商枚举 + * + * @author Lion Li + */ +@Getter +@AllArgsConstructor +public enum OssEnumd { + + /** + * 七牛云 + */ + QINIU("qiniu", QiniuOssStrategy.class), + + /** + * 阿里云 + */ + ALIYUN("aliyun", AliyunOssStrategy.class), + + /** + * 腾讯云 + */ + QCLOUD("qcloud", QcloudOssStrategy.class), + + /** + * minio + */ + MINIO("minio", MinioOssStrategy.class); + + private final String value; + + private final Class serviceClass; + + public static Class getServiceClass(String value) { + for (OssEnumd clazz : values()) { + if (clazz.getValue().equals(value)) { + return clazz.getServiceClass(); + } + } + return null; + } + + public static String getServiceName(String value) { + for (OssEnumd clazz : values()) { + if (clazz.getValue().equals(value)) { + return StringUtils.uncapitalize(clazz.getServiceClass().getSimpleName()); + } + } + return null; + } + + +} diff --git a/ruoyi/src/main/java/com/ruoyi/oss/properties/OssProperties.java b/ruoyi/src/main/java/com/ruoyi/oss/properties/OssProperties.java new file mode 100644 index 000000000..48a478b7a --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/oss/properties/OssProperties.java @@ -0,0 +1,48 @@ +package com.ruoyi.oss.properties; + +import lombok.Data; + +/** + * OSS对象存储 配置属性 + * + * @author Lion Li + */ +@Data +public class OssProperties { + + /** + * 域名 + */ + private String endpoint; + + /** + * 前缀 + */ + private String prefix; + + /** + * ACCESS_KEY + */ + private String accessKey; + + /** + * SECRET_KEY + */ + private String secretKey; + + /** + * 存储空间名 + */ + private String bucketName; + + /** + * 存储区域 + */ + private String region; + + /** + * 是否https(Y=是,N=否) + */ + private String isHttps; + +} diff --git a/ruoyi/src/main/java/com/ruoyi/oss/service/IOssStrategy.java b/ruoyi/src/main/java/com/ruoyi/oss/service/IOssStrategy.java new file mode 100644 index 000000000..34d25e477 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/oss/service/IOssStrategy.java @@ -0,0 +1,64 @@ +package com.ruoyi.oss.service; + +import com.ruoyi.oss.entity.UploadResult; + +import java.io.InputStream; + +/** + * 对象存储策略 + * + * @author Lion Li + */ +public interface IOssStrategy { + + void createBucket(); + + /** + * 获取服务商类型 + */ + String getServiceType(); + + /** + * 文件上传 + * + * @param data 文件字节数组 + * @param path 文件路径,包含文件名 + * @return 返回http地址 + */ + UploadResult upload(byte[] data, String path, String contentType); + + /** + * 文件删除 + * + * @param path 文件路径,包含文件名 + */ + void delete(String path); + + /** + * 文件上传 + * + * @param data 文件字节数组 + * @param suffix 后缀 + * @return 返回http地址 + */ + UploadResult uploadSuffix(byte[] data, String suffix, String contentType); + + /** + * 文件上传 + * + * @param inputStream 字节流 + * @param path 文件路径,包含文件名 + * @return 返回http地址 + */ + UploadResult upload(InputStream inputStream, String path, String contentType); + + /** + * 文件上传 + * + * @param inputStream 字节流 + * @param suffix 后缀 + * @return 返回http地址 + */ + UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType); + +} diff --git a/ruoyi/src/main/java/com/ruoyi/oss/service/abstractd/AbstractOssStrategy.java b/ruoyi/src/main/java/com/ruoyi/oss/service/abstractd/AbstractOssStrategy.java new file mode 100644 index 000000000..9fa52acb4 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/oss/service/abstractd/AbstractOssStrategy.java @@ -0,0 +1,60 @@ +package com.ruoyi.oss.service.abstractd; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.IdUtil; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.oss.entity.UploadResult; +import com.ruoyi.oss.properties.OssProperties; +import com.ruoyi.oss.service.IOssStrategy; + +import java.io.InputStream; + +/** + * 对象存储策略(支持七牛、阿里云、腾讯云、minio) + * + * @author Lion Li + */ +public abstract class AbstractOssStrategy implements IOssStrategy { + + protected OssProperties properties; + + public abstract void init(OssProperties properties); + + @Override + public abstract void createBucket(); + + @Override + public abstract String getServiceType(); + + public String getPath(String prefix, String suffix) { + // 生成uuid + String uuid = IdUtil.fastSimpleUUID(); + // 文件路径 + String path = DateUtils.datePath() + "/" + uuid; + if (StringUtils.isNotBlank(prefix)) { + path = prefix + "/" + path; + } + return path + suffix; + } + + @Override + public abstract UploadResult upload(byte[] data, String path, String contentType); + + @Override + public abstract void delete(String path); + + @Override + public UploadResult upload(InputStream inputStream, String path, String contentType) { + byte[] data = IoUtil.readBytes(inputStream); + return this.upload(data, path, contentType); + } + + @Override + public abstract UploadResult uploadSuffix(byte[] data, String suffix, String contentType); + + @Override + public abstract UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType); + + public abstract String getEndpointLink(); +} diff --git a/ruoyi/src/main/java/com/ruoyi/oss/service/impl/AliyunOssStrategy.java b/ruoyi/src/main/java/com/ruoyi/oss/service/impl/AliyunOssStrategy.java new file mode 100644 index 000000000..db9ad910e --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/oss/service/impl/AliyunOssStrategy.java @@ -0,0 +1,113 @@ +package com.ruoyi.oss.service.impl; + +import com.aliyun.oss.ClientConfiguration; +import com.aliyun.oss.OSSClient; +import com.aliyun.oss.common.auth.DefaultCredentialProvider; +import com.aliyun.oss.model.CannedAccessControlList; +import com.aliyun.oss.model.CreateBucketRequest; +import com.aliyun.oss.model.ObjectMetadata; +import com.aliyun.oss.model.PutObjectRequest; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.oss.entity.UploadResult; +import com.ruoyi.oss.enumd.OssEnumd; +import com.ruoyi.oss.exception.OssException; +import com.ruoyi.oss.properties.OssProperties; +import com.ruoyi.oss.service.abstractd.AbstractOssStrategy; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +/** + * 阿里云存储策略 + * + * @author Lion Li + */ +public class AliyunOssStrategy extends AbstractOssStrategy { + + private OSSClient client; + + @Override + public void init(OssProperties cloudStorageProperties) { + properties = cloudStorageProperties; + try { + ClientConfiguration configuration = new ClientConfiguration(); + DefaultCredentialProvider credentialProvider = new DefaultCredentialProvider( + properties.getAccessKey(), properties.getSecretKey()); + client = new OSSClient(properties.getEndpoint(), credentialProvider, configuration); + createBucket(); + } catch (Exception e) { + throw new OssException("阿里云存储配置错误! 请检查系统配置:[" + e.getMessage() + "]"); + } + } + + @Override + public void createBucket() { + try { + String bucketName = properties.getBucketName(); + if (client.doesBucketExist(bucketName)) { + return; + } + CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName); + createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead); + client.createBucket(createBucketRequest); + } catch (Exception e) { + throw new OssException("创建Bucket失败, 请核对阿里云配置信息:[" + e.getMessage() + "]"); + } + } + + @Override + public String getServiceType() { + return OssEnumd.ALIYUN.getValue(); + } + + @Override + public UploadResult upload(byte[] data, String path, String contentType) { + return upload(new ByteArrayInputStream(data), path, contentType); + } + + @Override + public UploadResult upload(InputStream inputStream, String path, String contentType) { + try { + ObjectMetadata metadata = new ObjectMetadata(); + metadata.setContentType(contentType); + client.putObject(new PutObjectRequest(properties.getBucketName(), path, inputStream, metadata)); + } catch (Exception e) { + throw new OssException("上传文件失败,请检查阿里云配置信息:[" + e.getMessage() + "]"); + } + return new UploadResult().setUrl(getEndpointLink() + "/" + path).setFilename(path); + } + + @Override + public void delete(String path) { + path = path.replace(getEndpointLink() + "/", ""); + try { + client.deleteObject(properties.getBucketName(), path); + } catch (Exception e) { + throw new OssException("上传文件失败,请检查阿里云配置信息:[" + e.getMessage() + "]"); + } + } + + @Override + public UploadResult uploadSuffix(byte[] data, String suffix, String contentType) { + return upload(data, getPath(properties.getPrefix(), suffix), contentType); + } + + @Override + public UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType) { + return upload(inputStream, getPath(properties.getPrefix(), suffix), contentType); + } + + @Override + public String getEndpointLink() { + String endpoint = properties.getEndpoint(); + StringBuilder sb = new StringBuilder(endpoint); + if (StringUtils.containsAnyIgnoreCase(endpoint, "http://")) { + sb.insert(7, properties.getBucketName() + "."); + } else if (StringUtils.containsAnyIgnoreCase(endpoint, "https://")) { + sb.insert(8, properties.getBucketName() + "."); + } else { + throw new OssException("Endpoint配置错误"); + } + return sb.toString(); + } +} diff --git a/ruoyi/src/main/java/com/ruoyi/oss/service/impl/MinioOssStrategy.java b/ruoyi/src/main/java/com/ruoyi/oss/service/impl/MinioOssStrategy.java new file mode 100644 index 000000000..0423dcc8a --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/oss/service/impl/MinioOssStrategy.java @@ -0,0 +1,181 @@ +package com.ruoyi.oss.service.impl; + +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.oss.entity.UploadResult; +import com.ruoyi.oss.enumd.OssEnumd; +import com.ruoyi.oss.enumd.PolicyType; +import com.ruoyi.oss.exception.OssException; +import com.ruoyi.oss.properties.OssProperties; +import com.ruoyi.oss.service.abstractd.AbstractOssStrategy; +import io.minio.*; +import org.springframework.http.MediaType; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +/** + * minio存储策略 + * + * @author Lion Li + */ +public class MinioOssStrategy extends AbstractOssStrategy { + + private MinioClient minioClient; + + @Override + public void init(OssProperties cloudStorageProperties) { + properties = cloudStorageProperties; + try { + minioClient = MinioClient.builder() + .endpoint(properties.getEndpoint()) + .credentials(properties.getAccessKey(), properties.getSecretKey()) + .build(); + createBucket(); + } catch (Exception e) { + throw new OssException("Minio存储配置错误! 请检查系统配置:[" + e.getMessage() + "]"); + } + } + + @Override + public void createBucket() { + try { + String bucketName = properties.getBucketName(); + boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()); + if (exists) { + return; + } + // 不存在就创建桶 + minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + minioClient.setBucketPolicy(SetBucketPolicyArgs.builder() + .bucket(bucketName) + .config(getPolicy(bucketName, PolicyType.READ)) + .build()); + } catch (Exception e) { + throw new OssException("创建Bucket失败, 请核对Minio配置信息:[" + e.getMessage() + "]"); + } + } + + @Override + public String getServiceType() { + return OssEnumd.MINIO.getValue(); + } + + @Override + public UploadResult upload(byte[] data, String path, String contentType) { + return upload(new ByteArrayInputStream(data), path, contentType); + } + + @Override + public UploadResult upload(InputStream inputStream, String path, String contentType) { + try { + minioClient.putObject(PutObjectArgs.builder() + .bucket(properties.getBucketName()) + .object(path) + .contentType(StringUtils.blankToDefault(contentType, MediaType.APPLICATION_OCTET_STREAM_VALUE)) + .stream(inputStream, inputStream.available(), -1) + .build()); + } catch (Exception e) { + throw new OssException("上传文件失败,请核对Minio配置信息:[" + e.getMessage() + "]"); + } + return new UploadResult().setUrl(getEndpointLink() + "/" + path).setFilename(path); + } + + @Override + public void delete(String path) { + path = path.replace(getEndpointLink() + "/", ""); + try { + minioClient.removeObject(RemoveObjectArgs.builder() + .bucket(properties.getBucketName()) + .object(path) + .build()); + } catch (Exception e) { + throw new OssException(e.getMessage()); + } + } + + @Override + public UploadResult uploadSuffix(byte[] data, String suffix, String contentType) { + return upload(data, getPath(properties.getPrefix(), suffix), contentType); + } + + @Override + public UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType) { + return upload(inputStream, getPath(properties.getPrefix(), suffix), contentType); + } + + @Override + public String getEndpointLink() { + return properties.getEndpoint() + "/" + properties.getBucketName(); + } + + private String getPolicy(String bucketName, PolicyType policyType) { + StringBuilder builder = new StringBuilder(); + builder.append("{\n"); + builder.append(" \"Statement\": [\n"); + builder.append(" {\n"); + builder.append(" \"Action\": [\n"); + if (policyType == PolicyType.WRITE) { + builder.append(" \"s3:GetBucketLocation\",\n"); + builder.append(" \"s3:ListBucketMultipartUploads\"\n"); + } else if (policyType == PolicyType.READ_WRITE) { + builder.append(" \"s3:GetBucketLocation\",\n"); + builder.append(" \"s3:ListBucket\",\n"); + builder.append(" \"s3:ListBucketMultipartUploads\"\n"); + } else { + builder.append(" \"s3:GetBucketLocation\"\n"); + } + builder.append(" ],\n"); + builder.append(" \"Effect\": \"Allow\",\n"); + builder.append(" \"Principal\": \"*\",\n"); + builder.append(" \"Resource\": \"arn:aws:s3:::"); + builder.append(bucketName); + builder.append("\"\n"); + builder.append(" },\n"); + if (PolicyType.READ.equals(policyType)) { + builder.append(" {\n"); + builder.append(" \"Action\": [\n"); + builder.append(" \"s3:ListBucket\"\n"); + builder.append(" ],\n"); + builder.append(" \"Effect\": \"Deny\",\n"); + builder.append(" \"Principal\": \"*\",\n"); + builder.append(" \"Resource\": \"arn:aws:s3:::"); + builder.append(bucketName); + builder.append("\"\n"); + builder.append(" },\n"); + } + builder.append(" {\n"); + builder.append(" \"Action\": "); + switch (policyType) { + case WRITE: + builder.append("[\n"); + builder.append(" \"s3:AbortMultipartUpload\",\n"); + builder.append(" \"s3:DeleteObject\",\n"); + builder.append(" \"s3:ListMultipartUploadParts\",\n"); + builder.append(" \"s3:PutObject\"\n"); + builder.append(" ],\n"); + break; + case READ_WRITE: + builder.append("[\n"); + builder.append(" \"s3:AbortMultipartUpload\",\n"); + builder.append(" \"s3:DeleteObject\",\n"); + builder.append(" \"s3:GetObject\",\n"); + builder.append(" \"s3:ListMultipartUploadParts\",\n"); + builder.append(" \"s3:PutObject\"\n"); + builder.append(" ],\n"); + break; + default: + builder.append("\"s3:GetObject\",\n"); + break; + } + builder.append(" \"Effect\": \"Allow\",\n"); + builder.append(" \"Principal\": \"*\",\n"); + builder.append(" \"Resource\": \"arn:aws:s3:::"); + builder.append(bucketName); + builder.append("/*\"\n"); + builder.append(" }\n"); + builder.append(" ],\n"); + builder.append(" \"Version\": \"2012-10-17\"\n"); + builder.append("}\n"); + return builder.toString(); + } +} diff --git a/ruoyi/src/main/java/com/ruoyi/oss/service/impl/QcloudOssStrategy.java b/ruoyi/src/main/java/com/ruoyi/oss/service/impl/QcloudOssStrategy.java new file mode 100644 index 000000000..156eb24c5 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/oss/service/impl/QcloudOssStrategy.java @@ -0,0 +1,121 @@ +package com.ruoyi.oss.service.impl; + +import com.qcloud.cos.COSClient; +import com.qcloud.cos.ClientConfig; +import com.qcloud.cos.auth.BasicCOSCredentials; +import com.qcloud.cos.auth.COSCredentials; +import com.qcloud.cos.http.HttpProtocol; +import com.qcloud.cos.model.*; +import com.qcloud.cos.region.Region; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.oss.entity.UploadResult; +import com.ruoyi.oss.enumd.OssEnumd; +import com.ruoyi.oss.exception.OssException; +import com.ruoyi.oss.properties.OssProperties; +import com.ruoyi.oss.service.abstractd.AbstractOssStrategy; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +/** + * 腾讯云存储策略 + * + * @author Lion Li + */ +public class QcloudOssStrategy extends AbstractOssStrategy { + + private COSClient client; + + @Override + public void init(OssProperties cloudStorageProperties) { + properties = cloudStorageProperties; + try { + COSCredentials credentials = new BasicCOSCredentials( + properties.getAccessKey(), properties.getSecretKey()); + // 初始化客户端配置 + ClientConfig clientConfig = new ClientConfig(); + // 设置bucket所在的区域,华南:gz 华北:tj 华东:sh + clientConfig.setRegion(new Region(properties.getRegion())); + if ("Y".equals(properties.getIsHttps())) { + clientConfig.setHttpProtocol(HttpProtocol.https); + } else { + clientConfig.setHttpProtocol(HttpProtocol.http); + } + client = new COSClient(credentials, clientConfig); + createBucket(); + } catch (Exception e) { + throw new OssException("腾讯云存储配置错误! 请检查系统配置:[" + e.getMessage() + "]"); + } + } + + @Override + public void createBucket() { + try { + String bucketName = properties.getBucketName(); + if (client.doesBucketExist(bucketName)) { + return; + } + CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName); + createBucketRequest.setCannedAcl(CannedAccessControlList.PublicRead); + client.createBucket(createBucketRequest); + } catch (Exception e) { + throw new OssException("创建Bucket失败, 请核对腾讯云配置信息:[" + e.getMessage() + "]"); + } + } + + @Override + public String getServiceType() { + return OssEnumd.QCLOUD.getValue(); + } + + @Override + public UploadResult upload(byte[] data, String path, String contentType) { + return upload(new ByteArrayInputStream(data), path, contentType); + } + + @Override + public UploadResult upload(InputStream inputStream, String path, String contentType) { + try { + ObjectMetadata metadata = new ObjectMetadata(); + metadata.setContentType(contentType); + client.putObject(new PutObjectRequest(properties.getBucketName(), path, inputStream, metadata)); + } catch (Exception e) { + throw new OssException("上传文件失败,请检查腾讯云配置信息:[" + e.getMessage() + "]"); + } + return new UploadResult().setUrl(getEndpointLink() + "/" + path).setFilename(path); + } + + @Override + public void delete(String path) { + path = path.replace(getEndpointLink() + "/", ""); + try { + client.deleteObject(new DeleteObjectRequest(properties.getBucketName(), path)); + } catch (Exception e) { + throw new OssException("上传文件失败,请检腾讯云查配置信息:[" + e.getMessage() + "]"); + } + } + + @Override + public UploadResult uploadSuffix(byte[] data, String suffix, String contentType) { + return upload(data, getPath(properties.getPrefix(), suffix), contentType); + } + + @Override + public UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType) { + return upload(inputStream, getPath(properties.getPrefix(), suffix), contentType); + } + + @Override + public String getEndpointLink() { + String endpoint = properties.getEndpoint(); + StringBuilder sb = new StringBuilder(endpoint); + if (StringUtils.containsAnyIgnoreCase(endpoint, "http://")) { + sb.insert(7, properties.getBucketName() + "."); + } else if (StringUtils.containsAnyIgnoreCase(endpoint, "https://")) { + sb.insert(8, properties.getBucketName() + "."); + } else { + throw new OssException("Endpoint配置错误"); + } + return sb.toString(); + } +} diff --git a/ruoyi/src/main/java/com/ruoyi/oss/service/impl/QiniuOssStrategy.java b/ruoyi/src/main/java/com/ruoyi/oss/service/impl/QiniuOssStrategy.java new file mode 100644 index 000000000..bf90aa824 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/oss/service/impl/QiniuOssStrategy.java @@ -0,0 +1,127 @@ +package com.ruoyi.oss.service.impl; + +import cn.hutool.core.util.ArrayUtil; +import com.qiniu.http.Response; +import com.qiniu.storage.BucketManager; +import com.qiniu.storage.Configuration; +import com.qiniu.storage.Region; +import com.qiniu.storage.UploadManager; +import com.qiniu.util.Auth; +import com.ruoyi.oss.entity.UploadResult; +import com.ruoyi.oss.enumd.OssEnumd; +import com.ruoyi.oss.exception.OssException; +import com.ruoyi.oss.properties.OssProperties; +import com.ruoyi.oss.service.abstractd.AbstractOssStrategy; + +import java.io.InputStream; + +/** + * 七牛云存储策略 + * + * @author Lion Li + */ +public class QiniuOssStrategy extends AbstractOssStrategy { + + private UploadManager uploadManager; + private BucketManager bucketManager; + private Auth auth; + + @Override + public void init(OssProperties cloudStorageProperties) { + properties = cloudStorageProperties; + try { + Configuration config = new Configuration(getRegion(properties.getRegion())); + // https设置 + config.useHttpsDomains = false; + config.useHttpsDomains = "Y".equals(properties.getIsHttps()); + uploadManager = new UploadManager(config); + auth = Auth.create(properties.getAccessKey(), properties.getSecretKey()); + String bucketName = properties.getBucketName(); + bucketManager = new BucketManager(auth, config); + + if (!ArrayUtil.contains(bucketManager.buckets(), bucketName)) { + bucketManager.createBucket(bucketName, properties.getRegion()); + } + } catch (Exception e) { + throw new OssException("七牛云存储配置错误! 请检查系统配置:[" + e.getMessage() + "]"); + } + } + + @Override + public void createBucket() { + try { + String bucketName = properties.getBucketName(); + if (ArrayUtil.contains(bucketManager.buckets(), bucketName)) { + return; + } + bucketManager.createBucket(bucketName, properties.getRegion()); + } catch (Exception e) { + throw new OssException("创建Bucket失败, 请核对七牛云配置信息:[" + e.getMessage() + "]"); + } + } + + @Override + public String getServiceType() { + return OssEnumd.QINIU.getValue(); + } + + @Override + public UploadResult upload(byte[] data, String path, String contentType) { + try { + String token = auth.uploadToken(properties.getBucketName()); + Response res = uploadManager.put(data, path, token, null, contentType, false); + if (!res.isOK()) { + throw new RuntimeException("上传七牛出错:" + res.error); + } + } catch (Exception e) { + throw new OssException("上传文件失败,请核对七牛配置信息:[" + e.getMessage() + "]"); + } + return new UploadResult().setUrl(getEndpointLink() + "/" + path).setFilename(path); + } + + @Override + public void delete(String path) { + try { + path = path.replace(getEndpointLink() + "/", ""); + Response res = bucketManager.delete(properties.getBucketName(), path); + if (!res.isOK()) { + throw new RuntimeException("删除七牛文件出错:" + res.error); + } + } catch (Exception e) { + throw new OssException(e.getMessage()); + } + } + + @Override + public UploadResult uploadSuffix(byte[] data, String suffix, String contentType) { + return upload(data, getPath(properties.getPrefix(), suffix), contentType); + } + + @Override + public UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType) { + return upload(inputStream, getPath(properties.getPrefix(), suffix), contentType); + } + + @Override + public String getEndpointLink() { + return properties.getEndpoint(); + } + + private Region getRegion(String region) { + switch (region) { + case "z0": + return Region.region0(); + case "z1": + return Region.region1(); + case "z2": + return Region.region2(); + case "na0": + return Region.regionNa0(); + case "as0": + return Region.regionAs0(); + default: + return Region.autoRegion(); + } + } + +} diff --git a/ruoyi/src/main/java/com/ruoyi/system/listener/SysUserImportListener.java b/ruoyi/src/main/java/com/ruoyi/system/listener/SysUserImportListener.java new file mode 100644 index 000000000..d0fd7d0e6 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/system/listener/SysUserImportListener.java @@ -0,0 +1,109 @@ +package com.ruoyi.system.listener; + +import cn.hutool.core.bean.BeanUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.ruoyi.common.core.domain.entity.SysUser; +import com.ruoyi.common.excel.ExcelListener; +import com.ruoyi.common.excel.ExcelResult; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.spring.SpringUtils; +import com.ruoyi.system.domain.vo.SysUserImportVo; +import com.ruoyi.system.service.ISysConfigService; +import com.ruoyi.system.service.ISysUserService; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * 系统用户自定义导入 + * + * @author Lion Li + */ +@Slf4j +public class SysUserImportListener extends AnalysisEventListener implements ExcelListener { + + private final ISysUserService userService; + + private final String password; + + private final Boolean isUpdateSupport; + + private final String operName; + + private int successNum = 0; + private int failureNum = 0; + private final StringBuilder successMsg = new StringBuilder(); + private final StringBuilder failureMsg = new StringBuilder(); + + public SysUserImportListener(Boolean isUpdateSupport) { + this.userService = SpringUtils.getBean(ISysUserService.class); + this.password = SpringUtils.getBean(ISysConfigService.class) + .selectConfigByKey("sys.user.initPassword"); + this.isUpdateSupport = isUpdateSupport; + this.operName = SecurityUtils.getUsername(); + } + + @Override + public void invoke(SysUserImportVo userVo, AnalysisContext context) { + SysUser user = this.userService.selectUserByUserName(userVo.getUserName()); + try { + // 验证是否存在这个用户 + if (StringUtils.isNull(user)) { + user = BeanUtil.toBean(userVo, SysUser.class); + user.setPassword(SecurityUtils.encryptPassword(password)); + user.setCreateBy(operName); + userService.insertUser(user); + successNum++; + successMsg.append("
").append(successNum).append("、账号 ").append(user.getUserName()).append(" 导入成功"); + } else if (isUpdateSupport) { + user.setUpdateBy(operName); + userService.updateUser(user); + successNum++; + successMsg.append("
").append(successNum).append("、账号 ").append(user.getUserName()).append(" 更新成功"); + } else { + failureNum++; + failureMsg.append("
").append(failureNum).append("、账号 ").append(user.getUserName()).append(" 已存在"); + } + } catch (Exception e) { + failureNum++; + String msg = "
" + failureNum + "、账号 " + user.getUserName() + " 导入失败:"; + failureMsg.append(msg).append(e.getMessage()); + log.error(msg, e); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + + } + + @Override + public ExcelResult getExcelResult() { + return new ExcelResult() { + + @Override + public String getAnalysis() { + if (failureNum > 0) { + failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); + throw new ServiceException(failureMsg.toString()); + } else { + successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:"); + } + return successMsg.toString(); + } + + @Override + public List getList() { + return null; + } + + @Override + public List getErrorList() { + return null; + } + }; + } +} diff --git a/ruoyi/src/main/java/com/ruoyi/system/runner/SystemApplicationRunner.java b/ruoyi/src/main/java/com/ruoyi/system/runner/SystemApplicationRunner.java new file mode 100644 index 000000000..4080a1ac3 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/system/runner/SystemApplicationRunner.java @@ -0,0 +1,42 @@ +package com.ruoyi.system.runner; + +import com.ruoyi.common.config.RuoYiConfig; +import com.ruoyi.system.service.ISysConfigService; +import com.ruoyi.system.service.ISysDictTypeService; +import com.ruoyi.system.service.ISysOssConfigService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.stereotype.Component; + +/** + * 初始化 system 模块对应业务数据 + * + * @author Lion Li + */ +@Slf4j +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@Component +public class SystemApplicationRunner implements ApplicationRunner { + + private final RuoYiConfig ruoyiConfig; + private final ISysConfigService configService; + private final ISysDictTypeService dictTypeService; + private final ISysOssConfigService ossConfigService; + + @Override + public void run(ApplicationArguments args) throws Exception { + ossConfigService.init(); + log.info("初始化OSS配置成功"); + if (ruoyiConfig.isCacheLazy()){ + return; + } + configService.loadingConfigCache(); + log.info("加载参数缓存数据成功"); + dictTypeService.loadingDictCache(); + log.info("加载字典缓存数据成功"); + } + +} diff --git a/ruoyi/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java b/ruoyi/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java index 62d497d45..86f4642ba 100644 --- a/ruoyi/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java +++ b/ruoyi/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java @@ -180,7 +180,6 @@ public class SysUserServiceImpl extends ServicePlusImpl() - .select(SysUser::getUserId, SysUser::getPhonenumber) .eq(SysUser::getPhonenumber, user.getPhonenumber()) .ne(SysUser::getUserId, userId)); if (count > 0) { @@ -199,7 +198,6 @@ public class SysUserServiceImpl extends ServicePlusImpl() - .select(SysUser::getUserId, SysUser::getEmail) .eq(SysUser::getEmail, user.getEmail()) .ne(SysUser::getUserId, userId)); if (count > 0) { diff --git a/ruoyi/src/main/resources/mapper/package-info.md b/ruoyi/src/main/resources/mapper/package-info.md new file mode 100644 index 000000000..c938b1e50 --- /dev/null +++ b/ruoyi/src/main/resources/mapper/package-info.md @@ -0,0 +1,3 @@ +java包使用 `.` 分割 resource 目录使用 `/` 分割 +
+此文件目的 防止文件夹粘连找不到 `xml` 文件 \ No newline at end of file diff --git a/script/sql/ry_20210908.sql b/script/sql/ry_20210908.sql index 4df76f655..428c24a03 100644 --- a/script/sql/ry_20210908.sql +++ b/script/sql/ry_20210908.sql @@ -644,10 +644,10 @@ create table gen_table_column ( drop table if exists sys_oss; create table sys_oss ( oss_id bigint(20) not null auto_increment comment '对象存储主键', - file_name varchar(64) not null default '' comment '文件名', - original_name varchar(64) not null default '' comment '原名', + file_name varchar(255) not null default '' comment '文件名', + original_name varchar(255) not null default '' comment '原名', file_suffix varchar(10) not null default '' comment '文件后缀名', - url varchar(200) not null comment 'URL地址', + url varchar(500) not null comment 'URL地址', create_time datetime default null comment '创建时间', create_by varchar(64) default '' comment '上传人', update_time datetime default null comment '更新时间',