首先我們來定義一個頂層消息接口:
- /**
- * 功能: 系統消息發送服務 <p>
- * 用法:
- * @version 1.0
- */
- public interface MessageService {
- /**
- * 根據消息模板表中的消息編號取得消息模板,填充,發送
- *
- * @param bmtCode 消息模板表中的消息編號
- * @param params 填充模板內容的參數
- * @param to 消息的接收人
- * @throws CheckException 模板不存在,或是發送消息出現異常
- */
- public void sendMessage(String bmtCode,Map params, String... to) throws CheckException;
- }
接着我們實現該接口:
- public class MessageServiceImpl implements MessageService{
- /**
- * Logger for this class
- */
- private static final Logger logger = Logger.getLogger(MessageServiceImpl.class);
- @Autowired
- private BaseMessageTempletDAO baseMessageTempletDAO;
- @Autowired
- private SenderFactory senderFactory;
- @Override
- public void sendMessage(String bmtCode, Map params, String... to)
- throws CheckException {
- // 檢查參數
- if (StringUtils.isEmpty(bmtCode) || ArrayUtils.isEmpty(to)){
- throw new CheckException("模板編號不能爲空,或消息的接收人不能爲空");
- }
- // 從數據庫取出模板
- BaseMessageTempletEO queryParam = new BaseMessageTempletEO();
- queryParam.setBmtCode(bmtCode);
- BaseMessageTempletEO template = null;
- try {
- template = baseMessageTempletDAO.selectEOByEO(queryParam);
- } catch (Exception e) {
- // 查詢失敗
- logger.error("查詢模板:" + bmtCode + " 時發生異常", e);
- throw new CheckException(e);
- }
- // 檢查模板是否存在
- if (template == null){
- logger.info("編號爲: " + bmtCode + " 的消息模板不存在.");
- throw new CheckException("編號爲: " + bmtCode + " 的消息模板不存在.");
- }
- // 檢查消息類型
- String msgType = template.getBmtType();
- if (StringUtils.isEmpty(msgType)){
- logger.info("編號爲: " + bmtCode + " 的消息模板消息類型未知.");
- throw new CheckException("編號爲: " + bmtCode + " 的消息模板消息類型未知,無法發送.");
- }
- // 解析標題
- String title = null;
- if (StringUtils.isNotEmpty(template.getBmtTitle()) && params != null){
- try {
- title = VelocityParserUtil.getInstance().parseVelocityTemplate(template.getBmtTitle(),params);
- } catch (Exception e) {
- logger.error("編號爲: " + bmtCode + " 的消息模板解析 <標題 > 時失敗");
- throw new CheckException(e);
- }
- }
- // 解析內容
- String content = null;
- if (StringUtils.isNotEmpty(template.getBmtContent()) && params != null){
- try {
- content = VelocityParserUtil.getInstance().parseVelocityTemplate(template.getBmtContent(),params);
- } catch (Exception e) {
- logger.error("編號爲: " + bmtCode + " 的消息模板解析 <內容> 時失敗");
- throw new CheckException(e);
- }
- }
- // 發送
- Sender sender = senderFactory.getSender(msgType);
- if (sender == null){
- // 找不到對應類型的發送器
- logger.error("編號爲: " + bmtCode + " 的消息模板,類型爲: " + msgType + " 沒有對應的消息發送器");
- throw new CheckException("編號爲: " + bmtCode + " 的消息模板,類型爲: " + msgType + " 沒有對應的消息發送器");
- }
- sender.sender(title, content, to);
- }
- }
大家看到了代碼涉及到了DAO和Factory,這裏注入DAO是因爲我們把消息發送的相關信息都放進了數據庫存儲起來,我們根據識別號,去判斷髮送短息還是郵件,發送的模板是什麼等等。那我們寫一個發送消息的工廠類SendFactory:
- /**
- * 功能: 根據不同的消息類型,取得適應的消息發送器
- * <p>
- * 用法:
- *
- * @version 1.0
- */
- public class SenderFactory {
- @Autowired
- @Qualifier("mailSenderAdapt")
- private Sender mailSender;
- @Autowired
- @Qualifier("smsSenderAdapt")
- private Sender smsSender;
- public Sender getSender(String type) {
- Sender sender = null;
- if (BaseMessageTempletEO.BMT_TYPE_MAIL.equalsIgnoreCase(type)) {
- // 郵件
- sender = mailSender;
- } else if (BaseMessageTempletEO.BMT_TYPE_SMS.equalsIgnoreCase(type)) {
- // 短信
- sender = smsSender;
- }
- return sender;
- }
- }
如你所看到的我們會if的判斷得知該請求是要發送郵件還是發送短信。
我們暫時放下前面的,定義一個頂層接口Sender:
- /**
- * 功能: 消息發送器接口<p>
- * 用法:
- * @version 1.0
- */
- public interface Sender {
- /**
- * @param title 消息的標題
- * @param content 消息的內容
- * @param to 消息的接收人
- * @throws CheckException
- */
- public void sender(String title, String content, String... to) throws CheckException;
- }
然後我們要分別定義郵件和短信接口,並實現頂層接口Sender:
- public class SmsSenderAdapt implements Sender {
- @Autowired
- @Qualifier("smsSenderImpl_commons")
- private SmsSender smsSender;
- @Override
- public void sender(String title, String content, String... to)
- throws CheckException {
- smsSender.sendSms(to, content);
- }
- public class MailSenderAdapt implements Sender {
- @Autowired
- @Qualifier("emailSenderImpl_commons")
- private EmailSender emailSender;
- @Autowired
- private ConfigService configService;
- @Override
- public void sender(String title, String content, String... to)
- throws CheckException {
- // 從數據庫取發件人,及發件人姓名
- String from = configService.getConfig(BasePropertyID.MAIL_SMTP_FROM_ID);
- String fromName = configService.getConfig(BasePropertyID.MAIL_SMTP_FROMNAME_ID);
- Mail mail = new Mail();
- mail.setFrom(from);
- mail.setFromName(fromName);
- mail.setTo(to);
- mail.setSubject(title);
- mail.setContent(content);
- emailSender.sendEmail(mail);
- }
- }
後面對sendEmail(mail)這個已經在上一篇實現了,大家可以返回去看一下,是不是明白了呢?
接下來我詳細介紹發送短信的代碼。
那好我們來時先剛剛短信的接口:
- /**
- * 功能: 短信發送服務
- * <p>
- * 用法:
- *
- * @version 1.0
- */
- public class SmsSenderImpl implements SmsSender,InitializingBean {
- /**
- * Logger for this class
- */
- private static final Logger logger = Logger.getLogger(SmsSenderImpl.class);
- @Autowired
- private ConfigService configService;
- private String smsUrl;
- private String cpidName;
- private String cpidValue;
- private String pwdName;
- private String pwdValue;
- private String pidName;
- private String pidValue;
- private String phoneName;
- private String msgName;
- private int maxLength = 60; // 默認值
- @Override
- public void sendSms(String mobilePhone, String message) throws CheckException {
- send(message, mobilePhone);
- }
- @Override
- public void sendSms(String[] mobilePhones, String message) throws CheckException {
- if (ArrayUtils.isEmpty(mobilePhones)){
- throw new CheckException("手機號碼不能爲空");
- }
- for (String phone : mobilePhones) {
- sendSms(phone, message);
- }
- }
- /**
- * 如果超過短信的長度,則分成幾條發
- * @param content
- * @param phoneNo
- * @return
- * @throws CheckException
- */
- private String send(String content,String phoneNo) throws CheckException{
- content = StringUtils.trimToEmpty(content);
- phoneNo = StringUtils.trimToEmpty(phoneNo);
- if (StringUtils.isEmpty(content)){
- throw new CheckException("短信內容爲空");
- }
- if (StringUtils.isEmpty(phoneNo)){
- throw new CheckException("手機號爲空");
- }
- // 如果服務未準備好,先初始化
- if (!isReady()) {
- try {
- init();
- // 初始化後,服務仍未準備好
- if (!isReady()) {
- throw new CheckException("郵件服務初始化異常");
- }
- } catch (Exception e) {
- logger.error("send(String, String)", e);
- throw new CheckException("郵件服務初始化異常");
- }
- }
- // 如果超過最大長度,則分成幾條發送
- int count = content.length() / maxLength;
- int reminder = content.length() % maxLength;
- if (reminder != 0 ){
- count += 1;
- }
- StringBuffer result = new StringBuffer();
- int i = 0;
- while (count > i){
- result.append(doSend(StringUtils.substring(content, i*maxLength, (i+1)*maxLength),phoneNo));
- result.append(";");
- i ++;
- }
- return result.toString();
- }
- private boolean isReady(){
- return !(smsUrl == null || cpidName == null || cpidValue == null
- || pwdName == null || pwdValue == null || pidName == null
- || pidValue == null || phoneName == null || msgName == null || maxLength <= 0);
- }
- /**
- * @param content
- * @param phoneNo
- * @return
- * @throws CheckException
- */
- private String doSend(String content,String phoneNo) throws CheckException{
- // 使用httpclient模擬http請求
- HttpClient client = new HttpClient();
- // 設置參數編碼
- client.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "GBK");
- PostMethod method = new PostMethod(smsUrl);
- method.addParameter(cpidName, cpidValue);
- method.addParameter(pidName, pidValue);
- method.addParameter(pwdName, pwdValue);
- method.addParameter(phoneName, phoneNo);
- method.addParameter(msgName, content);
- BufferedReader br = null;
- String reponse = null;
- try {
- int returnCode = client.executeMethod(method);
- if (returnCode != HttpStatus.SC_OK) {
- // 請求出錯
- throw new CheckException("短信接口異常");
- }
- br = new BufferedReader(new InputStreamReader(method.getResponseBodyAsStream()));
- reponse = br.readLine();
- String responseCode = StringUtils.substring(reponse, 0, 1);
- if (!"0".equals(responseCode)){
- throw new CheckException(getResponseMsg(responseCode));
- }
- } catch (Exception e) {
- logger.error("doSend(String, String)", e);
- if (e instanceof CheckException){
- throw (CheckException)e;
- }else{
- throw new CheckException("未知異常"); // 未知異常
- }
- } finally {
- method.releaseConnection();
- if (br != null)
- try {
- br.close();
- } catch (Exception e1) {
- logger.error("doSend(String, String)", e1);
- e1.printStackTrace();
- }
- }
- return reponse;
- }
- public void afterPropertiesSet() throws Exception {
- // 初始化
- init();
- }
- private void init() throws Exception{
- smsUrl = configService.getConfig(BasePropertyID.SMS_URL_ID);
- cpidName = configService.getConfig(BasePropertyID.SMS_CPID_NAME_ID);
- cpidValue = configService.getConfig(BasePropertyID.SMS_CPID_VALUE_ID);
- pwdName = configService.getConfig(BasePropertyID.SMS_PWD_NAME_ID);
- pwdValue = configService.getConfig(BasePropertyID.SMS_PWD_VALUE_ID);
- pidName = configService.getConfig(BasePropertyID.SMS_PID_NAME_ID);
- pidValue = configService.getConfig(BasePropertyID.SMS_PID_VALUE_ID);
- phoneName = configService.getConfig(BasePropertyID.SMS_PHONE_NAME_ID);
- msgName = configService.getConfig(BasePropertyID.SMS_MSG_NAME_ID);
- maxLength = configService.getConfigByInteger(BasePropertyID.SMS_MSG_MAXLENGTH_ID);
- }
- private String getResponseMsg(String code){
- String msg = "未知返回值:" + code;
- if ("1".equals(code)) {
- msg = "手機號碼非法";
- } else if ("2".equals(code)) {
- msg = "用戶存在於黑名單列表";
- } else if ("3".equals(code)) {
- msg = "接入用戶名或密碼錯誤";
- } else if ("4".equals(code)) {
- msg = "產品代碼不存在";
- } else if ("5".equals(code)) {
- msg = "IP非法";
- } else if ("6".equals(code)) {
- msg = "源號碼錯誤";
- } else if ("7".equals(code)) {
- msg = "調用網關錯誤";
- } else if ("8".equals(code)) {
- msg = "消息長度超過60";
- } else if ("-1".equals(code)) {
- msg = "短信內容爲空";
- } else if ("-2".equals(code)) {
- msg = "手機號爲空";
- }else if ("-3".equals(code)) {
- msg = "郵件服務初始化異常";
- }else if ("-4".equals(code)) {
- msg = "短信接口異常";
- }
- return msg;
- }
- }
和郵件發送是不是很類似,相信大家應該會理解吧。O(∩_∩)O哈哈~,我這裏發送的配置信息都直接初始化在了java代碼裏,大家也可以試着將其配置在xml文件裏,這樣更改更方便。