init:初始化项目结构

This commit is contained in:
zhangzq
2026-01-08 20:34:59 +08:00
parent 49e9ac502f
commit d4b4059195
20 changed files with 466 additions and 968 deletions

View File

@@ -33,7 +33,6 @@ import org.nl.dev.modular.email.enums.DevEmailEngineTypeEnum;
import org.nl.dev.modular.email.mapper.DevEmailMapper;
import org.nl.dev.modular.email.param.*;
import org.nl.dev.modular.email.service.DevEmailService;
import org.nl.dev.modular.email.util.DevEmailAliyunUtil;
import org.nl.dev.modular.email.util.DevEmailLocalUtil;
import org.nl.dev.modular.email.util.DevEmailTencentUtil;
@@ -84,42 +83,17 @@ public class DevEmailServiceImpl extends ServiceImpl<DevEmailMapper, DevEmail> i
@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

View File

@@ -1,214 +0,0 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
*
* 1.请不要删除和修改根目录下的LICENSE文件。
* 2.请不要删除和修改Snowy源码头部的版权声明。
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作。
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
package org.nl.dev.modular.email.util;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.aliyun.dm20151123.Client;
import com.aliyun.dm20151123.models.BatchSendMailRequest;
import com.aliyun.dm20151123.models.SingleSendMailRequest;
import com.aliyun.teaopenapi.models.Config;
import lombok.extern.slf4j.Slf4j;
import org.nl.common.exception.CommonException;
import org.nl.dev.api.DevConfigApi;
/**
* 阿里云邮件工具类
* 参考文档https://help.aliyun.com/document_detail/29459.html
*
* @author xuyuxiang
* @date 2022/6/17 10:17
**/
@Slf4j
public class DevEmailAliyunUtil {
private static Client 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";
/**
* 初始化操作的客户端
*
* @author xuyuxiang
* @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为空");
}
try {
client = new Client(new Config().setRegionId(regionId).setEndpoint("dm.aliyuncs.com").setAccessKeyId(accessKeyId).setAccessKeySecret(accessKeySecret));
} catch (Exception e) {
throw new CommonException(e.getMessage());
}
}
/**
* 发送纯文本邮件不使用模板频率限制100 QPS
*
* @param from 管理控制台中配置的发信地址,必传且必须正确
* @param user 发信人昵称长度小于15个字符可不传
* @param tos 目标地址,多个 email 地址可以用逗号分隔最多100个地址必传且必须正确
* @param subject 邮件主题,必传
* @param content 邮件 txt 正文限制28K必传
* @return 发送成功的回执id
* @author xuyuxiang
* @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.singleSendMail(singleSendMailRequest).getBody().getEnvId();
} catch (Exception 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
* @author xuyuxiang
* @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.singleSendMail(singleSendMailRequest).getBody().getEnvId();
} catch (Exception e) {
throw new CommonException(e.getMessage());
}
}
/**
* 使用模板发送邮件国内频率限制是20/min海外频率限制是10/min。
*
* @param from 管理控制台中配置的发信地址,必传且必须正确
* @param tagName 控制台创建的邮件标签,可不传
* @param toName 预先创建且上传了收件人的收件人列表名称,必传且必须正确
* @param templateName 预先创建且通过审核的模板名称,必传且必须正确
* @return 发送成功的回执id
* @author xuyuxiang
* @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.batchSendMail(batchSendMailRequest).getBody().getEnvId();
} catch (Exception e) {
throw new CommonException(e.getMessage());
}
}
/**
* 创建发送一个邮件的请求
*
* @author xuyuxiang
* @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);
}
//是否开启追踪功能开启需要备案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);
//是否开启追踪功能开启需要备案0关闭1开启
request.setClickTrace("0");
return request;
}
}

View File

@@ -28,13 +28,13 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.math3.dfp.DfpField;
import org.nl.dev.modular.file.entity.DevFile;
import org.nl.dev.modular.file.enums.DevFileEngineTypeEnum;
import org.nl.dev.modular.file.param.DevFileIdParam;
import org.nl.dev.modular.file.param.DevFileListParam;
import org.nl.dev.modular.file.param.DevFilePageParam;
import org.nl.dev.modular.file.param.DevFileUrlListParam;
import org.nl.dev.modular.file.util.DevFileAliyunUtil;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.nl.common.exception.CommonException;
@@ -51,7 +51,6 @@ import org.nl.dev.modular.file.util.DevFileTencentUtil;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
/**
@@ -143,10 +142,10 @@ public class DevFileServiceImpl extends ServiceImpl<DevFileMapper, DevFile> impl
String fileId = IdWorker.getIdStr();
// 存储桶名称
String bucketName;
String bucketName = null;
// 定义存储的url本地文件返回文件实际路径其他引擎返回网络地址
String storageUrl;
String storageUrl = null;
// 根据引擎类型执行不同方法
if(engine.equals(DevFileEngineTypeEnum.LOCAL.getValue())) {
@@ -156,9 +155,6 @@ public class DevFileServiceImpl extends ServiceImpl<DevFileMapper, DevFile> impl
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
@@ -187,7 +183,7 @@ public class DevFileServiceImpl extends ServiceImpl<DevFileMapper, DevFile> impl
StrUtil.DOT, true):null;
devFile.setSuffix(suffix);
devFile.setSizeKb(Convert.toStr(NumberUtil.div(new BigDecimal(file.getSize()), BigDecimal.valueOf(1024))
.setScale(0, RoundingMode.HALF_UP)));
.setScale(0, DfpField.RoundingMode.ROUND_HALF_UP.ordinal())));
devFile.setSizeInfo(FileUtil.readableFileSize(file.getSize()));
devFile.setObjName(ObjectUtil.isNotEmpty(devFile.getSuffix())?fileId + StrUtil.DOT + devFile.getSuffix():null);
// 如果是图片,则压缩生成缩略图

View File

@@ -1,471 +0,0 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
*
* 1.请不要删除和修改根目录下的LICENSE文件。
* 2.请不要删除和修改Snowy源码头部的版权声明。
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作。
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
package org.nl.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 jakarta.activation.MimetypesFileTypeMap;
import lombok.extern.slf4j.Slf4j;
import org.nl.dev.modular.file.enums.DevFileBucketAuthEnum;
import org.springframework.web.multipart.MultipartFile;
import org.nl.common.exception.CommonException;
import org.nl.dev.api.DevConfigApi;
import java.io.*;
import java.net.URL;
import java.util.Date;
import java.util.List;
/**
* 阿里云文件工具类
* 参考文档https://help.aliyun.com/document_detail/32010.html
*
* @author xuyuxiang
* @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";
/**
* 初始化操作的客户端
*
* @author xuyuxiang
* @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(endpoint)) {
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);
}
/**
* 获取默认存储桶名称
*
* @author xuyuxiang
* @date 2022/6/22 18:05
**/
public static String getDefaultBucketName() {
initClient();
return defaultBucketName;
}
/**
* 销毁操作的客户端
*
* @author xuyuxiang
* @date 2022/1/5 23:24
*/
public static void destroyClient() {
initClient();
client.shutdown();
}
/**
* 获取操作的客户端
*
* @author xuyuxiang
* @date 2022/1/5 23:24
*/
public OSS getClient() {
initClient();
return client;
}
/**
* 查询存储桶是否存在
* 例如传入参数examplebucket-1250000000返回true代表存在此桶
*
* @param bucketName 桶名称
* @author xuyuxiang
* @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 存储桶权限
* @author xuyuxiang
* @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
* @author xuyuxiang
* @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 文件
* @author xuyuxiang
* @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 文件
* @author xuyuxiang
* @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 文件字节数组
* @author xuyuxiang
* @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 文件流
* @author xuyuxiang
* @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 文件
* @author xuyuxiang
* @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 文件
* @author xuyuxiang
* @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 文件字节数组
* @author xuyuxiang
* @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 文件流
* @author xuyuxiang
* @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
* @author xuyuxiang
* @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 文件权限
* @author xuyuxiang
* @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 新文件名称
* @author xuyuxiang
* @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 时效
* @author xuyuxiang
* @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
* @author xuyuxiang
* @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
* @author xuyuxiang
* @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
*
* @author xuyuxiang
* @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;
}
}

View File

@@ -22,7 +22,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.nl.dev.modular.sms.enums.DevSmsEngineTypeEnum;
import org.nl.dev.modular.sms.param.*;
import org.nl.dev.modular.sms.util.DevSmsAliyunUtil;
import org.nl.dev.modular.sms.util.DevSmsTencentUtil;
import org.nl.dev.modular.sms.util.DevSmsXiaonuoUtil;
import org.springframework.stereotype.Service;
@@ -49,15 +49,7 @@ public class DevSmsServiceImpl extends ServiceImpl<DevSmsMapper, DevSms> impleme
@Transactional(rollbackFor = Exception.class)
@Override
public void sendAliyun(DevSmsSendAliyunParam devSmsSendAliyunParam) {
validPhone(devSmsSendAliyunParam.getPhoneNumbers());
String receiptInfo = DevSmsAliyunUtil.sendSms(devSmsSendAliyunParam.getPhoneNumbers(), devSmsSendAliyunParam.getSignName(),
devSmsSendAliyunParam.getTemplateCode(), devSmsSendAliyunParam.getTemplateParam());
DevSms devSms = new DevSms();
BeanUtil.copyProperties(devSmsSendAliyunParam, devSms);
devSms.setSignName(ObjectUtil.isNotEmpty(devSms.getSignName())?devSms.getSignName():DevSmsAliyunUtil.getDefaultSignName());
devSms.setEngine(DevSmsEngineTypeEnum.ALIYUN.getValue());
devSms.setReceiptInfo(receiptInfo);
this.save(devSms);
}
@Transactional(rollbackFor = Exception.class)

View File

@@ -1,133 +0,0 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
*
* 1.请不要删除和修改根目录下的LICENSE文件。
* 2.请不要删除和修改Snowy源码头部的版权声明。
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作。
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
package org.nl.dev.modular.sms.util;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.dysmsapi20170525.models.SendSmsResponseBody;
import com.aliyun.teaopenapi.models.Config;
import lombok.extern.slf4j.Slf4j;
import org.nl.common.exception.CommonException;
import org.nl.dev.api.DevConfigApi;
/**
* 阿里云短信工具类
* 参考文档https://next.api.aliyun.com/api-tools/sdk/Dysmsapi?version=2017-05-25&language=java-tea
*
* @author xuyuxiang
* @date 2022/1/2 17:05
*/
@Slf4j
public class DevSmsAliyunUtil {
private static Client client;
private static final String SNOWY_SMS_ALIYUN_ACCESS_KEY_ID_KEY = "SNOWY_SMS_ALIYUN_ACCESS_KEY_ID";
private static final String SNOWY_SMS_ALIYUN_ACCESS_KEY_SECRET_KEY = "SNOWY_SMS_ALIYUN_ACCESS_KEY_SECRET";
private static final String SNOWY_SMS_ALIYUN_END_POINT_KEY = "SNOWY_SMS_ALIYUN_END_POINT";
private static final String SNOWY_SMS_ALIYUN_DEFAULT_SIGN_NAME_KEY = "SNOWY_SMS_ALIYUN_DEFAULT_SIGN_NAME";
/**
* 初始化操作的客户端
*
* @author xuyuxiang
* @date 2022/1/5 23:24
*/
private static void initClient() {
DevConfigApi devConfigApi = SpringUtil.getBean(DevConfigApi.class);
/* accessKeyId */
String accessKeyId = devConfigApi.getValueByKey(SNOWY_SMS_ALIYUN_ACCESS_KEY_ID_KEY);
if(ObjectUtil.isEmpty(accessKeyId)) {
throw new CommonException("阿里云短信操作客户端未正确配置accessKeyId为空");
}
/* accessKeySecret */
String accessKeySecret = devConfigApi.getValueByKey(SNOWY_SMS_ALIYUN_ACCESS_KEY_SECRET_KEY);
if(ObjectUtil.isEmpty(accessKeySecret)) {
throw new CommonException("阿里云短信操作客户端未正确配置accessKeySecret为空");
}
/* endpoint */
String endpoint = devConfigApi.getValueByKey(SNOWY_SMS_ALIYUN_END_POINT_KEY);
if(ObjectUtil.isEmpty(endpoint)) {
throw new CommonException("阿里云短信操作客户端未正确配置endpoint为空");
}
try {
client = new Client(new Config().setAccessKeyId(accessKeyId).setAccessKeySecret(accessKeySecret).setEndpoint(endpoint));
} catch (Exception e) {
throw new CommonException(e.getMessage());
}
}
/**
* 发送短信
*
* @param phoneNumbers 手机号码,支持对多个手机号码发送短信,手机号码之间以半角逗号(,)分隔。
* 上限为1000个手机号码。批量调用相对于单条调用及时性稍有延迟。
* @param signName 短信服务控制台配置且审核通过的短信签名,为空则使用默认签名
* @param templateCode 短信服务控制台配置且审核通过的模板编码
* @param templateParam 短信模板变量对应的实际值JSON格式。支持传入多个参数示例{"name":"张三","number":"15038****76"}
* @return 发送的结果信息集合 com.aliyun.dysmsapi20170525.models.SendSmsResponse
* @author xuyuxiang
* @date 2022/2/24 13:42
**/
public static String sendSms(String phoneNumbers, String signName, String templateCode, String templateParam) {
try {
initClient();
if(ObjectUtil.isEmpty(signName)) {
signName = getDefaultSignName();
}
SendSmsRequest sendSmsRequest = new SendSmsRequest()
.setPhoneNumbers(phoneNumbers)
.setSignName(signName)
.setTemplateCode(templateCode)
.setTemplateParam(templateParam);
SendSmsResponse sendSmsResponse = client.sendSms(sendSmsRequest);
SendSmsResponseBody body = sendSmsResponse.getBody();
String code = body.getCode().toLowerCase();
if("ok".equals(code)) {
return JSONUtil.toJsonStr(body);
} else {
throw new CommonException(body.getMessage());
}
} catch (Exception e) {
throw new CommonException(e.getMessage());
}
}
/**
* 获取默认签名
*
* @author xuyuxiang
* @date 2024/1/26 16:40
**/
public static String getDefaultSignName() {
// 签名为空,则获取默认签名
DevConfigApi devConfigApi = SpringUtil.getBean(DevConfigApi.class);
String signName = devConfigApi.getValueByKey(SNOWY_SMS_ALIYUN_DEFAULT_SIGN_NAME_KEY);
if(ObjectUtil.isEmpty(signName)) {
throw new CommonException("阿里云短信操作客户端未正确配置signName为空");
}
return signName;
}
}

View File

@@ -44,7 +44,9 @@ import java.util.List;
@RestController
@Validated
public class MobileButtonController {
static {
System.out.println("移动端按钮控制器------------");
}
@Resource
private MobileButtonService mobileButtonService;

View File

@@ -31,6 +31,12 @@
<dependency>
<groupId>org.nl</groupId>
<artifactId>nl-plugin-dev-api</artifactId>
<exclusions>
<exclusion>
<artifactId>tea</artifactId>
<groupId>com.aliyun</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- 引入移动端接口,用于移动端菜单信息 -->