~
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
|
||||
|
||||
package mjkf.xinke.dev.core.aop;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.AfterReturning;
|
||||
import org.aspectj.lang.annotation.AfterThrowing;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
import mjkf.xinke.auth.core.pojo.SaBaseLoginUser;
|
||||
import mjkf.xinke.auth.core.util.StpLoginUserUtil;
|
||||
import mjkf.xinke.common.annotation.CommonLog;
|
||||
import mjkf.xinke.dev.modular.log.util.DevLogUtil;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 业务日志aop切面
|
||||
*
|
||||
*
|
||||
* @date 2020/3/20 11:47
|
||||
*/
|
||||
@Aspect
|
||||
@Order
|
||||
@Component
|
||||
public class DevLogAop {
|
||||
|
||||
/**
|
||||
* 日志切入点
|
||||
*
|
||||
*
|
||||
* @date 2020/3/23 17:10
|
||||
*/
|
||||
@Pointcut("@annotation(mjkf.xinke.common.annotation.CommonLog)")
|
||||
private void getLogPointCut() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作成功返回结果记录日志
|
||||
*
|
||||
*
|
||||
* @date 2022/9/2 15:24
|
||||
*/
|
||||
@AfterReturning(pointcut = "getLogPointCut()", returning = "result")
|
||||
public void doAfterReturning(JoinPoint joinPoint, Object result) {
|
||||
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
|
||||
Method method = methodSignature.getMethod();
|
||||
CommonLog commonLog = method.getAnnotation(CommonLog.class);
|
||||
String userName = "未知";
|
||||
try {
|
||||
SaBaseLoginUser loginUser = StpLoginUserUtil.getLoginUser();
|
||||
if(ObjectUtil.isNotNull(loginUser)) {
|
||||
userName = loginUser.getName();
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
// 异步记录日志
|
||||
DevLogUtil.executeOperationLog(commonLog, userName, joinPoint, JSONUtil.toJsonStr(result));
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作发生异常记录日志
|
||||
*
|
||||
*
|
||||
* @date 2022/9/2 15:24
|
||||
*/
|
||||
@AfterThrowing(pointcut = "getLogPointCut()", throwing = "exception")
|
||||
public void doAfterThrowing(JoinPoint joinPoint, Exception exception) {
|
||||
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
|
||||
Method method = methodSignature.getMethod();
|
||||
CommonLog commonLog = method.getAnnotation(CommonLog.class);
|
||||
String userName = "未知";
|
||||
try {
|
||||
SaBaseLoginUser loginUser = StpLoginUserUtil.getLoginUser();
|
||||
if(ObjectUtil.isNotNull(loginUser)) {
|
||||
userName = loginUser.getName();
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
//异步记录日志
|
||||
DevLogUtil.executeExceptionLog(commonLog, userName, joinPoint, exception);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
|
||||
package mjkf.xinke.dev.core.config;
|
||||
|
||||
import com.github.xiaoymin.knife4j.spring.extension.OpenApiExtensionResolver;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import springfox.documentation.builders.ApiInfoBuilder;
|
||||
import springfox.documentation.builders.PathSelectors;
|
||||
import springfox.documentation.builders.RequestHandlerSelectors;
|
||||
import springfox.documentation.service.Contact;
|
||||
import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
import mjkf.xinke.common.pojo.CommonResult;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 开发工具相关配置
|
||||
*
|
||||
*
|
||||
* @date 2022/7/7 16:18
|
||||
**/
|
||||
@Configuration
|
||||
public class DevConfigure {
|
||||
|
||||
@Resource
|
||||
private OpenApiExtensionResolver openApiExtensionResolver;
|
||||
|
||||
/**
|
||||
* API文档分组配置
|
||||
*
|
||||
*
|
||||
* @date 2022/7/7 16:18
|
||||
**/
|
||||
@Bean(value = "devDocApi")
|
||||
public Docket devDocApi() {
|
||||
return new Docket(DocumentationType.SWAGGER_2)
|
||||
.apiInfo(new ApiInfoBuilder()
|
||||
.title("开发工具DEV")
|
||||
.description("开发工具DEV")
|
||||
.termsOfServiceUrl("https://www.xiaonuo.vip")
|
||||
.contact(new Contact("SNOWY_TEAM","https://www.xiaonuo.vip", "xuyuxiang29@foxmail.com"))
|
||||
.version("2.0.0")
|
||||
.build())
|
||||
.globalResponseMessage(RequestMethod.GET, CommonResult.responseList())
|
||||
.globalResponseMessage(RequestMethod.POST, CommonResult.responseList())
|
||||
.groupName("开发工具DEV")
|
||||
.select()
|
||||
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
|
||||
.apis(RequestHandlerSelectors.basePackage("mjkf.xinke.dev"))
|
||||
.paths(PathSelectors.any())
|
||||
.build().extensions(openApiExtensionResolver.buildExtensions("开发工具DEV"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
|
||||
package mjkf.xinke.dev.core.listener;
|
||||
|
||||
import cn.hutool.cron.CronUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.NonNull;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import mjkf.xinke.common.exception.CommonException;
|
||||
import mjkf.xinke.common.timer.CommonTimerTaskRunner;
|
||||
import mjkf.xinke.dev.modular.job.entity.DevJob;
|
||||
import mjkf.xinke.dev.modular.job.enums.DevJobStatusEnum;
|
||||
import mjkf.xinke.dev.modular.job.service.DevJobService;
|
||||
|
||||
/**
|
||||
* 定时任务监听器,系统启动时将定时任务启动
|
||||
*
|
||||
*
|
||||
* @date 2022/8/5 16:07
|
||||
**/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class DevJobListener implements ApplicationListener<ApplicationStartedEvent>, Ordered {
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(@NonNull ApplicationStartedEvent applicationStartedEvent) {
|
||||
SpringUtil.getBean(DevJobService.class).list(new LambdaQueryWrapper<DevJob>()
|
||||
.eq(DevJob::getJobStatus, DevJobStatusEnum.RUNNING.getValue()).orderByAsc(DevJob::getSortCode))
|
||||
.forEach(devJob -> CronUtil.schedule(devJob.getId(), devJob.getCronExpression(), () -> {
|
||||
try {
|
||||
// 运行定时任务
|
||||
((CommonTimerTaskRunner) SpringUtil.getBean(Class.forName(devJob.getActionClass()))).action();
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new CommonException("定时任务找不到对应的类,名称为:{}", devJob.getActionClass());
|
||||
}
|
||||
}));
|
||||
// 设置秒级别的启用
|
||||
CronUtil.setMatchSecond(true);
|
||||
// 启动定时器执行器
|
||||
CronUtil.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return LOWEST_PRECEDENCE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.config.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import mjkf.xinke.common.annotation.CommonLog;
|
||||
import mjkf.xinke.common.pojo.CommonResult;
|
||||
import mjkf.xinke.common.pojo.CommonValidList;
|
||||
import mjkf.xinke.dev.modular.config.entity.DevConfig;
|
||||
import mjkf.xinke.dev.modular.config.enums.DevConfigCategoryEnum;
|
||||
import mjkf.xinke.dev.modular.config.param.*;
|
||||
import mjkf.xinke.dev.modular.config.service.DevConfigService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 配置控制器
|
||||
*
|
||||
*
|
||||
* @date 2022/4/22 10:56
|
||||
**/
|
||||
@Api(tags = "配置控制器")
|
||||
@ApiSupport(author = "SNOWY_TEAM", order = 1)
|
||||
@RestController
|
||||
@Validated
|
||||
public class DevConfigController {
|
||||
|
||||
@Resource
|
||||
private DevConfigService devConfigService;
|
||||
|
||||
/**
|
||||
* 获取配置分页
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 1)
|
||||
@ApiOperation("获取配置分页")
|
||||
@GetMapping("/dev/config/page")
|
||||
public CommonResult<Page<DevConfig>> page(DevConfigPageParam devConfigPageParam) {
|
||||
return CommonResult.data(devConfigService.page(devConfigPageParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统基础配置
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 2)
|
||||
@ApiOperation("获取系统基础配置")
|
||||
@GetMapping("/dev/config/sysBaseList")
|
||||
public CommonResult<List<DevConfig>> sysBaseList() {
|
||||
DevConfigListParam devConfigListParam = new DevConfigListParam();
|
||||
devConfigListParam.setCategory(DevConfigCategoryEnum.SYS_BASE.getValue());
|
||||
return CommonResult.data(devConfigService.list(devConfigListParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置列表
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 2)
|
||||
@ApiOperation("获取配置列表")
|
||||
@GetMapping("/dev/config/list")
|
||||
public CommonResult<List<DevConfig>> list(DevConfigListParam devConfigListParam) {
|
||||
return CommonResult.data(devConfigService.list(devConfigListParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加配置
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:47
|
||||
*/
|
||||
@ApiOperationSupport(order = 3)
|
||||
@ApiOperation("添加配置")
|
||||
@CommonLog("添加配置")
|
||||
@PostMapping("/dev/config/add")
|
||||
public CommonResult<String> add(@RequestBody @Valid DevConfigAddParam devConfigAddParam) {
|
||||
devConfigService.add(devConfigAddParam);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑配置
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:47
|
||||
*/
|
||||
@ApiOperationSupport(order = 4)
|
||||
@ApiOperation("编辑配置")
|
||||
@CommonLog("编辑配置")
|
||||
@PostMapping("/dev/config/edit")
|
||||
public CommonResult<String> edit(@RequestBody @Valid DevConfigEditParam devConfigEditParam) {
|
||||
devConfigService.edit(devConfigEditParam);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除配置
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 5)
|
||||
@ApiOperation("删除配置")
|
||||
@CommonLog("删除配置")
|
||||
@PostMapping("/dev/config/delete")
|
||||
public CommonResult<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
|
||||
CommonValidList<DevConfigIdParam> devConfigIdParamList) {
|
||||
devConfigService.delete(devConfigIdParamList);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置详情
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 6)
|
||||
@ApiOperation("获取配置详情")
|
||||
@GetMapping("/dev/config/detail")
|
||||
public CommonResult<DevConfig> detail(@Valid DevConfigIdParam devConfigIdParam) {
|
||||
return CommonResult.data(devConfigService.detail(devConfigIdParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置批量更新
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 7)
|
||||
@ApiOperation("配置批量更新")
|
||||
@CommonLog("配置批量更新")
|
||||
@PostMapping("/dev/config/editBatch")
|
||||
public CommonResult<String> editBatch(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
|
||||
CommonValidList<DevConfigBatchParam> devConfigBatchParamList) {
|
||||
devConfigService.editBatch(devConfigBatchParamList);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.config.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldStrategy;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import mjkf.xinke.common.pojo.CommonEntity;
|
||||
|
||||
/**
|
||||
* 配置实体
|
||||
*
|
||||
*
|
||||
* @date 2022/2/23 18:27
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("DEV_CONFIG")
|
||||
public class DevConfig extends CommonEntity {
|
||||
|
||||
/** id */
|
||||
@ApiModelProperty(value = "id", position = 1)
|
||||
private String id;
|
||||
|
||||
/** 租户id */
|
||||
@ApiModelProperty(value = "租户id", position = 2)
|
||||
private String tenantId;
|
||||
|
||||
/** 配置键 */
|
||||
@ApiModelProperty(value = "配置键", position = 3)
|
||||
private String configKey;
|
||||
|
||||
/** 配置值 */
|
||||
@ApiModelProperty(value = "配置值", position = 4)
|
||||
private String configValue;
|
||||
|
||||
/** 分类 */
|
||||
@ApiModelProperty(value = "分类", position = 5)
|
||||
private String category;
|
||||
|
||||
/** 备注 */
|
||||
@ApiModelProperty(value = "备注", position = 6)
|
||||
private String remark;
|
||||
|
||||
/** 排序码 */
|
||||
@ApiModelProperty(value = "排序码", position = 7)
|
||||
private Integer sortCode;
|
||||
|
||||
/** 扩展信息 */
|
||||
@ApiModelProperty(value = "扩展信息", position = 8)
|
||||
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
|
||||
private String extJson;
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.config.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
import mjkf.xinke.common.exception.CommonException;
|
||||
|
||||
/**
|
||||
* 配置分类枚举
|
||||
*
|
||||
*
|
||||
* @date 2022/7/6 22:21
|
||||
*/
|
||||
@Getter
|
||||
public enum DevConfigCategoryEnum {
|
||||
|
||||
/**
|
||||
* 系统基础
|
||||
*/
|
||||
SYS_BASE("SYS_BASE"),
|
||||
|
||||
/**
|
||||
* 业务定义
|
||||
*/
|
||||
BIZ_DEFINE("BIZ_DEFINE"),
|
||||
|
||||
/**
|
||||
* 三方登录-码云
|
||||
*/
|
||||
THIRD_GITEE("THIRD_GITEE"),
|
||||
|
||||
/**
|
||||
* 三方登录-微信
|
||||
*/
|
||||
THIRD_WECHAT("THIRD_WECHAT"),
|
||||
|
||||
/**
|
||||
* 文件-本地
|
||||
*/
|
||||
FILE_LOCAL("FILE_LOCAL"),
|
||||
|
||||
/**
|
||||
* 文件-腾讯云
|
||||
*/
|
||||
FILE_TENCENT("FILE_TENCENT"),
|
||||
|
||||
/**
|
||||
* 文件-阿里云
|
||||
*/
|
||||
FILE_ALIYUN("FILE_ALIYUN"),
|
||||
|
||||
/**
|
||||
* 文件-MINIO
|
||||
*/
|
||||
FILE_MINIO("FILE_MINIO"),
|
||||
|
||||
/**
|
||||
* 邮件-本地
|
||||
*/
|
||||
EMAIL_LOCAL("EMAIL_LOCAL"),
|
||||
|
||||
/**
|
||||
* 邮件-腾讯云
|
||||
*/
|
||||
EMAIL_TENCENT("EMAIL_TENCENT"),
|
||||
|
||||
/**
|
||||
* 邮件-阿里云
|
||||
*/
|
||||
EMAIL_ALIYUN("EMAIL_ALIYUN"),
|
||||
|
||||
/**
|
||||
* 短信-腾讯云
|
||||
*/
|
||||
SMS_TENCENT("SMS_TENCENT"),
|
||||
|
||||
/**
|
||||
* 短信-阿里云
|
||||
*/
|
||||
SMS_ALIYUN("SMS_ALIYUN"),
|
||||
|
||||
/**
|
||||
* 支付-支付宝
|
||||
*/
|
||||
PAY_ALI("PAY_ALI"),
|
||||
|
||||
/**
|
||||
* 支付-微信
|
||||
*/
|
||||
PAY_WX("PAY_WX");
|
||||
|
||||
private final String value;
|
||||
|
||||
DevConfigCategoryEnum(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static void validate(String value) {
|
||||
boolean flag = SYS_BASE.getValue().equals(value) || BIZ_DEFINE.getValue().equals(value) ||
|
||||
THIRD_GITEE.getValue().equals(value) || THIRD_WECHAT.getValue().equals(value) ||
|
||||
FILE_LOCAL.getValue().equals(value) || FILE_TENCENT.getValue().equals(value) ||
|
||||
FILE_ALIYUN.getValue().equals(value) || FILE_MINIO.getValue().equals(value) ||
|
||||
EMAIL_TENCENT.getValue().equals(value) || EMAIL_ALIYUN.getValue().equals(value) ||
|
||||
SMS_TENCENT.getValue().equals(value) || SMS_ALIYUN.getValue().equals(value) ||
|
||||
PAY_ALI.getValue().equals(value) || PAY_WX.getValue().equals(value);
|
||||
if(!flag) {
|
||||
throw new CommonException("不支持的配置分类:{}", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.config.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import mjkf.xinke.dev.modular.config.entity.DevConfig;
|
||||
|
||||
/**
|
||||
* 配置Mapper接口
|
||||
*
|
||||
*
|
||||
* @date 2022/4/22 10:43
|
||||
**/
|
||||
public interface DevConfigMapper extends BaseMapper<DevConfig> {
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="mjkf.xinke.dev.modular.config.mapper.DevConfigMapper">
|
||||
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.config.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 配置添加参数
|
||||
*
|
||||
*
|
||||
* @date 2022/7/30 17:53
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevConfigAddParam {
|
||||
|
||||
/** 配置键 */
|
||||
@ApiModelProperty(value = "配置键", required = true, position = 1)
|
||||
@NotBlank(message = "configKey不能为空")
|
||||
private String configKey;
|
||||
|
||||
/** 配置值 */
|
||||
@ApiModelProperty(value = "配置值", required = true, position = 2)
|
||||
@NotBlank(message = "configValue不能为空")
|
||||
private String configValue;
|
||||
|
||||
/** 备注 */
|
||||
@ApiModelProperty(value = "备注", position = 3)
|
||||
private String remark;
|
||||
|
||||
/** 排序码 */
|
||||
@ApiModelProperty(value = "排序码", required = true, position = 4)
|
||||
@NotNull(message = "sortCode不能为空")
|
||||
private Integer sortCode;
|
||||
|
||||
/** 扩展信息 */
|
||||
@ApiModelProperty(value = "扩展信息", position = 5)
|
||||
private String extJson;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.config.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 配置批量更新参数
|
||||
*
|
||||
*
|
||||
* @date 2022/7/7 17:01
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevConfigBatchParam {
|
||||
|
||||
/** 配置键 */
|
||||
@ApiModelProperty(value = "配置键", required = true, position = 1)
|
||||
@NotBlank(message = "configKey不能为空")
|
||||
private String configKey;
|
||||
|
||||
/** 配置值 */
|
||||
@ApiModelProperty(value = "配置值", required = true, position = 2)
|
||||
@NotBlank(message = "configValue不能为空")
|
||||
private String configValue;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.config.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 配置编辑参数
|
||||
*
|
||||
*
|
||||
* @date 2022/7/30 17:53
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevConfigEditParam {
|
||||
|
||||
/** id */
|
||||
@ApiModelProperty(value = "id", required = true, position = 1)
|
||||
@NotBlank(message = "id不能为空")
|
||||
private String id;
|
||||
|
||||
/** 配置键 */
|
||||
@ApiModelProperty(value = "配置键", required = true, position = 2)
|
||||
@NotBlank(message = "configKey不能为空")
|
||||
private String configKey;
|
||||
|
||||
/** 配置值 */
|
||||
@ApiModelProperty(value = "配置值", required = true, position = 3)
|
||||
@NotBlank(message = "configValue不能为空")
|
||||
private String configValue;
|
||||
|
||||
/** 备注 */
|
||||
@ApiModelProperty(value = "备注", position = 4)
|
||||
private String remark;
|
||||
|
||||
/** 排序码 */
|
||||
@ApiModelProperty(value = "排序码", required = true, position = 5)
|
||||
@NotNull(message = "sortCode不能为空")
|
||||
private Integer sortCode;
|
||||
|
||||
/** 扩展信息 */
|
||||
@ApiModelProperty(value = "扩展信息", position = 6)
|
||||
private String extJson;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.config.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 配置Id参数
|
||||
*
|
||||
*
|
||||
* @date 2022/7/30 17:52
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevConfigIdParam {
|
||||
|
||||
/** id */
|
||||
@ApiModelProperty(value = "id", required = true)
|
||||
@NotBlank(message = "id不能为空")
|
||||
private String id;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.config.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 配置列表参数
|
||||
*
|
||||
*
|
||||
* @date 2022/7/30 17:53
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevConfigListParam {
|
||||
|
||||
/** 配置分类 */
|
||||
@ApiModelProperty(value = "配置分类")
|
||||
private String category;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.config.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 配置查询参数
|
||||
*
|
||||
*
|
||||
* @date 2022/7/30 17:53
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevConfigPageParam {
|
||||
|
||||
/** 当前页 */
|
||||
@ApiModelProperty(value = "当前页码")
|
||||
private Integer current;
|
||||
|
||||
/** 每页条数 */
|
||||
@ApiModelProperty(value = "每页条数")
|
||||
private Integer size;
|
||||
|
||||
/** 排序字段 */
|
||||
@ApiModelProperty(value = "排序字段,字段驼峰名称,如:userName")
|
||||
private String sortField;
|
||||
|
||||
/** 排序方式 */
|
||||
@ApiModelProperty(value = "排序方式,升序:ASCEND;降序:DESCEND")
|
||||
private String sortOrder;
|
||||
|
||||
/** 配置键关键词 */
|
||||
@ApiModelProperty(value = "配置键关键词")
|
||||
private String searchKey;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.config.provider;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import mjkf.xinke.dev.api.DevConfigApi;
|
||||
import mjkf.xinke.dev.modular.config.service.DevConfigService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 配置API接口实现类
|
||||
*
|
||||
*
|
||||
* @date 2022/6/17 14:43
|
||||
**/
|
||||
@Service
|
||||
public class DevConfigApiProvider implements DevConfigApi {
|
||||
|
||||
@Resource
|
||||
private DevConfigService devConfigService;
|
||||
|
||||
@Override
|
||||
public String getValueByKey(String key) {
|
||||
return devConfigService.getValueByKey(key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.config.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import mjkf.xinke.dev.modular.config.entity.DevConfig;
|
||||
import mjkf.xinke.dev.modular.config.param.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 配置Service接口
|
||||
*
|
||||
*
|
||||
* @date 2022/4/22 10:41
|
||||
**/
|
||||
public interface DevConfigService extends IService<DevConfig> {
|
||||
|
||||
/**
|
||||
* 根据键获取值
|
||||
*
|
||||
*
|
||||
* @date 2022/4/22 14:52
|
||||
**/
|
||||
String getValueByKey(String key);
|
||||
|
||||
/**
|
||||
* 获取配置分页
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:08
|
||||
*/
|
||||
Page<DevConfig> page(DevConfigPageParam devConfigPageParam);
|
||||
|
||||
/**
|
||||
* 获取配置列表
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:08
|
||||
*/
|
||||
List<DevConfig> list(DevConfigListParam devConfigListParam);
|
||||
|
||||
/**
|
||||
* 添加配置
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:48
|
||||
*/
|
||||
void add(DevConfigAddParam devConfigAddParam);
|
||||
|
||||
/**
|
||||
* 编辑配置
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 21:13
|
||||
*/
|
||||
void edit(DevConfigEditParam devConfigEditParam);
|
||||
|
||||
/**
|
||||
* 删除配置
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 21:18
|
||||
*/
|
||||
void delete(List<DevConfigIdParam> devConfigIdParamList);
|
||||
|
||||
/**
|
||||
* 获取配置详情
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 21:18
|
||||
*/
|
||||
DevConfig detail(DevConfigIdParam devConfigIdParam);
|
||||
|
||||
/**
|
||||
* 获取配置详情
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 21:18
|
||||
*/
|
||||
DevConfig queryEntity(String id);
|
||||
|
||||
/**
|
||||
* 配置批量更新
|
||||
*
|
||||
*
|
||||
* @date 2022/6/28 11:09
|
||||
**/
|
||||
void editBatch(List<DevConfigBatchParam> devConfigBatchParamList);
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.config.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollStreamUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.DesensitizedUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import mjkf.xinke.common.cache.CommonCacheOperator;
|
||||
import mjkf.xinke.common.enums.CommonSortOrderEnum;
|
||||
import mjkf.xinke.common.exception.CommonException;
|
||||
import mjkf.xinke.common.page.CommonPageRequest;
|
||||
import mjkf.xinke.dev.modular.config.entity.DevConfig;
|
||||
import mjkf.xinke.dev.modular.config.enums.DevConfigCategoryEnum;
|
||||
import mjkf.xinke.dev.modular.config.mapper.DevConfigMapper;
|
||||
import mjkf.xinke.dev.modular.config.param.*;
|
||||
import mjkf.xinke.dev.modular.config.service.DevConfigService;
|
||||
import mjkf.xinke.ten.api.TenApi;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 配置Service接口实现类
|
||||
*
|
||||
*
|
||||
* @date 2022/4/22 10:41
|
||||
**/
|
||||
@Service
|
||||
public class DevConfigServiceImpl extends ServiceImpl<DevConfigMapper, DevConfig> implements DevConfigService {
|
||||
|
||||
private static final String CONFIG_CACHE_KEY = "dev-config:";
|
||||
|
||||
private static final String SNOWY_SYS_DEFAULT_PASSWORD_KEY = "SNOWY_SYS_DEFAULT_PASSWORD";
|
||||
|
||||
@Resource
|
||||
private TenApi tenApi;
|
||||
|
||||
@Resource
|
||||
private CommonCacheOperator commonCacheOperator;
|
||||
|
||||
@Override
|
||||
public String getValueByKey(String key) {
|
||||
// 缓存的键前缀
|
||||
String cacheKeyPrefix = CONFIG_CACHE_KEY + tenApi.getCurrentTenDomain() + ":";
|
||||
|
||||
// 从缓存中取
|
||||
Object cacheValue = commonCacheOperator.get(cacheKeyPrefix + key);
|
||||
if(ObjectUtil.isNotEmpty(cacheValue)) {
|
||||
return Convert.toStr(cacheValue);
|
||||
}
|
||||
DevConfig devConfig = this.getOne(new LambdaQueryWrapper<DevConfig>().eq(DevConfig::getConfigKey, key));
|
||||
if(ObjectUtil.isNotEmpty(devConfig)) {
|
||||
// 更新到缓存
|
||||
commonCacheOperator.put(cacheKeyPrefix + key, devConfig.getConfigValue());
|
||||
return devConfig.getConfigValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<DevConfig> page(DevConfigPageParam devConfigPageParam) {
|
||||
QueryWrapper<DevConfig> queryWrapper = new QueryWrapper<>();
|
||||
// 查询部分字段
|
||||
queryWrapper.lambda().select(DevConfig::getId, DevConfig::getConfigKey, DevConfig::getConfigValue,
|
||||
DevConfig::getCategory, DevConfig::getRemark, DevConfig::getSortCode);
|
||||
if(ObjectUtil.isNotEmpty(devConfigPageParam.getSearchKey())) {
|
||||
queryWrapper.lambda().like(DevConfig::getConfigKey, devConfigPageParam.getSearchKey());
|
||||
}
|
||||
if(ObjectUtil.isAllNotEmpty(devConfigPageParam.getSortField(), devConfigPageParam.getSortOrder())) {
|
||||
CommonSortOrderEnum.validate(devConfigPageParam.getSortOrder());
|
||||
queryWrapper.orderBy(true, devConfigPageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
|
||||
StrUtil.toUnderlineCase(devConfigPageParam.getSortField()));
|
||||
} else {
|
||||
queryWrapper.lambda().orderByAsc(DevConfig::getSortCode);
|
||||
}
|
||||
queryWrapper.lambda().eq(DevConfig::getCategory, DevConfigCategoryEnum.BIZ_DEFINE.getValue());
|
||||
return this.page(CommonPageRequest.defaultPage(), queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DevConfig> list(DevConfigListParam devConfigListParam) {
|
||||
LambdaQueryWrapper<DevConfig> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
// 查询部分字段
|
||||
lambdaQueryWrapper.select(DevConfig::getId, DevConfig::getConfigKey, DevConfig::getConfigValue,
|
||||
DevConfig::getCategory, DevConfig::getSortCode);
|
||||
if(ObjectUtil.isNotEmpty(devConfigListParam.getCategory())) {
|
||||
lambdaQueryWrapper.eq(DevConfig::getCategory, devConfigListParam.getCategory());
|
||||
}
|
||||
return this.list(lambdaQueryWrapper).stream().peek(devConfig -> {
|
||||
if(devConfig.getConfigKey().equals(SNOWY_SYS_DEFAULT_PASSWORD_KEY)) {
|
||||
devConfig.setConfigValue(DesensitizedUtil.password(devConfig.getConfigValue()));
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(DevConfigAddParam devConfigAddParam) {
|
||||
checkParam(devConfigAddParam);
|
||||
DevConfig devConfig = BeanUtil.toBean(devConfigAddParam, DevConfig.class);
|
||||
devConfig.setCategory(DevConfigCategoryEnum.BIZ_DEFINE.getValue());
|
||||
this.save(devConfig);
|
||||
}
|
||||
|
||||
private void checkParam(DevConfigAddParam devConfigAddParam) {
|
||||
boolean hasSameConfig = this.count(new LambdaQueryWrapper<DevConfig>()
|
||||
.eq(DevConfig::getConfigKey, devConfigAddParam.getConfigKey())) > 0;
|
||||
if (hasSameConfig) {
|
||||
throw new CommonException("存在重复的配置,配置键为:{}", devConfigAddParam.getConfigKey());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void edit(DevConfigEditParam devConfigEditParam) {
|
||||
DevConfig devConfig = this.queryEntity(devConfigEditParam.getId());
|
||||
checkParam(devConfigEditParam);
|
||||
BeanUtil.copyProperties(devConfigEditParam, devConfig);
|
||||
devConfig.setCategory(DevConfigCategoryEnum.BIZ_DEFINE.getValue());
|
||||
this.updateById(devConfig);
|
||||
// 移除对应的缓存
|
||||
commonCacheOperator.remove(CONFIG_CACHE_KEY + tenApi.getCurrentTenDomain() + ":" + devConfig.getConfigKey());
|
||||
}
|
||||
|
||||
private void checkParam(DevConfigEditParam devConfigEditParam) {
|
||||
boolean hasSameConfig = this.count(new LambdaQueryWrapper<DevConfig>()
|
||||
.eq(DevConfig::getConfigKey, devConfigEditParam.getConfigKey())
|
||||
.ne(DevConfig::getId, devConfigEditParam.getId())) > 0;
|
||||
if (hasSameConfig) {
|
||||
throw new CommonException("存在重复的配置,配置键为:{}", devConfigEditParam.getConfigKey());
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void delete(List<DevConfigIdParam> devConfigIdParamList) {
|
||||
List<String> devConfigIdList = CollStreamUtil.toList(devConfigIdParamList, DevConfigIdParam::getId);
|
||||
if(ObjectUtil.isNotEmpty(devConfigIdList)) {
|
||||
List<DevConfig> devConfigList = this.listByIds(devConfigIdList);
|
||||
if(ObjectUtil.isNotEmpty(devConfigList)) {
|
||||
List<String> devConfigResultList = CollectionUtil.newArrayList(devConfigList.stream()
|
||||
.map(DevConfig::getCategory).collect(Collectors.toSet()));
|
||||
if (devConfigResultList.size() != 1 || !devConfigResultList.get(0).equals(DevConfigCategoryEnum.BIZ_DEFINE.getValue())) {
|
||||
throw new CommonException("不可删除系统内置配置");
|
||||
}
|
||||
List<DevConfig> deleteDevConfigList = this.listByIds(devConfigIdList);
|
||||
// 执行删除
|
||||
this.removeByIds(devConfigIdList);
|
||||
|
||||
deleteDevConfigList.forEach(devConfig -> {
|
||||
// 移除对应的缓存
|
||||
commonCacheOperator.remove(CONFIG_CACHE_KEY + tenApi.getCurrentTenDomain() + ":" + devConfig.getConfigKey());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DevConfig detail(DevConfigIdParam devConfigIdParam) {
|
||||
return this.queryEntity(devConfigIdParam.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DevConfig queryEntity(String id) {
|
||||
DevConfig devConfig = this.getById(id);
|
||||
if(ObjectUtil.isEmpty(devConfig)) {
|
||||
throw new CommonException("配置不存在,id值为:{}", id);
|
||||
}
|
||||
return devConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void editBatch(List<DevConfigBatchParam> devConfigBatchParamList) {
|
||||
devConfigBatchParamList.forEach(devConfigBatchParam -> {
|
||||
this.update(new LambdaUpdateWrapper<DevConfig>()
|
||||
.eq(DevConfig::getConfigKey, devConfigBatchParam.getConfigKey())
|
||||
.set(DevConfig::getConfigValue, devConfigBatchParam.getConfigValue()));
|
||||
// 移除对应的缓存
|
||||
commonCacheOperator.remove(CONFIG_CACHE_KEY + tenApi.getCurrentTenDomain() + ":" + devConfigBatchParam.getConfigKey());
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dev;
|
||||
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import cn.hutool.core.lang.tree.TreeNode;
|
||||
import cn.hutool.core.lang.tree.TreeUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import mjkf.xinke.dev.api.DevApi;
|
||||
import mjkf.xinke.dev.modular.config.entity.DevConfig;
|
||||
import mjkf.xinke.dev.modular.config.enums.DevConfigCategoryEnum;
|
||||
import mjkf.xinke.dev.modular.config.service.DevConfigService;
|
||||
import mjkf.xinke.dev.modular.dict.entity.DevDict;
|
||||
import mjkf.xinke.dev.modular.dict.enums.DevDictCategoryEnum;
|
||||
import mjkf.xinke.dev.modular.dict.service.DevDictService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 开发工具模块综合API接口实现类
|
||||
*
|
||||
*
|
||||
* @date 2022/9/26 14:30
|
||||
**/
|
||||
@Service
|
||||
public class DevApiProvider implements DevApi {
|
||||
|
||||
@Resource
|
||||
private DevDictService devDictService;
|
||||
|
||||
@Resource
|
||||
private DevConfigService devConfigService;
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void initTenDataForCategoryId(String tenId, String tenName) {
|
||||
|
||||
// ==============给租户初始化配置=================
|
||||
List<DevConfig> devConfigList = devConfigService.list(new LambdaQueryWrapper<DevConfig>().ne(DevConfig::getCategory,
|
||||
DevConfigCategoryEnum.BIZ_DEFINE.getValue())).stream().peek(devConfig -> {
|
||||
devConfig.setId(null);
|
||||
devConfig.setTenantId(tenId);
|
||||
// 非系统基础的设置为“未配置”
|
||||
if(!devConfig.getCategory().equals(DevConfigCategoryEnum.SYS_BASE.getValue())) {
|
||||
devConfig.setConfigValue("未配置");
|
||||
}
|
||||
// 将系统名称设置为租户名称
|
||||
if("SNOWY_SYS_NAME".equals(devConfig.getConfigKey())) {
|
||||
devConfig.setConfigValue(tenName);
|
||||
}
|
||||
// 将系统默认工作台数据设置为空
|
||||
if("SNOWY_SYS_DEFAULT_WORKBENCH_DATA".equals(devConfig.getConfigKey())) {
|
||||
devConfig.setConfigValue("{\"shortcut\":[]}");
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
// 批量保存配置
|
||||
devConfigService.saveBatch(devConfigList);
|
||||
|
||||
// ==============给租户初始化字典=================
|
||||
List<DevDict> devDictList = devDictService.list(new LambdaQueryWrapper<DevDict>().eq(DevDict::getCategory,
|
||||
DevDictCategoryEnum.FRM.getValue()));
|
||||
List<TreeNode<String>> treeNodeList = devDictList.stream().map(devDict ->
|
||||
new TreeNode<>(devDict.getId(), devDict.getParentId(),
|
||||
devDict.getDictLabel(), devDict.getSortCode()).setExtra(JSONUtil.parseObj(devDict)))
|
||||
.collect(Collectors.toList());
|
||||
List<Tree<String>> treeList = TreeUtil.build(treeNodeList, "0");
|
||||
// 批量保存字典
|
||||
execRecursionInsertDict("0", treeList, tenId);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void removeTenDataForCategoryId(String tenId) {
|
||||
// ==============移除租户初始化的配置=================
|
||||
devConfigService.remove(new LambdaQueryWrapper<DevConfig>().eq(DevConfig::getTenantId, tenId));
|
||||
|
||||
// ==============移除租户初始化的字典=================
|
||||
devDictService.remove(new LambdaQueryWrapper<DevDict>().eq(DevDict::getTenantId, tenId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归插入字典
|
||||
*
|
||||
*
|
||||
* @date 2022/9/26 15:33
|
||||
**/
|
||||
private void execRecursionInsertDict(String parentId, List<Tree<String>> treeList, String tenId) {
|
||||
treeList.forEach(tree -> {
|
||||
DevDict devDict = JSONUtil.toBean(JSONUtil.parseObj(tree), DevDict.class);
|
||||
devDict.setId(null);
|
||||
devDict.setParentId(parentId);
|
||||
devDict.setTenantId(tenId);
|
||||
devDictService.save(devDict);
|
||||
String dictId = devDict.getId();
|
||||
List<Tree<String>> children = tree.getChildren();
|
||||
if(ObjectUtil.isNotEmpty(children)) {
|
||||
execRecursionInsertDict(dictId, children, tenId);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dfc.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import mjkf.xinke.common.annotation.CommonLog;
|
||||
import mjkf.xinke.common.pojo.CommonResult;
|
||||
import mjkf.xinke.common.pojo.CommonValidList;
|
||||
import mjkf.xinke.dev.modular.dfc.entity.DevDfc;
|
||||
import mjkf.xinke.dev.modular.dfc.param.*;
|
||||
import mjkf.xinke.dev.modular.dfc.result.DevDfcDbsSelectorResult;
|
||||
import mjkf.xinke.dev.modular.dfc.result.DevDfcTableColumnResult;
|
||||
import mjkf.xinke.dev.modular.dfc.result.DevDfcTableResult;
|
||||
import mjkf.xinke.dev.modular.dfc.service.DevDfcService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 动态字段配置控制器
|
||||
*
|
||||
*
|
||||
* @date 2023/08/04 08:18
|
||||
*/
|
||||
@Api(tags = "动态字段配置控制器")
|
||||
@ApiSupport(author = "SNOWY_TEAM", order = 1)
|
||||
@RestController
|
||||
@Validated
|
||||
public class DevDfcController {
|
||||
|
||||
@Resource
|
||||
private DevDfcService devDfcService;
|
||||
|
||||
/**
|
||||
* 获取动态字段配置分页
|
||||
*
|
||||
*
|
||||
* @date 2023/08/04 08:18
|
||||
*/
|
||||
@ApiOperationSupport(order = 1)
|
||||
@ApiOperation("获取动态字段配置分页")
|
||||
@GetMapping("/dev/dfc/page")
|
||||
public CommonResult<Page<DevDfc>> page(DevDfcPageParam devDfcPageParam) {
|
||||
return CommonResult.data(devDfcService.page(devDfcPageParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加动态字段配置
|
||||
*
|
||||
*
|
||||
* @date 2023/08/04 08:18
|
||||
*/
|
||||
@ApiOperationSupport(order = 2)
|
||||
@ApiOperation("添加动态字段配置")
|
||||
@CommonLog("添加动态字段配置")
|
||||
@PostMapping("/dev/dfc/add")
|
||||
public CommonResult<String> add(@RequestBody @Valid DevDfcAddParam devDfcAddParam) {
|
||||
devDfcService.add(devDfcAddParam);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑动态字段配置
|
||||
*
|
||||
*
|
||||
* @date 2023/08/04 08:18
|
||||
*/
|
||||
@ApiOperationSupport(order = 3)
|
||||
@ApiOperation("编辑动态字段配置")
|
||||
@CommonLog("编辑动态字段配置")
|
||||
@PostMapping("/dev/dfc/edit")
|
||||
public CommonResult<String> edit(@RequestBody @Valid DevDfcEditParam devDfcEditParam) {
|
||||
devDfcService.edit(devDfcEditParam);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除动态字段配置
|
||||
*
|
||||
*
|
||||
* @date 2023/08/04 08:18
|
||||
*/
|
||||
@ApiOperationSupport(order = 4)
|
||||
@ApiOperation("删除动态字段配置")
|
||||
@CommonLog("删除动态字段配置")
|
||||
@PostMapping("/dev/dfc/delete")
|
||||
public CommonResult<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
|
||||
CommonValidList<DevDfcIdParam> devDfcIdParamList) {
|
||||
devDfcService.delete(devDfcIdParamList);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取动态字段配置详情
|
||||
*
|
||||
*
|
||||
* @date 2023/08/04 08:18
|
||||
*/
|
||||
@ApiOperationSupport(order = 5)
|
||||
@ApiOperation("获取动态字段配置详情")
|
||||
@GetMapping("/dev/dfc/detail")
|
||||
public CommonResult<DevDfc> detail(@Valid DevDfcIdParam devDfcIdParam) {
|
||||
return CommonResult.data(devDfcService.detail(devDfcIdParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有数据源信息
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 6)
|
||||
@ApiOperation("获取所有数据源信息")
|
||||
@GetMapping("/dev/dfc/dbsSelector")
|
||||
public CommonResult<List<DevDfcDbsSelectorResult>> dbsSelector() {
|
||||
return CommonResult.data(devDfcService.dbsSelector());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据数据源id获取对应库所有表信息
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 7)
|
||||
@ApiOperation("根据数据源id获取对应库所有表信息")
|
||||
@GetMapping("/dev/dfc/tablesByDbsId")
|
||||
public CommonResult<List<DevDfcTableResult>> tablesByDbsId(@Valid DevDfcDbsTableParam devDfcDbsTableParam) {
|
||||
return CommonResult.data(devDfcService.tablesByDbsId(devDfcDbsTableParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前库数据表内所有字段信息
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 8)
|
||||
@ApiOperation("获取当前库数据表内所有字段信息")
|
||||
@GetMapping("/dev/dfc/tableColumns")
|
||||
public CommonResult<List<DevDfcTableColumnResult>> tableColumns(@Valid DevDfcTableColumnParam genBasicTableColumnParam) {
|
||||
return CommonResult.data(devDfcService.tableColumns(genBasicTableColumnParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据数据源id获取对应库数据表内所有字段信息
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 9)
|
||||
@ApiOperation("根据数据源id获取对应库数据表内所有字段信息")
|
||||
@GetMapping("/dev/dfc/tableColumnsByDbsId")
|
||||
public CommonResult<List<DevDfcTableColumnResult>> tableColumnsByDbsId(@Valid DevDfcDbsTableColumnParam dbsTableColumnParam) {
|
||||
return CommonResult.data(devDfcService.tableColumnsByDbsId(dbsTableColumnParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前库所有表信息
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 10)
|
||||
@ApiOperation("获取当前库所有表信息")
|
||||
@GetMapping("/dev/dfc/tables")
|
||||
public CommonResult<List<DevDfcTableResult>> tables() {
|
||||
return CommonResult.data(devDfcService.tables());
|
||||
}
|
||||
|
||||
/**
|
||||
* 迁移数据
|
||||
*
|
||||
*
|
||||
* @date 2023/8/7 22:53
|
||||
*/
|
||||
@ApiOperationSupport(order = 11)
|
||||
@ApiOperation("迁移数据")
|
||||
@PostMapping("/dev/dfc/migrate")
|
||||
public CommonResult<String> migrate(@RequestBody @Valid DevDfcMigrateParam devDfcMigrateParam) {
|
||||
devDfcService.migrate(devDfcMigrateParam);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dfc.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.fhs.core.trans.vo.TransPojo;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import mjkf.xinke.common.pojo.CommonEntity;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 动态字段配置实体
|
||||
*
|
||||
*
|
||||
* @date 2023/08/04 08:18
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("DEV_DFC")
|
||||
public class DevDfc extends CommonEntity implements TransPojo {
|
||||
|
||||
/** 主键 */
|
||||
@TableId
|
||||
@ApiModelProperty(value = "主键", position = 1)
|
||||
private String id;
|
||||
|
||||
/** 租户id */
|
||||
@ApiModelProperty(value = "租户id", position = 2)
|
||||
private String tenantId;
|
||||
|
||||
/** 数据源 */
|
||||
@ApiModelProperty(value = "数据源", position = 3)
|
||||
private String dbsId;
|
||||
|
||||
/** 表名称 */
|
||||
@ApiModelProperty(value = "表名称", position = 4)
|
||||
private String tableName;
|
||||
|
||||
/** 排序码 */
|
||||
@ApiModelProperty(value = "排序码", position = 5)
|
||||
private Integer sortCode;
|
||||
|
||||
/** 表单域属性名 */
|
||||
@ApiModelProperty(value = "表单域属性名", position = 6)
|
||||
private String name;
|
||||
|
||||
/** 标签文本 */
|
||||
@ApiModelProperty(value = "标签文本", position = 7)
|
||||
private String label;
|
||||
|
||||
/** 必填 */
|
||||
@ApiModelProperty(value = "必填", position = 8)
|
||||
private Integer required;
|
||||
|
||||
/** 提示语 */
|
||||
@ApiModelProperty(value = "提示语", position = 9)
|
||||
private String placeholder;
|
||||
|
||||
/** 字段类型 */
|
||||
@ApiModelProperty(value = "字段类型", position = 10)
|
||||
private String type;
|
||||
|
||||
/** 选择项类型 */
|
||||
@ApiModelProperty(value = "选择项类型", position = 11)
|
||||
private String selectOptionType;
|
||||
|
||||
/** 字典 */
|
||||
@ApiModelProperty(value = "字典", position = 12)
|
||||
private String dictTypeCode;
|
||||
|
||||
/** 选择项api地址 */
|
||||
@ApiModelProperty(value = "选择项api地址", position = 13)
|
||||
private String selOptionApiUrl;
|
||||
|
||||
/** 已选择数据api地址 */
|
||||
@ApiModelProperty(value = "已选择数据api地址", position = 14)
|
||||
private String selDataApiUrl;
|
||||
|
||||
/** 是否多选 */
|
||||
@ApiModelProperty(value = "是否多选", position = 15)
|
||||
private Integer isMultiple;
|
||||
|
||||
/** 状态 */
|
||||
@ApiModelProperty(value = "状态", position = 16)
|
||||
private String status;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dfc.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 动态字段配置枚举
|
||||
*
|
||||
*
|
||||
* @date 2023/08/04 08:18
|
||||
**/
|
||||
@Getter
|
||||
public enum DevDfcEnum {
|
||||
|
||||
/**
|
||||
* 正常
|
||||
*/
|
||||
ENABLE("ENABLE"),
|
||||
|
||||
/**
|
||||
* 停用
|
||||
*/
|
||||
DISABLED("DISABLED");
|
||||
|
||||
private final String value;
|
||||
|
||||
DevDfcEnum(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dfc.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import mjkf.xinke.dev.modular.dfc.entity.DevDfc;
|
||||
|
||||
/**
|
||||
* 动态字段配置Mapper接口
|
||||
*
|
||||
*
|
||||
* @date 2023/08/04 08:18
|
||||
**/
|
||||
public interface DevDfcMapper extends BaseMapper<DevDfc> {
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="mjkf.xinke.dev.modular.dfc.mapper.DevDfcMapper">
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,74 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dfc.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 动态字段配置添加参数
|
||||
*
|
||||
*
|
||||
* @date 2023/08/04 08:18
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevDfcAddParam {
|
||||
|
||||
/** 数据源 */
|
||||
@ApiModelProperty(value = "数据源", position = 1)
|
||||
private String dbsId;
|
||||
|
||||
/** 表名称 */
|
||||
@ApiModelProperty(value = "表名称", position = 2)
|
||||
private String tableName;
|
||||
|
||||
/** 排序码 */
|
||||
@ApiModelProperty(value = "排序码", position = 3)
|
||||
private Integer sortCode;
|
||||
|
||||
/** 表单域属性名 */
|
||||
@ApiModelProperty(value = "表单域属性名", position = 4)
|
||||
private String name;
|
||||
|
||||
/** 标签文本 */
|
||||
@ApiModelProperty(value = "标签文本", position = 5)
|
||||
private String label;
|
||||
|
||||
/** 必填 */
|
||||
@ApiModelProperty(value = "必填", position = 6)
|
||||
private Integer required;
|
||||
|
||||
/** 提示语 */
|
||||
@ApiModelProperty(value = "提示语", position = 7)
|
||||
private String placeholder;
|
||||
|
||||
/** 字段类型 */
|
||||
@ApiModelProperty(value = "字段类型", position = 8)
|
||||
private String type;
|
||||
|
||||
/** 选择项类型 */
|
||||
@ApiModelProperty(value = "选择项类型", position = 9)
|
||||
private String selectOptionType;
|
||||
|
||||
/** 字典 */
|
||||
@ApiModelProperty(value = "字典", position = 10)
|
||||
private String dictTypeCode;
|
||||
|
||||
/** 选择项api地址 */
|
||||
@ApiModelProperty(value = "选择项api地址", position = 11)
|
||||
private String selOptionApiUrl;
|
||||
|
||||
/** 已选择数据api地址 */
|
||||
@ApiModelProperty(value = "已选择数据api地址", position = 12)
|
||||
private String selDataApiUrl;
|
||||
|
||||
/** 是否多选 */
|
||||
@ApiModelProperty(value = "是否多选", position = 13)
|
||||
private Integer isMultiple;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dfc.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 数据源库字段列表参数
|
||||
*
|
||||
*
|
||||
* @date 2022/7/29 9:59
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevDfcDbsTableColumnParam {
|
||||
|
||||
/** 数据源Id */
|
||||
@ApiModelProperty(value = "数据源Id", required = true, position = 1)
|
||||
@NotBlank(message = "dbsId不能为空")
|
||||
private String dbsId;
|
||||
|
||||
/** 表名称 */
|
||||
@ApiModelProperty(value = "表名称", required = true, position = 1)
|
||||
@NotBlank(message = "tableName不能为空")
|
||||
private String tableName;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dfc.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 数据源库表参数
|
||||
*
|
||||
*
|
||||
* @date 2022/7/29 9:59
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevDfcDbsTableParam {
|
||||
|
||||
/** 数据源Id */
|
||||
@ApiModelProperty(value = "数据源Id", required = true, position = 1)
|
||||
@NotBlank(message = "dbsId不能为空")
|
||||
private String dbsId;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dfc.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 动态字段配置编辑参数
|
||||
*
|
||||
*
|
||||
* @date 2023/08/04 08:18
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevDfcEditParam {
|
||||
|
||||
/** 主键 */
|
||||
@ApiModelProperty(value = "主键", required = true, position = 1)
|
||||
@NotBlank(message = "id不能为空")
|
||||
private String id;
|
||||
|
||||
/** 数据源 */
|
||||
@ApiModelProperty(value = "数据源", position = 2)
|
||||
private String dbsId;
|
||||
|
||||
/** 表名称 */
|
||||
@ApiModelProperty(value = "表名称", position = 3)
|
||||
private String tableName;
|
||||
|
||||
/** 排序码 */
|
||||
@ApiModelProperty(value = "排序码", position = 4)
|
||||
private Integer sortCode;
|
||||
|
||||
/** 表单域属性名 */
|
||||
@ApiModelProperty(value = "表单域属性名", position = 5)
|
||||
private String name;
|
||||
|
||||
/** 标签文本 */
|
||||
@ApiModelProperty(value = "标签文本", position = 6)
|
||||
private String label;
|
||||
|
||||
/** 必填 */
|
||||
@ApiModelProperty(value = "必填", position = 7)
|
||||
private Integer required;
|
||||
|
||||
/** 提示语 */
|
||||
@ApiModelProperty(value = "提示语", position = 8)
|
||||
private String placeholder;
|
||||
|
||||
/** 字段类型 */
|
||||
@ApiModelProperty(value = "字段类型", position = 9)
|
||||
private String type;
|
||||
|
||||
/** 选择项类型 */
|
||||
@ApiModelProperty(value = "选择项类型", position = 10)
|
||||
private String selectOptionType;
|
||||
|
||||
/** 字典 */
|
||||
@ApiModelProperty(value = "字典", position = 11)
|
||||
private String dictTypeCode;
|
||||
|
||||
/** 选择项api地址 */
|
||||
@ApiModelProperty(value = "选择项api地址", position = 12)
|
||||
private String selOptionApiUrl;
|
||||
|
||||
/** 已选择数据api地址 */
|
||||
@ApiModelProperty(value = "已选择数据api地址", position = 13)
|
||||
private String selDataApiUrl;
|
||||
|
||||
/** 是否多选 */
|
||||
@ApiModelProperty(value = "是否多选", position = 14)
|
||||
private Integer isMultiple;
|
||||
|
||||
/** 状态 */
|
||||
@ApiModelProperty(value = "状态", position = 15)
|
||||
private String status;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dfc.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 动态字段配置Id参数
|
||||
*
|
||||
*
|
||||
* @date 2023/08/04 08:18
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevDfcIdParam {
|
||||
|
||||
/** 主键 */
|
||||
@ApiModelProperty(value = "主键", required = true)
|
||||
@NotBlank(message = "id不能为空")
|
||||
private String id;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package mjkf.xinke.dev.modular.dfc.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 迁移数据参数
|
||||
*
|
||||
*
|
||||
* @date 2023/8/7 22:59
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevDfcMigrateParam {
|
||||
/** 主键 */
|
||||
@ApiModelProperty(value = "主键", required = true, position = 1)
|
||||
@NotBlank(message = "id不能为空")
|
||||
private String id;
|
||||
|
||||
/** 数据源Id */
|
||||
@ApiModelProperty(value = "数据源Id", required = true, position = 2)
|
||||
@NotBlank(message = "dbsId不能为空")
|
||||
private String dbsId;
|
||||
|
||||
/** 表名称 */
|
||||
@ApiModelProperty(value = "表名称", required = true, position = 3)
|
||||
@NotBlank(message = "tableName不能为空")
|
||||
private String tableName;
|
||||
|
||||
/** 字段名称 */
|
||||
@ApiModelProperty(value = "字段名称", required = true, position = 4)
|
||||
@NotBlank(message = "tableColumn不能为空")
|
||||
private String tableColumn;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dfc.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 动态字段配置查询参数
|
||||
*
|
||||
*
|
||||
* @date 2023/08/04 08:18
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevDfcPageParam {
|
||||
|
||||
/** 当前页 */
|
||||
@ApiModelProperty(value = "当前页码")
|
||||
private Integer current;
|
||||
|
||||
/** 每页条数 */
|
||||
@ApiModelProperty(value = "每页条数")
|
||||
private Integer size;
|
||||
|
||||
/** 排序字段 */
|
||||
@ApiModelProperty(value = "排序字段,字段驼峰名称,如:userName")
|
||||
private String sortField;
|
||||
|
||||
/** 排序方式 */
|
||||
@ApiModelProperty(value = "排序方式,升序:ASCEND;降序:DESCEND")
|
||||
private String sortOrder;
|
||||
|
||||
/** 关键词 */
|
||||
@ApiModelProperty(value = "关键词")
|
||||
private String searchKey;
|
||||
|
||||
/** 数据源 */
|
||||
@ApiModelProperty(value = "数据源")
|
||||
private String dbsId;
|
||||
|
||||
/** 表名称 */
|
||||
@ApiModelProperty(value = "表名称")
|
||||
private String tableName;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dfc.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 数据源库字段列表参数
|
||||
*
|
||||
*
|
||||
* @date 2022/7/29 9:59
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevDfcTableColumnParam {
|
||||
|
||||
/** 表名称 */
|
||||
@ApiModelProperty(value = "表名称", required = true)
|
||||
@NotBlank(message = "tableName不能为空")
|
||||
private String tableName;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dfc.provider;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import org.springframework.stereotype.Service;
|
||||
import mjkf.xinke.dev.api.DevDfcApi;
|
||||
import mjkf.xinke.dev.modular.dfc.service.DevDfcService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 动态字段API接口实现类
|
||||
*
|
||||
*
|
||||
* @date 2022/9/2 16:05
|
||||
*/
|
||||
@Service
|
||||
public class DevDfcApiProvider implements DevDfcApi {
|
||||
|
||||
@Resource
|
||||
private DevDfcService devDfcService;
|
||||
|
||||
@Override
|
||||
public List<JSONObject> getTableFieldList(String dbsId, String tableName) {
|
||||
return devDfcService.getTableFieldList(dbsId, tableName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dfc.result;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 代码生成模块所需要用到的数据源选择器的结果
|
||||
*
|
||||
*
|
||||
* @date 2022/7/19 18:55
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevDfcDbsSelectorResult {
|
||||
|
||||
/** id */
|
||||
@ApiModelProperty(value = "id", position = 1)
|
||||
private String id;
|
||||
|
||||
/** 名称 */
|
||||
@ApiModelProperty(value = "名称", position = 2)
|
||||
private String poolName;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dfc.result;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 数据库表字段结果
|
||||
*
|
||||
*
|
||||
* @date 2022/7/19 19:06
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevDfcTableColumnResult {
|
||||
|
||||
/** 字段名称 */
|
||||
@ApiModelProperty(value = "字段名称", position = 1)
|
||||
private String columnName;
|
||||
|
||||
/** 字段类型 */
|
||||
@ApiModelProperty(value = "字段类型", position = 2)
|
||||
private String typeName;
|
||||
|
||||
/** 字段注释 */
|
||||
@ApiModelProperty(value = "字段注释", position = 3)
|
||||
private String columnRemark;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dfc.result;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 数据库表字段结果
|
||||
*
|
||||
*
|
||||
* @date 2022/7/19 19:06
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevDfcTableResult {
|
||||
|
||||
/** 表名称 */
|
||||
@ApiModelProperty(value = "表名称", position = 1)
|
||||
private String tableName;
|
||||
|
||||
/** 表注释 */
|
||||
@ApiModelProperty(value = "表注释", position = 2)
|
||||
private String tableRemark;
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dfc.service;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import mjkf.xinke.dev.modular.dfc.entity.DevDfc;
|
||||
import mjkf.xinke.dev.modular.dfc.param.*;
|
||||
import mjkf.xinke.dev.modular.dfc.result.DevDfcDbsSelectorResult;
|
||||
import mjkf.xinke.dev.modular.dfc.result.DevDfcTableColumnResult;
|
||||
import mjkf.xinke.dev.modular.dfc.result.DevDfcTableResult;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 动态字段配置Service接口
|
||||
*
|
||||
*
|
||||
* @date 2023/08/04 08:18
|
||||
**/
|
||||
public interface DevDfcService extends IService<DevDfc> {
|
||||
|
||||
/**
|
||||
* 获取动态字段配置分页
|
||||
*
|
||||
*
|
||||
* @date 2023/08/04 08:18
|
||||
*/
|
||||
Page<DevDfc> page(DevDfcPageParam devDfcPageParam);
|
||||
|
||||
/**
|
||||
* 添加动态字段配置
|
||||
*
|
||||
*
|
||||
* @date 2023/08/04 08:18
|
||||
*/
|
||||
void add(DevDfcAddParam devDfcAddParam);
|
||||
|
||||
/**
|
||||
* 编辑动态字段配置
|
||||
*
|
||||
*
|
||||
* @date 2023/08/04 08:18
|
||||
*/
|
||||
void edit(DevDfcEditParam devDfcEditParam);
|
||||
|
||||
/**
|
||||
* 删除动态字段配置
|
||||
*
|
||||
*
|
||||
* @date 2023/08/04 08:18
|
||||
*/
|
||||
void delete(List<DevDfcIdParam> devDfcIdParamList);
|
||||
|
||||
/**
|
||||
* 获取动态字段配置详情
|
||||
*
|
||||
*
|
||||
* @date 2023/08/04 08:18
|
||||
*/
|
||||
DevDfc detail(DevDfcIdParam devDfcIdParam);
|
||||
|
||||
/**
|
||||
* 获取动态字段配置详情
|
||||
*
|
||||
*
|
||||
* @date 2023/08/04 08:18
|
||||
**/
|
||||
DevDfc queryEntity(String id);
|
||||
|
||||
/**
|
||||
* 获取所有数据源信息
|
||||
*
|
||||
*
|
||||
* @date 2023/2/1 10:43
|
||||
**/
|
||||
List<DevDfcDbsSelectorResult> dbsSelector();
|
||||
|
||||
/**
|
||||
* 获取所有表信息
|
||||
*
|
||||
*
|
||||
* @date 2022/10/25 22:33
|
||||
**/
|
||||
List<DevDfcTableResult> tablesByDbsId(DevDfcDbsTableParam devDfcDbsTableParam);
|
||||
|
||||
/**
|
||||
* 获取所有表信息
|
||||
*
|
||||
*
|
||||
* @date 2022/10/25 22:33
|
||||
**/
|
||||
List<DevDfcTableResult> tables();
|
||||
|
||||
/**
|
||||
* 获取表内所有字段信息
|
||||
*
|
||||
*
|
||||
* @date 2022/10/25 22:33
|
||||
**/
|
||||
List<DevDfcTableColumnResult> tableColumns(DevDfcTableColumnParam genBasicTableColumnParam);
|
||||
|
||||
/**
|
||||
* 获取表内所有字段信息
|
||||
*
|
||||
*
|
||||
* @date 2022/10/25 22:33
|
||||
**/
|
||||
List<DevDfcTableColumnResult> tableColumnsByDbsId(DevDfcDbsTableColumnParam dbsTableColumnParam);
|
||||
|
||||
/**
|
||||
* 获取表中字段配置
|
||||
*
|
||||
*
|
||||
* @date 2023/08/02 21:31
|
||||
*/
|
||||
List<JSONObject> getTableFieldList(String dbsId, String tableName);
|
||||
|
||||
/**
|
||||
* 迁移数据
|
||||
*
|
||||
*
|
||||
* @date 2023/08/02 21:31
|
||||
*/
|
||||
void migrate(DevDfcMigrateParam devDfcMigrateParam);
|
||||
}
|
||||
@@ -0,0 +1,368 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dfc.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollStreamUtil;
|
||||
import cn.hutool.core.lang.Console;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import mjkf.xinke.common.enums.CommonSortOrderEnum;
|
||||
import mjkf.xinke.common.exception.CommonException;
|
||||
import mjkf.xinke.common.page.CommonPageRequest;
|
||||
import mjkf.xinke.dbs.api.DbsApi;
|
||||
import mjkf.xinke.dev.modular.dfc.entity.DevDfc;
|
||||
import mjkf.xinke.dev.modular.dfc.enums.DevDfcEnum;
|
||||
import mjkf.xinke.dev.modular.dfc.mapper.DevDfcMapper;
|
||||
import mjkf.xinke.dev.modular.dfc.param.*;
|
||||
import mjkf.xinke.dev.modular.dfc.result.DevDfcDbsSelectorResult;
|
||||
import mjkf.xinke.dev.modular.dfc.result.DevDfcTableColumnResult;
|
||||
import mjkf.xinke.dev.modular.dfc.result.DevDfcTableResult;
|
||||
import mjkf.xinke.dev.modular.dfc.service.DevDfcService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.sql.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 动态字段配置Service接口实现类
|
||||
*
|
||||
*
|
||||
* @date 2023/08/04 08:18
|
||||
**/
|
||||
@Service
|
||||
public class DevDfcServiceImpl extends ServiceImpl<DevDfcMapper, DevDfc> implements DevDfcService {
|
||||
|
||||
private static final String DB_URL_KEY = "spring.datasource.dynamic.datasource.master.url";
|
||||
|
||||
private static final String DB_USERNAME_KEY = "spring.datasource.dynamic.datasource.master.username";
|
||||
|
||||
private static final String DB_PASSWORD_KEY = "spring.datasource.dynamic.datasource.master.password";
|
||||
|
||||
@Resource
|
||||
private Environment environment;
|
||||
|
||||
@Resource
|
||||
private DbsApi dbsApi;
|
||||
|
||||
@Override
|
||||
public Page<DevDfc> page(DevDfcPageParam devDfcPageParam) {
|
||||
QueryWrapper<DevDfc> queryWrapper = new QueryWrapper<>();
|
||||
if(ObjectUtil.isNotEmpty(devDfcPageParam.getDbsId())) {
|
||||
queryWrapper.lambda().eq(DevDfc::getDbsId, devDfcPageParam.getDbsId());
|
||||
}
|
||||
if(ObjectUtil.isNotEmpty(devDfcPageParam.getTableName())) {
|
||||
queryWrapper.lambda().eq(DevDfc::getTableName, devDfcPageParam.getTableName());
|
||||
}
|
||||
if(ObjectUtil.isAllNotEmpty(devDfcPageParam.getSortField(), devDfcPageParam.getSortOrder())) {
|
||||
CommonSortOrderEnum.validate(devDfcPageParam.getSortOrder());
|
||||
queryWrapper.orderBy(true, devDfcPageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
|
||||
StrUtil.toUnderlineCase(devDfcPageParam.getSortField()));
|
||||
} else {
|
||||
queryWrapper.lambda().orderByAsc(DevDfc::getDbsId).orderByAsc(DevDfc::getTableName).orderByAsc(DevDfc::getSortCode);
|
||||
}
|
||||
return this.page(CommonPageRequest.defaultPage(), queryWrapper);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void add(DevDfcAddParam devDfcAddParam) {
|
||||
DevDfc devDfc = BeanUtil.toBean(devDfcAddParam, DevDfc.class);
|
||||
boolean repeatName = this.count(new LambdaQueryWrapper<DevDfc>()
|
||||
.eq(DevDfc::getDbsId, devDfc.getDbsId())
|
||||
.eq(DevDfc::getTableName, devDfc.getTableName())
|
||||
.eq(DevDfc::getName, devDfc.getName())) > 0;
|
||||
if(repeatName) {
|
||||
throw new CommonException("存在重复的表单域属性名,表单域属性名为:{}", devDfc.getName());
|
||||
}
|
||||
devDfc.setStatus(DevDfcEnum.ENABLE.getValue());
|
||||
this.save(devDfc);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void edit(DevDfcEditParam devDfcEditParam) {
|
||||
DevDfc devDfc = this.queryEntity(devDfcEditParam.getId());
|
||||
BeanUtil.copyProperties(devDfcEditParam, devDfc);
|
||||
boolean repeatName = this.count(new LambdaQueryWrapper<DevDfc>()
|
||||
.eq(DevDfc::getDbsId, devDfc.getDbsId())
|
||||
.eq(DevDfc::getTableName, devDfc.getTableName())
|
||||
.eq(DevDfc::getName, devDfc.getName())
|
||||
.ne(DevDfc::getId, devDfc.getId())) > 0;
|
||||
if(repeatName) {
|
||||
throw new CommonException("存在重复的表单域属性名,表单域属性名为:{}", devDfc.getName());
|
||||
}
|
||||
this.updateById(devDfc);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void delete(List<DevDfcIdParam> devDfcIdParamList) {
|
||||
// 执行删除
|
||||
this.removeByIds(CollStreamUtil.toList(devDfcIdParamList, DevDfcIdParam::getId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DevDfc detail(DevDfcIdParam devDfcIdParam) {
|
||||
return this.queryEntity(devDfcIdParam.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DevDfc queryEntity(String id) {
|
||||
DevDfc devDfc = this.getById(id);
|
||||
if(ObjectUtil.isEmpty(devDfc)) {
|
||||
throw new CommonException("动态字段配置不存在,id值为:{}", id);
|
||||
}
|
||||
return devDfc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DevDfcDbsSelectorResult> dbsSelector() {
|
||||
return dbsApi.dbsSelector().stream()
|
||||
.map(jsonObject -> JSONUtil.toBean(jsonObject, DevDfcDbsSelectorResult.class)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DevDfcTableResult> tablesByDbsId(DevDfcDbsTableParam devDfcDbsTableParam) {
|
||||
JSONObject jsonObject = dbsApi.dbsDetail(devDfcDbsTableParam.getDbsId());
|
||||
String poolName = jsonObject.getStr("poolName");
|
||||
String url = jsonObject.getStr("url");
|
||||
String userName = jsonObject.getStr("username");
|
||||
String password = jsonObject.getStr("password");
|
||||
if(ObjectUtil.hasEmpty(url, userName, password)) {
|
||||
throw new CommonException("数据源{}配置信息不完整", poolName);
|
||||
}
|
||||
return queryTables(url, userName, password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DevDfcTableResult> tables() {
|
||||
String url = environment.getProperty(DB_URL_KEY);
|
||||
String userName = environment.getProperty(DB_USERNAME_KEY);
|
||||
String password = environment.getProperty(DB_PASSWORD_KEY);
|
||||
if(ObjectUtil.hasEmpty(url, userName, password)) {
|
||||
throw new CommonException("当前数据源配置信息不完整");
|
||||
}
|
||||
return this.queryTables(url, userName, password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DevDfcTableColumnResult> tableColumns(DevDfcTableColumnParam genBasicTableColumnParam) {
|
||||
String url = environment.getProperty(DB_URL_KEY);
|
||||
String userName = environment.getProperty(DB_USERNAME_KEY);
|
||||
String password = environment.getProperty(DB_PASSWORD_KEY);
|
||||
if(ObjectUtil.hasEmpty(url, userName, password)) {
|
||||
throw new CommonException("当前数据源配置信息不完整");
|
||||
}
|
||||
return this.queryTableColumns(url, userName, password, genBasicTableColumnParam.getTableName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DevDfcTableColumnResult> tableColumnsByDbsId(DevDfcDbsTableColumnParam dbsTableColumnParam) {
|
||||
JSONObject jsonObject = dbsApi.dbsDetail(dbsTableColumnParam.getDbsId());
|
||||
String poolName = jsonObject.getStr("poolName");
|
||||
String url = jsonObject.getStr("url");
|
||||
String userName = jsonObject.getStr("username");
|
||||
String password = jsonObject.getStr("password");
|
||||
if(ObjectUtil.hasEmpty(url, userName, password)) {
|
||||
throw new CommonException("数据源{}配置信息不完整", poolName);
|
||||
}
|
||||
return queryTableColumns(url, userName, password, dbsTableColumnParam.getTableName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JSONObject> getTableFieldList(String dbsId, String tableName) {
|
||||
QueryWrapper<DevDfc> queryWrapper = new QueryWrapper<>();
|
||||
if(ObjectUtil.isNotEmpty(dbsId)) {
|
||||
queryWrapper.lambda().eq(DevDfc::getDbsId, dbsId);
|
||||
}
|
||||
if(ObjectUtil.isNotEmpty(tableName)) {
|
||||
queryWrapper.lambda().eq(DevDfc::getTableName, tableName);
|
||||
}
|
||||
queryWrapper.lambda().eq(DevDfc::getStatus, DevDfcEnum.ENABLE.getValue());
|
||||
queryWrapper.lambda().orderByAsc(DevDfc::getSortCode);
|
||||
return this.list(queryWrapper)
|
||||
.stream()
|
||||
.map(item -> JSONUtil.createObj()
|
||||
.set("name", item.getName())
|
||||
.set("label", item.getLabel())
|
||||
.set("type", item.getType())
|
||||
.set("required", item.getRequired())
|
||||
.set("placeholder", item.getPlaceholder())
|
||||
.set("selectOptionType", item.getSelectOptionType())
|
||||
.set("dictTypeCode", item.getDictTypeCode())
|
||||
.set("selOptionApiUrl", item.getSelOptionApiUrl())
|
||||
.set("selDataApiUrl", item.getSelDataApiUrl())
|
||||
.set("isMultiple", item.getIsMultiple())
|
||||
)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void migrate(DevDfcMigrateParam devDfcMigrateParam) {
|
||||
String url = environment.getProperty(DB_URL_KEY);
|
||||
String userName = environment.getProperty(DB_USERNAME_KEY);
|
||||
String password = environment.getProperty(DB_PASSWORD_KEY);
|
||||
if (!"master".equals(devDfcMigrateParam.getDbsId())){
|
||||
JSONObject jsonObject = dbsApi.dbsDetail(devDfcMigrateParam.getDbsId());
|
||||
url = jsonObject.getStr("url");
|
||||
userName = jsonObject.getStr("username");
|
||||
password = jsonObject.getStr("password");
|
||||
}
|
||||
if(ObjectUtil.hasEmpty(url, userName, password)) {
|
||||
throw new CommonException("当前数据源配置信息不完整");
|
||||
}
|
||||
this.migrateData(url, userName, password, devDfcMigrateParam);
|
||||
}
|
||||
/**
|
||||
* 迁移数据
|
||||
*
|
||||
*
|
||||
* @date 2023/2/1 10:31
|
||||
**/
|
||||
private void migrateData(String url, String userName, String password, DevDfcMigrateParam devDfcMigrateParam){
|
||||
Connection conn = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
conn = DriverManager.getConnection(url, userName, password);
|
||||
DevDfc devDfc = this.getById(devDfcMigrateParam.getId());
|
||||
|
||||
boolean executeUpdateSql = false;
|
||||
PreparedStatement preparedStatement = conn.prepareStatement(StrUtil.format("SELECT COUNT(*) FROM {} WHERE {} IS NOT NULL", devDfc.getTableName(), devDfcMigrateParam.getTableColumn()));
|
||||
ResultSet resultSet = preparedStatement.executeQuery();
|
||||
while (resultSet.next()) {
|
||||
if (resultSet.getInt(1) <= 0){
|
||||
executeUpdateSql = true;
|
||||
}
|
||||
}
|
||||
if(!executeUpdateSql) {
|
||||
preparedStatement.close();
|
||||
conn.close();
|
||||
throw new CommonException("目标字段存在数据,终止数据迁移");
|
||||
}
|
||||
|
||||
if (url.toLowerCase().contains("jdbc:mysql")) {
|
||||
preparedStatement = conn.prepareStatement(StrUtil.format("UPDATE {} SET {} = JSON_UNQUOTE(JSON_EXTRACT(EXT_JSON, '$.{}'))", devDfc.getTableName(), devDfcMigrateParam.getTableColumn(), devDfc.getName()));
|
||||
}
|
||||
if (!url.toLowerCase().contains("jdbc:mysql")) {
|
||||
preparedStatement = conn.prepareStatement(StrUtil.format("UPDATE {} SET {} = JSON_VALUE(EXT_JSON, '$.{}')", devDfc.getTableName(), devDfcMigrateParam.getTableColumn(), devDfc.getName()));
|
||||
}
|
||||
preparedStatement.executeUpdate();
|
||||
preparedStatement.close();
|
||||
conn.close();
|
||||
} catch (SQLException sqlException) {
|
||||
sqlException.printStackTrace();
|
||||
throw new CommonException("获取数据库表失败");
|
||||
} finally {
|
||||
JdbcUtils.closeResultSet(rs);
|
||||
JdbcUtils.closeConnection(conn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询指定数据源中的所有表
|
||||
*
|
||||
*
|
||||
* @date 2023/2/1 10:31
|
||||
**/
|
||||
private List<DevDfcTableResult> queryTables(String url, String userName, String password) {
|
||||
Connection conn = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
conn = DriverManager.getConnection(url, userName, password);
|
||||
DatabaseMetaData metaData = conn.getMetaData();
|
||||
String schema = null;
|
||||
if (metaData.getURL().toLowerCase().contains("jdbc:oracle")) {
|
||||
schema = metaData.getUserName();
|
||||
}
|
||||
List<DevDfcTableResult> tables = new ArrayList<>();
|
||||
rs = metaData.getTables(null, schema, "%", new String[]{"TABLE"});
|
||||
while (rs.next()) {
|
||||
String tableName = rs.getString("TABLE_NAME");
|
||||
if (!StrUtil.startWithIgnoreCase(tableName, "ACT_")
|
||||
&& !StrUtil.startWithIgnoreCase(tableName, "CLIENT_")
|
||||
&& !StrUtil.startWithIgnoreCase(tableName, "DEV_")
|
||||
&& !StrUtil.startWithIgnoreCase(tableName, "EXT_")
|
||||
&& !StrUtil.startWithIgnoreCase(tableName, "GEN_")
|
||||
&& !StrUtil.startWithIgnoreCase(tableName, "MOBILE_")
|
||||
&& !StrUtil.startWithIgnoreCase(tableName, "PAY_")
|
||||
&& !StrUtil.startWithIgnoreCase(tableName, "AUTH_")
|
||||
) {
|
||||
DevDfcTableResult genBasicTableResult = new DevDfcTableResult();
|
||||
genBasicTableResult.setTableName(tableName);
|
||||
String remarks = rs.getString("REMARKS");
|
||||
if(ObjectUtil.isEmpty(remarks)) {
|
||||
genBasicTableResult.setTableRemark(tableName);
|
||||
} else {
|
||||
genBasicTableResult.setTableRemark(remarks);
|
||||
}
|
||||
tables.add(genBasicTableResult);
|
||||
}
|
||||
}
|
||||
return tables;
|
||||
} catch (SQLException sqlException) {
|
||||
sqlException.printStackTrace();
|
||||
throw new CommonException("获取数据库表失败");
|
||||
} finally {
|
||||
JdbcUtils.closeResultSet(rs);
|
||||
JdbcUtils.closeConnection(conn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询指定数据源中指定表的所有字段
|
||||
*
|
||||
*
|
||||
* @date 2023/2/1 11:09
|
||||
**/
|
||||
private List<DevDfcTableColumnResult> queryTableColumns(String url, String userName, String password, String tableName) {
|
||||
Connection conn = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
conn = DriverManager.getConnection(url, userName, password);
|
||||
DatabaseMetaData metaData = conn.getMetaData();
|
||||
String schema = null;
|
||||
if (metaData.getURL().toLowerCase().contains("jdbc:oracle")) {
|
||||
schema = metaData.getUserName();
|
||||
}
|
||||
List<DevDfcTableColumnResult> columns = new ArrayList<>();
|
||||
rs = metaData.getColumns(null, schema, tableName, "%");
|
||||
while (rs.next()) {
|
||||
String columnName = rs.getString("COLUMN_NAME").toUpperCase();
|
||||
DevDfcTableColumnResult devDfcTableColumnResult = new DevDfcTableColumnResult();
|
||||
devDfcTableColumnResult.setColumnName(columnName);
|
||||
String remarks = rs.getString("REMARKS");
|
||||
if(ObjectUtil.isEmpty(remarks)) {
|
||||
devDfcTableColumnResult.setColumnRemark(columnName);
|
||||
} else {
|
||||
devDfcTableColumnResult.setColumnRemark(remarks);
|
||||
}
|
||||
String typeName = rs.getString("TYPE_NAME").toUpperCase();
|
||||
if(ObjectUtil.isEmpty(typeName)) {
|
||||
devDfcTableColumnResult.setTypeName("NONE");
|
||||
} else {
|
||||
devDfcTableColumnResult.setTypeName(typeName);
|
||||
}
|
||||
columns.add(devDfcTableColumnResult);
|
||||
}
|
||||
return columns;
|
||||
} catch (SQLException sqlException) {
|
||||
sqlException.printStackTrace();
|
||||
throw new CommonException("获取数据库表字段失败,表名称:{}", tableName);
|
||||
} finally {
|
||||
JdbcUtils.closeResultSet(rs);
|
||||
JdbcUtils.closeConnection(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dict.controller;
|
||||
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import mjkf.xinke.common.annotation.CommonLog;
|
||||
import mjkf.xinke.common.pojo.CommonResult;
|
||||
import mjkf.xinke.common.pojo.CommonValidList;
|
||||
import mjkf.xinke.dev.modular.dict.entity.DevDict;
|
||||
import mjkf.xinke.dev.modular.dict.param.*;
|
||||
import mjkf.xinke.dev.modular.dict.service.DevDictService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 字典控制器
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 14:58
|
||||
**/
|
||||
@Api(tags = "字典控制器")
|
||||
@ApiSupport(author = "SNOWY_TEAM", order = 2)
|
||||
@RestController
|
||||
@Validated
|
||||
public class DevDictController {
|
||||
|
||||
@Resource
|
||||
private DevDictService devDictService;
|
||||
|
||||
/**
|
||||
* 获取字典分页
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 1)
|
||||
@ApiOperation("获取字典分页")
|
||||
@GetMapping("/dev/dict/page")
|
||||
public CommonResult<Page<DevDict>> page(DevDictPageParam devDictPageParam) {
|
||||
return CommonResult.data(devDictService.page(devDictPageParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字典列表
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 2)
|
||||
@ApiOperation("获取字典列表")
|
||||
@GetMapping("/dev/dict/list")
|
||||
public CommonResult<List<DevDict>> list(DevDictListParam devDictListParam) {
|
||||
return CommonResult.data(devDictService.list(devDictListParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字典树
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 3)
|
||||
@ApiOperation("获取字典树")
|
||||
@GetMapping("/dev/dict/tree")
|
||||
public CommonResult<List<Tree<String>>> tree(DevDictTreeParam devDictTreeParam) {
|
||||
return CommonResult.data(devDictService.tree(devDictTreeParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加字典
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:47
|
||||
*/
|
||||
@ApiOperationSupport(order = 4)
|
||||
@ApiOperation("添加字典")
|
||||
@CommonLog("添加字典")
|
||||
@PostMapping("/dev/dict/add")
|
||||
public CommonResult<String> add(@RequestBody @Valid DevDictAddParam devDictAddParam) {
|
||||
devDictService.add(devDictAddParam);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑字典
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:47
|
||||
*/
|
||||
@ApiOperationSupport(order = 5)
|
||||
@ApiOperation("编辑字典")
|
||||
@CommonLog("编辑字典")
|
||||
@PostMapping("/dev/dict/edit")
|
||||
public CommonResult<String> edit(@RequestBody @Valid DevDictEditParam devDictEditParam) {
|
||||
devDictService.edit(devDictEditParam);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除字典
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 6)
|
||||
@ApiOperation("删除字典")
|
||||
@CommonLog("删除字典")
|
||||
@PostMapping("/dev/dict/delete")
|
||||
public CommonResult<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
|
||||
CommonValidList<DevDictIdParam> devDictIdParamList) {
|
||||
devDictService.delete(devDictIdParamList);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字典详情
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 7)
|
||||
@ApiOperation("获取字典详情")
|
||||
@GetMapping("/dev/dict/detail")
|
||||
public CommonResult<DevDict> detail(@Valid DevDictIdParam devDictIdParam) {
|
||||
return CommonResult.data(devDictService.detail(devDictIdParam));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dict.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldStrategy;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import mjkf.xinke.common.pojo.CommonEntity;
|
||||
|
||||
/**
|
||||
* 字典实体
|
||||
*
|
||||
*
|
||||
* @date 2022/2/23 18:27
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("DEV_DICT")
|
||||
public class DevDict extends CommonEntity {
|
||||
|
||||
/** id */
|
||||
@ApiModelProperty(value = "id", position = 1)
|
||||
private String id;
|
||||
|
||||
/** 租户id */
|
||||
@ApiModelProperty(value = "租户id", position = 2)
|
||||
private String tenantId;
|
||||
|
||||
/** 父id */
|
||||
@ApiModelProperty(value = "父id", position = 3)
|
||||
private String parentId;
|
||||
|
||||
/** 字典文字 */
|
||||
@ApiModelProperty(value = "字典文字", position = 4)
|
||||
private String dictLabel;
|
||||
|
||||
/** 字典值 */
|
||||
@ApiModelProperty(value = "字典值", position = 5)
|
||||
private String dictValue;
|
||||
|
||||
/** 分类 */
|
||||
@ApiModelProperty(value = "分类", position = 6)
|
||||
private String category;
|
||||
|
||||
/** 排序码 */
|
||||
@ApiModelProperty(value = "排序码", position = 7)
|
||||
private Integer sortCode;
|
||||
|
||||
/** 扩展信息 */
|
||||
@ApiModelProperty(value = "扩展信息", position = 8)
|
||||
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
|
||||
private String extJson;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dict.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
import mjkf.xinke.common.exception.CommonException;
|
||||
|
||||
/**
|
||||
* 字典分类枚举
|
||||
*
|
||||
*
|
||||
* @date 2022/7/6 22:21
|
||||
*/
|
||||
@Getter
|
||||
public enum DevDictCategoryEnum {
|
||||
|
||||
/**
|
||||
* 框架
|
||||
*/
|
||||
FRM("FRM"),
|
||||
|
||||
/**
|
||||
* 业务
|
||||
*/
|
||||
BIZ("BIZ");
|
||||
|
||||
private final String value;
|
||||
|
||||
DevDictCategoryEnum(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static void validate(String value) {
|
||||
boolean flag = FRM.getValue().equals(value) || BIZ.getValue().equals(value);
|
||||
if(!flag) {
|
||||
throw new CommonException("不支持的字典分类:{}", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dict.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import mjkf.xinke.dev.modular.dict.entity.DevDict;
|
||||
|
||||
/**
|
||||
* 字典Mapper接口
|
||||
*
|
||||
*
|
||||
* @date 2022/4/22 10:40
|
||||
**/
|
||||
public interface DevDictMapper extends BaseMapper<DevDict> {
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="mjkf.xinke.dev.modular.dict.mapper.DevDictMapper">
|
||||
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,49 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dict.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 字典添加参数
|
||||
*
|
||||
*
|
||||
* @date 2022/7/30 21:48
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevDictAddParam {
|
||||
|
||||
/** 父id */
|
||||
@ApiModelProperty(value = "父id", position = 1)
|
||||
@NotBlank(message = "parentId不能为空")
|
||||
private String parentId;
|
||||
|
||||
/** 字典文字 */
|
||||
@ApiModelProperty(value = "字典文字", position = 2)
|
||||
@NotBlank(message = "dictLabel不能为空")
|
||||
private String dictLabel;
|
||||
|
||||
/** 字典值 */
|
||||
@ApiModelProperty(value = "字典值", position = 3)
|
||||
@NotBlank(message = "dictValue不能为空")
|
||||
private String dictValue;
|
||||
|
||||
/** 分类 */
|
||||
@ApiModelProperty(value = "分类", position = 4)
|
||||
@NotBlank(message = "category不能为空")
|
||||
private String category;
|
||||
|
||||
/** 排序码 */
|
||||
@ApiModelProperty(value = "排序码", position = 5)
|
||||
@NotNull(message = "sortCode不能为空")
|
||||
private Integer sortCode;
|
||||
|
||||
/** 扩展信息 */
|
||||
@ApiModelProperty(value = "扩展信息", position = 6)
|
||||
private String extJson;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dict.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 字典编辑参数
|
||||
*
|
||||
*
|
||||
* @date 2022/7/30 21:48
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevDictEditParam {
|
||||
|
||||
/** id */
|
||||
@ApiModelProperty(value = "id", position = 1)
|
||||
@NotBlank(message = "id不能为空")
|
||||
private String id;
|
||||
|
||||
/** 父id */
|
||||
@ApiModelProperty(value = "父id", position = 2)
|
||||
@NotBlank(message = "parentId不能为空")
|
||||
private String parentId;
|
||||
|
||||
/** 字典文字 */
|
||||
@ApiModelProperty(value = "字典文字", position = 3)
|
||||
@NotBlank(message = "dictLabel不能为空")
|
||||
private String dictLabel;
|
||||
|
||||
/** 字典值 */
|
||||
@ApiModelProperty(value = "字典值", position = 4)
|
||||
@NotBlank(message = "dictValue不能为空")
|
||||
private String dictValue;
|
||||
|
||||
/** 分类 */
|
||||
@ApiModelProperty(value = "分类", position = 5)
|
||||
@NotBlank(message = "category不能为空")
|
||||
private String category;
|
||||
|
||||
/** 排序码 */
|
||||
@ApiModelProperty(value = "排序码", position = 6)
|
||||
@NotNull(message = "sortCode不能为空")
|
||||
private Integer sortCode;
|
||||
|
||||
/** 扩展信息 */
|
||||
@ApiModelProperty(value = "扩展信息", position = 7)
|
||||
private String extJson;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dict.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 字典Id参数
|
||||
*
|
||||
*
|
||||
* @date 2022/7/30 21:48
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevDictIdParam {
|
||||
|
||||
/** id */
|
||||
@ApiModelProperty(value = "id", required = true)
|
||||
@NotBlank(message = "id不能为空")
|
||||
private String id;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dict.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 字典列表参数
|
||||
*
|
||||
*
|
||||
* @date 2022/7/30 21:49
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevDictListParam {
|
||||
|
||||
/** 父id */
|
||||
@ApiModelProperty(value = "父id")
|
||||
private String parentId;
|
||||
|
||||
/** 字典分类 */
|
||||
@ApiModelProperty(value = "字典分类")
|
||||
private String category;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dict.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 字典查询参数
|
||||
*
|
||||
*
|
||||
* @date 2022/7/30 21:49
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevDictPageParam {
|
||||
|
||||
/** 当前页 */
|
||||
@ApiModelProperty(value = "当前页码")
|
||||
private Integer current;
|
||||
|
||||
/** 每页条数 */
|
||||
@ApiModelProperty(value = "每页条数")
|
||||
private Integer size;
|
||||
|
||||
/** 排序字段 */
|
||||
@ApiModelProperty(value = "排序字段,字段驼峰名称,如:userName")
|
||||
private String sortField;
|
||||
|
||||
/** 排序方式 */
|
||||
@ApiModelProperty(value = "排序方式,升序:ASCEND;降序:DESCEND")
|
||||
private String sortOrder;
|
||||
|
||||
/** 父id */
|
||||
@ApiModelProperty(value = "父id")
|
||||
private String parentId;
|
||||
|
||||
/** 字典分类 */
|
||||
@ApiModelProperty(value = "字典分类")
|
||||
private String category;
|
||||
|
||||
/** 字典文字关键词 */
|
||||
@ApiModelProperty(value = "字典文字关键词")
|
||||
private String searchKey;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dict.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 字典树参数
|
||||
*
|
||||
*
|
||||
* @date 2022/7/30 21:49
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevDictTreeParam {
|
||||
|
||||
/** 字典分类 */
|
||||
@ApiModelProperty(value = "字典分类")
|
||||
private String category;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dict.provider;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import mjkf.xinke.dev.api.DevDictApi;
|
||||
|
||||
/**
|
||||
* 字典API接口实现类
|
||||
*
|
||||
*
|
||||
* @date 2022/9/2 16:05
|
||||
*/
|
||||
@Service
|
||||
public class DevDictApiProvider implements DevDictApi {
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dict.service;
|
||||
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import mjkf.xinke.dev.modular.dict.entity.DevDict;
|
||||
import mjkf.xinke.dev.modular.dict.param.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 字典Service接口
|
||||
*
|
||||
*
|
||||
* @date 2022/4/22 10:41
|
||||
**/
|
||||
public interface DevDictService extends IService<DevDict> {
|
||||
|
||||
/**
|
||||
* 获取字典分页
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:08
|
||||
*/
|
||||
Page<DevDict> page(DevDictPageParam devDictPageParam);
|
||||
|
||||
/**
|
||||
* 获取字典列表
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:08
|
||||
*/
|
||||
List<DevDict> list(DevDictListParam devDictListParam);
|
||||
|
||||
/**
|
||||
* 获取字典树
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:08
|
||||
*/
|
||||
List<Tree<String>> tree(DevDictTreeParam devDictTreeParam);
|
||||
|
||||
/**
|
||||
* 添加字典
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:48
|
||||
*/
|
||||
void add(DevDictAddParam devDictAddParam);
|
||||
|
||||
/**
|
||||
* 编辑字典
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 21:13
|
||||
*/
|
||||
void edit(DevDictEditParam devDictEditParam);
|
||||
|
||||
/**
|
||||
* 删除字典
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 21:18
|
||||
*/
|
||||
void delete(List<DevDictIdParam> devDictIdParamList);
|
||||
|
||||
/**
|
||||
* 获取字典详情
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 21:18
|
||||
*/
|
||||
DevDict detail(DevDictIdParam devDictIdParam);
|
||||
|
||||
/**
|
||||
* 获取字典详情
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 21:18
|
||||
*/
|
||||
DevDict queryEntity(String id);
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.dict.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollStreamUtil;
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import cn.hutool.core.lang.tree.TreeNode;
|
||||
import cn.hutool.core.lang.tree.TreeUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.fhs.trans.service.impl.DictionaryTransService;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.stereotype.Service;
|
||||
import mjkf.xinke.common.enums.CommonSortOrderEnum;
|
||||
import mjkf.xinke.common.exception.CommonException;
|
||||
import mjkf.xinke.common.page.CommonPageRequest;
|
||||
import mjkf.xinke.dev.modular.dict.entity.DevDict;
|
||||
import mjkf.xinke.dev.modular.dict.enums.DevDictCategoryEnum;
|
||||
import mjkf.xinke.dev.modular.dict.mapper.DevDictMapper;
|
||||
import mjkf.xinke.dev.modular.dict.param.*;
|
||||
import mjkf.xinke.dev.modular.dict.service.DevDictService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 字典Service接口实现类
|
||||
*
|
||||
*
|
||||
* @date 2022/4/22 10:41
|
||||
**/
|
||||
@Service
|
||||
public class DevDictServiceImpl extends ServiceImpl<DevDictMapper, DevDict> implements DevDictService, InitializingBean {
|
||||
|
||||
private static final String ROOT_PARENT_ID = "0";
|
||||
|
||||
@Resource
|
||||
private DictionaryTransService dictionaryTransService;
|
||||
|
||||
@Override
|
||||
public Page<DevDict> page(DevDictPageParam devDictPageParam) {
|
||||
QueryWrapper<DevDict> queryWrapper = new QueryWrapper<>();
|
||||
// 查询部分字段
|
||||
queryWrapper.lambda().select(DevDict::getId, DevDict::getParentId, DevDict::getCategory, DevDict::getDictLabel,
|
||||
DevDict::getDictValue, DevDict::getSortCode);
|
||||
if (ObjectUtil.isNotEmpty(devDictPageParam.getParentId())) {
|
||||
queryWrapper.lambda().eq(DevDict::getParentId, devDictPageParam.getParentId())
|
||||
.or().eq(DevDict::getId, devDictPageParam.getParentId());
|
||||
}
|
||||
if (ObjectUtil.isNotEmpty(devDictPageParam.getCategory())) {
|
||||
queryWrapper.lambda().eq(DevDict::getCategory, devDictPageParam.getCategory());
|
||||
}
|
||||
if (ObjectUtil.isNotEmpty(devDictPageParam.getSearchKey())) {
|
||||
queryWrapper.lambda().like(DevDict::getDictLabel, devDictPageParam.getSearchKey());
|
||||
}
|
||||
if (ObjectUtil.isAllNotEmpty(devDictPageParam.getSortField(), devDictPageParam.getSortOrder())) {
|
||||
CommonSortOrderEnum.validate(devDictPageParam.getSortOrder());
|
||||
queryWrapper.orderBy(true, devDictPageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
|
||||
StrUtil.toUnderlineCase(devDictPageParam.getSortField()));
|
||||
} else {
|
||||
queryWrapper.lambda().orderByAsc(DevDict::getSortCode);
|
||||
}
|
||||
return this.page(CommonPageRequest.defaultPage(), queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DevDict> list(DevDictListParam devDictListParam) {
|
||||
LambdaQueryWrapper<DevDict> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
if (ObjectUtil.isNotEmpty(devDictListParam.getParentId())) {
|
||||
lambdaQueryWrapper.eq(DevDict::getParentId, devDictListParam.getParentId());
|
||||
}
|
||||
if (ObjectUtil.isNotEmpty(devDictListParam.getCategory())) {
|
||||
lambdaQueryWrapper.eq(DevDict::getCategory, devDictListParam.getCategory());
|
||||
}
|
||||
return this.list(lambdaQueryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tree<String>> tree(DevDictTreeParam devDictTreeParam) {
|
||||
LambdaQueryWrapper<DevDict> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
lambdaQueryWrapper.orderByAsc(DevDict::getSortCode);
|
||||
if (ObjectUtil.isNotEmpty(devDictTreeParam.getCategory())) {
|
||||
lambdaQueryWrapper.eq(DevDict::getCategory, devDictTreeParam.getCategory());
|
||||
}
|
||||
List<DevDict> devDictList = this.list(lambdaQueryWrapper);
|
||||
List<TreeNode<String>> treeNodeList = devDictList.stream().map(devDict ->
|
||||
new TreeNode<>(devDict.getId(), devDict.getParentId(),
|
||||
devDict.getDictLabel(), devDict.getSortCode()).setExtra(JSONUtil.parseObj(devDict)))
|
||||
.collect(Collectors.toList());
|
||||
return TreeUtil.build(treeNodeList, "0");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(DevDictAddParam devDictAddParam) {
|
||||
checkParam(devDictAddParam);
|
||||
DevDict devDict = BeanUtil.toBean(devDictAddParam, DevDict.class);
|
||||
this.save(devDict);
|
||||
refreshTransCache();
|
||||
}
|
||||
|
||||
private void checkParam(DevDictAddParam devDictAddParam) {
|
||||
DevDictCategoryEnum.validate(devDictAddParam.getCategory());
|
||||
boolean hasSameDictLabel = this.count(new LambdaQueryWrapper<DevDict>()
|
||||
.eq(DevDict::getParentId, devDictAddParam.getParentId())
|
||||
.eq(DevDict::getCategory, devDictAddParam.getCategory())
|
||||
.eq(DevDict::getDictLabel, devDictAddParam.getDictLabel())) > 0;
|
||||
if (hasSameDictLabel) {
|
||||
throw new CommonException("存在重复的字典文字,名称为:{}", devDictAddParam.getDictLabel());
|
||||
}
|
||||
|
||||
boolean hasSameDictValue = this.count(new LambdaQueryWrapper<DevDict>()
|
||||
.eq(DevDict::getParentId, devDictAddParam.getParentId())
|
||||
.eq(DevDict::getDictValue, devDictAddParam.getDictValue())) > 0;
|
||||
if (hasSameDictValue) {
|
||||
throw new CommonException("存在重复的字典值,名称为:{}", devDictAddParam.getDictValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void edit(DevDictEditParam devDictEditParam) {
|
||||
DevDict devDict = this.queryEntity(devDictEditParam.getId());
|
||||
checkParam(devDictEditParam);
|
||||
BeanUtil.copyProperties(devDictEditParam, devDict);
|
||||
this.updateById(devDict);
|
||||
refreshTransCache();
|
||||
}
|
||||
|
||||
private void checkParam(DevDictEditParam devDictEditParam) {
|
||||
DevDictCategoryEnum.validate(devDictEditParam.getCategory());
|
||||
boolean hasSameDictLabel = this.count(new LambdaQueryWrapper<DevDict>()
|
||||
.eq(DevDict::getParentId, devDictEditParam.getParentId())
|
||||
.eq(DevDict::getCategory, devDictEditParam.getCategory())
|
||||
.eq(DevDict::getDictLabel, devDictEditParam.getDictLabel())
|
||||
.ne(DevDict::getId, devDictEditParam.getId())) > 0;
|
||||
if (hasSameDictLabel) {
|
||||
throw new CommonException("存在重复的字典文字,名称为:{}", devDictEditParam.getDictLabel());
|
||||
}
|
||||
|
||||
boolean hasSameDictValue = this.count(new LambdaQueryWrapper<DevDict>()
|
||||
.eq(DevDict::getParentId, devDictEditParam.getParentId())
|
||||
.eq(DevDict::getDictValue, devDictEditParam.getDictValue())
|
||||
.ne(DevDict::getId, devDictEditParam.getId())) > 0;
|
||||
if (hasSameDictValue) {
|
||||
throw new CommonException("存在重复的字典值,名称为:{}", devDictEditParam.getDictValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(List<DevDictIdParam> devDictIdParamList) {
|
||||
List<String> devDictIdList = CollStreamUtil.toList(devDictIdParamList, DevDictIdParam::getId);
|
||||
if (ObjectUtil.isNotEmpty(devDictIdList)) {
|
||||
boolean systemDict = this.listByIds(devDictIdList).stream().map(DevDict::getCategory)
|
||||
.collect(Collectors.toSet()).contains(DevDictCategoryEnum.FRM.getValue());
|
||||
if (systemDict) {
|
||||
throw new CommonException("不可删除系统内置字典");
|
||||
}
|
||||
// 删除
|
||||
this.removeByIds(devDictIdList);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DevDict detail(DevDictIdParam devDictIdParam) {
|
||||
return this.queryEntity(devDictIdParam.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DevDict queryEntity(String id) {
|
||||
DevDict devDict = this.getById(id);
|
||||
if (ObjectUtil.isEmpty(devDict)) {
|
||||
throw new CommonException("字典不存在,id值为:{}", id);
|
||||
}
|
||||
return devDict;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
refreshTransCache();
|
||||
}
|
||||
|
||||
private void refreshTransCache() {
|
||||
// 异步不阻塞主线程,不会 增加启动用时
|
||||
CompletableFuture.supplyAsync(() -> {
|
||||
// 使用redis能解决共享问题,但是性能没有直接取缓存的好。
|
||||
dictionaryTransService.makeUseRedis();
|
||||
List<DevDict> devDictList = super.list(new LambdaQueryWrapper<>());
|
||||
// 非root级别的字典根据ParentId分组
|
||||
Map<String,List<DevDict>> devDictGroupByPIDMap = devDictList.stream().filter(dict -> !ROOT_PARENT_ID
|
||||
.equals(dict.getParentId())).collect(Collectors.groupingBy(DevDict::getParentId));
|
||||
Map<String,String> parentDictIdValMap = devDictList.stream().filter(dict -> ROOT_PARENT_ID
|
||||
.equals(dict.getParentId())).collect(Collectors.toMap(DevDict::getId, DevDict::getDictValue));
|
||||
for (String parentId : parentDictIdValMap.keySet()) {
|
||||
if(devDictGroupByPIDMap.containsKey(parentId)){
|
||||
dictionaryTransService.refreshCache(parentDictIdValMap.get(parentId), devDictGroupByPIDMap.get(parentId).stream()
|
||||
.collect(Collectors.toMap(DevDict::getDictValue, DevDict::getDictLabel)));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.email.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import mjkf.xinke.common.annotation.CommonLog;
|
||||
import mjkf.xinke.common.pojo.CommonResult;
|
||||
import mjkf.xinke.common.pojo.CommonValidList;
|
||||
import mjkf.xinke.dev.modular.email.entity.DevEmail;
|
||||
import mjkf.xinke.dev.modular.email.param.*;
|
||||
import mjkf.xinke.dev.modular.email.service.DevEmailService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
||||
/**
|
||||
* 邮件控制器
|
||||
*
|
||||
*
|
||||
* @date 2022/2/23 18:26
|
||||
**/
|
||||
@Api(tags = "邮件控制器")
|
||||
@ApiSupport(author = "SNOWY_TEAM", order = 3)
|
||||
@RestController
|
||||
@Validated
|
||||
public class DevEmailController {
|
||||
|
||||
@Resource
|
||||
private DevEmailService devEmailService;
|
||||
|
||||
/**
|
||||
* 发送邮件——本地TXT
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:47
|
||||
*/
|
||||
@ApiOperationSupport(order = 1)
|
||||
@ApiOperation("发送本地文本邮件")
|
||||
@CommonLog("发送本地文本邮件")
|
||||
@PostMapping("/dev/email/sendLocalTxt")
|
||||
public CommonResult<String> sendLocal(@RequestBody @Valid DevEmailSendLocalTxtParam devEmailSendLocalTxtParam) {
|
||||
devEmailService.sendLocal(devEmailSendLocalTxtParam);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送邮件——本地HTML
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:47
|
||||
*/
|
||||
@ApiOperationSupport(order = 2)
|
||||
@ApiOperation("发送本地HTML邮件")
|
||||
@CommonLog("发送本地HTML邮件")
|
||||
@PostMapping("/dev/email/sendLocalHtml")
|
||||
public CommonResult<String> sendLocal(@RequestBody @Valid DevEmailSendLocalHtmlParam devEmailSendLocalHtmlParam) {
|
||||
devEmailService.sendLocal(devEmailSendLocalHtmlParam);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送邮件——阿里云TXT
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:47
|
||||
*/
|
||||
@ApiOperationSupport(order = 3)
|
||||
@ApiOperation("发送阿里云文本邮件")
|
||||
@CommonLog("发送阿里云文本邮件")
|
||||
@PostMapping("/dev/email/sendAliyunTxt")
|
||||
public CommonResult<String> sendAliyun(@RequestBody @Valid DevEmailSendAliyunTxtParam devEmailSendAliyunTxtParam) {
|
||||
devEmailService.sendAliyun(devEmailSendAliyunTxtParam);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送邮件——阿里云HTML
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:47
|
||||
*/
|
||||
@ApiOperationSupport(order = 4)
|
||||
@ApiOperation("发送阿里云HTML邮件")
|
||||
@CommonLog("发送阿里云HTML邮件")
|
||||
@PostMapping("/dev/email/sendAliyunHtml")
|
||||
public CommonResult<String> sendAliyun(@RequestBody @Valid DevEmailSendAliyunHtmlParam devEmailSendAliyunHtmlParam) {
|
||||
devEmailService.sendAliyun(devEmailSendAliyunHtmlParam);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送邮件——阿里云TMP
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:47
|
||||
*/
|
||||
@ApiOperationSupport(order = 5)
|
||||
@ApiOperation("发送阿里云模板邮件")
|
||||
@CommonLog("发送阿里云模板邮件")
|
||||
@PostMapping("/dev/email/sendAliyunTmp")
|
||||
public CommonResult<String> sendAliyun(@RequestBody @Valid DevEmailSendAliyunTmpParam devEmailSendAliyunTmpParam) {
|
||||
devEmailService.sendAliyun(devEmailSendAliyunTmpParam);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送邮件——腾讯云TXT
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:47
|
||||
*/
|
||||
@ApiOperationSupport(order = 6)
|
||||
@ApiOperation("发送腾讯云文本邮件")
|
||||
@CommonLog("发送腾讯云文本邮件")
|
||||
@PostMapping("/dev/email/sendTencentTxt")
|
||||
public CommonResult<String> sendTencent(@RequestBody @Valid DevEmailSendTencentTxtParam devEmailSendTencentTxtParam) {
|
||||
devEmailService.sendTencent(devEmailSendTencentTxtParam);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送邮件——腾讯云HTML
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:47
|
||||
*/
|
||||
@ApiOperationSupport(order = 7)
|
||||
@ApiOperation("发送腾讯云HTML邮件")
|
||||
@CommonLog("发送腾讯云HTML邮件")
|
||||
@PostMapping("/dev/email/sentTencentHtml")
|
||||
public CommonResult<String> sendTencent(@RequestBody @Valid DevEmailSendTencentHtmlParam devEmailSendTencentHtmlParam) {
|
||||
devEmailService.sendTencent(devEmailSendTencentHtmlParam);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送邮件——腾讯云TMP
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:47
|
||||
*/
|
||||
@ApiOperationSupport(order = 8)
|
||||
@ApiOperation("发送腾讯云模板邮件")
|
||||
@CommonLog("发送腾讯云模板邮件")
|
||||
@PostMapping("/dev/email/sentTencentTmp")
|
||||
public CommonResult<String> sendTencent(@RequestBody @Valid DevEmailSendTencentTmpParam devEmailSendTencentTmpParam) {
|
||||
devEmailService.sendTencent(devEmailSendTencentTmpParam);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取邮件分页
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 9)
|
||||
@ApiOperation("获取邮件分页")
|
||||
@GetMapping("/dev/email/page")
|
||||
public CommonResult<Page<DevEmail>> page(DevEmailPageParam devEmailPageParam) {
|
||||
return CommonResult.data(devEmailService.page(devEmailPageParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除邮件
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 10)
|
||||
@ApiOperation("删除邮件")
|
||||
@CommonLog("删除邮件")
|
||||
@PostMapping("/dev/email/delete")
|
||||
public CommonResult<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
|
||||
CommonValidList<DevEmailIdParam> devEmailIdParamList) {
|
||||
devEmailService.delete(devEmailIdParamList);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取邮件详情
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 11)
|
||||
@ApiOperation("获取邮件详情")
|
||||
@GetMapping("/dev/email/detail")
|
||||
public CommonResult<DevEmail> detail(@Valid DevEmailIdParam devEmailIdParam) {
|
||||
return CommonResult.data(devEmailService.detail(devEmailIdParam));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.email.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import mjkf.xinke.common.pojo.CommonEntity;
|
||||
|
||||
/**
|
||||
* 邮件实体
|
||||
*
|
||||
*
|
||||
* @date 2022/2/23 18:27
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("DEV_EMAIL")
|
||||
public class DevEmail extends CommonEntity {
|
||||
|
||||
/** id */
|
||||
@ApiModelProperty(value = "主键", position = 1)
|
||||
private String id;
|
||||
|
||||
/** 租户id */
|
||||
@ApiModelProperty(value = "租户id", position = 2)
|
||||
private String tenantId;
|
||||
|
||||
/** 邮件引擎 */
|
||||
@ApiModelProperty(value = "邮件引擎", position = 3)
|
||||
private String engine;
|
||||
|
||||
/** 发件人邮箱 */
|
||||
@ApiModelProperty(value = "发件人邮箱", position = 4)
|
||||
private String sendAccount;
|
||||
|
||||
/** 发件人昵称 */
|
||||
@ApiModelProperty(value = "发件人昵称", position = 5)
|
||||
private String sendUser;
|
||||
|
||||
/** 接收人 */
|
||||
@ApiModelProperty(value = "接收人", position = 6)
|
||||
private String receiveAccounts;
|
||||
|
||||
/** 邮件主题 */
|
||||
@ApiModelProperty(value = "邮件主题", position = 7)
|
||||
private String subject;
|
||||
|
||||
/** 邮件正文 */
|
||||
@ApiModelProperty(value = "邮件正文", position = 8)
|
||||
private String content;
|
||||
|
||||
/** 标签名 */
|
||||
@ApiModelProperty(value = "标签名", position = 9)
|
||||
private String tagName;
|
||||
|
||||
/** 模板名 */
|
||||
@ApiModelProperty(value = "模板名", position = 10)
|
||||
private String templateName;
|
||||
|
||||
/** 发送参数 */
|
||||
@ApiModelProperty(value = "发送参数", position = 11)
|
||||
private String templateParam;
|
||||
|
||||
/** 回执信息 */
|
||||
@ApiModelProperty(value = "回执信息", position = 12)
|
||||
private String receiptInfo;
|
||||
|
||||
/** 扩展信息 */
|
||||
@ApiModelProperty(value = "扩展信息", position = 13)
|
||||
private String extJson;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.email.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 邮件发送引擎类型枚举
|
||||
*
|
||||
*
|
||||
* @date 2022/6/16 16:14
|
||||
**/
|
||||
@Getter
|
||||
public enum DevEmailEngineTypeEnum {
|
||||
|
||||
/** 本地 */
|
||||
LOCAL("LOCAL"),
|
||||
|
||||
/** 阿里云 */
|
||||
ALIYUN("ALIYUN"),
|
||||
|
||||
/** 腾讯云 */
|
||||
TENCENT("TENCENT");
|
||||
|
||||
private final String value;
|
||||
|
||||
DevEmailEngineTypeEnum(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.email.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 邮件类型枚举
|
||||
*
|
||||
*
|
||||
* @date 2022/6/16 16:14
|
||||
**/
|
||||
@Getter
|
||||
public enum DevEmailTypeEnum {
|
||||
|
||||
/** 纯文本 */
|
||||
TEXT("TEXT"),
|
||||
|
||||
/** 富文本 */
|
||||
HTML("HTML"),
|
||||
|
||||
/** 模板 */
|
||||
TEMPLATE("TEMPLATE");
|
||||
|
||||
private final String value;
|
||||
|
||||
DevEmailTypeEnum(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.email.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import mjkf.xinke.dev.modular.email.entity.DevEmail;
|
||||
|
||||
/**
|
||||
* 邮件Mapper接口
|
||||
*
|
||||
*
|
||||
* @date 2022/2/23 18:40
|
||||
**/
|
||||
public interface DevEmailMapper extends BaseMapper<DevEmail> {
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="mjkf.xinke.dev.modular.email.mapper.DevEmailMapper">
|
||||
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.email.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 邮件Id参数
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 15:38
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevEmailIdParam {
|
||||
|
||||
/** id */
|
||||
@ApiModelProperty(value = "id", required = true)
|
||||
@NotBlank(message = "id不能为空")
|
||||
private String id;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.email.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 邮件查询参数
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 15:38
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevEmailPageParam {
|
||||
|
||||
/** 当前页 */
|
||||
@ApiModelProperty(value = "当前页码")
|
||||
private Integer current;
|
||||
|
||||
/** 每页条数 */
|
||||
@ApiModelProperty(value = "每页条数")
|
||||
private Integer size;
|
||||
|
||||
/** 排序字段 */
|
||||
@ApiModelProperty(value = "排序字段,字段驼峰名称,如:userName")
|
||||
private String sortField;
|
||||
|
||||
/** 排序方式 */
|
||||
@ApiModelProperty(value = "排序方式,升序:ASCEND;降序:DESCEND")
|
||||
private String sortOrder;
|
||||
|
||||
/** 邮件引擎 */
|
||||
@ApiModelProperty(value = "邮件引擎")
|
||||
private String engine;
|
||||
|
||||
/** 邮件主题关键词 */
|
||||
@ApiModelProperty(value = "邮件主题关键词")
|
||||
private String searchKey;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.email.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 邮件发送——阿里云HTML参数
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 15:38
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevEmailSendAliyunHtmlParam {
|
||||
|
||||
/** 发件人邮箱 */
|
||||
@ApiModelProperty(value = "发件人邮箱,即管理控制台中配置的发信地址", required = true, position = 1)
|
||||
@NotBlank(message = "sendAccount不能为空")
|
||||
private String sendAccount;
|
||||
|
||||
/** 接收人 */
|
||||
@ApiModelProperty(value = "接收人邮箱地址,多个逗号拼接", required = true, position = 2)
|
||||
@NotBlank(message = "receiveAccounts不能为空")
|
||||
private String receiveAccounts;
|
||||
|
||||
/** 邮件主题 */
|
||||
@ApiModelProperty(value = "邮件主题", required = true, position = 3)
|
||||
@NotBlank(message = "subject不能为空")
|
||||
private String subject;
|
||||
|
||||
/** 邮件正文 */
|
||||
@ApiModelProperty(value = "邮件正文", required = true, position = 4)
|
||||
@NotBlank(message = "content不能为空")
|
||||
private String content;
|
||||
|
||||
/** 发件人昵称 */
|
||||
@ApiModelProperty(value = "发件人昵称", position = 5)
|
||||
private String sendUser;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.email.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 邮件发送——阿里云TMP参数
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 15:38
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevEmailSendAliyunTmpParam {
|
||||
|
||||
/** 发件人邮箱 */
|
||||
@ApiModelProperty(value = "管理控制台中配置的发信地址", required = true, position = 1)
|
||||
@NotBlank(message = "sendAccount不能为空")
|
||||
private String sendAccount;
|
||||
|
||||
/** 接收人 */
|
||||
@ApiModelProperty(value = "预先创建且上传了收件人的收件人列表名称", required = true, position = 2)
|
||||
@NotBlank(message = "receiveAccounts不能为空")
|
||||
private String receiveAccounts;
|
||||
|
||||
/** 模板名 */
|
||||
@ApiModelProperty(value = "预先创建且通过审核的模板名称", required = true, position = 4)
|
||||
@NotBlank(message = "templateName不能为空")
|
||||
private String templateName;
|
||||
|
||||
/** 标签名 */
|
||||
@ApiModelProperty(value = "标签名", position = 5)
|
||||
private String tagName;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.email.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 邮件发送——阿里云TXT参数
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 15:38
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevEmailSendAliyunTxtParam {
|
||||
|
||||
/** 发件人邮箱 */
|
||||
@ApiModelProperty(value = "发件人邮箱,即管理控制台中配置的发信地址", required = true, position = 1)
|
||||
@NotBlank(message = "sendAccount不能为空")
|
||||
private String sendAccount;
|
||||
|
||||
/** 接收人 */
|
||||
@ApiModelProperty(value = "接收人邮箱地址,多个逗号拼接", required = true, position = 2)
|
||||
@NotBlank(message = "receiveAccounts不能为空")
|
||||
private String receiveAccounts;
|
||||
|
||||
/** 邮件主题 */
|
||||
@ApiModelProperty(value = "邮件主题", required = true, position = 3)
|
||||
@NotBlank(message = "subject不能为空")
|
||||
private String subject;
|
||||
|
||||
/** 邮件正文 */
|
||||
@ApiModelProperty(value = "邮件正文", required = true, position = 4)
|
||||
@NotBlank(message = "content不能为空")
|
||||
private String content;
|
||||
|
||||
/** 发件人昵称 */
|
||||
@ApiModelProperty(value = "发件人昵称", position = 5)
|
||||
private String sendUser;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.email.param;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 邮件发送——本地HTML参数
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 15:38
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevEmailSendLocalHtmlParam {
|
||||
|
||||
/** 接收人 */
|
||||
@ApiModelProperty(value = "接收人邮箱地址,多个逗号拼接", required = true, position = 1)
|
||||
@NotBlank(message = "receiveAccounts不能为空")
|
||||
private String receiveAccounts;
|
||||
|
||||
/** 邮件主题 */
|
||||
@ApiModelProperty(value = "邮件主题", required = true, position = 2)
|
||||
@NotBlank(message = "subject不能为空")
|
||||
private String subject;
|
||||
|
||||
/** 邮件正文 */
|
||||
@ApiModelProperty(value = "邮件正文", required = true, position = 3)
|
||||
@NotBlank(message = "content不能为空")
|
||||
private String content;
|
||||
|
||||
/** 图片展位符 */
|
||||
@ApiModelProperty(value = "图片展位符", position = 4, hidden = true)
|
||||
private Map<String, InputStream> imageMap = MapUtil.newHashMap();
|
||||
|
||||
/** 附件列表 */
|
||||
@ApiModelProperty(value = "附件列表", position = 5, hidden = true)
|
||||
private List<File> files = CollectionUtil.newArrayList();
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.email.param;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 邮件发送——本地TXT参数
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 15:38
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevEmailSendLocalTxtParam {
|
||||
|
||||
/** 接收人 */
|
||||
@ApiModelProperty(value = "接收人邮箱地址,多个逗号拼接", required = true, position = 1)
|
||||
@NotBlank(message = "receiveAccounts不能为空")
|
||||
private String receiveAccounts;
|
||||
|
||||
/** 邮件主题 */
|
||||
@ApiModelProperty(value = "邮件主题", required = true, position = 2)
|
||||
@NotBlank(message = "subject不能为空")
|
||||
private String subject;
|
||||
|
||||
/** 邮件正文 */
|
||||
@ApiModelProperty(value = "邮件正文", required = true, position = 3)
|
||||
@NotBlank(message = "content不能为空")
|
||||
private String content;
|
||||
|
||||
/** 附件列表 */
|
||||
@ApiModelProperty(value = "附件列表", position = 4, hidden = true)
|
||||
private List<File> files = CollectionUtil.newArrayList();
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.email.param;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 邮件发送——腾讯云HTML参数
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 15:38
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevEmailSendTencentHtmlParam {
|
||||
|
||||
/** 发件人邮箱 */
|
||||
@ApiModelProperty(value = "管理控制台中配置的发信地址", required = true, position = 1)
|
||||
@NotBlank(message = "sendAccount不能为空")
|
||||
private String sendAccount;
|
||||
|
||||
/** 接收人 */
|
||||
@ApiModelProperty(value = "接收人邮箱地址,多个逗号拼接", required = true, position = 2)
|
||||
@NotBlank(message = "receiveAccounts不能为空")
|
||||
private String receiveAccounts;
|
||||
|
||||
/** 邮件主题 */
|
||||
@ApiModelProperty(value = "邮件主题", required = true, position = 3)
|
||||
@NotBlank(message = "subject不能为空")
|
||||
private String subject;
|
||||
|
||||
/** 邮件正文 */
|
||||
@ApiModelProperty(value = "邮件正文", required = true, position = 4)
|
||||
@NotBlank(message = "content不能为空")
|
||||
private String content;
|
||||
|
||||
/** 发件人昵称 */
|
||||
@ApiModelProperty(value = "发件人昵称", position = 5)
|
||||
private String sendUser;
|
||||
|
||||
/** 附件列表 */
|
||||
@ApiModelProperty(value = "附件列表", position = 6, hidden = true)
|
||||
List<JSONObject> attachmentList = CollectionUtil.newArrayList();
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.email.param;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 邮件发送——腾讯云TMP参数
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 15:38
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevEmailSendTencentTmpParam {
|
||||
|
||||
/** 发件人邮箱 */
|
||||
@ApiModelProperty(value = "管理控制台中配置的发信地址", required = true, position = 1)
|
||||
@NotBlank(message = "sendAccount不能为空")
|
||||
private String sendAccount;
|
||||
|
||||
/** 接收人 */
|
||||
@ApiModelProperty(value = "预先创建且上传了收件人的收件人列表id", required = true, position = 2)
|
||||
@NotBlank(message = "receiveAccounts不能为空")
|
||||
private String receiveAccounts;
|
||||
|
||||
/** 模板名 */
|
||||
@ApiModelProperty(value = "预先创建且通过审核的模板Id", required = true, position = 3)
|
||||
@NotBlank(message = "templateName不能为空")
|
||||
private String templateName;
|
||||
|
||||
/** 邮件主题 */
|
||||
@ApiModelProperty(value = "邮件主题", required = true, position = 4)
|
||||
@NotBlank(message = "subject不能为空")
|
||||
private String subject;
|
||||
|
||||
/** 发件人昵称 */
|
||||
@ApiModelProperty(value = "发件人昵称", position = 5)
|
||||
private String sendUser;
|
||||
|
||||
/** 发送参数 */
|
||||
@ApiModelProperty(value = "预先创建且通过审核的模板的参数json", position = 6)
|
||||
private String templateParam;
|
||||
|
||||
/** 附件列表 */
|
||||
@ApiModelProperty(value = "附件列表", position = 7, hidden = true)
|
||||
List<JSONObject> attachmentList = CollectionUtil.newArrayList();
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.email.param;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 邮件发送——腾讯云TXT参数
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 15:38
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevEmailSendTencentTxtParam {
|
||||
|
||||
/** 发件人邮箱 */
|
||||
@ApiModelProperty(value = "管理控制台中配置的发信地址", required = true, position = 1)
|
||||
@NotBlank(message = "sendAccount不能为空")
|
||||
private String sendAccount;
|
||||
|
||||
/** 接收人 */
|
||||
@ApiModelProperty(value = "接收人邮箱地址,多个逗号拼接", required = true, position = 2)
|
||||
@NotBlank(message = "receiveAccounts不能为空")
|
||||
private String receiveAccounts;
|
||||
|
||||
/** 邮件主题 */
|
||||
@ApiModelProperty(value = "邮件主题", required = true, position = 3)
|
||||
@NotBlank(message = "subject不能为空")
|
||||
private String subject;
|
||||
|
||||
/** 邮件正文 */
|
||||
@ApiModelProperty(value = "邮件正文", required = true, position = 4)
|
||||
@NotBlank(message = "content不能为空")
|
||||
private String content;
|
||||
|
||||
/** 发件人昵称 */
|
||||
@ApiModelProperty(value = "发件人昵称", position = 5)
|
||||
private String sendUser;
|
||||
|
||||
/** 附件列表 */
|
||||
@ApiModelProperty(value = "附件列表", position = 6, hidden = true)
|
||||
List<JSONObject> attachmentList = CollectionUtil.newArrayList();
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.email.provider;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import org.springframework.stereotype.Service;
|
||||
import mjkf.xinke.dev.api.DevEmailApi;
|
||||
import mjkf.xinke.dev.modular.email.param.*;
|
||||
import mjkf.xinke.dev.modular.email.service.DevEmailService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 邮件API接口提供者
|
||||
*
|
||||
*
|
||||
* @date 2022/6/22 15:32
|
||||
**/
|
||||
@Service
|
||||
public class DevEmailApiProvider implements DevEmailApi {
|
||||
|
||||
@Resource
|
||||
private DevEmailService devEmailService;
|
||||
|
||||
@Override
|
||||
public void sendTextEmailLocal(String tos, String subject, String content, List<File> files) {
|
||||
DevEmailSendLocalTxtParam devEmailSendLocalTxtParam = new DevEmailSendLocalTxtParam();
|
||||
devEmailSendLocalTxtParam.setReceiveAccounts(tos);
|
||||
devEmailSendLocalTxtParam.setSubject(subject);
|
||||
devEmailSendLocalTxtParam.setContent(content);
|
||||
devEmailSendLocalTxtParam.setFiles(files);
|
||||
devEmailService.sendLocal(devEmailSendLocalTxtParam);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendHtmlEmailLocal(String tos, String subject, String content, Map<String, InputStream> imageMap, List<File> files) {
|
||||
DevEmailSendLocalHtmlParam devEmailSendLocalHtmlParam = new DevEmailSendLocalHtmlParam();
|
||||
devEmailSendLocalHtmlParam.setReceiveAccounts(tos);
|
||||
devEmailSendLocalHtmlParam.setSubject(subject);
|
||||
devEmailSendLocalHtmlParam.setContent(content);
|
||||
devEmailSendLocalHtmlParam.setImageMap(imageMap);
|
||||
devEmailSendLocalHtmlParam.setFiles(files);
|
||||
devEmailService.sendLocal(devEmailSendLocalHtmlParam);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTextEmailAliyun(String from, String user, String tos, String subject, String content) {
|
||||
DevEmailSendAliyunTxtParam devEmailSendAliyunTxtParam = new DevEmailSendAliyunTxtParam();
|
||||
devEmailSendAliyunTxtParam.setSendAccount(from);
|
||||
devEmailSendAliyunTxtParam.setSendUser(user);
|
||||
devEmailSendAliyunTxtParam.setReceiveAccounts(tos);
|
||||
devEmailSendAliyunTxtParam.setSubject(subject);
|
||||
devEmailSendAliyunTxtParam.setContent(content);
|
||||
devEmailService.sendAliyun(devEmailSendAliyunTxtParam);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendHtmlEmailAliyun(String from, String user, String tos, String subject, String content) {
|
||||
DevEmailSendAliyunHtmlParam devEmailSendAliyunHtmlParam = new DevEmailSendAliyunHtmlParam();
|
||||
devEmailSendAliyunHtmlParam.setSendAccount(from);
|
||||
devEmailSendAliyunHtmlParam.setSendUser(user);
|
||||
devEmailSendAliyunHtmlParam.setReceiveAccounts(tos);
|
||||
devEmailSendAliyunHtmlParam.setSubject(subject);
|
||||
devEmailSendAliyunHtmlParam.setContent(content);
|
||||
devEmailService.sendAliyun(devEmailSendAliyunHtmlParam);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendEmailWithTemplateAliyun(String from, String tagName, String toName, String templateName) {
|
||||
DevEmailSendAliyunTmpParam devEmailSendAliyunTmpParam = new DevEmailSendAliyunTmpParam();
|
||||
devEmailSendAliyunTmpParam.setReceiveAccounts(toName);
|
||||
devEmailSendAliyunTmpParam.setTagName(tagName);
|
||||
devEmailSendAliyunTmpParam.setTemplateName(templateName);
|
||||
devEmailService.sendAliyun(devEmailSendAliyunTmpParam);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTextEmailTencent(String from, String user, String tos, String subject, String content, List<JSONObject> attachmentList) {
|
||||
DevEmailSendTencentTxtParam devEmailSendTencentTxtParam = new DevEmailSendTencentTxtParam();
|
||||
devEmailSendTencentTxtParam.setSendAccount(from);
|
||||
devEmailSendTencentTxtParam.setSendUser(user);
|
||||
devEmailSendTencentTxtParam.setReceiveAccounts(tos);
|
||||
devEmailSendTencentTxtParam.setSubject(subject);
|
||||
devEmailSendTencentTxtParam.setContent(content);
|
||||
devEmailSendTencentTxtParam.setAttachmentList(attachmentList);
|
||||
devEmailService.sendTencent(devEmailSendTencentTxtParam);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendHtmlEmailTencent(String from, String user, String tos, String subject, String content, List<JSONObject> attachmentList) {
|
||||
DevEmailSendTencentHtmlParam devEmailSendTencentHtmlParam = new DevEmailSendTencentHtmlParam();
|
||||
devEmailSendTencentHtmlParam.setSendAccount(from);
|
||||
devEmailSendTencentHtmlParam.setSendUser(user);
|
||||
devEmailSendTencentHtmlParam.setReceiveAccounts(tos);
|
||||
devEmailSendTencentHtmlParam.setSubject(subject);
|
||||
devEmailSendTencentHtmlParam.setContent(content);
|
||||
devEmailSendTencentHtmlParam.setAttachmentList(attachmentList);
|
||||
devEmailService.sendTencent(devEmailSendTencentHtmlParam);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendEmailWithTemplateTencent(String from, String user, String toId, String templateId, String templateParam, String subject, List<JSONObject> attachmentList) {
|
||||
DevEmailSendTencentTmpParam devEmailSendTencentTmpParam = new DevEmailSendTencentTmpParam();
|
||||
devEmailSendTencentTmpParam.setSendAccount(from);
|
||||
devEmailSendTencentTmpParam.setSendUser(user);
|
||||
devEmailSendTencentTmpParam.setReceiveAccounts(toId);
|
||||
devEmailSendTencentTmpParam.setTemplateName(templateId);
|
||||
devEmailSendTencentTmpParam.setAttachmentList(attachmentList);
|
||||
devEmailService.sendTencent(devEmailSendTencentTmpParam);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.email.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import mjkf.xinke.dev.modular.email.entity.DevEmail;
|
||||
import mjkf.xinke.dev.modular.email.param.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 邮件Service接口
|
||||
*
|
||||
*
|
||||
* @date 2022/2/23 18:27
|
||||
**/
|
||||
public interface DevEmailService extends IService<DevEmail> {
|
||||
|
||||
/**
|
||||
* 发送邮件——本地TXT
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 18:37
|
||||
**/
|
||||
void sendLocal(DevEmailSendLocalTxtParam devEmailSendLocalTxtParam);
|
||||
|
||||
/**
|
||||
* 发送邮件——本地HTML
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 18:37
|
||||
**/
|
||||
void sendLocal(DevEmailSendLocalHtmlParam devEmailSendLocalHtmlParam);
|
||||
|
||||
/**
|
||||
* 发送邮件——阿里云TXT
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 18:37
|
||||
**/
|
||||
void sendAliyun(DevEmailSendAliyunTxtParam devEmailSendAliyunTxtParam);
|
||||
|
||||
/**
|
||||
* 发送邮件——阿里云HTML
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 18:37
|
||||
**/
|
||||
void sendAliyun(DevEmailSendAliyunHtmlParam devEmailSendAliyunHtmlParam);
|
||||
|
||||
/**
|
||||
* 发送邮件——阿里云TMP
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 18:37
|
||||
**/
|
||||
void sendAliyun(DevEmailSendAliyunTmpParam devEmailSendAliyunTmpParam);
|
||||
|
||||
/**
|
||||
* 发送邮件——腾讯云TXT
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 18:37
|
||||
**/
|
||||
void sendTencent(DevEmailSendTencentTxtParam devEmailSendTencentTxtParam);
|
||||
|
||||
/**
|
||||
* 发送邮件——腾讯云HTML
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 18:37
|
||||
**/
|
||||
void sendTencent(DevEmailSendTencentHtmlParam devEmailSendTencentHtmlParam);
|
||||
|
||||
/**
|
||||
* 发送邮件——腾讯云TMP
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 18:37
|
||||
**/
|
||||
void sendTencent(DevEmailSendTencentTmpParam devEmailSendTencentTmpParam);
|
||||
|
||||
/**
|
||||
* 获取邮件分页
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:08
|
||||
*/
|
||||
Page<DevEmail> page(DevEmailPageParam devEmailPageParam);
|
||||
|
||||
/**
|
||||
* 删除邮件
|
||||
*
|
||||
*
|
||||
* @date 2022/8/4 10:36
|
||||
**/
|
||||
void delete(List<DevEmailIdParam> devEmailIdParamList);
|
||||
|
||||
/**
|
||||
* 获取邮件详情
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:08
|
||||
*/
|
||||
DevEmail detail(DevEmailIdParam devEmailIdParam);
|
||||
|
||||
/**
|
||||
* 获取邮件详情
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:08
|
||||
*/
|
||||
DevEmail queryEntity(String id);
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.email.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollStreamUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.mail.MailAccount;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import mjkf.xinke.common.enums.CommonSortOrderEnum;
|
||||
import mjkf.xinke.common.exception.CommonException;
|
||||
import mjkf.xinke.common.page.CommonPageRequest;
|
||||
import mjkf.xinke.common.util.CommonEmailUtil;
|
||||
import mjkf.xinke.dev.modular.email.entity.DevEmail;
|
||||
import mjkf.xinke.dev.modular.email.enums.DevEmailEngineTypeEnum;
|
||||
import mjkf.xinke.dev.modular.email.mapper.DevEmailMapper;
|
||||
import mjkf.xinke.dev.modular.email.param.*;
|
||||
import mjkf.xinke.dev.modular.email.service.DevEmailService;
|
||||
import mjkf.xinke.dev.modular.email.util.DevEmailAliyunUtil;
|
||||
import mjkf.xinke.dev.modular.email.util.DevEmailLocalUtil;
|
||||
import mjkf.xinke.dev.modular.email.util.DevEmailTencentUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 邮件Service接口实现类
|
||||
*
|
||||
*
|
||||
* @date 2022/2/23 18:43
|
||||
**/
|
||||
@Service
|
||||
public class DevEmailServiceImpl extends ServiceImpl<DevEmailMapper, DevEmail> implements DevEmailService {
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void sendLocal(DevEmailSendLocalTxtParam devEmailSendLocalTxtParam) {
|
||||
CommonEmailUtil.validEmail(devEmailSendLocalTxtParam.getReceiveAccounts());
|
||||
String receiptInfo = DevEmailLocalUtil.sendTextEmail(devEmailSendLocalTxtParam.getReceiveAccounts(),
|
||||
devEmailSendLocalTxtParam.getSubject(), devEmailSendLocalTxtParam.getContent(), devEmailSendLocalTxtParam.getFiles());
|
||||
DevEmail devEmail = new DevEmail();
|
||||
BeanUtil.copyProperties(devEmailSendLocalTxtParam, devEmail);
|
||||
devEmail.setEngine(DevEmailEngineTypeEnum.LOCAL.getValue());
|
||||
devEmail.setReceiptInfo(receiptInfo);
|
||||
MailAccount client = DevEmailLocalUtil.getClient();
|
||||
devEmail.setSendAccount(client.getFrom());
|
||||
devEmail.setSendUser(client.getUser());
|
||||
this.save(devEmail);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void sendLocal(DevEmailSendLocalHtmlParam devEmailSendLocalHtmlParam) {
|
||||
CommonEmailUtil.validEmail(devEmailSendLocalHtmlParam.getReceiveAccounts());
|
||||
String receiptInfo = DevEmailLocalUtil.sendHtmlEmail(devEmailSendLocalHtmlParam.getReceiveAccounts(),
|
||||
devEmailSendLocalHtmlParam.getSubject(), devEmailSendLocalHtmlParam.getContent(), devEmailSendLocalHtmlParam.getImageMap(),
|
||||
devEmailSendLocalHtmlParam.getFiles());
|
||||
DevEmail devEmail = new DevEmail();
|
||||
BeanUtil.copyProperties(devEmailSendLocalHtmlParam, devEmail);
|
||||
devEmail.setEngine(DevEmailEngineTypeEnum.LOCAL.getValue());
|
||||
devEmail.setReceiptInfo(receiptInfo);
|
||||
MailAccount client = DevEmailLocalUtil.getClient();
|
||||
devEmail.setSendAccount(client.getFrom());
|
||||
devEmail.setSendUser(client.getUser());
|
||||
this.save(devEmail);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void sendAliyun(DevEmailSendAliyunTxtParam devEmailSendAliyunTxtParam) {
|
||||
CommonEmailUtil.validEmail(devEmailSendAliyunTxtParam.getReceiveAccounts());
|
||||
String receiptInfo = DevEmailAliyunUtil.sendTextEmail(devEmailSendAliyunTxtParam.getSendAccount(),
|
||||
devEmailSendAliyunTxtParam.getSendUser(), devEmailSendAliyunTxtParam.getReceiveAccounts(),
|
||||
devEmailSendAliyunTxtParam.getSubject(), devEmailSendAliyunTxtParam.getContent());
|
||||
DevEmail devEmail = new DevEmail();
|
||||
BeanUtil.copyProperties(devEmailSendAliyunTxtParam, devEmail);
|
||||
devEmail.setEngine(DevEmailEngineTypeEnum.ALIYUN.getValue());
|
||||
devEmail.setReceiptInfo(receiptInfo);
|
||||
this.save(devEmail);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void sendAliyun(DevEmailSendAliyunHtmlParam devEmailSendAliyunHtmlParam) {
|
||||
CommonEmailUtil.validEmail(devEmailSendAliyunHtmlParam.getReceiveAccounts());
|
||||
String receiptInfo = DevEmailAliyunUtil.sendHtmlEmail(devEmailSendAliyunHtmlParam.getSendAccount(),
|
||||
devEmailSendAliyunHtmlParam.getSendUser(), devEmailSendAliyunHtmlParam.getReceiveAccounts(),
|
||||
devEmailSendAliyunHtmlParam.getSubject(), devEmailSendAliyunHtmlParam.getContent());
|
||||
DevEmail devEmail = new DevEmail();
|
||||
BeanUtil.copyProperties(devEmailSendAliyunHtmlParam, devEmail);
|
||||
devEmail.setEngine(DevEmailEngineTypeEnum.ALIYUN.getValue());
|
||||
devEmail.setReceiptInfo(receiptInfo);
|
||||
this.save(devEmail);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendAliyun(DevEmailSendAliyunTmpParam devEmailSendAliyunTmpParam) {
|
||||
CommonEmailUtil.validEmail(devEmailSendAliyunTmpParam.getReceiveAccounts());
|
||||
String receiptInfo = DevEmailAliyunUtil.sendEmailWithTemplate(devEmailSendAliyunTmpParam.getSendAccount(),
|
||||
devEmailSendAliyunTmpParam.getTagName(), devEmailSendAliyunTmpParam.getReceiveAccounts(),
|
||||
devEmailSendAliyunTmpParam.getTemplateName());
|
||||
DevEmail devEmail = new DevEmail();
|
||||
BeanUtil.copyProperties(devEmailSendAliyunTmpParam, devEmail);
|
||||
devEmail.setEngine(DevEmailEngineTypeEnum.ALIYUN.getValue());
|
||||
devEmail.setReceiptInfo(receiptInfo);
|
||||
this.save(devEmail);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTencent(DevEmailSendTencentTxtParam devEmailSendTencentTxtParam) {
|
||||
CommonEmailUtil.validEmail(devEmailSendTencentTxtParam.getReceiveAccounts());
|
||||
String receiptInfo = DevEmailTencentUtil.sendTextEmail(devEmailSendTencentTxtParam.getSendAccount(),
|
||||
devEmailSendTencentTxtParam.getSendUser(), devEmailSendTencentTxtParam.getReceiveAccounts(),
|
||||
devEmailSendTencentTxtParam.getSubject(), devEmailSendTencentTxtParam.getContent(),
|
||||
devEmailSendTencentTxtParam.getAttachmentList());
|
||||
DevEmail devEmail = new DevEmail();
|
||||
BeanUtil.copyProperties(devEmailSendTencentTxtParam, devEmail);
|
||||
devEmail.setEngine(DevEmailEngineTypeEnum.TENCENT.getValue());
|
||||
devEmail.setReceiptInfo(receiptInfo);
|
||||
this.save(devEmail);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTencent(DevEmailSendTencentHtmlParam devEmailSendTencentHtmlParam) {
|
||||
CommonEmailUtil.validEmail(devEmailSendTencentHtmlParam.getReceiveAccounts());
|
||||
String receiptInfo = DevEmailTencentUtil.sendHtmlEmail(devEmailSendTencentHtmlParam.getSendAccount(),
|
||||
devEmailSendTencentHtmlParam.getSendUser(), devEmailSendTencentHtmlParam.getReceiveAccounts(),
|
||||
devEmailSendTencentHtmlParam.getSubject(), devEmailSendTencentHtmlParam.getContent(),
|
||||
devEmailSendTencentHtmlParam.getAttachmentList());
|
||||
DevEmail devEmail = new DevEmail();
|
||||
BeanUtil.copyProperties(devEmailSendTencentHtmlParam, devEmail);
|
||||
devEmail.setEngine(DevEmailEngineTypeEnum.TENCENT.getValue());
|
||||
devEmail.setReceiptInfo(receiptInfo);
|
||||
this.save(devEmail);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTencent(DevEmailSendTencentTmpParam devEmailSendTencentTmpParam) {
|
||||
CommonEmailUtil.validEmail(devEmailSendTencentTmpParam.getReceiveAccounts());
|
||||
String receiptInfo = DevEmailTencentUtil.sendEmailWithTemplate(devEmailSendTencentTmpParam.getSendAccount(),
|
||||
devEmailSendTencentTmpParam.getSendUser(), devEmailSendTencentTmpParam.getReceiveAccounts(),
|
||||
devEmailSendTencentTmpParam.getTemplateName(), devEmailSendTencentTmpParam.getTemplateParam(),
|
||||
devEmailSendTencentTmpParam.getSubject(), CollectionUtil.newArrayList());
|
||||
DevEmail devEmail = new DevEmail();
|
||||
BeanUtil.copyProperties(devEmailSendTencentTmpParam, devEmail);
|
||||
devEmail.setEngine(DevEmailEngineTypeEnum.TENCENT.getValue());
|
||||
devEmail.setReceiptInfo(receiptInfo);
|
||||
this.save(devEmail);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<DevEmail> page(DevEmailPageParam devEmailPageParam) {
|
||||
QueryWrapper<DevEmail> queryWrapper = new QueryWrapper<>();
|
||||
if(ObjectUtil.isNotEmpty(devEmailPageParam.getEngine())) {
|
||||
queryWrapper.lambda().eq(DevEmail::getEngine, devEmailPageParam.getEngine());
|
||||
}
|
||||
if(ObjectUtil.isNotEmpty(devEmailPageParam.getSearchKey())) {
|
||||
queryWrapper.lambda().like(DevEmail::getSubject, devEmailPageParam.getSearchKey());
|
||||
}
|
||||
if(ObjectUtil.isAllNotEmpty(devEmailPageParam.getSortField(), devEmailPageParam.getSortOrder())) {
|
||||
CommonSortOrderEnum.validate(devEmailPageParam.getSortOrder());
|
||||
queryWrapper.orderBy(true, devEmailPageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
|
||||
StrUtil.toUnderlineCase(devEmailPageParam.getSortField()));
|
||||
}
|
||||
return this.page(CommonPageRequest.defaultPage(), queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(List<DevEmailIdParam> devEmailIdParamList) {
|
||||
this.removeByIds(CollStreamUtil.toList(devEmailIdParamList, DevEmailIdParam::getId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DevEmail detail(DevEmailIdParam devEmailIdParam) {
|
||||
return this.queryEntity(devEmailIdParam.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DevEmail queryEntity(String id) {
|
||||
DevEmail devEmail = this.getById(id);
|
||||
if(ObjectUtil.isEmpty(devEmail)) {
|
||||
throw new CommonException("邮件发送记录不存在,id值为:{}", id);
|
||||
}
|
||||
return devEmail;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.email.util;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.aliyuncs.DefaultAcsClient;
|
||||
import com.aliyuncs.IAcsClient;
|
||||
import com.aliyuncs.dm.model.v20151123.BatchSendMailRequest;
|
||||
import com.aliyuncs.dm.model.v20151123.SingleSendMailRequest;
|
||||
import com.aliyuncs.exceptions.ClientException;
|
||||
import com.aliyuncs.http.MethodType;
|
||||
import com.aliyuncs.profile.DefaultProfile;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import mjkf.xinke.common.exception.CommonException;
|
||||
import mjkf.xinke.dev.api.DevConfigApi;
|
||||
|
||||
/**
|
||||
* 阿里云邮件工具类
|
||||
* 参考文档:https://help.aliyun.com/document_detail/29459.html
|
||||
*
|
||||
*
|
||||
* @date 2022/6/17 10:17
|
||||
**/
|
||||
@Slf4j
|
||||
public class DevEmailAliyunUtil {
|
||||
|
||||
private static IAcsClient client;
|
||||
|
||||
private static final String SNOWY_EMAIL_ALIYUN_ACCESS_KEY_ID_KEY = "SNOWY_EMAIL_ALIYUN_ACCESS_KEY_ID";
|
||||
private static final String SNOWY_EMAIL_ALIYUN_ACCESS_KEY_SECRET_KEY = "SNOWY_EMAIL_ALIYUN_ACCESS_KEY_SECRET";
|
||||
private static final String SNOWY_EMAIL_ALIYUN_REGION_ID_KEY = "SNOWY_EMAIL_ALIYUN_REGION_ID";
|
||||
|
||||
/**
|
||||
* 初始化操作的客户端
|
||||
*
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
private static void initClient() {
|
||||
|
||||
DevConfigApi devConfigApi = SpringUtil.getBean(DevConfigApi.class);
|
||||
|
||||
/* accessKeyId */
|
||||
String accessKeyId = devConfigApi.getValueByKey(SNOWY_EMAIL_ALIYUN_ACCESS_KEY_ID_KEY);
|
||||
|
||||
if(ObjectUtil.isEmpty(accessKeyId)) {
|
||||
throw new CommonException("阿里云邮件操作客户端未正确配置:accessKeyId为空");
|
||||
}
|
||||
|
||||
/* accessKeySecret */
|
||||
String accessKeySecret = devConfigApi.getValueByKey(SNOWY_EMAIL_ALIYUN_ACCESS_KEY_SECRET_KEY);
|
||||
|
||||
if(ObjectUtil.isEmpty(accessKeySecret)) {
|
||||
throw new CommonException("阿里云邮件操作客户端未正确配置:accessKeySecret为空");
|
||||
}
|
||||
|
||||
/* regionId */
|
||||
String regionId = devConfigApi.getValueByKey(SNOWY_EMAIL_ALIYUN_REGION_ID_KEY);
|
||||
|
||||
if(ObjectUtil.isEmpty(regionId)) {
|
||||
throw new CommonException("阿里云邮件操作客户端未正确配置:regionId为空");
|
||||
}
|
||||
|
||||
client = new DefaultAcsClient(DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret));
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送纯文本邮件(不使用模板,频率限制100 QPS)
|
||||
*
|
||||
* @param from 管理控制台中配置的发信地址,必传且必须正确
|
||||
* @param user 发信人昵称,长度小于15个字符,可不传
|
||||
* @param tos 目标地址,多个 email 地址可以用逗号分隔,最多100个地址,必传且必须正确
|
||||
* @param subject 邮件主题,必传
|
||||
* @param content 邮件 txt 正文,限制28K,必传
|
||||
* @return 发送成功的回执id
|
||||
*
|
||||
* @date 2022/2/23 14:24
|
||||
**/
|
||||
public static String sendTextEmail(String from, String user, String tos, String subject, String content) {
|
||||
try {
|
||||
initClient();
|
||||
SingleSendMailRequest singleSendMailRequest = createSingleSendRequest(from, user, tos, subject, content, false);
|
||||
return client.getAcsResponse(singleSendMailRequest).getEnvId();
|
||||
} catch (ClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送HTML邮件(不使用模板,频率限制100 QPS)
|
||||
*
|
||||
* @param from 管理控制台中配置的发信地址,必传且必须正确
|
||||
* @param user 发信人昵称,长度小于15个字符,可不传
|
||||
* @param tos 目标地址,多个 email 地址可以用逗号分隔,最多100个地址,必传且必须正确
|
||||
* @param subject 邮件主题,必传
|
||||
* @param content 邮件 html 正文,限制28K,必传
|
||||
* @return 发送成功的回执id
|
||||
*
|
||||
* @date 2022/2/23 14:24
|
||||
**/
|
||||
public static String sendHtmlEmail(String from, String user, String tos, String subject, String content) {
|
||||
try {
|
||||
initClient();
|
||||
SingleSendMailRequest singleSendMailRequest = createSingleSendRequest(from, user, tos, subject, content, true);
|
||||
return client.getAcsResponse(singleSendMailRequest).getEnvId();
|
||||
} catch (ClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用模板发送邮件,国内频率限制是20/min;海外频率限制是10/min。
|
||||
*
|
||||
* @param from 管理控制台中配置的发信地址,必传且必须正确
|
||||
* @param tagName 控制台创建的邮件标签,可不传
|
||||
* @param toName 预先创建且上传了收件人的收件人列表名称,必传且必须正确
|
||||
* @param templateName 预先创建且通过审核的模板名称,必传且必须正确
|
||||
* @return 发送成功的回执id
|
||||
*
|
||||
* @date 2022/2/23 14:24
|
||||
**/
|
||||
public static String sendEmailWithTemplate(String from, String tagName, String toName, String templateName) {
|
||||
try {
|
||||
initClient();
|
||||
BatchSendMailRequest batchSendMailRequest = createBatchSendRequest(from, tagName, toName, templateName);
|
||||
return client.getAcsResponse(batchSendMailRequest).getEnvId();
|
||||
} catch (ClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 创建发送一个邮件的请求
|
||||
*
|
||||
*
|
||||
* @date 2022/2/23 13:33
|
||||
**/
|
||||
private static SingleSendMailRequest createSingleSendRequest(String from, String user, String tos, String subject, String content, boolean isHtml) {
|
||||
SingleSendMailRequest request = new SingleSendMailRequest();
|
||||
|
||||
// 控制台创建的发信地址
|
||||
request.setAccountName(from);
|
||||
|
||||
// 发信人昵称
|
||||
request.setFromAlias(user);
|
||||
|
||||
// 地址类型:0-为随机账号,1-为发信地址
|
||||
request.setAddressType(1);
|
||||
|
||||
// 使用管理台配置的回信地址
|
||||
request.setReplyToAddress(true);
|
||||
|
||||
// 目标地址
|
||||
request.setToAddress(tos);
|
||||
|
||||
// 邮件主题
|
||||
request.setSubject(subject);
|
||||
|
||||
//如果采用byte[].toString的方式的话请确保最终转换成utf-8的格式再放入htmlbody和textbody,若编码不一致则会被当成垃圾邮件。
|
||||
if(isHtml) {
|
||||
request.setHtmlBody(content);
|
||||
} else {
|
||||
request.setTextBody(content);
|
||||
}
|
||||
|
||||
//SDK 采用的是http协议的发信方式, 默认是GET方法,有一定的长度限制。
|
||||
//若textBody、htmlBody或content的大小不确定,建议采用POST方式提交,避免出现uri is not valid异常
|
||||
request.setSysMethod(MethodType.POST);
|
||||
|
||||
//是否开启追踪功能,开启需要备案,0关闭,1开启
|
||||
request.setClickTrace("0");
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建发送批量邮件的请求
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/10/30 22:39
|
||||
*/
|
||||
private static BatchSendMailRequest createBatchSendRequest(String from, String tagName, String toName, String templateName) {
|
||||
BatchSendMailRequest request = new BatchSendMailRequest();
|
||||
|
||||
// 控制台创建的发信地址
|
||||
request.setAccountName(from);
|
||||
|
||||
// 预先创建且上传了收件人的收件人列表名称
|
||||
request.setReceiversName(toName);
|
||||
|
||||
// 邮件模板,在控制台创建,相当于邮件的内容
|
||||
request.setTemplateName(templateName);
|
||||
|
||||
// 地址类型:0-为随机账号,1-为发信地址
|
||||
request.setAddressType(1);
|
||||
|
||||
// 控制台创建的标签
|
||||
request.setTagName(tagName);
|
||||
|
||||
//SDK 采用的是http协议的发信方式, 默认是GET方法,有一定的长度限制。
|
||||
//若textBody、htmlBody或content的大小不确定,建议采用POST方式提交,避免出现uri is not valid异常
|
||||
request.setSysMethod(MethodType.POST);
|
||||
|
||||
//是否开启追踪功能,开启需要备案,0关闭,1开启
|
||||
request.setClickTrace("0");
|
||||
|
||||
return request;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.email.util;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.extra.mail.MailAccount;
|
||||
import cn.hutool.extra.mail.MailUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import mjkf.xinke.common.exception.CommonException;
|
||||
import mjkf.xinke.dev.api.DevConfigApi;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 本地邮件工具类
|
||||
*
|
||||
*
|
||||
* @date 2022/6/17 11:15
|
||||
**/
|
||||
@Slf4j
|
||||
public class DevEmailLocalUtil {
|
||||
|
||||
private static MailAccount mailAccount;
|
||||
|
||||
private static final String SNOWY_EMAIL_LOCAL_FROM_KEY = "SNOWY_EMAIL_LOCAL_FROM";
|
||||
private static final String SNOWY_EMAIL_LOCAL_PASSWORD_KEY = "SNOWY_EMAIL_LOCAL_PASSWORD";
|
||||
|
||||
/**
|
||||
* 初始化操作的客户端
|
||||
*
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
private static void initClient() {
|
||||
|
||||
DevConfigApi devConfigApi = SpringUtil.getBean(DevConfigApi.class);
|
||||
|
||||
/* 发件人(必须正确,否则发送失败) */
|
||||
String from = devConfigApi.getValueByKey(SNOWY_EMAIL_LOCAL_FROM_KEY);
|
||||
|
||||
if(ObjectUtil.isEmpty(from)) {
|
||||
throw new CommonException("本地邮件操作客户端未正确配置:from为空");
|
||||
}
|
||||
|
||||
/* 密码(注意,某些邮箱需要为SMTP服务单独设置授权码,详情查看相关帮助) */
|
||||
String pass = devConfigApi.getValueByKey(SNOWY_EMAIL_LOCAL_PASSWORD_KEY);
|
||||
|
||||
if(ObjectUtil.isEmpty(pass)) {
|
||||
throw new CommonException("本地邮件操作客户端未正确配置:pass为空");
|
||||
}
|
||||
|
||||
mailAccount = new MailAccount();
|
||||
mailAccount.setFrom(from);
|
||||
mailAccount.setPass(pass);
|
||||
}
|
||||
|
||||
public static MailAccount getClient() {
|
||||
initClient();
|
||||
return mailAccount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送纯文本邮件
|
||||
*
|
||||
* @param tos 收件人邮箱,逗号拼接
|
||||
* @param subject 邮件主题
|
||||
* @param content 邮件内容
|
||||
* @param files 附件列表
|
||||
* @return 发送成功的回执id
|
||||
*
|
||||
* @date 2022/2/7 22:29
|
||||
*/
|
||||
public static String sendTextEmail(String tos, String subject, String content, List<File> files) {
|
||||
try {
|
||||
initClient();
|
||||
return MailUtil.send(mailAccount, tos, subject, content, false, ArrayUtil.toArray(files, File.class));
|
||||
} catch (Exception e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送HTML邮件
|
||||
*
|
||||
* @param tos 收件人邮箱列表,逗号拼接
|
||||
* @param subject 邮件主题
|
||||
* @param content 邮件内容
|
||||
* @param imageMap – 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER
|
||||
* @param files 附件列表
|
||||
* @return 发送成功的回执id
|
||||
*
|
||||
* @date 2022/2/7 22:29
|
||||
*/
|
||||
public static String sendHtmlEmail(String tos, String subject, String content, Map<String, InputStream> imageMap, List<File> files) {
|
||||
try {
|
||||
initClient();
|
||||
return MailUtil.send(mailAccount, tos, subject, content, imageMap, true, ArrayUtil.toArray(files, File.class));
|
||||
} catch (Exception e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.email.util;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.tencentcloudapi.common.Credential;
|
||||
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
|
||||
import com.tencentcloudapi.ses.v20201002.SesClient;
|
||||
import com.tencentcloudapi.ses.v20201002.models.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import mjkf.xinke.common.exception.CommonException;
|
||||
import mjkf.xinke.dev.api.DevConfigApi;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 腾讯云邮件工具类
|
||||
* 参考文档:https://cloud.tencent.com/document/api/1288/51034
|
||||
*
|
||||
*
|
||||
* @date 2022/6/17 11:26
|
||||
**/
|
||||
@Slf4j
|
||||
public class DevEmailTencentUtil {
|
||||
|
||||
private static SesClient client;
|
||||
|
||||
private static final String SNOWY_EMAIL_TENCENT_SECRET_ID_KEY = "SNOWY_EMAIL_TENCENT_SECRET_ID";
|
||||
private static final String SNOWY_EMAIL_TENCENT_SECRET_KEY_KEY = "SNOWY_EMAIL_TENCENT_SECRET_KEY";
|
||||
private static final String SNOWY_EMAIL_TENCENT_REGION_ID_KEY = "SNOWY_EMAIL_TENCENT_REGION_ID";
|
||||
|
||||
/**
|
||||
* 初始化操作的客户端
|
||||
*
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
private static void initClient() {
|
||||
|
||||
DevConfigApi devConfigApi = SpringUtil.getBean(DevConfigApi.class);
|
||||
|
||||
/* secretId */
|
||||
String secretId = devConfigApi.getValueByKey(SNOWY_EMAIL_TENCENT_SECRET_ID_KEY);
|
||||
|
||||
if(ObjectUtil.isEmpty(secretId)) {
|
||||
throw new CommonException("腾讯云邮件操作客户端未正确配置:secretId为空");
|
||||
}
|
||||
|
||||
/* secretKey */
|
||||
String secretKey = devConfigApi.getValueByKey(SNOWY_EMAIL_TENCENT_SECRET_KEY_KEY);
|
||||
|
||||
if(ObjectUtil.isEmpty(secretKey)) {
|
||||
throw new CommonException("腾讯云邮件操作客户端未正确配置:secretKey为空");
|
||||
}
|
||||
|
||||
/* regionId */
|
||||
String regionId = devConfigApi.getValueByKey(SNOWY_EMAIL_TENCENT_REGION_ID_KEY);
|
||||
|
||||
if(ObjectUtil.isEmpty(regionId)) {
|
||||
throw new CommonException("腾讯云邮件操作客户端未正确配置:regionId为空");
|
||||
}
|
||||
|
||||
client = new SesClient(new Credential(secretId, secretKey), regionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送纯文本邮件(不使用模板,默认接口请求频率限制:20次/秒。)
|
||||
*
|
||||
* @param from 管理控制台中配置的发信地址,必传且必须正确
|
||||
* @param user 发信人昵称,可不传
|
||||
* @param tos 目标地址,多个 email 地址可以用逗号分隔,最多50个地址,必传且必须正确,非群发邮件请多次调用API发送
|
||||
* @param subject 邮件主题,必传
|
||||
* @param content 邮件 txt 正文,必传,注意:腾讯云api目前要求请求包大小不得超过8 MB。
|
||||
* @param attachmentList 需要发送附件时,填写附件相关参数,格式:[{"FileName": "xxxx", "Content": "xxx"}]
|
||||
* 支持的格式与说明见:https://cloud.tencent.com/document/api/1288/51053#Attachment
|
||||
* @return 发送成功的回执id
|
||||
*
|
||||
* @date 2022/2/23 14:24
|
||||
**/
|
||||
public static String sendTextEmail(String from, String user, String tos, String subject, String content, List<JSONObject> attachmentList) {
|
||||
try {
|
||||
initClient();
|
||||
SendEmailRequest singleSendMailRequest = createSingleSendRequest(from, user, tos, subject, content, false, attachmentList);
|
||||
return client.SendEmail(singleSendMailRequest).getMessageId();
|
||||
} catch (TencentCloudSDKException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送HTML邮件(不使用模板,默认接口请求频率限制:20次/秒。)
|
||||
*
|
||||
* @param from 管理控制台中配置的发信地址,必传且必须正确
|
||||
* @param user 发信人昵称,可不传
|
||||
* @param tos 目标地址,多个 email 地址可以用逗号分隔,最多50个地址,必传且必须正确,非群发邮件请多次调用API发送
|
||||
* @param subject 邮件主题,必传
|
||||
* @param content 邮件 txt 正文,必传,注意:腾讯云api目前要求请求包大小不得超过8 MB。
|
||||
* @param attachmentList 需要发送附件时,填写附件相关参数,格式:[{"FileName": "xxxx", "Content": "xxx"}]
|
||||
* 支持的格式与说明见:https://cloud.tencent.com/document/api/1288/51053#Attachment
|
||||
* @return 发送成功的回执id
|
||||
*
|
||||
* @date 2022/2/23 14:24
|
||||
**/
|
||||
public static String sendHtmlEmail(String from, String user, String tos, String subject, String content, List<JSONObject> attachmentList) {
|
||||
try {
|
||||
initClient();
|
||||
SendEmailRequest singleSendMailRequest = createSingleSendRequest(from, user, tos, subject, content, true, attachmentList);
|
||||
return client.SendEmail(singleSendMailRequest).getMessageId();
|
||||
} catch (TencentCloudSDKException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用模板发送邮件,默认接口请求频率限制:20次/秒。
|
||||
*
|
||||
* @param from 管理控制台中配置的发信地址,必传且必须正确
|
||||
* @param user 发信人昵称,可不传
|
||||
* @param toId 预先创建且上传了收件人的收件人列表id,必传且必须正确
|
||||
* @param templateId 预先创建且通过审核的模板Id,必传且必须正确
|
||||
* @param templateParam 预先创建且通过审核的模板的参数json,格式{"name":"张三"},可不传
|
||||
* @param subject 邮件主题,必传
|
||||
* @param attachmentList 需要发送附件时,填写附件相关参数,格式:[{"FileName": "xxxx", "Content": "xxx"}]
|
||||
* 支持的格式与说明见:https://cloud.tencent.com/document/api/1288/51053#Attachment
|
||||
* @return 发送成功的回执id
|
||||
*
|
||||
* @date 2022/2/23 14:24
|
||||
**/
|
||||
public static String sendEmailWithTemplate(String from, String user, String toId, String templateId,
|
||||
String templateParam, String subject, List<JSONObject> attachmentList) {
|
||||
try {
|
||||
initClient();
|
||||
BatchSendEmailRequest batchSendEmailRequest = createBatchSendRequest(from, user, toId, templateId, templateParam, subject, attachmentList);
|
||||
return client.BatchSendEmail(batchSendEmailRequest).getTaskId().toString();
|
||||
} catch (TencentCloudSDKException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建发送一个邮件的请求
|
||||
*
|
||||
*
|
||||
* @date 2022/2/23 13:33
|
||||
**/
|
||||
private static SendEmailRequest createSingleSendRequest(String from, String user, String tos, String subject,
|
||||
String content, boolean isHtml, List<JSONObject> attachmentList) {
|
||||
SendEmailRequest sendEmailRequest = new SendEmailRequest();
|
||||
sendEmailRequest.setFromEmailAddress(ObjectUtil.isNotEmpty(user)?user + " <" + from + ">" :from);
|
||||
sendEmailRequest.setDestination(StrUtil.splitToArray(tos, StrUtil.COMMA));
|
||||
sendEmailRequest.setSubject(subject);
|
||||
Simple simple = new Simple();
|
||||
if(isHtml) {
|
||||
simple.setHtml(Base64.encode(content));
|
||||
} else {
|
||||
simple.setText(Base64.encode(content));
|
||||
}
|
||||
sendEmailRequest.setSimple(simple);
|
||||
if(ObjectUtil.isNotEmpty(attachmentList)) {
|
||||
Attachment[] attachments = (Attachment[]) attachmentList.stream().map(jsonObject -> {
|
||||
Attachment attachment = new Attachment();
|
||||
BeanUtil.copyProperties(jsonObject, attachment);
|
||||
return attachment;
|
||||
}).toArray();
|
||||
sendEmailRequest.setAttachments(attachments);
|
||||
}
|
||||
return sendEmailRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建发送批量邮件的请求
|
||||
*
|
||||
*
|
||||
* @date 2022/2/23 13:33
|
||||
**/
|
||||
private static BatchSendEmailRequest createBatchSendRequest(String from, String user, String toId, String templateId,
|
||||
String templateParam, String subject, List<JSONObject> attachmentList) {
|
||||
BatchSendEmailRequest batchSendEmailRequest = new BatchSendEmailRequest();
|
||||
batchSendEmailRequest.setFromEmailAddress(ObjectUtil.isNotEmpty(user)?user + " <" + from + ">" :from);
|
||||
batchSendEmailRequest.setReceiverId(Convert.toLong(toId));
|
||||
Template template = new Template();
|
||||
template.setTemplateID(Convert.toLong(templateId));
|
||||
template.setTemplateData(templateParam);
|
||||
batchSendEmailRequest.setTemplate(template);
|
||||
batchSendEmailRequest.setSubject(subject);
|
||||
batchSendEmailRequest.setTaskType(1L);
|
||||
if(ObjectUtil.isNotEmpty(attachmentList)) {
|
||||
Attachment[] attachments = (Attachment[]) attachmentList.stream().map(jsonObject -> {
|
||||
Attachment attachment = new Attachment();
|
||||
BeanUtil.copyProperties(jsonObject, attachment);
|
||||
return attachment;
|
||||
}).toArray();
|
||||
batchSendEmailRequest.setAttachments(attachments);
|
||||
}
|
||||
return batchSendEmailRequest;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.file.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import mjkf.xinke.common.annotation.CommonLog;
|
||||
import mjkf.xinke.common.pojo.CommonResult;
|
||||
import mjkf.xinke.common.pojo.CommonValidList;
|
||||
import mjkf.xinke.dev.api.DevConfigApi;
|
||||
import mjkf.xinke.dev.modular.file.entity.DevFile;
|
||||
import mjkf.xinke.dev.modular.file.enums.DevFileEngineTypeEnum;
|
||||
import mjkf.xinke.dev.modular.file.param.DevFileIdParam;
|
||||
import mjkf.xinke.dev.modular.file.param.DevFileListParam;
|
||||
import mjkf.xinke.dev.modular.file.param.DevFilePageParam;
|
||||
import mjkf.xinke.dev.modular.file.service.DevFileService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 文件控制器
|
||||
*
|
||||
*
|
||||
* @date 2022/2/23 18:26
|
||||
**/
|
||||
@Api(tags = "文件控制器")
|
||||
@ApiSupport(author = "SNOWY_TEAM", order = 4)
|
||||
@RestController
|
||||
@Validated
|
||||
public class DevFileController {
|
||||
|
||||
/** 默认文件引擎 */
|
||||
private static final String SNOWY_SYS_DEFAULT_FILE_ENGINE_KEY = "SNOWY_SYS_DEFAULT_FILE_ENGINE";
|
||||
|
||||
@Resource
|
||||
private DevConfigApi devConfigApi;
|
||||
|
||||
@Resource
|
||||
private DevFileService devFileService;
|
||||
|
||||
/**
|
||||
* 动态上传文件返回id
|
||||
*
|
||||
*
|
||||
* @date 2021/10/13 14:01
|
||||
**/
|
||||
@ApiOperationSupport(order = 1)
|
||||
@ApiOperation("动态上传文件返回id")
|
||||
@CommonLog("动态上传文件返回id")
|
||||
@PostMapping("/dev/file/uploadDynamicReturnId")
|
||||
public CommonResult<String> uploadDynamicReturnId(@RequestPart("file") MultipartFile file) {
|
||||
return CommonResult.data(devFileService.uploadReturnId(devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_FILE_ENGINE_KEY), file));
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态上传文件返回url
|
||||
*
|
||||
*
|
||||
* @date 2021/10/13 14:01
|
||||
**/
|
||||
@ApiOperationSupport(order = 2)
|
||||
@ApiOperation("动态上传文件返回url")
|
||||
@CommonLog("动态上传文件返回url")
|
||||
@PostMapping("/dev/file/uploadDynamicReturnUrl")
|
||||
public CommonResult<String> uploadDynamicReturnUrl(@RequestPart("file") MultipartFile file) {
|
||||
return CommonResult.data(devFileService.uploadReturnUrl(devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_FILE_ENGINE_KEY), file));
|
||||
}
|
||||
|
||||
/**
|
||||
* 本地文件上传,返回文件id
|
||||
*
|
||||
*
|
||||
* @date 2021/10/13 14:01
|
||||
**/
|
||||
@ApiOperationSupport(order = 3)
|
||||
@ApiOperation("上传本地文件返回id")
|
||||
@CommonLog("上传本地文件返回id")
|
||||
@PostMapping("/dev/file/uploadLocalReturnId")
|
||||
public CommonResult<String> uploadLocalReturnId(@RequestPart("file") MultipartFile file) {
|
||||
return CommonResult.data(devFileService.uploadReturnId(DevFileEngineTypeEnum.LOCAL.getValue(), file));
|
||||
}
|
||||
|
||||
/**
|
||||
* 本地文件上传,返回文件Url
|
||||
*
|
||||
*
|
||||
* @date 2021/10/13 14:01
|
||||
**/
|
||||
@ApiOperationSupport(order = 4)
|
||||
@ApiOperation("上传本地文件返回url")
|
||||
@CommonLog("上传本地文件返回url")
|
||||
@PostMapping("/dev/file/uploadLocalReturnUrl")
|
||||
public CommonResult<String> uploadLocalReturnUrl(@RequestPart("file") MultipartFile file) {
|
||||
return CommonResult.data(devFileService.uploadReturnUrl(DevFileEngineTypeEnum.LOCAL.getValue(), file));
|
||||
}
|
||||
|
||||
/**
|
||||
* 阿里云文件上传,返回文件id
|
||||
*
|
||||
*
|
||||
* @date 2021/10/13 14:01
|
||||
**/
|
||||
@ApiOperationSupport(order = 5)
|
||||
@ApiOperation("上传阿里云文件返回id")
|
||||
@CommonLog("上传阿里云文件返回id")
|
||||
@PostMapping("/dev/file/uploadAliyunReturnId")
|
||||
public CommonResult<String> uploadAliyunReturnId(@RequestPart("file") MultipartFile file) {
|
||||
return CommonResult.data(devFileService.uploadReturnId(DevFileEngineTypeEnum.ALIYUN.getValue(), file));
|
||||
}
|
||||
|
||||
/**
|
||||
* 阿里云文件上传,返回文件Url
|
||||
*
|
||||
*
|
||||
* @date 2021/10/13 14:01
|
||||
**/
|
||||
@ApiOperationSupport(order = 6)
|
||||
@ApiOperation("上传阿里云文件返回url")
|
||||
@CommonLog("上传阿里云文件返回url")
|
||||
@PostMapping("/dev/file/uploadAliyunReturnUrl")
|
||||
public CommonResult<String> uploadAliyunReturnUrl(@RequestPart("file") MultipartFile file) {
|
||||
return CommonResult.data(devFileService.uploadReturnUrl(DevFileEngineTypeEnum.ALIYUN.getValue(), file));
|
||||
}
|
||||
|
||||
/**
|
||||
* 腾讯云文件上传,返回文件id
|
||||
*
|
||||
*
|
||||
* @date 2021/10/13 14:01
|
||||
**/
|
||||
@ApiOperationSupport(order = 7)
|
||||
@ApiOperation("上传腾讯云文件返回id")
|
||||
@CommonLog("上传腾讯云文件返回id")
|
||||
@PostMapping("/dev/file/uploadTencentReturnId")
|
||||
public CommonResult<String> uploadTencentReturnId(@RequestPart("file") MultipartFile file) {
|
||||
return CommonResult.data(devFileService.uploadReturnId(DevFileEngineTypeEnum.TENCENT.getValue(), file));
|
||||
}
|
||||
|
||||
/**
|
||||
* 腾讯云文件上传,返回文件Url
|
||||
*
|
||||
*
|
||||
* @date 2021/10/13 14:01
|
||||
**/
|
||||
@ApiOperationSupport(order = 8)
|
||||
@ApiOperation("上传腾讯云文件返回url")
|
||||
@CommonLog("上传腾讯云文件返回url")
|
||||
@PostMapping("/dev/file/uploadTencentReturnUrl")
|
||||
public CommonResult<String> uploadTencentReturnUrl(@RequestPart("file") MultipartFile file) {
|
||||
return CommonResult.data(devFileService.uploadReturnUrl(DevFileEngineTypeEnum.TENCENT.getValue(), file));
|
||||
}
|
||||
|
||||
/**
|
||||
* MINIO文件上传,返回文件id
|
||||
*
|
||||
*
|
||||
* @date 2021/10/13 14:01
|
||||
**/
|
||||
@ApiOperationSupport(order = 9)
|
||||
@ApiOperation("上传MINIO文件返回id")
|
||||
@CommonLog("上传MINIO文件返回id")
|
||||
@PostMapping("/dev/file/uploadMinioReturnId")
|
||||
public CommonResult<String> uploadMinioReturnId(@RequestPart("file") MultipartFile file) {
|
||||
return CommonResult.data(devFileService.uploadReturnId(DevFileEngineTypeEnum.MINIO.getValue(), file));
|
||||
}
|
||||
|
||||
/**
|
||||
* MINIO文件上传,返回文件Url
|
||||
*
|
||||
*
|
||||
* @date 2021/10/13 14:01
|
||||
**/
|
||||
@ApiOperationSupport(order = 10)
|
||||
@ApiOperation("上传MINIO文件返回url")
|
||||
@CommonLog("上传MINIO文件返回url")
|
||||
@PostMapping("/dev/file/uploadMinioReturnUrl")
|
||||
public CommonResult<String> uploadMinioReturnUrl(@RequestPart("file") MultipartFile file) {
|
||||
return CommonResult.data(devFileService.uploadReturnUrl(DevFileEngineTypeEnum.MINIO.getValue(), file));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件分页列表
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 11)
|
||||
@ApiOperation("获取文件分页列表")
|
||||
@GetMapping("/dev/file/page")
|
||||
public CommonResult<Page<DevFile>> page(DevFilePageParam devFilePageParam) {
|
||||
return CommonResult.data(devFileService.page(devFilePageParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件列表
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 12)
|
||||
@ApiOperation("获取文件列表")
|
||||
@GetMapping("/dev/file/list")
|
||||
public CommonResult<List<DevFile>> list(DevFileListParam devFileListParam) {
|
||||
return CommonResult.data(devFileService.list(devFileListParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 15:44
|
||||
**/
|
||||
@ApiOperationSupport(order = 13)
|
||||
@ApiOperation("下载文件")
|
||||
@CommonLog("下载文件")
|
||||
@GetMapping(value = "/dev/file/download", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
|
||||
public void download(@Valid DevFileIdParam devFileIdParam, HttpServletResponse response) throws IOException {
|
||||
devFileService.download(devFileIdParam, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 14)
|
||||
@ApiOperation("删除文件")
|
||||
@CommonLog("删除文件")
|
||||
@PostMapping(value = "/dev/file/delete")
|
||||
public CommonResult<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
|
||||
CommonValidList<DevFileIdParam> devFileIdParamList) {
|
||||
devFileService.delete(devFileIdParamList);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件详情
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 15:44
|
||||
**/
|
||||
@ApiOperationSupport(order = 15)
|
||||
@ApiOperation("获取文件详情")
|
||||
@GetMapping("/dev/file/detail")
|
||||
public CommonResult<DevFile> detail(@Valid DevFileIdParam devFileIdParam) {
|
||||
return CommonResult.data(devFileService.detail(devFileIdParam));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.file.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import mjkf.xinke.common.pojo.CommonEntity;
|
||||
|
||||
/**
|
||||
* 文件实体
|
||||
*
|
||||
*
|
||||
* @date 2022/2/23 18:27
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("DEV_FILE")
|
||||
public class DevFile extends CommonEntity {
|
||||
|
||||
/** id */
|
||||
@ApiModelProperty(value = "主键", position = 1)
|
||||
private String id;
|
||||
|
||||
/** 租户id */
|
||||
@ApiModelProperty(value = "租户id", position = 2)
|
||||
private String tenantId;
|
||||
|
||||
/** 存储引擎 */
|
||||
@ApiModelProperty(value = "存储引擎", position = 3)
|
||||
private String engine;
|
||||
|
||||
/** 存储桶 */
|
||||
@ApiModelProperty(value = "存储桶", position = 4)
|
||||
private String bucket;
|
||||
|
||||
/** 文件名称 */
|
||||
@ApiModelProperty(value = "文件名称", position = 5)
|
||||
private String name;
|
||||
|
||||
/** 文件后缀 */
|
||||
@ApiModelProperty(value = "文件后缀", position = 6)
|
||||
private String suffix;
|
||||
|
||||
/** 文件大小kb */
|
||||
@ApiModelProperty(value = "文件大小kb", position = 7)
|
||||
private String sizeKb;
|
||||
|
||||
/** 文件大小(格式化后) */
|
||||
@ApiModelProperty(value = "文件大小(格式化后)", position = 8)
|
||||
private String sizeInfo;
|
||||
|
||||
/** 文件的对象名(唯一名称) */
|
||||
@ApiModelProperty(value = "文件的对象名(唯一名称)", position = 9)
|
||||
private String objName;
|
||||
|
||||
/** 文件存储路径 */
|
||||
@ApiModelProperty(value = "文件存储路径", position = 10)
|
||||
private String storagePath;
|
||||
|
||||
/** 文件下载路径 */
|
||||
@ApiModelProperty(value = "文件下载路径", position = 11)
|
||||
private String downloadPath;
|
||||
|
||||
/** 图片缩略图 */
|
||||
@ApiModelProperty(value = "图片缩略图", position = 12)
|
||||
private String thumbnail;
|
||||
|
||||
/** 扩展信息 */
|
||||
@ApiModelProperty(value = "扩展信息", position = 13)
|
||||
private String extJson;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.file.enums;
|
||||
|
||||
/**
|
||||
* 文件存储桶的权限策略枚举
|
||||
*
|
||||
*
|
||||
* @date 2022/1/5 23:29
|
||||
*/
|
||||
public enum DevFileBucketAuthEnum {
|
||||
|
||||
/**
|
||||
* 私有的(仅有 owner 可以读写)
|
||||
*/
|
||||
PRIVATE,
|
||||
|
||||
/**
|
||||
* 公有读,私有写( owner 可以读写, 其他客户可以读)
|
||||
*/
|
||||
PUBLIC_READ,
|
||||
|
||||
/**
|
||||
* 公共读写(即所有人都可以读写,慎用)
|
||||
*/
|
||||
PUBLIC_READ_WRITE
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.file.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 文件存储引擎类型枚举
|
||||
*
|
||||
*
|
||||
* @date 2022/6/16 16:14
|
||||
**/
|
||||
@Getter
|
||||
public enum DevFileEngineTypeEnum {
|
||||
|
||||
/** 本地 */
|
||||
LOCAL("LOCAL"),
|
||||
|
||||
/** 阿里云 */
|
||||
ALIYUN("ALIYUN"),
|
||||
|
||||
/** 腾讯云 */
|
||||
TENCENT("TENCENT"),
|
||||
|
||||
/** MINIO */
|
||||
MINIO("MINIO");
|
||||
|
||||
private final String value;
|
||||
|
||||
DevFileEngineTypeEnum(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.file.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import mjkf.xinke.dev.modular.file.entity.DevFile;
|
||||
|
||||
/**
|
||||
* 文件Mapper接口
|
||||
*
|
||||
*
|
||||
* @date 2022/2/23 18:40
|
||||
**/
|
||||
public interface DevFileMapper extends BaseMapper<DevFile> {
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="mjkf.xinke.dev.modular.file.mapper.DevFileMapper">
|
||||
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.file.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 文件Id参数
|
||||
*
|
||||
*
|
||||
* @date 2022/7/31 10:24
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevFileIdParam {
|
||||
|
||||
/** id */
|
||||
@ApiModelProperty(value = "id", required = true)
|
||||
@NotBlank(message = "id不能为空")
|
||||
private String id;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.file.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 文件列表参数
|
||||
*
|
||||
*
|
||||
* @date 2022/7/31 10:24
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevFileListParam {
|
||||
|
||||
/** 文件引擎 */
|
||||
@ApiModelProperty(value = "文件引擎")
|
||||
private String engine;
|
||||
|
||||
/** 文件名关键词 */
|
||||
@ApiModelProperty(value = "文件名关键词")
|
||||
private String searchKey;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.file.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 文件分页列表参数
|
||||
*
|
||||
*
|
||||
* @date 2022/7/31 10:24
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevFilePageParam {
|
||||
|
||||
/** 文件引擎 */
|
||||
@ApiModelProperty(value = "文件引擎")
|
||||
private String engine;
|
||||
|
||||
/** 文件名关键词 */
|
||||
@ApiModelProperty(value = "文件名关键词")
|
||||
private String searchKey;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.file.provider;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import mjkf.xinke.dev.api.DevFileApi;
|
||||
import mjkf.xinke.dev.modular.file.enums.DevFileEngineTypeEnum;
|
||||
import mjkf.xinke.dev.modular.file.service.DevFileService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 文件API接口提供者
|
||||
*
|
||||
*
|
||||
* @date 2022/6/22 15:32
|
||||
**/
|
||||
@Service
|
||||
public class DevFileApiProvider implements DevFileApi {
|
||||
|
||||
@Resource
|
||||
private DevFileService devFileService;
|
||||
|
||||
@Override
|
||||
public String storageFileWithReturnUrlLocal(MultipartFile file) {
|
||||
return devFileService.uploadReturnUrl(DevFileEngineTypeEnum.LOCAL.getValue(), file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String storageFileWithReturnIdLocal(MultipartFile file) {
|
||||
return devFileService.uploadReturnId(DevFileEngineTypeEnum.LOCAL.getValue(), file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String storageFileWithReturnUrlAliyun(MultipartFile file) {
|
||||
return devFileService.uploadReturnUrl(DevFileEngineTypeEnum.ALIYUN.getValue(), file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String storageFileWithReturnIdAliyun(MultipartFile file) {
|
||||
return devFileService.uploadReturnId(DevFileEngineTypeEnum.ALIYUN.getValue(), file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String storageFileWithReturnUrlTencent(MultipartFile file) {
|
||||
return devFileService.uploadReturnUrl(DevFileEngineTypeEnum.TENCENT.getValue(), file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String storageFileWithReturnIdTencent(MultipartFile file) {
|
||||
return devFileService.uploadReturnId(DevFileEngineTypeEnum.TENCENT.getValue(), file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String storageFileWithReturnUrlMinio(MultipartFile file) {
|
||||
return devFileService.uploadReturnUrl(DevFileEngineTypeEnum.MINIO.getValue(), file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String storageFileWithReturnIdMinio(MultipartFile file) {
|
||||
return devFileService.uploadReturnId(DevFileEngineTypeEnum.MINIO.getValue(), file);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.file.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import mjkf.xinke.dev.modular.file.entity.DevFile;
|
||||
import mjkf.xinke.dev.modular.file.param.DevFileIdParam;
|
||||
import mjkf.xinke.dev.modular.file.param.DevFileListParam;
|
||||
import mjkf.xinke.dev.modular.file.param.DevFilePageParam;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 文件Service接口
|
||||
*
|
||||
*
|
||||
* @date 2022/2/23 18:27
|
||||
**/
|
||||
public interface DevFileService extends IService<DevFile> {
|
||||
|
||||
/**
|
||||
* MultipartFile文件上传,返回文件id
|
||||
*
|
||||
*
|
||||
* @date 2022/4/22 15:53
|
||||
**/
|
||||
String uploadReturnId(String engine, MultipartFile file);
|
||||
|
||||
/**
|
||||
* MultipartFile文件上传,返回文件Url
|
||||
*
|
||||
*
|
||||
* @date 2022/4/22 15:53
|
||||
**/
|
||||
String uploadReturnUrl(String engine, MultipartFile file);
|
||||
|
||||
/**
|
||||
* 文件分页列表接口
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 15:44
|
||||
**/
|
||||
Page<DevFile> page(DevFilePageParam devFilePageParam);
|
||||
|
||||
/**
|
||||
* 文件列表接口
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 15:44
|
||||
**/
|
||||
List<DevFile> list(DevFileListParam devFileListParam);
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 15:44
|
||||
**/
|
||||
void download(DevFileIdParam devFileIdParam, HttpServletResponse response) throws IOException;
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*
|
||||
*
|
||||
* @date 2022/8/4 10:36
|
||||
**/
|
||||
void delete(List<DevFileIdParam> devFileIdParamList);
|
||||
|
||||
/**
|
||||
* 获取文件详情
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 21:18
|
||||
*/
|
||||
DevFile detail(DevFileIdParam devFileIdParam);
|
||||
|
||||
/**
|
||||
* 获取文件详情
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 21:18
|
||||
*/
|
||||
DevFile queryEntity(String id);
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.file.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollStreamUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.img.ImgUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import mjkf.xinke.common.exception.CommonException;
|
||||
import mjkf.xinke.common.page.CommonPageRequest;
|
||||
import mjkf.xinke.common.prop.CommonProperties;
|
||||
import mjkf.xinke.common.util.CommonDownloadUtil;
|
||||
import mjkf.xinke.common.util.CommonResponseUtil;
|
||||
import mjkf.xinke.dev.modular.file.entity.DevFile;
|
||||
import mjkf.xinke.dev.modular.file.enums.DevFileEngineTypeEnum;
|
||||
import mjkf.xinke.dev.modular.file.mapper.DevFileMapper;
|
||||
import mjkf.xinke.dev.modular.file.param.DevFileIdParam;
|
||||
import mjkf.xinke.dev.modular.file.param.DevFileListParam;
|
||||
import mjkf.xinke.dev.modular.file.param.DevFilePageParam;
|
||||
import mjkf.xinke.dev.modular.file.service.DevFileService;
|
||||
import mjkf.xinke.dev.modular.file.util.DevFileAliyunUtil;
|
||||
import mjkf.xinke.dev.modular.file.util.DevFileLocalUtil;
|
||||
import mjkf.xinke.dev.modular.file.util.DevFileMinIoUtil;
|
||||
import mjkf.xinke.dev.modular.file.util.DevFileTencentUtil;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 文件Service接口实现类
|
||||
*
|
||||
*
|
||||
* @date 2022/2/23 18:43
|
||||
**/
|
||||
@Service
|
||||
public class DevFileServiceImpl extends ServiceImpl<DevFileMapper, DevFile> implements DevFileService {
|
||||
|
||||
@Resource
|
||||
private CommonProperties commonProperties;
|
||||
|
||||
@Override
|
||||
public String uploadReturnId(String engine, MultipartFile file) {
|
||||
return this.storageFile(engine, file, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String uploadReturnUrl(String engine, MultipartFile file) {
|
||||
return this.storageFile(engine, file, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<DevFile> page(DevFilePageParam devFilePageParam) {
|
||||
QueryWrapper<DevFile> queryWrapper = new QueryWrapper<>();
|
||||
if(ObjectUtil.isNotEmpty(devFilePageParam.getEngine())) {
|
||||
queryWrapper.lambda().eq(DevFile::getEngine, devFilePageParam.getEngine());
|
||||
}
|
||||
if(ObjectUtil.isNotEmpty(devFilePageParam.getSearchKey())) {
|
||||
queryWrapper.lambda().like(DevFile::getName, devFilePageParam.getSearchKey());
|
||||
}
|
||||
return this.page(CommonPageRequest.defaultPage(), queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DevFile> list(DevFileListParam devFileListParam) {
|
||||
QueryWrapper<DevFile> queryWrapper = new QueryWrapper<>();
|
||||
if(ObjectUtil.isNotEmpty(devFileListParam.getEngine())) {
|
||||
queryWrapper.lambda().eq(DevFile::getEngine, devFileListParam.getEngine());
|
||||
}
|
||||
if(ObjectUtil.isNotEmpty(devFileListParam.getSearchKey())) {
|
||||
queryWrapper.lambda().like(DevFile::getName, devFileListParam.getSearchKey());
|
||||
}
|
||||
return this.list(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(DevFileIdParam devFileIdParam, HttpServletResponse response) throws IOException {
|
||||
DevFile devFile;
|
||||
try {
|
||||
devFile = this.queryEntity(devFileIdParam.getId());
|
||||
} catch (Exception e) {
|
||||
CommonResponseUtil.renderError(response, e.getMessage());
|
||||
return;
|
||||
}
|
||||
if(!devFile.getEngine().equals(DevFileEngineTypeEnum.LOCAL.getValue())) {
|
||||
CommonResponseUtil.renderError(response, "非本地文件不支持此方式下载,id值为:" + devFile.getId());
|
||||
return;
|
||||
}
|
||||
File file = FileUtil.file(devFile.getStoragePath());
|
||||
if(!FileUtil.exist(file)) {
|
||||
CommonResponseUtil.renderError(response, "找不到存储的文件,id值为:" + devFile.getId());
|
||||
return;
|
||||
}
|
||||
CommonDownloadUtil.download(devFile.getName(), IoUtil.readBytes(FileUtil.getInputStream(file)), response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(List<DevFileIdParam> devFileIdParamList) {
|
||||
this.removeByIds(CollStreamUtil.toList(devFileIdParamList, DevFileIdParam::getId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件
|
||||
*
|
||||
*
|
||||
* @date 2022/6/16 16:24
|
||||
**/
|
||||
private String storageFile(String engine, MultipartFile file, boolean returnFileId) {
|
||||
|
||||
// 如果引擎为空,默认使用本地
|
||||
if(ObjectUtil.isEmpty(engine)) {
|
||||
engine = DevFileEngineTypeEnum.LOCAL.getValue();
|
||||
}
|
||||
|
||||
// 生成id
|
||||
String fileId = IdWorker.getIdStr();
|
||||
|
||||
// 存储桶名称
|
||||
String bucketName;
|
||||
|
||||
// 定义存储的url,本地文件返回文件实际路径,其他引擎返回网络地址
|
||||
String storageUrl;
|
||||
|
||||
// 根据引擎类型执行不同方法
|
||||
if(engine.equals(DevFileEngineTypeEnum.LOCAL.getValue())) {
|
||||
|
||||
// 使用固定名称defaultBucketName
|
||||
bucketName = "defaultBucketName";
|
||||
storageUrl = DevFileLocalUtil.storageFileWithReturnUrl(bucketName, genFileKey(fileId, file), file);
|
||||
} else if(engine.equals(DevFileEngineTypeEnum.ALIYUN.getValue())) {
|
||||
|
||||
// 使用阿里云默认配置的bucketName
|
||||
bucketName = DevFileAliyunUtil.getDefaultBucketName();
|
||||
storageUrl = DevFileAliyunUtil.storageFileWithReturnUrl(bucketName, genFileKey(fileId, file), file);
|
||||
} else if(engine.equals(DevFileEngineTypeEnum.TENCENT.getValue())) {
|
||||
|
||||
// 使用腾讯云默认配置的bucketName
|
||||
bucketName = DevFileTencentUtil.getDefaultBucketName();
|
||||
storageUrl = DevFileTencentUtil.storageFileWithReturnUrl(bucketName, genFileKey(fileId, file), file);
|
||||
} else if(engine.equals(DevFileEngineTypeEnum.MINIO.getValue())) {
|
||||
|
||||
// 使用MINIO默认配置的bucketName
|
||||
bucketName = DevFileMinIoUtil.getDefaultBucketName();
|
||||
storageUrl = DevFileMinIoUtil.storageFileWithReturnUrl(bucketName, genFileKey(fileId, file), file);
|
||||
} else {
|
||||
throw new CommonException("不支持的文件引擎:{}", engine);
|
||||
}
|
||||
|
||||
// 将文件信息保存到数据库
|
||||
DevFile devFile = new DevFile();
|
||||
|
||||
// 设置文件id
|
||||
devFile.setId(fileId);
|
||||
|
||||
// 设置存储引擎类型
|
||||
devFile.setEngine(engine);
|
||||
devFile.setBucket(bucketName);
|
||||
devFile.setName(file.getOriginalFilename());
|
||||
String suffix = ObjectUtil.isNotEmpty(file.getOriginalFilename())?StrUtil.subAfter(file.getOriginalFilename(),
|
||||
StrUtil.DOT, true):null;
|
||||
devFile.setSuffix(suffix);
|
||||
devFile.setSizeKb(Convert.toStr(NumberUtil.div(new BigDecimal(file.getSize()), BigDecimal.valueOf(1024))
|
||||
.setScale(0, BigDecimal.ROUND_HALF_UP)));
|
||||
devFile.setSizeInfo(FileUtil.readableFileSize(file.getSize()));
|
||||
devFile.setObjName(ObjectUtil.isNotEmpty(devFile.getSuffix())?fileId + StrUtil.DOT + devFile.getSuffix():null);
|
||||
// 如果是图片,则压缩生成缩略图
|
||||
if(ObjectUtil.isNotEmpty(suffix)) {
|
||||
if(isPic(suffix)) {
|
||||
try {
|
||||
devFile.setThumbnail(ImgUtil.toBase64DataUri(ImgUtil.scale(ImgUtil.toImage(file.getBytes()),
|
||||
100, 100, null), suffix));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 存储路径
|
||||
devFile.setStoragePath(storageUrl);
|
||||
|
||||
// 定义下载地址
|
||||
String downloadUrl;
|
||||
|
||||
// 下载路径,注意:本地文件下载地址设置为下载接口地址 + 文件id
|
||||
if(engine.equals(DevFileEngineTypeEnum.LOCAL.getValue())) {
|
||||
String apiUrl = commonProperties.getBackendUrl();
|
||||
if(ObjectUtil.isEmpty(apiUrl)) {
|
||||
throw new CommonException("后端域名地址未正确配置:mjkf-xinke.config.common.backend-url为空");
|
||||
}
|
||||
downloadUrl= apiUrl + "/dev/file/download?id=" + fileId;
|
||||
devFile.setDownloadPath(downloadUrl);
|
||||
} else {
|
||||
// 阿里云、腾讯云、MINIO可以直接使用存储地址(公网)作为下载地址
|
||||
downloadUrl= storageUrl;
|
||||
devFile.setDownloadPath(devFile.getStoragePath());
|
||||
}
|
||||
|
||||
this.save(devFile);
|
||||
|
||||
// 如果是返回id则返回文件id
|
||||
if(returnFileId) {
|
||||
return fileId;
|
||||
} else {
|
||||
// 否则返回下载地址
|
||||
return downloadUrl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成文件的key,格式如 2021/10/11/1377109572375810050.docx
|
||||
*
|
||||
*
|
||||
* @date 2022/4/22 15:58
|
||||
**/
|
||||
public String genFileKey(String fileId, MultipartFile file) {
|
||||
|
||||
// 获取文件原始名称
|
||||
String originalFileName = file.getOriginalFilename();
|
||||
|
||||
// 获取文件后缀
|
||||
String fileSuffix = FileUtil.getSuffix(originalFileName);
|
||||
|
||||
// 生成文件的对象名称,格式如:1377109572375810050.docx
|
||||
String fileObjectName = fileId + StrUtil.DOT + fileSuffix;
|
||||
|
||||
// 获取日期文件夹,格式如,2021/10/11/
|
||||
String dateFolderPath = DateUtil.thisYear() + StrUtil.SLASH +
|
||||
(DateUtil.thisMonth() + 1) + StrUtil.SLASH +
|
||||
DateUtil.thisDayOfMonth() + StrUtil.SLASH;
|
||||
|
||||
// 返回
|
||||
return dateFolderPath + fileObjectName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DevFile detail(DevFileIdParam devFileIdParam) {
|
||||
return this.queryEntity(devFileIdParam.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DevFile queryEntity(String id) {
|
||||
DevFile devFile = this.getById(id);
|
||||
if(ObjectUtil.isEmpty(devFile)) {
|
||||
throw new CommonException("文件不存在,id值为:{}", id);
|
||||
}
|
||||
return devFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件后缀判断是否图片
|
||||
*
|
||||
*
|
||||
* @date 2020/7/6 15:31
|
||||
*/
|
||||
private static boolean isPic(String fileSuffix) {
|
||||
fileSuffix = fileSuffix.toLowerCase();
|
||||
return ImgUtil.IMAGE_TYPE_GIF.equals(fileSuffix)
|
||||
|| ImgUtil.IMAGE_TYPE_JPG.equals(fileSuffix)
|
||||
|| ImgUtil.IMAGE_TYPE_JPEG.equals(fileSuffix)
|
||||
|| ImgUtil.IMAGE_TYPE_BMP.equals(fileSuffix)
|
||||
|| ImgUtil.IMAGE_TYPE_PNG.equals(fileSuffix)
|
||||
|| ImgUtil.IMAGE_TYPE_PSD.equals(fileSuffix);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,460 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.file.util;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.aliyun.oss.*;
|
||||
import com.aliyun.oss.model.CannedAccessControlList;
|
||||
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
|
||||
import com.aliyun.oss.model.OSSObject;
|
||||
import com.aliyun.oss.model.ObjectMetadata;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import mjkf.xinke.common.exception.CommonException;
|
||||
import mjkf.xinke.dev.api.DevConfigApi;
|
||||
import mjkf.xinke.dev.modular.file.enums.DevFileBucketAuthEnum;
|
||||
|
||||
import javax.activation.MimetypesFileTypeMap;
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 阿里云文件工具类
|
||||
* 参考文档:https://help.aliyun.com/document_detail/32010.html
|
||||
*
|
||||
*
|
||||
* @date 2022/1/2 18:13
|
||||
*/
|
||||
@Slf4j
|
||||
public class DevFileAliyunUtil {
|
||||
|
||||
private static OSS client;
|
||||
|
||||
private static String defaultBucketName;
|
||||
|
||||
private static final String SNOWY_FILE_ALIYUN_ACCESS_KEY_ID_KEY = "SNOWY_FILE_ALIYUN_ACCESS_KEY_ID";
|
||||
private static final String SNOWY_FILE_ALIYUN_ACCESS_KEY_SECRET_KEY = "SNOWY_FILE_ALIYUN_ACCESS_KEY_SECRET";
|
||||
private static final String SNOWY_FILE_ALIYUN_END_POINT_KEY = "SNOWY_FILE_ALIYUN_END_POINT";
|
||||
private static final String SNOWY_FILE_ALIYUN_DEFAULT_BUCKET_NAME = "SNOWY_FILE_ALIYUN_DEFAULT_BUCKET_NAME";
|
||||
|
||||
/**
|
||||
* 初始化操作的客户端
|
||||
*
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
private static void initClient() {
|
||||
|
||||
DevConfigApi devConfigApi = SpringUtil.getBean(DevConfigApi.class);
|
||||
|
||||
/* accessKeyId */
|
||||
String accessKeyId = devConfigApi.getValueByKey(SNOWY_FILE_ALIYUN_ACCESS_KEY_ID_KEY);
|
||||
|
||||
if(ObjectUtil.isEmpty(accessKeyId)) {
|
||||
throw new CommonException("阿里云文件操作客户端未正确配置:accessKeyId为空");
|
||||
}
|
||||
|
||||
/* accessKeySecret */
|
||||
String accessKeySecret = devConfigApi.getValueByKey(SNOWY_FILE_ALIYUN_ACCESS_KEY_SECRET_KEY);
|
||||
|
||||
if(ObjectUtil.isEmpty(accessKeySecret)) {
|
||||
throw new CommonException("阿里云文件操作客户端未正确配置:accessKeySecret为空");
|
||||
}
|
||||
|
||||
/* endpoint */
|
||||
String endpoint = devConfigApi.getValueByKey(SNOWY_FILE_ALIYUN_END_POINT_KEY);
|
||||
|
||||
if(ObjectUtil.isEmpty(accessKeySecret)) {
|
||||
throw new CommonException("阿里云文件操作客户端未正确配置:endpoint为空");
|
||||
}
|
||||
|
||||
/* 默认BucketName */
|
||||
defaultBucketName = devConfigApi.getValueByKey(SNOWY_FILE_ALIYUN_DEFAULT_BUCKET_NAME);
|
||||
|
||||
if(ObjectUtil.isEmpty(defaultBucketName)) {
|
||||
throw new CommonException("阿里云文件操作客户端未正确配置:defaultBucketName为空");
|
||||
}
|
||||
|
||||
client = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取默认存储桶名称
|
||||
*
|
||||
*
|
||||
* @date 2022/6/22 18:05
|
||||
**/
|
||||
public static String getDefaultBucketName() {
|
||||
initClient();
|
||||
return defaultBucketName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁操作的客户端
|
||||
*
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void destroyClient() {
|
||||
initClient();
|
||||
client.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取操作的客户端
|
||||
*
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public OSS getClient() {
|
||||
initClient();
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询存储桶是否存在
|
||||
* 例如:传入参数examplebucket-1250000000,返回true代表存在此桶
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public boolean doesBucketExist(String bucketName) {
|
||||
try {
|
||||
initClient();
|
||||
return client.doesBucketExist(bucketName);
|
||||
} catch (OSSException | ClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置预定义策略
|
||||
* 预定义策略如公有读、公有读写、私有读
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param devFileBucketAuthEnum 存储桶权限
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void setBucketAcl(String bucketName, DevFileBucketAuthEnum devFileBucketAuthEnum) {
|
||||
try {
|
||||
initClient();
|
||||
if (devFileBucketAuthEnum.equals(DevFileBucketAuthEnum.PRIVATE)) {
|
||||
client.setBucketAcl(bucketName, CannedAccessControlList.Private);
|
||||
} else if (devFileBucketAuthEnum.equals(DevFileBucketAuthEnum.PUBLIC_READ)) {
|
||||
client.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
|
||||
} else if (devFileBucketAuthEnum.equals(DevFileBucketAuthEnum.PUBLIC_READ_WRITE)) {
|
||||
client.setBucketAcl(bucketName, CannedAccessControlList.PublicReadWrite);
|
||||
}
|
||||
} catch (OSSException | ClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否存在文件
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static boolean isExistingFile(String bucketName, String key) {
|
||||
try {
|
||||
initClient();
|
||||
return client.doesObjectExist(bucketName, key);
|
||||
} catch (OSSException | ClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,不返回地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param file 文件
|
||||
*
|
||||
* @date 2022/1/5 23:45
|
||||
*/
|
||||
public static void storageFile(String bucketName, String key, File file) {
|
||||
BufferedInputStream inputStream;
|
||||
try {
|
||||
inputStream = FileUtil.getInputStream(file);
|
||||
} catch (IORuntimeException e) {
|
||||
throw new CommonException("获取文件流异常,名称是:{}", file.getName());
|
||||
}
|
||||
storageFile(bucketName, key, inputStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,不返回地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param multipartFile 文件
|
||||
*
|
||||
* @date 2022/1/5 23:45
|
||||
*/
|
||||
public static void storageFile(String bucketName, String key, MultipartFile multipartFile) {
|
||||
InputStream inputStream;
|
||||
try {
|
||||
inputStream = multipartFile.getInputStream();
|
||||
} catch (IOException e) {
|
||||
throw new CommonException("获取文件流异常,名称是:{}", multipartFile.getName());
|
||||
}
|
||||
storageFile(bucketName, key, inputStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,不返回地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param bytes 文件字节数组
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void storageFile(String bucketName, String key, byte[] bytes) {
|
||||
ByteArrayInputStream byteArrayInputStream = null;
|
||||
try {
|
||||
initClient();
|
||||
byteArrayInputStream = new ByteArrayInputStream(bytes);
|
||||
ObjectMetadata objectMetadata = new ObjectMetadata();
|
||||
objectMetadata.setContentType(getFileContentType(key));
|
||||
client.putObject(bucketName, key, byteArrayInputStream, objectMetadata);
|
||||
} catch (OSSException | ClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
} finally {
|
||||
IoUtil.close(byteArrayInputStream);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,不返回地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param inputStream 文件流
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void storageFile(String bucketName, String key, InputStream inputStream) {
|
||||
try {
|
||||
initClient();
|
||||
ObjectMetadata objectMetadata = new ObjectMetadata();
|
||||
objectMetadata.setContentType(getFileContentType(key));
|
||||
client.putObject(bucketName, key, inputStream, objectMetadata);
|
||||
} catch (OSSException | ClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
} finally {
|
||||
IoUtil.close(inputStream);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,返回外网地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param file 文件
|
||||
*
|
||||
* @date 2022/1/5 23:45
|
||||
*/
|
||||
public static String storageFileWithReturnUrl(String bucketName, String key, File file) {
|
||||
storageFile(bucketName, key, file);
|
||||
setFileAcl(bucketName, key, DevFileBucketAuthEnum.PUBLIC_READ);
|
||||
return getFileAuthUrl(bucketName, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,返回外网地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param multipartFile 文件
|
||||
*
|
||||
* @date 2022/1/5 23:45
|
||||
*/
|
||||
public static String storageFileWithReturnUrl(String bucketName, String key, MultipartFile multipartFile) {
|
||||
storageFile(bucketName, key, multipartFile);
|
||||
setFileAcl(bucketName, key, DevFileBucketAuthEnum.PUBLIC_READ);
|
||||
return getFileAuthUrl(bucketName, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,返回外网地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param bytes 文件字节数组
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static String storageFileWithReturnUrl(String bucketName, String key, byte[] bytes) {
|
||||
storageFile(bucketName, key, bytes);
|
||||
setFileAcl(bucketName, key, DevFileBucketAuthEnum.PUBLIC_READ);
|
||||
return getFileAuthUrl(bucketName, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,返回外网地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param inputStream 文件流
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static String storageFileWithReturnUrl(String bucketName, String key, InputStream inputStream) {
|
||||
storageFile(bucketName, key, inputStream);
|
||||
setFileAcl(bucketName, key, DevFileBucketAuthEnum.PUBLIC_READ);
|
||||
return getFileAuthUrl(bucketName, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某个bucket下的文件字节
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static byte[] getFileBytes(String bucketName, String key) {
|
||||
InputStream objectContent = null;
|
||||
try {
|
||||
initClient();
|
||||
OSSObject ossObject = client.getObject(bucketName, key);
|
||||
objectContent = ossObject.getObjectContent();
|
||||
return IoUtil.readBytes(objectContent);
|
||||
} catch (OSSException | ClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
} finally {
|
||||
IoUtil.close(objectContent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置文件访问权限管理
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param devFileBucketAuthEnum 文件权限
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void setFileAcl(String bucketName, String key, DevFileBucketAuthEnum devFileBucketAuthEnum) {
|
||||
try {
|
||||
initClient();
|
||||
if (devFileBucketAuthEnum.equals(DevFileBucketAuthEnum.PRIVATE)) {
|
||||
client.setObjectAcl(bucketName, key, CannedAccessControlList.Private);
|
||||
} else if (devFileBucketAuthEnum.equals(DevFileBucketAuthEnum.PUBLIC_READ)) {
|
||||
client.setObjectAcl(bucketName, key, CannedAccessControlList.PublicRead);
|
||||
} else if (devFileBucketAuthEnum.equals(DevFileBucketAuthEnum.PUBLIC_READ_WRITE)) {
|
||||
client.setObjectAcl(bucketName, key, CannedAccessControlList.PublicReadWrite);
|
||||
}
|
||||
} catch (OSSException | ClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拷贝文件
|
||||
*
|
||||
* @param originBucketName 源文件桶
|
||||
* @param originFileKey 源文件名称
|
||||
* @param newBucketName 新文件桶
|
||||
* @param newFileKey 新文件名称
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void copyFile(String originBucketName, String originFileKey, String newBucketName, String newFileKey) {
|
||||
try {
|
||||
initClient();
|
||||
client.copyObject(originBucketName, originFileKey, newBucketName, newFileKey);
|
||||
} catch (OSSException | ClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件的下载地址(带鉴权和有效时间的),生成外网地址
|
||||
*
|
||||
* @param bucketName 文件桶
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param timeoutMillis 时效
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static String getFileAuthUrl(String bucketName, String key, Long timeoutMillis) {
|
||||
initClient();
|
||||
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, key, HttpMethod.GET);
|
||||
Date expirationDate = new Date(System.currentTimeMillis() + timeoutMillis);
|
||||
request.setExpiration(expirationDate);
|
||||
URL url;
|
||||
try {
|
||||
url = client.generatePresignedUrl(request);
|
||||
} catch (OSSException | ClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件的下载地址(永久的,文件必须为公有读),生成外网地址
|
||||
*
|
||||
* @param bucketName 文件桶
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static String getFileAuthUrl(String bucketName, String key) {
|
||||
try {
|
||||
initClient();
|
||||
OSSClient ossClient = (OSSClient) client;
|
||||
List<String> urlList = StrUtil.split(ossClient.getEndpoint().toString(), StrUtil.COLON + StrUtil.SLASH + StrUtil.SLASH);
|
||||
return urlList.get(0) + StrUtil.COLON + StrUtil.SLASH + StrUtil.SLASH + bucketName + StrUtil.DOT + urlList.get(1) + StrUtil.SLASH + key;
|
||||
} catch (OSSException | ClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*
|
||||
* @param bucketName 文件桶
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void deleteFile(String bucketName, String key) {
|
||||
try{
|
||||
initClient();
|
||||
client.deleteObject(bucketName, key);
|
||||
} catch (OSSException | ClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件名获取ContentType
|
||||
*
|
||||
*
|
||||
* @date 2022/1/6 11:27
|
||||
**/
|
||||
private static String getFileContentType(String key) {
|
||||
// 根据文件名获取contentType
|
||||
String contentType = "application/octet-stream";
|
||||
if (key.contains(".")) {
|
||||
contentType = MimetypesFileTypeMap.getDefaultFileTypeMap().getContentType(key);
|
||||
}
|
||||
return contentType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,352 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.file.util;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.hutool.system.SystemUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import mjkf.xinke.common.exception.CommonException;
|
||||
import mjkf.xinke.dev.api.DevConfigApi;
|
||||
import mjkf.xinke.dev.modular.file.enums.DevFileBucketAuthEnum;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* 本地文件工具类
|
||||
*
|
||||
*
|
||||
* @date 2022/1/2 18:13
|
||||
*/
|
||||
@Slf4j
|
||||
public class DevFileLocalUtil {
|
||||
|
||||
private static JSONObject client;
|
||||
|
||||
private static final String SNOWY_FILE_LOCAL_FOLDER_FOR_WINDOWS_KEY = "SNOWY_FILE_LOCAL_FOLDER_FOR_WINDOWS";
|
||||
private static final String SNOWY_FILE_LOCAL_FOLDER_FOR_UNIX_KEY = "SNOWY_FILE_LOCAL_FOLDER_FOR_UNIX";
|
||||
|
||||
/**
|
||||
* 初始化操作的客户端
|
||||
*
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
private static void initClient() {
|
||||
|
||||
String uploadFileFolder;
|
||||
|
||||
DevConfigApi devConfigApi = SpringUtil.getBean(DevConfigApi.class);
|
||||
|
||||
if(SystemUtil.getOsInfo().isWindows()) {
|
||||
|
||||
/* 本地文件上传的位置 windows系统 */
|
||||
String localFolderForWindows = devConfigApi.getValueByKey(SNOWY_FILE_LOCAL_FOLDER_FOR_WINDOWS_KEY);
|
||||
|
||||
if(ObjectUtil.isEmpty(localFolderForWindows)) {
|
||||
throw new CommonException("本地文件操作客户端未正确配置:SNOWY_FILE_LOCAL_FOLDER_FOR_WINDOWS为空");
|
||||
}
|
||||
uploadFileFolder = localFolderForWindows;
|
||||
} else {
|
||||
|
||||
/* 本地文件上传的位置 unix系列系统(linux、mac等) */
|
||||
String localFolderForUnix = devConfigApi.getValueByKey(SNOWY_FILE_LOCAL_FOLDER_FOR_UNIX_KEY);
|
||||
|
||||
if(ObjectUtil.isEmpty(localFolderForUnix)) {
|
||||
throw new CommonException("本地文件操作客户端未正确配置:SNOWY_FILE_LOCAL_FOLDER_FOR_UNIX为空");
|
||||
}
|
||||
uploadFileFolder = localFolderForUnix;
|
||||
}
|
||||
if(!FileUtil.exist(uploadFileFolder)) {
|
||||
FileUtil.mkdir(uploadFileFolder);
|
||||
}
|
||||
client = JSONUtil.createObj();
|
||||
client.set("localFileUploadFolder", uploadFileFolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁操作的客户端
|
||||
*
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void destroyClient() {
|
||||
client.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取操作的客户端
|
||||
*
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static JSONObject getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上传地址
|
||||
*
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static String getUploadFileFolder() {
|
||||
return client.getStr("localFileUploadFolder");
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询存储桶是否存在
|
||||
* 例如:传入参数examplebucket-1250000000,返回true代表存在此桶
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static boolean doesBucketExist(String bucketName) {
|
||||
initClient();
|
||||
return FileUtil.exist(getUploadFileFolder() + FileUtil.FILE_SEPARATOR + bucketName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置预定义策略
|
||||
* 预定义策略如公有读、公有读写、私有读
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param devFileBucketAuthEnum 存储桶权限
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void setBucketAcl(String bucketName, DevFileBucketAuthEnum devFileBucketAuthEnum) {
|
||||
// 无需
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否存在文件
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static boolean isExistingFile(String bucketName, String key) {
|
||||
initClient();
|
||||
return FileUtil.exist(getUploadFileFolder() + FileUtil.FILE_SEPARATOR + bucketName + FileUtil.FILE_SEPARATOR + key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,不返回地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param file 文件
|
||||
*
|
||||
* @date 2022/1/5 23:45
|
||||
*/
|
||||
public static void storageFile(String bucketName, String key, File file) {
|
||||
BufferedInputStream inputStream;
|
||||
try {
|
||||
inputStream = FileUtil.getInputStream(file);
|
||||
} catch (IORuntimeException e) {
|
||||
throw new CommonException("获取文件流异常,名称是:{}", file.getName());
|
||||
}
|
||||
storageFile(bucketName, key, inputStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,不返回地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param multipartFile 文件
|
||||
*
|
||||
* @date 2022/1/5 23:45
|
||||
*/
|
||||
public static void storageFile(String bucketName, String key, MultipartFile multipartFile) {
|
||||
InputStream inputStream;
|
||||
try {
|
||||
inputStream = multipartFile.getInputStream();
|
||||
} catch (IOException e) {
|
||||
throw new CommonException("获取文件流异常,名称是:{}", multipartFile.getName());
|
||||
}
|
||||
storageFile(bucketName, key, inputStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,不返回地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param bytes 文件字节数组
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void storageFile(String bucketName, String key, byte[] bytes) {
|
||||
initClient();
|
||||
FileUtil.writeBytes(bytes, getUploadFileFolder() + FileUtil.FILE_SEPARATOR + bucketName + FileUtil.FILE_SEPARATOR + key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,不返回地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param inputStream 文件流
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void storageFile(String bucketName, String key, InputStream inputStream) {
|
||||
initClient();
|
||||
FileUtil.writeFromStream(inputStream, getUploadFileFolder() + FileUtil.FILE_SEPARATOR + bucketName + FileUtil.FILE_SEPARATOR + key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,返回存储的地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param file 文件
|
||||
*
|
||||
* @date 2022/1/5 23:45
|
||||
*/
|
||||
public static String storageFileWithReturnUrl(String bucketName, String key, File file) {
|
||||
storageFile(bucketName, key, file);
|
||||
return getFileAuthUrl(bucketName, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,返回存储的地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param multipartFile 文件
|
||||
*
|
||||
* @date 2022/1/5 23:45
|
||||
*/
|
||||
public static String storageFileWithReturnUrl(String bucketName, String key, MultipartFile multipartFile) {
|
||||
storageFile(bucketName, key, multipartFile);
|
||||
return getFileAuthUrl(bucketName, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,返回存储的地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param bytes 文件字节数组
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static String storageFileWithReturnUrl(String bucketName, String key, byte[] bytes) {
|
||||
storageFile(bucketName, key, bytes);
|
||||
return getFileAuthUrl(bucketName, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,返回存储的地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param inputStream 文件流
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static String storageFileWithReturnUrl(String bucketName, String key, InputStream inputStream) {
|
||||
storageFile(bucketName, key, inputStream);
|
||||
return getFileAuthUrl(bucketName, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某个bucket下的文件字节
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static byte[] getFileBytes(String bucketName, String key) {
|
||||
File file = getFileByBucketNameAndKey(bucketName, key);
|
||||
return FileUtil.readBytes(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置文件访问权限管理
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param devFileBucketAuthEnum 文件权限
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void setFileAcl(String bucketName, String key, DevFileBucketAuthEnum devFileBucketAuthEnum) {
|
||||
// 无需
|
||||
}
|
||||
|
||||
/**
|
||||
* 拷贝文件
|
||||
*
|
||||
* @param originBucketName 源文件桶
|
||||
* @param originFileKey 源文件名称
|
||||
* @param newBucketName 新文件桶
|
||||
* @param newFileKey 新文件名称
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void copyFile(String originBucketName, String originFileKey, String newBucketName, String newFileKey) {
|
||||
initClient();
|
||||
File file = getFileByBucketNameAndKey(originBucketName, originFileKey);
|
||||
File newFile = FileUtil.file(getUploadFileFolder() + FileUtil.FILE_SEPARATOR + newBucketName + FileUtil.FILE_SEPARATOR + newFileKey);
|
||||
FileUtil.copy(file, newFile, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件的实际存储地址
|
||||
*
|
||||
* @param bucketName 文件桶
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static String getFileAuthUrl(String bucketName, String key) {
|
||||
initClient();
|
||||
File file = getFileByBucketNameAndKey(bucketName, key);
|
||||
return file.getAbsolutePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*
|
||||
* @param bucketName 文件桶
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void deleteFile(String bucketName, String key) {
|
||||
File file = getFileByBucketNameAndKey(bucketName, key);
|
||||
FileUtil.del(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据桶名称和文件key获取文件
|
||||
*
|
||||
* @param bucketName 文件桶
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static File getFileByBucketNameAndKey(String bucketName, String key) {
|
||||
initClient();
|
||||
String path = getUploadFileFolder() + FileUtil.FILE_SEPARATOR + bucketName + FileUtil.FILE_SEPARATOR + key;
|
||||
File file = FileUtil.file(path);
|
||||
if(!FileUtil.exist(file)) {
|
||||
throw new CommonException("文件{}不存在", path);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,455 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.file.util;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.json.JSONArray;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import io.minio.*;
|
||||
import io.minio.http.Method;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import mjkf.xinke.common.exception.CommonException;
|
||||
import mjkf.xinke.dev.api.DevConfigApi;
|
||||
import mjkf.xinke.dev.modular.file.enums.DevFileBucketAuthEnum;
|
||||
|
||||
import javax.activation.MimetypesFileTypeMap;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* MINIO文件工具类
|
||||
* 参考文档:http://docs.minio.org.cn/docs/master/java-client-quickstart-guide
|
||||
*
|
||||
*
|
||||
* @date 2022/1/2 18:13
|
||||
*/
|
||||
@Slf4j
|
||||
public class DevFileMinIoUtil {
|
||||
|
||||
private static MinioClient client;
|
||||
|
||||
private static String defaultBucketName;
|
||||
|
||||
private static final String SNOWY_FILE_MINIO_ACCESS_KEY_KEY = "SNOWY_FILE_MINIO_ACCESS_KEY";
|
||||
private static final String SNOWY_FILE_MINIO_SECRET_KEY_KEY = "SNOWY_FILE_MINIO_SECRET_KEY";
|
||||
private static final String SNOWY_FILE_MINIO_END_POINT_KEY = "SNOWY_FILE_MINIO_END_POINT";
|
||||
private static final String SNOWY_FILE_MINIO_DEFAULT_BUCKET_NAME = "SNOWY_FILE_MINIO_DEFAULT_BUCKET_NAME";
|
||||
|
||||
|
||||
/**
|
||||
* 初始化操作的客户端
|
||||
*
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
private static void initClient() {
|
||||
|
||||
DevConfigApi devConfigApi = SpringUtil.getBean(DevConfigApi.class);
|
||||
|
||||
/* accessKey */
|
||||
String accessKey = devConfigApi.getValueByKey(SNOWY_FILE_MINIO_ACCESS_KEY_KEY);
|
||||
|
||||
if(ObjectUtil.isEmpty(accessKey)) {
|
||||
throw new CommonException("MINIO文件操作客户端未正确配置:accessKey为空");
|
||||
}
|
||||
|
||||
/* secretKey */
|
||||
String secretKey = devConfigApi.getValueByKey(SNOWY_FILE_MINIO_SECRET_KEY_KEY);
|
||||
|
||||
if(ObjectUtil.isEmpty(secretKey)) {
|
||||
throw new CommonException("MINIO文件操作客户端未正确配置:secretKey为空");
|
||||
}
|
||||
|
||||
/* endpoint */
|
||||
String endpoint = devConfigApi.getValueByKey(SNOWY_FILE_MINIO_END_POINT_KEY);
|
||||
|
||||
if(ObjectUtil.isEmpty(endpoint)) {
|
||||
throw new CommonException("MINIO文件操作客户端未正确配置:secretKey为空");
|
||||
}
|
||||
|
||||
/* 默认BucketName */
|
||||
defaultBucketName = devConfigApi.getValueByKey(SNOWY_FILE_MINIO_DEFAULT_BUCKET_NAME);
|
||||
|
||||
if(ObjectUtil.isEmpty(defaultBucketName)) {
|
||||
throw new CommonException("MINIO文件操作客户端未正确配置:defaultBucketName为空");
|
||||
}
|
||||
|
||||
client = MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取默认存储桶名称
|
||||
*
|
||||
*
|
||||
* @date 2022/6/22 18:05
|
||||
**/
|
||||
public static String getDefaultBucketName() {
|
||||
initClient();
|
||||
return defaultBucketName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁操作的客户端
|
||||
*
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void destroyClient() {
|
||||
// 无需
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取操作的客户端
|
||||
*
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static MinioClient getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询存储桶是否存在
|
||||
* 例如:传入参数examplebucket-1250000000,返回true代表存在此桶
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static boolean doesBucketExist(String bucketName) {
|
||||
try {
|
||||
initClient();
|
||||
BucketExistsArgs bucketExistsArgs = BucketExistsArgs.builder().bucket(bucketName).build();
|
||||
client.bucketExists(bucketExistsArgs);
|
||||
} catch (Exception e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置预定义策略
|
||||
* 预定义策略如公有读、公有读写、私有读
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param devFileBucketAuthEnum 存储桶权限
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void setBucketAcl(String bucketName, DevFileBucketAuthEnum devFileBucketAuthEnum) {
|
||||
setFileAcl(bucketName, "*", devFileBucketAuthEnum);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否存在文件
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static boolean isExistingFile(String bucketName, String key) {
|
||||
try {
|
||||
initClient();
|
||||
GetObjectArgs getObjectArgs = GetObjectArgs.builder().bucket(bucketName).object(key).build();
|
||||
InputStream object = client.getObject(getObjectArgs);
|
||||
return !ObjectUtil.isEmpty(object);
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,不返回地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param file 文件
|
||||
*
|
||||
* @date 2022/1/5 23:45
|
||||
*/
|
||||
public static void storageFile(String bucketName, String key, File file) {
|
||||
BufferedInputStream inputStream;
|
||||
try {
|
||||
inputStream = FileUtil.getInputStream(file);
|
||||
} catch (IORuntimeException e) {
|
||||
throw new CommonException("获取文件流异常,名称是:{}", file.getName());
|
||||
}
|
||||
storageFile(bucketName, key, inputStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,不返回地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param multipartFile 文件
|
||||
*
|
||||
* @date 2022/1/5 23:45
|
||||
*/
|
||||
public static void storageFile(String bucketName, String key, MultipartFile multipartFile) {
|
||||
InputStream inputStream;
|
||||
try {
|
||||
inputStream = multipartFile.getInputStream();
|
||||
} catch (IOException e) {
|
||||
throw new CommonException("获取文件流异常,名称是:{}", multipartFile.getName());
|
||||
}
|
||||
storageFile(bucketName, key, inputStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,不返回地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param bytes 文件字节数组
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void storageFile(String bucketName, String key, byte[] bytes) {
|
||||
ByteArrayInputStream byteArrayInputStream = null;
|
||||
try {
|
||||
initClient();
|
||||
byteArrayInputStream = new ByteArrayInputStream(bytes);
|
||||
PutObjectArgs putObjectArgs = PutObjectArgs.builder().bucket(bucketName).object(key)
|
||||
.contentType(getFileContentType(key)).stream(byteArrayInputStream, bytes.length, -1).build();
|
||||
client.putObject(putObjectArgs);
|
||||
} catch (Exception e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
} finally {
|
||||
IoUtil.close(byteArrayInputStream);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,不返回地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param inputStream 文件流
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void storageFile(String bucketName, String key, InputStream inputStream) {
|
||||
try {
|
||||
initClient();
|
||||
PutObjectArgs putObjectArgs = PutObjectArgs.builder().bucket(bucketName).object(key)
|
||||
.contentType(getFileContentType(key)).stream(inputStream, inputStream.available(), -1).build();
|
||||
client.putObject(putObjectArgs);
|
||||
} catch (Exception e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
} finally {
|
||||
IoUtil.close(inputStream);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,返回外网地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param file 文件
|
||||
*
|
||||
* @date 2022/1/5 23:45
|
||||
*/
|
||||
public static String storageFileWithReturnUrl(String bucketName, String key, File file) {
|
||||
storageFile(bucketName, key, file);
|
||||
setFileAcl(bucketName, key, DevFileBucketAuthEnum.PUBLIC_READ);
|
||||
return getFileAuthUrl(bucketName, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,返回外网地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param multipartFile 文件
|
||||
*
|
||||
* @date 2022/1/5 23:45
|
||||
*/
|
||||
public static String storageFileWithReturnUrl(String bucketName, String key, MultipartFile multipartFile) {
|
||||
storageFile(bucketName, key, multipartFile);
|
||||
setFileAcl(bucketName, key, DevFileBucketAuthEnum.PUBLIC_READ);
|
||||
return getFileAuthUrl(bucketName, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,返回外网地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param bytes 文件字节数组
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static String storageFileWithReturnUrl(String bucketName, String key, byte[] bytes) {
|
||||
storageFile(bucketName, key, bytes);
|
||||
setFileAcl(bucketName, key, DevFileBucketAuthEnum.PUBLIC_READ);
|
||||
return getFileAuthUrl(bucketName, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,返回外网地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param inputStream 文件流
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static String storageFileWithReturnUrl(String bucketName, String key, InputStream inputStream) {
|
||||
storageFile(bucketName, key, inputStream);
|
||||
setFileAcl(bucketName, key, DevFileBucketAuthEnum.PUBLIC_READ);
|
||||
return getFileAuthUrl(bucketName, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某个bucket下的文件字节
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static byte[] getFileBytes(String bucketName, String key) {
|
||||
try {
|
||||
initClient();
|
||||
GetObjectArgs getObjectArgs = GetObjectArgs.builder().bucket(bucketName).object(key).build();
|
||||
InputStream inputStream = client.getObject(getObjectArgs);
|
||||
return IoUtil.readBytes(inputStream);
|
||||
} catch (Exception e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置文件访问权限管理
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param devFileBucketAuthEnum 文件权限
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void setFileAcl(String bucketName, String key, DevFileBucketAuthEnum devFileBucketAuthEnum) {
|
||||
try {
|
||||
JSONObject configObject = JSONUtil.createObj().set("Version", "2012-10-17");
|
||||
JSONArray statementArray = JSONUtil.createArray();
|
||||
JSONArray actionArray = JSONUtil.createArray();
|
||||
if(devFileBucketAuthEnum.equals(DevFileBucketAuthEnum.PUBLIC_READ)) {
|
||||
actionArray.put("s3:GetObject");
|
||||
}
|
||||
if(devFileBucketAuthEnum.equals(DevFileBucketAuthEnum.PUBLIC_READ_WRITE)) {
|
||||
actionArray.put("s3:GetObject");
|
||||
actionArray.put("s3:PutObject");
|
||||
}
|
||||
JSONObject statementObject = JSONUtil.createObj();
|
||||
statementObject.set("Effect", "Allow").set("Principal", JSONUtil.createObj().set("AWS", JSONUtil.createArray().put("*")))
|
||||
.set("Action", actionArray).set("Resource", JSONUtil.createArray().put("arn:aws:s3:::" + bucketName + "/*"));
|
||||
statementArray.put(statementObject);
|
||||
configObject.set("Statement", statementArray);
|
||||
String config = JSONUtil.toJsonStr(configObject);
|
||||
SetBucketPolicyArgs setBucketPolicyArgs = SetBucketPolicyArgs.builder().bucket(bucketName).config(config).build();
|
||||
client.setBucketPolicy(setBucketPolicyArgs);
|
||||
} catch (Exception e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拷贝文件
|
||||
*
|
||||
* @param originBucketName 源文件桶
|
||||
* @param originFileKey 源文件名称
|
||||
* @param newBucketName 新文件桶
|
||||
* @param newFileKey 新文件名称
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void copyFile(String originBucketName, String originFileKey, String newBucketName, String newFileKey) {
|
||||
try {
|
||||
initClient();
|
||||
CopySource copySource = CopySource.builder().bucket(originBucketName).object(originFileKey).build();
|
||||
CopyObjectArgs copyObjectArgs = CopyObjectArgs.builder().source(copySource).bucket(newBucketName).object(newFileKey).build();
|
||||
client.copyObject(copyObjectArgs);
|
||||
} catch (Exception e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件的下载地址(带鉴权和有效时间的),生成外网地址
|
||||
*
|
||||
* @param bucketName 文件桶
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param timeoutMillis 时效
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static String getFileAuthUrl(String bucketName, String key, Long timeoutMillis) {
|
||||
try {
|
||||
initClient();
|
||||
GetPresignedObjectUrlArgs getPresignedObjectUrlArgs = GetPresignedObjectUrlArgs.builder().bucket(bucketName)
|
||||
.object(key).method(Method.GET).expiry(timeoutMillis.intValue()).build();
|
||||
return client.getPresignedObjectUrl(getPresignedObjectUrlArgs);
|
||||
} catch (Exception e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件的下载地址(永久的,文件必须为公有读),生成外网地址
|
||||
*
|
||||
* @param bucketName 文件桶
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static String getFileAuthUrl(String bucketName, String key) {
|
||||
try {
|
||||
initClient();
|
||||
DevConfigApi devConfigApi = SpringUtil.getBean(DevConfigApi.class);
|
||||
return devConfigApi.getValueByKey(SNOWY_FILE_MINIO_END_POINT_KEY) + StrUtil.SLASH + bucketName + StrUtil.SLASH + key;
|
||||
} catch (Exception e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*
|
||||
* @param bucketName 文件桶
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void deleteFile(String bucketName, String key) {
|
||||
try {
|
||||
RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().bucket(bucketName).object(key).build();
|
||||
client.removeObject(removeObjectArgs);
|
||||
} catch (Exception e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件名获取ContentType
|
||||
*
|
||||
*
|
||||
* @date 2022/1/6 11:27
|
||||
**/
|
||||
private static String getFileContentType(String key) {
|
||||
// 根据文件名获取contentType
|
||||
String contentType = "application/octet-stream";
|
||||
if (key.contains(".")) {
|
||||
contentType = MimetypesFileTypeMap.getDefaultFileTypeMap().getContentType(key);
|
||||
}
|
||||
return contentType;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,492 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.file.util;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
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.exception.CosClientException;
|
||||
import com.qcloud.cos.http.HttpMethodName;
|
||||
import com.qcloud.cos.model.*;
|
||||
import com.qcloud.cos.region.Region;
|
||||
import com.qcloud.cos.transfer.TransferManager;
|
||||
import com.qcloud.cos.transfer.TransferManagerConfiguration;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import mjkf.xinke.common.exception.CommonException;
|
||||
import mjkf.xinke.dev.api.DevConfigApi;
|
||||
import mjkf.xinke.dev.modular.file.enums.DevFileBucketAuthEnum;
|
||||
|
||||
import javax.activation.MimetypesFileTypeMap;
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
* 腾讯云文件工具类
|
||||
* 参考文档:https://cloud.tencent.com/document/product/436/10199
|
||||
*
|
||||
*
|
||||
* @date 2022/1/2 18:13
|
||||
*/
|
||||
@Slf4j
|
||||
public class DevFileTencentUtil {
|
||||
|
||||
private static COSClient client;
|
||||
|
||||
private static String defaultBucketName;
|
||||
|
||||
private static TransferManager transferManager;
|
||||
|
||||
private static final String SNOWY_FILE_TENCENT_SECRET_ID_KEY = "SNOWY_FILE_TENCENT_SECRET_ID";
|
||||
private static final String SNOWY_FILE_TENCENT_SECRET_KEY_KEY = "SNOWY_FILE_TENCENT_SECRET_KEY";
|
||||
private static final String SNOWY_FILE_TENCENT_REGION_ID_KEY = "SNOWY_FILE_TENCENT_REGION_ID";
|
||||
private static final String SNOWY_FILE_TENCENT_DEFAULT_BUCKET_NAME = "SNOWY_FILE_TENCENT_DEFAULT_BUCKET_NAME";
|
||||
|
||||
/**
|
||||
* 初始化操作的客户端
|
||||
*
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
private static void initClient() {
|
||||
|
||||
DevConfigApi devConfigApi = SpringUtil.getBean(DevConfigApi.class);
|
||||
|
||||
/* secretId */
|
||||
String secretId = devConfigApi.getValueByKey(SNOWY_FILE_TENCENT_SECRET_ID_KEY);
|
||||
|
||||
if(ObjectUtil.isEmpty(secretId)) {
|
||||
throw new CommonException("腾讯云文件操作客户端未正确配置:secretId为空");
|
||||
}
|
||||
|
||||
/* secretKey */
|
||||
String secretKey = devConfigApi.getValueByKey(SNOWY_FILE_TENCENT_SECRET_KEY_KEY);
|
||||
|
||||
if(ObjectUtil.isEmpty(secretKey)) {
|
||||
throw new CommonException("腾讯云文件操作客户端未正确配置:secretKey为空");
|
||||
}
|
||||
|
||||
/* regionId */
|
||||
String regionId = devConfigApi.getValueByKey(SNOWY_FILE_TENCENT_REGION_ID_KEY);
|
||||
|
||||
if(ObjectUtil.isEmpty(regionId)) {
|
||||
throw new CommonException("腾讯云文件操作客户端未正确配置:regionId为空");
|
||||
}
|
||||
|
||||
/* 默认BucketName */
|
||||
defaultBucketName = devConfigApi.getValueByKey(SNOWY_FILE_TENCENT_DEFAULT_BUCKET_NAME);
|
||||
|
||||
if(ObjectUtil.isEmpty(defaultBucketName)) {
|
||||
throw new CommonException("腾讯云文件操作客户端未正确配置:defaultBucketName为空");
|
||||
}
|
||||
|
||||
|
||||
// 1.初始化用户身份信息
|
||||
Region region = new Region(regionId);
|
||||
COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
|
||||
|
||||
// 2.设置 bucket 的区域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
|
||||
|
||||
ClientConfig clientConfig = new ClientConfig(region);
|
||||
|
||||
// 3.生成 cos 客户端。
|
||||
client = new COSClient(cred, clientConfig);
|
||||
|
||||
// 4.线程池大小,建议在客户端与 COS 网络充足(例如使用腾讯云的 CVM,同地域上传 COS)的情况下,设置成16或32即可,可较充分的利用网络资源
|
||||
// 对于使用公网传输且网络带宽质量不高的情况,建议减小该值,避免因网速过慢,造成请求超时。
|
||||
ExecutorService threadPool = Executors.newFixedThreadPool(32);
|
||||
|
||||
// 5.传入一个线程池, 若不传入线程池,默认 TransferManager 中会生成一个单线程的线程池。
|
||||
transferManager = new TransferManager(client, threadPool);
|
||||
|
||||
// 6.设置高级接口的分块上传阈值和分块大小为10MB
|
||||
TransferManagerConfiguration transferManagerConfiguration = new TransferManagerConfiguration();
|
||||
transferManagerConfiguration.setMultipartUploadThreshold(10 * 1024 * 1024);
|
||||
transferManagerConfiguration.setMinimumUploadPartSize(10 * 1024 * 1024);
|
||||
transferManager.setConfiguration(transferManagerConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取默认存储桶名称
|
||||
*
|
||||
*
|
||||
* @date 2022/6/22 18:05
|
||||
**/
|
||||
public static String getDefaultBucketName() {
|
||||
initClient();
|
||||
return defaultBucketName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁操作的客户端
|
||||
*
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void destroyClient() {
|
||||
initClient();
|
||||
client.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取操作的客户端
|
||||
*
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static COSClient getClient() {
|
||||
initClient();
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询存储桶是否存在
|
||||
* 例如:传入参数examplebucket-1250000000,返回true代表存在此桶
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static boolean doesBucketExist(String bucketName) {
|
||||
try {
|
||||
initClient();
|
||||
return client.doesBucketExist(bucketName);
|
||||
} catch (CosClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置预定义策略
|
||||
* 预定义策略如公有读、公有读写、私有读
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param devFileBucketAuthEnum 存储桶权限
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void setBucketAcl(String bucketName, DevFileBucketAuthEnum devFileBucketAuthEnum) {
|
||||
try {
|
||||
initClient();
|
||||
if (devFileBucketAuthEnum.equals(DevFileBucketAuthEnum.PRIVATE)) {
|
||||
client.setBucketAcl(bucketName, CannedAccessControlList.Private);
|
||||
} else if (devFileBucketAuthEnum.equals(DevFileBucketAuthEnum.PUBLIC_READ)) {
|
||||
client.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
|
||||
} else if (devFileBucketAuthEnum.equals(DevFileBucketAuthEnum.PUBLIC_READ_WRITE)) {
|
||||
client.setBucketAcl(bucketName, CannedAccessControlList.PublicReadWrite);
|
||||
}
|
||||
} catch (CosClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否存在文件
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static boolean isExistingFile(String bucketName, String key) {
|
||||
try {
|
||||
initClient();
|
||||
client.getObjectMetadata(bucketName, key);
|
||||
return true;
|
||||
} catch (CosClientException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,不返回地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param file 文件
|
||||
*
|
||||
* @date 2022/1/5 23:45
|
||||
*/
|
||||
public static void storageFile(String bucketName, String key, File file) {
|
||||
BufferedInputStream inputStream;
|
||||
try {
|
||||
inputStream = FileUtil.getInputStream(file);
|
||||
} catch (IORuntimeException e) {
|
||||
throw new CommonException("获取文件流异常,名称是:{}", file.getName());
|
||||
}
|
||||
storageFile(bucketName, key, inputStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,不返回地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param multipartFile 文件
|
||||
*
|
||||
* @date 2022/1/5 23:45
|
||||
*/
|
||||
public static void storageFile(String bucketName, String key, MultipartFile multipartFile) {
|
||||
InputStream inputStream;
|
||||
try {
|
||||
inputStream = multipartFile.getInputStream();
|
||||
} catch (IOException e) {
|
||||
throw new CommonException("获取文件流异常,名称是:{}", multipartFile.getName());
|
||||
}
|
||||
storageFile(bucketName, key, inputStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,不返回地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param bytes 文件字节数组
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void storageFile(String bucketName, String key, byte[] bytes) {
|
||||
ByteArrayInputStream byteArrayInputStream = null;
|
||||
try {
|
||||
initClient();
|
||||
byteArrayInputStream = new ByteArrayInputStream(bytes);
|
||||
ObjectMetadata objectMetadata = new ObjectMetadata();
|
||||
objectMetadata.setContentType(getFileContentType(key));
|
||||
client.putObject(bucketName, key, byteArrayInputStream, objectMetadata);
|
||||
} catch (CosClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
} finally {
|
||||
IoUtil.close(byteArrayInputStream);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,不返回地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param inputStream 文件流
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void storageFile(String bucketName, String key, InputStream inputStream) {
|
||||
try {
|
||||
initClient();
|
||||
ObjectMetadata objectMetadata = new ObjectMetadata();
|
||||
objectMetadata.setContentType(getFileContentType(key));
|
||||
client.putObject(bucketName, key, inputStream, objectMetadata);
|
||||
} catch (CosClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
} finally {
|
||||
IoUtil.close(inputStream);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,返回外网地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param file 文件
|
||||
*
|
||||
* @date 2022/1/5 23:45
|
||||
*/
|
||||
public static String storageFileWithReturnUrl(String bucketName, String key, File file) {
|
||||
storageFile(bucketName, key, file);
|
||||
setFileAcl(bucketName, key, DevFileBucketAuthEnum.PUBLIC_READ);
|
||||
return getFileAuthUrl(bucketName, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,返回外网地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param multipartFile 文件
|
||||
*
|
||||
* @date 2022/1/5 23:45
|
||||
*/
|
||||
public static String storageFileWithReturnUrl(String bucketName, String key, MultipartFile multipartFile) {
|
||||
storageFile(bucketName, key, multipartFile);
|
||||
setFileAcl(bucketName, key, DevFileBucketAuthEnum.PUBLIC_READ);
|
||||
return getFileAuthUrl(bucketName, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,返回外网地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param bytes 文件字节数组
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static String storageFileWithReturnUrl(String bucketName, String key, byte[] bytes) {
|
||||
storageFile(bucketName, key, bytes);
|
||||
setFileAcl(bucketName, key, DevFileBucketAuthEnum.PUBLIC_READ);
|
||||
return getFileAuthUrl(bucketName, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件,返回外网地址
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param inputStream 文件流
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static String storageFileWithReturnUrl(String bucketName, String key, InputStream inputStream) {
|
||||
storageFile(bucketName, key, inputStream);
|
||||
setFileAcl(bucketName, key, DevFileBucketAuthEnum.PUBLIC_READ);
|
||||
return getFileAuthUrl(bucketName, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某个bucket下的文件字节
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static byte[] getFileBytes(String bucketName, String key) {
|
||||
COSObjectInputStream cosObjectInput = null;
|
||||
try {
|
||||
initClient();
|
||||
GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key);
|
||||
COSObject cosObject = client.getObject(getObjectRequest);
|
||||
cosObjectInput = cosObject.getObjectContent();
|
||||
return IoUtil.readBytes(cosObjectInput);
|
||||
} catch (CosClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
} finally {
|
||||
IoUtil.close(cosObjectInput);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置文件访问权限管理
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param devFileBucketAuthEnum 文件权限
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void setFileAcl(String bucketName, String key, DevFileBucketAuthEnum devFileBucketAuthEnum) {
|
||||
try {
|
||||
initClient();
|
||||
if (devFileBucketAuthEnum.equals(DevFileBucketAuthEnum.PRIVATE)) {
|
||||
client.setObjectAcl(bucketName, key, CannedAccessControlList.Private);
|
||||
} else if (devFileBucketAuthEnum.equals(DevFileBucketAuthEnum.PUBLIC_READ)) {
|
||||
client.setObjectAcl(bucketName, key, CannedAccessControlList.PublicRead);
|
||||
} else if (devFileBucketAuthEnum.equals(DevFileBucketAuthEnum.PUBLIC_READ_WRITE)) {
|
||||
client.setObjectAcl(bucketName, key, CannedAccessControlList.PublicReadWrite);
|
||||
}
|
||||
} catch (CosClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拷贝文件
|
||||
*
|
||||
* @param originBucketName 源文件桶
|
||||
* @param originFileKey 源文件名称
|
||||
* @param newBucketName 新文件桶
|
||||
* @param newFileKey 新文件名称
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void copyFile(String originBucketName, String originFileKey, String newBucketName, String newFileKey) {
|
||||
try {
|
||||
initClient();
|
||||
transferManager.copy(originBucketName, originFileKey, newBucketName, newFileKey);
|
||||
} catch (CosClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件的下载地址(带鉴权和有效时间的),生成外网地址
|
||||
*
|
||||
* @param bucketName 文件桶
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
* @param timeoutMillis 时效
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static String getFileAuthUrl(String bucketName, String key, Long timeoutMillis) {
|
||||
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, key, HttpMethodName.GET);
|
||||
Date expirationDate = new Date(System.currentTimeMillis() + timeoutMillis);
|
||||
request.setExpiration(expirationDate);
|
||||
URL url;
|
||||
try {
|
||||
initClient();
|
||||
url = client.generatePresignedUrl(request);
|
||||
} catch (CosClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件的下载地址(永久的,文件必须为公有读),生成外网地址
|
||||
*
|
||||
* @param bucketName 文件桶
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static String getFileAuthUrl(String bucketName, String key) {
|
||||
URL url;
|
||||
try {
|
||||
initClient();
|
||||
url = client.getObjectUrl(bucketName, key);
|
||||
} catch (CosClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*
|
||||
* @param bucketName 文件桶
|
||||
* @param key 唯一标示id,例如a.txt, doc/a.txt
|
||||
*
|
||||
* @date 2022/1/5 23:24
|
||||
*/
|
||||
public static void deleteFile(String bucketName, String key) {
|
||||
try{
|
||||
initClient();
|
||||
client.deleteObject(bucketName, key);
|
||||
} catch (CosClientException e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件名获取ContentType
|
||||
*
|
||||
*
|
||||
* @date 2022/1/6 11:27
|
||||
**/
|
||||
private static String getFileContentType(String key) {
|
||||
// 根据文件名获取contentType
|
||||
String contentType = "application/octet-stream";
|
||||
if (key.contains(".")) {
|
||||
contentType = MimetypesFileTypeMap.getDefaultFileTypeMap().getContentType(key);
|
||||
}
|
||||
return contentType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.job.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import mjkf.xinke.common.annotation.CommonLog;
|
||||
import mjkf.xinke.common.pojo.CommonResult;
|
||||
import mjkf.xinke.common.pojo.CommonValidList;
|
||||
import mjkf.xinke.dev.modular.job.entity.DevJob;
|
||||
import mjkf.xinke.dev.modular.job.param.*;
|
||||
import mjkf.xinke.dev.modular.job.service.DevJobService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 定时任务控制器
|
||||
*
|
||||
*
|
||||
* @date 2022/8/5 10:48
|
||||
**/
|
||||
@Api(tags = "定时任务控制器")
|
||||
@ApiSupport(author = "SNOWY_TEAM", order = 7)
|
||||
@RestController
|
||||
@Validated
|
||||
public class DevJobController {
|
||||
|
||||
@Resource
|
||||
private DevJobService devJobService;
|
||||
|
||||
/**
|
||||
* 获取定时任务分页
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 1)
|
||||
@ApiOperation("获取定时任务分页")
|
||||
@GetMapping("/dev/job/page")
|
||||
public CommonResult<Page<DevJob>> page(DevJobPageParam devJobPageParam) {
|
||||
return CommonResult.data(devJobService.page(devJobPageParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取定时任务列表
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 2)
|
||||
@ApiOperation("获取定时任务列表")
|
||||
@GetMapping("/dev/job/list")
|
||||
public CommonResult<List<DevJob>> list(DevJobListParam devJobListParam) {
|
||||
return CommonResult.data(devJobService.list(devJobListParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加定时任务
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:47
|
||||
*/
|
||||
@ApiOperationSupport(order = 3)
|
||||
@ApiOperation("添加定时任务")
|
||||
@CommonLog("添加定时任务")
|
||||
@PostMapping("/dev/job/add")
|
||||
public CommonResult<String> add(@RequestBody @Valid DevJobAddParam devJobAddParam) {
|
||||
devJobService.add(devJobAddParam);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑定时任务
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:47
|
||||
*/
|
||||
@ApiOperationSupport(order = 4)
|
||||
@ApiOperation("编辑定时任务")
|
||||
@CommonLog("编辑定时任务")
|
||||
@PostMapping("/dev/job/edit")
|
||||
public CommonResult<String> edit(@RequestBody @Valid DevJobEditParam devJobEditParam) {
|
||||
devJobService.edit(devJobEditParam);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除定时任务
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 5)
|
||||
@ApiOperation("删除定时任务")
|
||||
@CommonLog("删除定时任务")
|
||||
@PostMapping("/dev/job/delete")
|
||||
public CommonResult<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
|
||||
CommonValidList<DevJobIdParam> devJobIdParamList) {
|
||||
devJobService.delete(devJobIdParamList);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取定时任务详情
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 6)
|
||||
@ApiOperation("获取定时任务详情")
|
||||
@GetMapping("/dev/job/detail")
|
||||
public CommonResult<DevJob> detail(@Valid DevJobIdParam devJobIdParam) {
|
||||
return CommonResult.data(devJobService.detail(devJobIdParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止定时任务
|
||||
*
|
||||
*
|
||||
* @date 2021/10/13 14:01
|
||||
**/
|
||||
@ApiOperationSupport(order = 6)
|
||||
@ApiOperation("停止定时任务")
|
||||
@CommonLog("停止定时任务")
|
||||
@PostMapping("/dev/job/stopJob")
|
||||
public CommonResult<String> stopJob(@RequestBody DevJobIdParam devJobIdParam) {
|
||||
devJobService.stopJob(devJobIdParam);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行定时任务
|
||||
*
|
||||
*
|
||||
* @date 2021/10/13 14:01
|
||||
**/
|
||||
@ApiOperationSupport(order = 7)
|
||||
@ApiOperation("运行定时任务")
|
||||
@CommonLog("运行定时任务")
|
||||
@PostMapping("/dev/job/runJob")
|
||||
public CommonResult<String> runJob(@RequestBody @Valid DevJobIdParam devJobIdParam) {
|
||||
devJobService.runJob(devJobIdParam);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 立即运行定时任务
|
||||
*
|
||||
*
|
||||
* @date 2021/10/13 14:01
|
||||
**/
|
||||
@ApiOperationSupport(order = 8)
|
||||
@ApiOperation("立即运行定时任务")
|
||||
@CommonLog("立即运行定时任务")
|
||||
@PostMapping("/dev/job/runJobNow")
|
||||
public CommonResult<String> runJobNow(@RequestBody @Valid DevJobIdParam devJobIdParam) {
|
||||
devJobService.runJobNow(devJobIdParam);
|
||||
return CommonResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取定时任务类
|
||||
*
|
||||
*
|
||||
* @date 2022/4/24 20:00
|
||||
*/
|
||||
@ApiOperationSupport(order = 9)
|
||||
@ApiOperation("获取定时任务类")
|
||||
@GetMapping("/dev/job/getActionClass")
|
||||
public CommonResult<List<String>> getActionClass() {
|
||||
return CommonResult.data(devJobService.getActionClass());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.job.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldStrategy;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import mjkf.xinke.common.pojo.CommonEntity;
|
||||
|
||||
/**
|
||||
* 定时任务实体类
|
||||
*
|
||||
*
|
||||
* @date 2022/8/5 10:38
|
||||
**/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("DEV_JOB")
|
||||
public class DevJob extends CommonEntity {
|
||||
|
||||
/** id */
|
||||
@ApiModelProperty(value = "id", position = 1)
|
||||
private String id;
|
||||
|
||||
/** 租户id */
|
||||
@ApiModelProperty(value = "租户id", position = 2)
|
||||
private String tenantId;
|
||||
|
||||
/** 名称 */
|
||||
@ApiModelProperty(value = "名称", position = 3)
|
||||
private String name;
|
||||
|
||||
/** 编码 */
|
||||
@ApiModelProperty(value = "编码", position = 4)
|
||||
private String code;
|
||||
|
||||
/** 分类 */
|
||||
@ApiModelProperty(value = "分类", position = 5)
|
||||
private String category;
|
||||
|
||||
/** 任务类名 */
|
||||
@ApiModelProperty(value = "任务类名", position = 6)
|
||||
private String actionClass;
|
||||
|
||||
/** cron表达式 */
|
||||
@ApiModelProperty(value = "cron表达式", position = 7)
|
||||
private String cronExpression;
|
||||
|
||||
/** 任务状态 */
|
||||
@ApiModelProperty(value = "任务状态", position = 8)
|
||||
private String jobStatus;
|
||||
|
||||
/** 排序码 */
|
||||
@ApiModelProperty(value = "排序码", position = 9)
|
||||
private Integer sortCode;
|
||||
|
||||
/** 扩展信息 */
|
||||
@ApiModelProperty(value = "扩展信息", position = 10)
|
||||
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
|
||||
private String extJson;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.job.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
import mjkf.xinke.common.exception.CommonException;
|
||||
|
||||
/**
|
||||
* 定时任务分类枚举
|
||||
*
|
||||
*
|
||||
* @date 2022/7/6 22:21
|
||||
*/
|
||||
@Getter
|
||||
public enum DevJobCategoryEnum {
|
||||
|
||||
/**
|
||||
* 框架
|
||||
*/
|
||||
FRM("FRM"),
|
||||
|
||||
/**
|
||||
* 业务
|
||||
*/
|
||||
BIZ("BIZ");
|
||||
|
||||
private final String value;
|
||||
|
||||
DevJobCategoryEnum(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static void validate(String value) {
|
||||
boolean flag = FRM.getValue().equals(value) || BIZ.getValue().equals(value);
|
||||
if(!flag) {
|
||||
throw new CommonException("不支持的定时任务分类:{}", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.job.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
import mjkf.xinke.common.exception.CommonException;
|
||||
|
||||
/**
|
||||
* 定时任务状态枚举
|
||||
*
|
||||
*
|
||||
* @date 2022/4/27 21:47
|
||||
*/
|
||||
@Getter
|
||||
public enum DevJobStatusEnum {
|
||||
|
||||
/**
|
||||
* 运行
|
||||
*/
|
||||
RUNNING("RUNNING"),
|
||||
|
||||
/**
|
||||
* 停止
|
||||
*/
|
||||
STOPPED("STOPPED");
|
||||
|
||||
private final String value;
|
||||
|
||||
DevJobStatusEnum(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static void validate(String value) {
|
||||
boolean flag = RUNNING.getValue().equals(value) || STOPPED.getValue().equals(value);
|
||||
if(!flag) {
|
||||
throw new CommonException("不支持的定时任务状态:{}", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.job.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import mjkf.xinke.dev.modular.job.entity.DevJob;
|
||||
|
||||
/**
|
||||
* 定时任务Mapper接口
|
||||
*
|
||||
*
|
||||
* @date 2022/8/5 10:45
|
||||
**/
|
||||
public interface DevJobMapper extends BaseMapper<DevJob> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="mjkf.xinke.dev.modular.job.mapper.DevJobMapper">
|
||||
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,49 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.job.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 定时任务添加参数
|
||||
*
|
||||
*
|
||||
* @date 2022/7/30 17:53
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevJobAddParam {
|
||||
|
||||
/** 名称 */
|
||||
@ApiModelProperty(value = "名称", required = true, position = 1)
|
||||
@NotBlank(message = "name不能为空")
|
||||
private String name;
|
||||
|
||||
/** 分类 */
|
||||
@ApiModelProperty(value = "分类", required = true, position = 2)
|
||||
@NotBlank(message = "category不能为空")
|
||||
private String category;
|
||||
|
||||
/** 任务类名 */
|
||||
@ApiModelProperty(value = "任务类名", required = true, position = 3)
|
||||
@NotBlank(message = "actionClass不能为空")
|
||||
private String actionClass;
|
||||
|
||||
/** cron表达式 */
|
||||
@ApiModelProperty(value = "cron表达式", required = true, position = 4)
|
||||
@NotBlank(message = "cronExpression不能为空")
|
||||
private String cronExpression;
|
||||
|
||||
/** 排序码 */
|
||||
@ApiModelProperty(value = "排序码", required = true, position = 5)
|
||||
@NotNull(message = "sortCode不能为空")
|
||||
private Integer sortCode;
|
||||
|
||||
/** 扩展信息 */
|
||||
@ApiModelProperty(value = "扩展信息", position = 6)
|
||||
private String extJson;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.job.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 定时任务编辑参数
|
||||
*
|
||||
*
|
||||
* @date 2022/7/30 17:53
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevJobEditParam {
|
||||
|
||||
/** id */
|
||||
@ApiModelProperty(value = "id", required = true, position = 1)
|
||||
@NotBlank(message = "id不能为空")
|
||||
private String id;
|
||||
|
||||
/** 名称 */
|
||||
@ApiModelProperty(value = "名称", required = true, position = 2)
|
||||
@NotBlank(message = "name不能为空")
|
||||
private String name;
|
||||
|
||||
/** 分类 */
|
||||
@ApiModelProperty(value = "分类", required = true, position = 3)
|
||||
@NotBlank(message = "category不能为空")
|
||||
private String category;
|
||||
|
||||
/** 任务类名 */
|
||||
@ApiModelProperty(value = "任务类名", required = true, position = 4)
|
||||
@NotBlank(message = "actionClass不能为空")
|
||||
private String actionClass;
|
||||
|
||||
/** cron表达式 */
|
||||
@ApiModelProperty(value = "cron表达式", required = true, position = 5)
|
||||
@NotBlank(message = "cronExpression不能为空")
|
||||
private String cronExpression;
|
||||
|
||||
/** 排序码 */
|
||||
@ApiModelProperty(value = "排序码", required = true, position = 6)
|
||||
@NotNull(message = "sortCode不能为空")
|
||||
private Integer sortCode;
|
||||
|
||||
/** 扩展信息 */
|
||||
@ApiModelProperty(value = "扩展信息", position = 7)
|
||||
private String extJson;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.job.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 定时任务Id参数
|
||||
*
|
||||
*
|
||||
* @date 2022/7/30 17:52
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevJobIdParam {
|
||||
|
||||
/** id */
|
||||
@ApiModelProperty(value = "id", required = true)
|
||||
@NotBlank(message = "id不能为空")
|
||||
private String id;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.job.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 定时任务列表参数
|
||||
*
|
||||
*
|
||||
* @date 2022/7/30 17:53
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevJobListParam {
|
||||
|
||||
/** 任务分类 */
|
||||
@ApiModelProperty(value = "任务分类")
|
||||
private String category;
|
||||
|
||||
/** 名称关键词 */
|
||||
@ApiModelProperty(value = "名称关键词")
|
||||
private String searchKey;
|
||||
|
||||
/** 任务状态 */
|
||||
@ApiModelProperty(value = "任务状态")
|
||||
private String jobStatus;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
package mjkf.xinke.dev.modular.job.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 定时任务查询参数
|
||||
*
|
||||
*
|
||||
* @date 2022/7/30 17:53
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevJobPageParam {
|
||||
|
||||
/** 当前页 */
|
||||
@ApiModelProperty(value = "当前页码")
|
||||
private Integer current;
|
||||
|
||||
/** 每页条数 */
|
||||
@ApiModelProperty(value = "每页条数")
|
||||
private Integer size;
|
||||
|
||||
/** 排序字段 */
|
||||
@ApiModelProperty(value = "排序字段,字段驼峰名称,如:userName")
|
||||
private String sortField;
|
||||
|
||||
/** 排序方式 */
|
||||
@ApiModelProperty(value = "排序方式,升序:ASCEND;降序:DESCEND")
|
||||
private String sortOrder;
|
||||
|
||||
/** 任务分类 */
|
||||
@ApiModelProperty(value = "任务分类")
|
||||
private String category;
|
||||
|
||||
/** 名称关键词 */
|
||||
@ApiModelProperty(value = "名称关键词")
|
||||
private String searchKey;
|
||||
|
||||
/** 任务状态 */
|
||||
@ApiModelProperty(value = "任务状态")
|
||||
private String jobStatus;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user