短信平台使用的是阿里云的短信服务,jeecgboot已集成短信发送功能,但没有保存短信结果,不方便一些业务的统计
新建一个短信结果对象
@Data
public class SmsResult implements Serializable {
private String mobile;
private Boolean success;
private String code;
private String message;
private String requestId;
private String bizId;
private Integer smsType;
}
DySmsHelper中新增一个短信发送方法
/**
* @param phone 短信号码,可以是用逗号分隔的字符串,此时是群发,最多是1000个号码
* @param templateParamJson
* @param dySmsEnum
* @return
* @throws ClientException
*/
public static SmsResult sendSmsForResult(String phone, JSONObject templateParamJson, DySmsEnum dySmsEnum) throws ClientException {
//可自助调整超时时间
System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
System.setProperty("sun.net.client.defaultReadTimeout", "10000");
//update-begin-author:taoyan date:20200811 for:配置类数据获取
StaticConfig staticConfig = SpringContextUtils.getBean(StaticConfig.class);
setAccessKeyId(staticConfig.getAccessKeyId());
setAccessKeySecret(staticConfig.getAccessKeySecret());
//update-end-author:taoyan date:20200811 for:配置类数据获取
//初始化acsClient,暂不支持region化
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
IAcsClient acsClient = new DefaultAcsClient(profile);
//验证json参数
validateParam(templateParamJson, dySmsEnum);
//组装请求对象-具体描述见控制台-文档部分内容
SendSmsRequest request = new SendSmsRequest();
//必填:待发送手机号
request.setPhoneNumbers(phone);
//必填:短信签名-可在短信控制台中找到
request.setSignName(dySmsEnum.getSignName());
//必填:短信模板-可在短信控制台中找到
request.setTemplateCode(dySmsEnum.getTemplateCode());
//可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
request.setTemplateParam(templateParamJson.toJSONString());
//选填-上行短信扩展码(无特殊需求用户请忽略此字段)
//request.setSmsUpExtendCode("90997");
//可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
//request.setOutId("yourOutId");
//hint 此处可能会抛出异常,注意catch
SmsResult result = new SmsResult();
result.setMobile(phone);
switch (dySmsEnum) {
case REGISTER_TEMPLATE_CODE:
result.setSmsType(SmsTypeEnum.Reg.getCode());
break;
case FORGET_PASSWORD_TEMPLATE_CODE:
result.setSmsType(SmsTypeEnum.Forget.getCode());
break;
case MEET_NOTICE_TEMPLATE_CODE:
result.setSmsType(SmsTypeEnum.Notice.getCode());
break;
default:
result.setSmsType(SmsTypeEnum.Other.getCode());
}
try {
SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
logger.info("短信接口返回的数据----------------");
String bizId = sendSmsResponse.getBizId();
logger.info("{Code:" + sendSmsResponse.getCode() + ",Message:" + sendSmsResponse.getMessage() + ",RequestId:" + sendSmsResponse.getRequestId() + ",BizId:" + bizId + "}");
result.setSuccess(true);
result.setCode(sendSmsResponse.getCode());
result.setMessage(sendSmsResponse.getMessage());
result.setRequestId(sendSmsResponse.getRequestId());
result.setBizId(bizId);
} catch (Exception e) {
result.setSuccess(false);
result.setMessage(e.getMessage());
}
return result;
}
新建一个用于保存的短信结果对象(建表后生成相关的实体,mapper,业务类)
/**
* @Description: 短信结果
* @Author: jeecg-boot
* @Date: 2022-03-23
* @Version: V1.0
*/
@Data
@TableName("meet_sms_result")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@ApiModel(value="meet_sms_result对象", description="短信结果")
public class SmsResult implements Serializable {
private static final long serialVersionUID = 1L;
/**id*/
@TableId(type = IdType.ASSIGN_ID)
@ApiModelProperty(value = "id")
private java.lang.String id;
/**手机号码*/
@Excel(name = "手机号码", width = 15)
@ApiModelProperty(value = "手机号码")
private java.lang.String mobile;
/**类型*/
@Excel(name = "类型", width = 15)
@ApiModelProperty(value = "类型")
private java.lang.Integer smsType;
/**是否成功*/
@Excel(name = "是否成功", width = 15)
@ApiModelProperty(value = "是否成功")
private java.lang.Boolean success;
/**代码*/
@Excel(name = "代码", width = 15)
@ApiModelProperty(value = "代码")
private java.lang.String code;
/**返回消息*/
@Excel(name = "返回消息", width = 15)
@ApiModelProperty(value = "返回消息")
private java.lang.String message;
/**requestId*/
@Excel(name = "requestId", width = 15)
@ApiModelProperty(value = "requestId")
private java.lang.String requestId;
/**bizId*/
@Excel(name = "bizId", width = 15)
@ApiModelProperty(value = "bizId")
private java.lang.String bizId;
/**创建人*/
@ApiModelProperty(value = "创建人")
private java.lang.String createBy;
/**创建日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@ApiModelProperty(value = "创建日期")
private java.util.Date createTime;
/**更新人*/
@ApiModelProperty(value = "更新人")
private java.lang.String updateBy;
/**更新日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern="yyyy-MM-dd")
@ApiModelProperty(value = "更新日期")
private java.util.Date updateTime;
@ApiModelProperty(value = "发送时间")
private String sendDate;
@ApiModelProperty(value = "接收时间")
private String receiveDate;
@ApiModelProperty(value = "运营商状态码,DELIVERED是成功")
private String errCode;
/**
* 1:等待回执。
* 2:发送失败。
* 3:发送成功。
*/
@ApiModelProperty(value = "短信发送状态")
private String sendStatus;
public static SmsResult fromSendResult(org.jeecg.modules.base.entity.SmsResult result){
SmsResult r = new SmsResult();
r.setMobile(result.getMobile());
r.setSmsType(result.getSmsType());
r.setSuccess(result.getSuccess());
r.setCode(result.getCode());
r.setMessage(result.getMessage());
r.setRequestId(result.getRequestId());
r.setBizId(result.getBizId());
return r;
}
}
SmsResultServiceImpl中增加查询短信结果并保存的方法
/**
* 查询发送结果
*
* @param phones
* @param bizId
* @return
*/
@Override
@Async("asyncServiceExecutor")
public void getSendDetail(String phones, String bizId, String sendDate, Integer smsType, String reserveRoomId, Boolean saveSmsResult) {
try {
Thread.sleep(10000L);
//可自助调整超时时间
System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
System.setProperty("sun.net.client.defaultReadTimeout", "10000");
//update-begin-author:taoyan date:20200811 for:配置类数据获取
StaticConfig staticConfig = SpringContextUtils.getBean(StaticConfig.class);
DySmsHelper.setAccessKeyId(staticConfig.getAccessKeyId());
DySmsHelper.setAccessKeySecret(staticConfig.getAccessKeySecret());
//update-end-author:taoyan date:20200811 for:配置类数据获取
//初始化acsClient,暂不支持region化
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", DySmsHelper.getAccessKeyId(), DySmsHelper.getAccessKeySecret());
try {
DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
} catch (ClientException e) {
return;
}
IAcsClient acsClient = new DefaultAcsClient(profile);
String[] phoneList = phones.split(",");
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
SimpleDateFormat sendDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
List<SmsResult> list = new ArrayList<>();
List<ReservePerson> personList = new ArrayList<>();
for (String s : phoneList) {
QuerySendDetailsRequest detailsRequest = new QuerySendDetailsRequest();
detailsRequest.setPhoneNumber(s);
detailsRequest.setBizId(bizId);
if (StrUtil.isEmpty(sendDate)) {
detailsRequest.setSendDate(dateFormat.format(new Date()));
} else {
try {
Date parse = sendDateFormat.parse(sendDate);
String format = dateFormat.format(parse);
detailsRequest.setSendDate(format);
} catch (ParseException e) {
detailsRequest.setSendDate(dateFormat.format(new Date()));
}
}
detailsRequest.setPageSize(1L);
detailsRequest.setCurrentPage(1L);
QuerySendDetailsResponse acsResponse = null;
try {
acsResponse = acsClient.getAcsResponse(detailsRequest);
List<QuerySendDetailsResponse.SmsSendDetailDTO> smsSendDetailDTOs = acsResponse.getSmsSendDetailDTOs();
for (QuerySendDetailsResponse.SmsSendDetailDTO smsSendDetailDTO : smsSendDetailDTOs) {
log.info("查询结果:{} , 接收时间:{},错误代码:{},内容:{},电话号码:{}",
smsSendDetailDTO.getSendStatus(), smsSendDetailDTO.getReceiveDate(),
smsSendDetailDTO.getErrCode(), smsSendDetailDTO.getContent(),
smsSendDetailDTO.getPhoneNum());
SmsResult result = new SmsResult();
result.setMobile(s);
result.setBizId(bizId);
result.setSmsType(smsType);
result.setSendDate(smsSendDetailDTO.getSendDate());
result.setReceiveDate(smsSendDetailDTO.getReceiveDate());
result.setSendStatus(smsSendDetailDTO.getSendStatus().toString());
result.setErrCode(smsSendDetailDTO.getErrCode());
list.add(result);
//如果是通知类短信,生成通知对象,保存到参会人员表中
if (smsType.equals(SmsTypeEnum.Notice.getCode())) {
ReservePerson reservePerson = createReservePerson(result, reserveRoomId);
personList.add(reservePerson);
}
}
} catch (ClientException e) {
e.printStackTrace();
}
}
if (saveSmsResult) {
this.saveBatch(list);
}
if (smsType.equals(SmsTypeEnum.Notice.getCode())) {
this.saveNoticeResult(personList, reserveRoomId);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 使用短信结果生成参会人员短信通知对象
*
* @param smsResult
* @param reserveRoomId
* @return
*/
private ReservePerson createReservePerson(SmsResult smsResult, String reserveRoomId) {
ReservePerson reservePerson = new ReservePerson();
reservePerson.setReserveRoomId(reserveRoomId);
reservePerson.setBizId(smsResult.getBizId());
reservePerson.setMobile(smsResult.getMobile());
reservePerson.setSendSms(true);
reservePerson.setSendDate(smsResult.getSendDate());
reservePerson.setReceiveDate(smsResult.getReceiveDate());
reservePerson.setSendStatus(smsResult.getSendStatus().toString());
reservePerson.setErrCode(smsResult.getErrCode());
return reservePerson;
}
/**
* 保存短信通知结果
*
* @param list
*/
private void saveNoticeResult(List<ReservePerson> list, String reserveRoomId) {
if (list.size() == 0) return;
List<String> phones = list.stream().map(f -> f.getMobile()).collect(Collectors.toList());
List<ReservePerson> records = reservePersonService.list(new LambdaQueryWrapper<ReservePerson>()
.eq(ReservePerson::getReserveRoomId, reserveRoomId)
.in(ReservePerson::getMobile, phones));
for (ReservePerson reservePerson : list) {
ReservePerson reservePerson1 = records.stream().filter(f -> f.getMobile().equals(reservePerson.getMobile())).findFirst().orElse(null);
if (reservePerson1 != null) {
reservePerson.setId(reservePerson1.getId());
}
}
reservePersonService.updateBatchById(list);
}
控制器中使用:
@ApiOperation(value = "参会人员-发送短信")
@PostMapping(value = "/sendSms")
public Result<?> sendSms(@RequestBody JSONObject jObj) {
Integer type = jObj.getInteger("type"); //发送类型: 1=全部发送,2=给选择的号码发送
String reserveRoomId = jObj.getString("reserveRoomId");
ReserveRoomVo vo = reserveRoomService.getVoByReserveRoomId(reserveRoomId);
if (vo == null) {
return Result.error("未找到预约会议室记录");
}
List<String> phoneList = new ArrayList<>();
if(type==1){
phoneList=reservePersonService.getPhones(reserveRoomId);
}else{
JSONArray phones = jObj.getJSONArray("phones");
for (Object phone : phones) {
phoneList.add(phone.toString());
}
}
if(phoneList.size()==0){
return Result.error("未找到任何电话号码");
}
if(phoneList.size()>1000){
return Result.error("一次最多发送1000条短信");
}
//短信参数
JSONObject obj = new JSONObject();
obj.put("time", String.format("%s %s - %s", vo.getMeetDate(), vo.getBeginTime(), vo.getEndTime()));
obj.put("place", vo.getCompanyName());
obj.put("content", vo.getTitle());
String phones = String.join(",",phoneList);
try {
SmsResult smsResult = DySmsHelper.sendSmsForResult(phones, obj, DySmsEnum.MEET_NOTICE_TEMPLATE_CODE);
if (smsResult.getCode().equals("OK")) {
smsResultService.getSendDetail(smsResult.getMobile(), smsResult.getBizId(),null, smsResult.getSmsType(), reserveRoomId,true);//开启线程,查询发送结果
return Result.OK();
}else{
return Result.error(smsResult.getMessage());
}
} catch (ClientException e) {
return Result.error(e.getMessage());
}
}
@ApiOperation(value = "参会人员-查询短信发送结果")
@PostMapping(value="/getSmsResultDetail")
public Result<?> getSmsResultDetail(@RequestBody JSONObject jObj){
String reserveRoomId = jObj.getString("reserveRoomId");
String bizId = jObj.getString("bizId");
String sendDate = jObj.getString("sendDate");
List<ReservePerson> list = reservePersonService.list(new LambdaQueryWrapper<ReservePerson>().eq(ReservePerson::getReserveRoomId, reserveRoomId)
.eq(ReservePerson::getBizId, bizId));
List<String> collect = list.stream().map(f -> f.getMobile()).collect(Collectors.toList());
if(collect.size()>0){
String phones = String.join(",", collect);
smsResultService.getSendDetail(phones, bizId,sendDate, SmsTypeEnum.Notice.getCode(), reserveRoomId,false);//开启线程,查询发送结果
}
return Result.OK();
}
短信参数模板,需在阿里云控制台中设置,并需审核通过,实际情况为:头天上午通过审核,第二天才能正常发送,
提醒您有一条会议短消息,兹定于${time}于${place}召开${content}会议,请准时参加。特此通知。