update 补全漏提交文件

This commit is contained in:
疯狂的狮子Li 2021-11-29 22:07:22 +08:00
parent c76ab64e8a
commit fd45cdb882
27 changed files with 1507 additions and 5 deletions

View File

@ -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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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<T> extends AnalysisEventListener<T> implements ExcelListener<T> {
/**
* 是否Validator检验默认为是
*/
private Boolean isValidate = Boolean.TRUE;
/**
* excel 表头数据
*/
private Map<Integer, String> headMap;
/**
* 导入回执
*/
private ExcelResult<T> 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("第{}行-第{}列-表头{}: 解析异常<br/>",
rowIndex + 1, columnIndex + 1, headMap.get(columnIndex));
if (log.isDebugEnabled()) {
log.error(errMsg);
}
}
if (exception instanceof ConstraintViolationException) {
ConstraintViolationException constraintViolationException = (ConstraintViolationException) exception;
Set<ConstraintViolation<?>> 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<Integer, String> 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<T> getExcelResult() {
return excelResult;
}
}

View File

@ -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<T> implements ExcelResult<T> {
/**
* 数据对象list
*/
@Setter
private List<T> list;
/**
* 错误信息列表
*/
@Setter
private List<String> errorList;
public DefautExcelResult() {
this.list = new ArrayList<>();
this.errorList = new ArrayList<>();
}
public DefautExcelResult(List<T> list, List<String> errorList) {
this.list = list;
this.errorList = errorList;
}
public DefautExcelResult(ExcelResult<T> excelResult) {
this.list = excelResult.getList();
this.errorList = excelResult.getErrorList();
}
@Override
public List<T> getList() {
return list;
}
@Override
public List<String> 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 "";
}
}
}
}

View File

@ -0,0 +1,14 @@
package com.ruoyi.common.excel;
import com.alibaba.excel.read.listener.ReadListener;
/**
* Excel 导入监听
*
* @author Lion Li
*/
public interface ExcelListener<T> extends ReadListener<T> {
ExcelResult<T> getExcelResult();
}

View File

@ -0,0 +1,26 @@
package com.ruoyi.common.excel;
import java.util.List;
/**
* excel返回对象
*
* @author Lion Li
*/
public interface ExcelResult<T> {
/**
* 对象列表
*/
List<T> getList();
/**
* 错误列表
*/
List<String> getErrorList();
/**
* 导入回执
*/
String getAnalysis();
}

View File

@ -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 <T> List<Tree<Long>> build(List<T> list, NodeParser<T, Long> nodeParser) {
return TreeUtil.build(list, DEFAULT_PARENT_ID, DEFAULT_CONFIG, nodeParser);
}
}

View File

@ -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 <T> void validate(T object, Class<?>... groups) {
Set<ConstraintViolation<T>> validate = VALID.validate(object, groups);
if (!validate.isEmpty()) {
throw new ConstraintViolationException("参数校验异常", validate);
}
}
}

View File

@ -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;
}

View File

@ -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<Integer> SYSTEM_DATA_IDS = Arrays.asList(1, 2, 3, 4);
}

View File

@ -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;
}
}

View File

@ -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;
/**
* 是否httpsY=,N=
*/
private String isHttps;
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}
}

View File

@ -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<SysUserImportVo> implements ExcelListener<SysUserImportVo> {
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("<br/>").append(successNum).append("、账号 ").append(user.getUserName()).append(" 导入成功");
} else if (isUpdateSupport) {
user.setUpdateBy(operName);
userService.updateUser(user);
successNum++;
successMsg.append("<br/>").append(successNum).append("、账号 ").append(user.getUserName()).append(" 更新成功");
} else {
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("、账号 ").append(user.getUserName()).append(" 已存在");
}
} catch (Exception e) {
failureNum++;
String msg = "<br/>" + failureNum + "、账号 " + user.getUserName() + " 导入失败:";
failureMsg.append(msg).append(e.getMessage());
log.error(msg, e);
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
}
@Override
public ExcelResult<SysUserImportVo> getExcelResult() {
return new ExcelResult<SysUserImportVo>() {
@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<SysUserImportVo> getList() {
return null;
}
@Override
public List<String> getErrorList() {
return null;
}
};
}
}

View File

@ -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("加载字典缓存数据成功");
}
}

View File

@ -180,7 +180,6 @@ public class SysUserServiceImpl extends ServicePlusImpl<SysUserMapper, SysUser,
public String checkPhoneUnique(SysUser user) {
Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
long count = count(new LambdaQueryWrapper<SysUser>()
.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<SysUserMapper, SysUser,
public String checkEmailUnique(SysUser user) {
Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
long count = count(new LambdaQueryWrapper<SysUser>()
.select(SysUser::getUserId, SysUser::getEmail)
.eq(SysUser::getEmail, user.getEmail())
.ne(SysUser::getUserId, userId));
if (count > 0) {

View File

@ -0,0 +1,3 @@
java包使用 `.` 分割 resource 目录使用 `/` 分割
<br>
此文件目的 防止文件夹粘连找不到 `xml` 文件

View File

@ -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 '更新时间',