package com.tourguide.integration.sms; 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 com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.tourguide.common.exception.BusinessException; import com.tourguide.config.properties.AliyunSmsProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import java.util.Collections; import java.util.HashMap; import java.util.Map; @Component public class AliyunSmsCodeSender implements SmsCodeSender { private static final Logger LOGGER = LoggerFactory.getLogger(AliyunSmsCodeSender.class); private static final String SUCCESS_CODE = "OK"; private final AliyunSmsProperties properties; private final ObjectMapper objectMapper; public AliyunSmsCodeSender(AliyunSmsProperties properties, ObjectMapper objectMapper) { this.properties = properties; this.objectMapper = objectMapper; } @Override public void sendLoginCode(String phone, String code) { ensureConfigured(); try { SendSmsResponse response = createClient().sendSms(new SendSmsRequest() .setPhoneNumbers(phone) .setSignName(properties.getSignName()) .setTemplateCode(properties.getLoginTemplateCode()) .setTemplateParam(templateParam(code))); ensureSuccess(phone, response == null ? null : response.getBody()); } catch (BusinessException exception) { throw exception; } catch (Exception exception) { LOGGER.error("调用阿里云短信服务失败,手机号:{}", maskPhone(phone), exception); throw new BusinessException(502, "短信服务暂不可用,请稍后再试"); } } @Override public void sendGuideAuditResult(String phone, String guideName, boolean approved) { String templateCode = approved ? properties.getGuideAuditApprovedTemplateCode() : properties.getGuideAuditRejectedTemplateCode(); if (!hasCommonConfiguration() || !StringUtils.hasText(templateCode)) { LOGGER.warn("导游审核短信模板未配置,跳过发送,手机号:{},审核结果:{}", maskPhone(phone), approved); return; } Map parameters = new HashMap(); parameters.put("name", guideName == null ? "导游" : guideName); try { SendSmsResponse response = createClient().sendSms(new SendSmsRequest() .setPhoneNumbers(phone) .setSignName(properties.getSignName()) .setTemplateCode(templateCode) .setTemplateParam(objectMapper.writeValueAsString(parameters))); ensureSuccess(phone, response == null ? null : response.getBody()); } catch (BusinessException exception) { throw exception; } catch (Exception exception) { LOGGER.error("调用阿里云导游审核短信服务失败,手机号:{}", maskPhone(phone), exception); throw new BusinessException(502, "审核短信发送失败"); } } private Client createClient() throws Exception { Config config = new Config() .setAccessKeyId(properties.getAccessKeyId()) .setAccessKeySecret(properties.getAccessKeySecret()); config.endpoint = properties.getEndpoint(); return new Client(config); } private String templateParam(String code) throws JsonProcessingException { return objectMapper.writeValueAsString(Collections.singletonMap("code", code)); } private void ensureSuccess(String phone, SendSmsResponseBody body) { if (body != null && SUCCESS_CODE.equals(body.getCode())) { return; } String aliyunCode = body == null ? null : body.getCode(); String aliyunMessage = body == null ? null : body.getMessage(); LOGGER.warn("阿里云短信发送失败,手机号:{},错误码:{},错误信息:{}", maskPhone(phone), aliyunCode, aliyunMessage); throw new BusinessException(502, "验证码发送失败,请稍后再试"); } private void ensureConfigured() { if (!hasCommonConfiguration() || !StringUtils.hasText(properties.getLoginTemplateCode())) { throw new BusinessException(503, "阿里云短信配置未完成"); } } private boolean hasCommonConfiguration() { return StringUtils.hasText(properties.getAccessKeyId()) && StringUtils.hasText(properties.getAccessKeySecret()) && StringUtils.hasText(properties.getEndpoint()) && StringUtils.hasText(properties.getSignName()); } private String maskPhone(String phone) { if (phone == null || phone.length() < 7) { return "****"; } return phone.substring(0, 3) + "****" + phone.substring(phone.length() - 4); } }