开发过程中,需要发送信息给客户,调用第三方:容联七陌的短信平台 https://developer.7moor.com/v2docs/sms/;
首先需要将自己需要的短信模板想七陌报备, 模板样例: 尊敬的{1}先生您好,您的订单{2},如有问题请致电110;
其中的{1}{2}就是可变量,在发送信息时需要传递;最终客户收到的信息可能是这样的: [签名]尊敬的张三先生您好,您的订单OR123456789,如有问题请致电110;
其中签名也是报备短信模板一起规定的;
各个运营商为了防止你发送大批量的重复短信,会有一个拦截机制,规定一定时间内,同样的短信发送数量,例如五分钟两条;
运营商还有一个短信拦截机制,就是过滤一些敏感词汇,如果你的短信中含有敏感词汇,手机上就收不到短信,
但是!!! 你发送一条短信时,七陌不管你的手机号码会不会收到短信,只要他们发送成功了,就会返回给你说短信发送成功!
所以,在短信模板报备时,就必须注意,是否含有敏感词汇!不然的话,你发送一条短信,七陌告诉你成功了,但是,手机上没有收到信息!
为了规避运营商针对同样内容一定时间内短信数量的限制,可以报备多个内容相同但是签名不同的短信模板,在自己的代码中,根据七陌返回的信息判断,发送失败,就换一个短信模板发送.
所以,在自己的数据库中,需要两张表,一张表存七陌返回的报备的短信模板信息,另一张表存自己的短信模板信息:
(mysql数据库)
CREATE TABLE `t_msg_template` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id', `message_channel` varchar(32) DEFAULT NULL COMMENT '信息对接方:qimo', `message_type` char(2) DEFAULT NULL COMMENT '信息类型:1-短信;2-语音', `open_api_id` varchar(32) DEFAULT NULL COMMENT '对接方返回的模板主键', `num` int(10) DEFAULT NULL COMMENT '模板编号,发送信息时要传的参数', `name` varchar(32) DEFAULT NULL COMMENT '模板名称', `content` longtext COMMENT '模板内容,其中含有变量用{1},{2},按顺序增长', `vars` int(32) DEFAULT NULL COMMENT '变量个数', `sign` varchar(32) DEFAULT NULL COMMENT '签名', `is_deleted` char(1) NOT NULL DEFAULT 'N' COMMENT '是否删除', `creator` varchar(32) NOT NULL COMMENT '创建者', `modifier` varchar(32) NOT NULL COMMENT '修改者', `gmt_created` datetime NOT NULL COMMENT '创建时间', `gmt_modified` datetime NOT NULL COMMENT '修改时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 COMMENT='短信模板表'; |
CREATE TABLE `t_msg_detail_template` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id', `message_code` varchar(32) DEFAULT NULL COMMENT '短信模板code', `message_name` varchar(32) DEFAULT NULL COMMENT '短信模板名称', `expression` varchar(256) DEFAULT NULL COMMENT '表达式', `remark` varchar(256) DEFAULT NULL COMMENT '备注', `message_nums` varchar(32) NOT NULL COMMENT '短信模板num-多个用逗号隔开', `phone_number` varchar(256) DEFAULT NULL COMMENT '群发特定短信的号码-多个用逗号隔开', `is_deleted` char(1) NOT NULL DEFAULT 'N' COMMENT '是否删除', `creator` varchar(32) NOT NULL COMMENT '创建者', `modifier` varchar(32) NOT NULL COMMENT '修改者', `gmt_created` datetime NOT NULL COMMENT '创建时间', `gmt_modified` datetime NOT NULL COMMENT '修改时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8 COMMENT='内部短信详细模板'; |
这样就可以在自己的模板表中配置多个七陌的短信模板num,在他们返回发送失败,因为同一个内容一定时间内被拦截时,可以使用下一个签名的短信模板;在自己的短信详情模板中,加了expression字段,用于发送短信时,从一个大的Dto对象中,取出这条短信模板想要的特定字段,传递给七陌,拼接成想要的短信,这样一来,想要调用此接口发送短信,只要传入电话号码,模板编号,确定的参数即可在这个接口内部拼接完成.
/** * 七陌-发送短信 * * @param qimoProperty 七陌接口-关键参数 * @param requestDto 请求信息 * @return 七陌返回结果 */ public static Result<QimoSendMessageResponseDto> sendMessage(QimoProperty qimoProperty, SendMessageDto requestDto) { Result<QimoSendMessageResponseDto> result = new Result<>(); QimoSendMessageResponseDto responseDto = new QimoSendMessageResponseDto(); // 七陌的短信模板编号 String[] numsArray = requestDto.getMessageNums().split(QimoConstants.STRING_SPLIT_1); for (String num : numsArray) { // 请求参数 JSONObject parameter = new JSONObject(); parameter.put("num", requestDto.getPhoneNumber()); // 发送短信电话号码 parameter.put("templateNum", num); // 七陌的短信模板编号 JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(requestDto)); // 请求参数拼接表达式 String expression = requestDto.getExpression(); // 处理表达式 替换其中变量 Result<String> dealResult = QimoCheckUtils.dealExpressionItem(expression, jsonObject); if (dealResult.isSuccess()) { expression = dealResult.getValue(); } else { return TransformValue.copyErrorInfo(dealResult, result); } String[] expressionArray = expression.split(QimoConstants.STRING_SPLIT_1); for (int i = 0; i < expressionArray.length; i++) { parameter.put(String.format(QimoConstants.STRING_FORMAT_2, QimoConstants.VAR, i + 1), expressionArray[i]); } // 校验qimoProperty QimoCheckUtils.checkProperty(qimoProperty); String accountId = qimoProperty.getAccountId(); String apiSecret = qimoProperty.getApiSecret(); String currentTime = getCurrentTime(); // 签名 String sign = QimoMessageUtils.genSign(accountId, apiSecret, currentTime); // 包头授权信息 String authorization = QimoMessageUtils.genAuthorization(accountId, currentTime); RestTemplate restTemplate = new RestTemplate(); HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.add("Authorization", authorization); String response = RestUtils.postJsonWithHeaders(restTemplate, httpHeaders, qimoProperty.getSendMessageUrl(), JSON.toJSONString(parameter), accountId, sign); // 七陌-返回信息乱码处理 response = EncodeUtils.genRightString(response, QimoConstants.ENCODE_METHOD_ISO_8859_1, QimoConstants.ENCODE_METHOD_UTF_8); log.info("七陌返回的信息-response:{}", response); responseDto = JSONObject.parseObject(response, QimoSendMessageResponseDto.class); if (responseDto.getSuccess()) { result.setValue(responseDto).setSuccess(true); break; } } result = responseDto.getSuccess() ? result.setValue(responseDto).setSuccess(true) : TransformValue.setErrorInfo(result, responseDto.getFlag(), responseDto.getMessage()); return result; } |
package com.yifenqi.qimo.utils; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import org.apache.commons.lang.StringUtils; import org.springframework.util.CollectionUtils; import com.alibaba.fastjson.JSONObject; import com.github.myoss.phoenix.core.lang.dto.Result; import com.github.myoss.phoenix.core.lang.dto.TransformValue; import com.yifenqi.bank.constants.CodeMsgEnum; import com.yifenqi.common.DateUtils; import com.yifenqi.common.StringDealUtils; import com.yifenqi.qimo.common.QimoConstants; import com.yifenqi.qimo.config.QimoProperty; /** * 七陌校验工具类 * * @author zhangshiwei * @time 2018年8月16日下午4:30:04 */ @SuppressWarnings("all") public class QimoCheckUtils { /** * 校验 七陌接口-关键参数 * * @param property 参数 * @return 未传入则报错 */ public static Result checkProperty(QimoProperty property) { Result result = new Result(); if (null == property) { return TransformValue.setErrorInfo(result, CodeMsgEnum.VALUE_IS_BLANK.getCode(), "property为null!"); } return result; } /** * 根据表达式去除请求参数对象中的特定值 * * @param expression 表达式 * @param jsonObject 请求参数对象 * @return 特定请求参数 */ public static Result<String> dealExpressionItem(String expression, JSONObject jsonObject) { Result<String> dealResult = new Result<>(); // [@{userName},@{userName}] List<String> expressionItemList = StringDealUtils.subStrWithAffix(expression, QimoConstants.STRING_SPLIT_5, QimoConstants.STRING_SPLIT_6); if (!CollectionUtils.isEmpty(expressionItemList)) { for (int i = 0; i < expressionItemList.size(); i++) { String paramStr = expressionItemList.get(i); // @{userName} String paramStrNoEspecial = paramStr.replace(QimoConstants.STRING_SPLIT_5, StringUtils.EMPTY) .replace(QimoConstants.STRING_SPLIT_6, StringUtils.EMPTY); // userName String param = jsonObject.getString(paramStrNoEspecial); // 请求参数 // 此参数是时间Date格式的时间戳 需要转换处理 curDt billDt if (paramStrNoEspecial.contains(QimoConstants.DT)) { param = genDateString(param); } if (StringUtils.isBlank(param)) { return TransformValue.setErrorInfo(dealResult, paramStrNoEspecial, "请求参数不能为空"); } else { expression = expression.replace(paramStr, param); } } } return dealResult.setValue(expression); } /** * 获取符合格式的时间 * * @param timeStamp 时间 * @return 目的格式的时间 yyyy年MM月dd日 */ public static String genDateString(String timeStamp) { Date date = DateUtils.parseTimestampToDate(Long.parseLong(timeStamp)); String currentDateTime = new SimpleDateFormat(QimoConstants.MESSAGE_TIME_FORMAT).format(date); return currentDateTime; } } |
注意:
七陌短信接口的对接,要求头文件组装Authorization加入授权参数,进行base64编码,具体参考七陌文档;
还需要签名sign参数,使用特定的参数进行MD5加密,具体参考七陌文档;
然后使用post方式访问;
最后,七陌返回的数据,你接收到的可能乱码!因为他们返回的数据,编码方式是ISO-8859-1;
可以使用一个方法获取当前字符串的编码方式,然后进行反编码:
package com.yifenqi.common; import java.io.UnsupportedEncodingException; import lombok.extern.slf4j.Slf4j; /** * 处理乱码字符串 * * @author zhangshiwei * @time 2018年8月20日下午3:28:15 */ @Slf4j public class EncodeUtils { /** * 将乱码的字符串按照指定格式重新编码 * * @param str 乱码的字符串 * @param encodeMethodList 指定的编码方式 * @return 不乱码中文字符串 */ public static String genRightString(String str, String encodeMethod) { String currentMethod = getEncodMethod(str); log.info("此字符串的编码方式为:{}", currentMethod); try { return new String(str.getBytes(currentMethod), encodeMethod); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return null; } /** * 获取字符串的编码方式:GB2312 , ISO-8859-1 ,UTF-8 , GBK , UTF-16 , UTF-16BE , * UTF-16LE * * @param str 待检查字符串 * @return 编码方式 */ public static String getEncodMethod(String str) { String encode = "GB2312"; encode = "ISO-8859-1"; try { if (str.equals(new String(str.getBytes(encode), encode))) { return encode; } } catch (Exception exception1) { } encode = "UTF-8"; try { if (str.equals(new String(str.getBytes(encode), encode))) { String s2 = encode; return s2; } } catch (Exception exception2) { } encode = "GBK"; try { if (str.equals(new String(str.getBytes(encode), encode))) { String s3 = encode; return s3; } } catch (Exception exception3) { } encode = "UTF-16"; try { if (str.equals(new String(str.getBytes(encode), encode))) { String s3 = encode; return s3; } } catch (Exception exception3) { } encode = "UTF-16BE"; try { if (str.equals(new String(str.getBytes(encode), encode))) { String s3 = encode; return s3; } } catch (Exception exception3) { } encode = "UTF-16LE"; try { if (str.equals(new String(str.getBytes(encode), encode))) { String s3 = encode; return s3; } } catch (Exception exception3) { } return ""; } /** * @param str 乱码字符串 * @param errorMethod 错误的编码方式 * @param rightMethod 想要的编码方式 * @return 正确的中文字符串 */ public static String genRightString(String str, String errorMethod, String rightMethod) { try { return new String(str.getBytes(errorMethod), rightMethod); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return null; } } |
解决乱码问题;