init:初始化项目结构
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
// 如果是图片,则压缩生成缩略图
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,9 @@ import java.util.List;
|
||||
@RestController
|
||||
@Validated
|
||||
public class MobileButtonController {
|
||||
|
||||
static {
|
||||
System.out.println("移动端按钮控制器------------");
|
||||
}
|
||||
@Resource
|
||||
private MobileButtonService mobileButtonService;
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
<!-- 引入移动端接口,用于移动端菜单信息 -->
|
||||
|
||||
Reference in New Issue
Block a user