发表于: 2020-01-15 16:12:19
2 1222
啥也不说就是干!!
今天完成的事情:
1、消息队列实现发短信及邮件
使用阿里云短息及邮件 API
添加相关依赖
<!--短信sdk-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>3.3.1</version>
<!--<scope>system</scope>-->
<!--<systemPath>${basedir}/lib/aliyun-java-sdk-core-3.3.1.jar</systemPath>-->
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<version>1.0.0</version>
<!--<scope>system</scope>-->
<!--<systemPath>${basedir}/lib/aliyun-java-sdk-dysmsapi-1.0.0.jar</systemPath>-->
</dependency>
<!--邮件-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dm</artifactId>
<version>3.1.0</version>
</dependency>
发送短信的方法:SmsCodeSender
@Component
public class SmsCodeSender {
@Value("${aliyun.smssdk.accessKeyId}")
private String accessKeyId;
@Value("${aliyun.smssdk.accessKeySecret}")
private String accessKeySecret;
@Value("${aliyun.smssdk.signName}")
private String signName;
@Value("${aliyun.smssdk.templateCode}")
private String templateCode;
@Value("${aliyun.smssdk.product}")
private String product;
@Value("${aliyun.smssdk.domain}")
private String domain;
@Value("${aliyun.smssdk.defaultConnectTimeout}")
private String defaultConnectTimeout;
@Value("${aliyun.smssdk.defaultReadTimeout}")
private String defaultReadTimeout;
@Autowired
private RedisCache redisCache;
@Value("${aliyun.smssdk.expireTime}")
private int expireTime;
private static final String SMS_KEY_PATTERN = "sms:login_code";
public SendSmsResponse sendMessage(SmsInfo smsInfo) {
try {
//可自助调整超时时间
System.setProperty("sun.net.client.defaultConnectTimeout", defaultConnectTimeout);
System.setProperty("sun.net.client.defaultReadTimeout", defaultReadTimeout);
//初始化acsClient,暂不支持region化
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
IAcsClient acsClient = new DefaultAcsClient(profile);
//组装请求对象-具体描述见控制台-文档部分内容
SendSmsRequest request = new SendSmsRequest();
//必填:待发送手机号
request.setPhoneNumbers(smsInfo.getPhoneNum());
//必填:短信签名-可在短信控制台中找到
request.setSignName(signName);
//必填:短信模板-可在短信控制台中找到
request.setTemplateCode("{\"code\":\"" + smsInfo.getContent() + "\"}");
//可选:模板中的变量替换JSON串,如模板内容为"您的验证码为${code},有效时间5分钟。" ,此处的值为
request.setTemplateParam(smsInfo.getContent());
//选填-上行短信扩展码(无特殊需求用户请忽略此字段)
//request.setSmsUpExtendCode("90997");
//可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
request.setOutId(smsInfo.getOutId());
//hint 此处可能会抛出异常,注意catch
SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
if (sendSmsResponse == null) {
smsInfo.setResCode(2);
smsInfo.setResMsg("sendSmsResponse为空,验证码发送失败");
} else if (!StringUtils.isEmpty(sendSmsResponse.getCode()) && sendSmsResponse.getCode().equals("OK")) {
smsInfo.setResCode(1);
smsInfo.setResMsg("验证码发送成功!");
//发送成功存入缓存
redisCache.setCacheObject(SMS_KEY_PATTERN + smsInfo.getPhoneNum() + "_" + smsInfo.getContent(), smsInfo, expireTime, TimeUnit.MINUTES);
} else {
smsInfo.setResCode(2);
smsInfo.setResMsg(StringUtils.isEmpty(sendSmsResponse.getMessage()) ? "请稍后重试" : sendSmsResponse.getMessage());
}
return sendSmsResponse;
} catch (ClientException e) {
e.printStackTrace();
smsInfo.setResCode(2);
smsInfo.setResMsg("调用阿里云sms发生错误");
}
return null;
}
}
Rabbit 发送短信的消息队列生产者:
@Service
public class SmsCodeSendService {
@Autowired
private RabbitTemplate rabbitTemplate;
// @Autowired
// private BatchingRabbitTemplate batchingRabbitTemplate;
public SmsInfo sendSMSLoginCode(String phoneNum){
SmsInfo smsInfo = new SmsInfo();
smsInfo.setId(UUID.fastUUID().toString());
smsInfo.setContent(RandomStringUtils.randomNumeric(4));
smsInfo.setOutId(UUID.fastUUID().toString());
smsInfo.setPhoneNum(phoneNum);
CorrelationData correlationData = new CorrelationData();
correlationData.setId(smsInfo.getId());
rabbitTemplate.convertAndSend("sms-exchange",
"sms.login.code", //消息路由键
smsInfo, //发送内容
correlationData); //消息唯一 id
return smsInfo;
}
}
发送短信消息队列消费者
@Component
public class SmsCodeReceiver {
@Autowired
private SmsCodeSender sendSmsCodeService;
@RabbitHandler
@RabbitListener(
bindings = @QueueBinding(
value = @Queue(value = "sms-code-queue", durable = "true"),
exchange = @Exchange(name = "sms-exchange", durable = "true",
type = "topic"),
key = "sms.login.code"
)
)
public void onOrderMessage(@Payload SmsInfo smsInfo,
@Headers Map<String, Object> headers,
Channel channel) throws Exception {
//消费者消费消息
System.out.println("收到消息,开始消费....");
System.out.println("发送短信 id:" + smsInfo.getId());
sendSmsCodeService.sendMessage(smsInfo);
Long deliverTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
//给 MQ 一个反馈
channel.basicAck(deliverTag, false);
}
}
2、发送邮件
@Service
public class EmailSender {
@Value("${aliyun.emailsdk.accountName}")
private String accountName;
@Value("${aliyun.emailsdk.fromAlias}")
private String fromAlias;
@Value("${aliyun.emailsdk.tagName}")
private String tagName;
public void sendMail(EmailInfo emailInfo){
// 如果是除杭州region外的其它region(如新加坡、澳洲Region),需要将下面的"cn-hangzhou"替换为"ap-southeast-1"、或"ap-southeast-2"。
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", "<your accessKey>", "<your accessSecret>");
// 如果是除杭州region外的其它region(如新加坡region), 需要做如下处理
//try {
//DefaultProfile.addEndpoint("dm.ap-southeast-1.aliyuncs.com", "ap-southeast-1", "Dm", "dm.ap-southeast-1.aliyuncs.com");
//} catch (ClientException e) {
//e.printStackTrace();
//}
IAcsClient client = new DefaultAcsClient(profile);
SingleSendMailRequest request = new SingleSendMailRequest();
try {
//request.setVersion("2017-06-22");// 如果是除杭州region外的其它region(如新加坡region),必须指定为2017-06-22
request.setAccountName(accountName);
request.setFromAlias(fromAlias);
request.setAddressType(1);
request.setTagName(tagName);
request.setReplyToAddress(true);
request.setToAddress(emailInfo.getToAddress());
//可以给多个收件人发送邮件,收件人之间用逗号分开,批量发信建议使用BatchSendMailRequest方式
//request.setToAddress("邮箱1,邮箱2");
request.setSubject(emailInfo.getSubject());
//如果采用byte[].toString的方式的话请确保最终转换成utf-8的格式再放入htmlbody和textbody,若编码不一致则会被当成垃圾邮件。
//注意:文本邮件的大小限制为3M,过大的文本会导致连接超时或413错误
request.setTextBody(emailInfo.getContent());
//SDK 采用的是http协议的发信方式, 默认是GET方法,有一定的长度限制。
//若textBody、htmlBody或content的大小不确定,建议采用POST方式提交,避免出现uri is not valid异常
request.setMethod(MethodType.POST);
//开启需要备案,0关闭,1开启
//request.setClickTrace("0");
//如果调用成功,正常返回httpResponse;如果调用失败则抛出异常,需要在异常中捕获错误异常码;错误异常码请参考对应的API文档;
SingleSendMailResponse httpResponse = client.getAcsResponse(request);
} catch (ServerException e) {
//捕获错误异常码
System.out.println("ErrCode : " + e.getErrCode());
e.printStackTrace();
}
catch (ClientException e) {
//捕获错误异常码
System.out.println("ErrCode : " + e.getErrCode());
e.printStackTrace();
}
}
}
发送邮件消息队列生产者
@Service
public class EmailSendService {
@Autowired
private RabbitTemplate rabbitTemplate;
// @Autowired
// private BatchingRabbitTemplate batchingRabbitTemplate;
public EmailInfo sendEmail(String address,String subject,String content){
EmailInfo emailInfo = new EmailInfo();
emailInfo.setToAddress(address);
emailInfo.setSubject(subject);
emailInfo.setContent(content);
emailInfo.setId(UUID.fastUUID().toString());
CorrelationData correlationData = new CorrelationData();
correlationData.setId(emailInfo.getId());
rabbitTemplate.convertAndSend("email-exchange",
"email.register", //消息路由键
emailInfo, //发送内容
correlationData); //消息唯一 id
return emailInfo;
}
}
发送邮件消息队列消费者
@Component
public class EmailReceiver {
@Autowired
private EmailSender sendEmailService;
@RabbitHandler
@RabbitListener(
bindings = @QueueBinding(
value = @Queue(value = "email-queue", durable = "true"),
exchange = @Exchange(name = "email-exchange", durable = "true",
type = "topic"),
key = "email.#"
)
)
public void onEmailMessage(@Payload EmailInfo emailInfo,
@Headers Map<String, Object> headers,
Channel channel) throws Exception {
//消费者消费消息
System.out.println("收到消息,开始消费....");
System.out.println("发送邮件 id:" + emailInfo.getId());
sendEmailService.sendMail(emailInfo);
Long deliverTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
//给 MQ 一个反馈
channel.basicAck(deliverTag, false);
}
}
在Controller 中写对应的接口
@PostMapping("/sendSmsCode")
public CommonResult<Boolean> sendSmsCode(
@NotBlank
@Pattern(regexp = "^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\\d{8}$",message = "手机号格式不正确") String phoneNum){
authService.sendSMSCode(phoneNum);
return CommonResult.success(true,"验证码发送成功,请注意查收");
}
@PostMapping("/sendEmail")
public CommonResult<Boolean> sendEmail(@RequestParam String toAddress,String content,String subject){
authService.sendEmail(toAddress,subject,content);
return CommonResult.success(true,"邮件发送成功,请注意查收");
}
对应的 Service 实现类
@Override
public SmsInfo sendSMSCode(String phone) {
return smsCodeSendService.sendSMSLoginCode(phone);
}
@Override
public EmailInfo sendEmail(String toAddress, String subject, String content) {
return emailSendService.sendEmail(toAddress,subject,content);
}
调用第三方 api 没啥好说的,就是根据文档来配置,调用 API 方法,传参数。
短信跟邮件由于没有付费充值,所以暂时没法真实的的发送,这里只是模拟一下过程
明天计划的事情:
学习 SpringBoot 文件上传,及阿里云图片存储
遇到的问题:
无
收获:
集成第三方的短信邮件服务
评论