上次介绍了基于Velocity模板java邮件发送,这次我们对程序做了一次重构,实现的是根据相应的请求发送邮件或者短信。 首先我们来定义一个顶层消息接口:
[java]
view plaincopy/**
* 功能: 系统消息发送服务 <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;
}
[java]
view plain copy/**
* 功能: 系统消息发送服务 <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;
}
接着我们实现该接口:
[java]
view plaincopypublic 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);
}
}
[java]
view plain copypublic 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:
[java]
view plaincopy/**
* 功能: 根据不同的消息类型,取得适应的消息发送器
* <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;
}
}
[java]
view plain copy/**
* 功能: 根据不同的消息类型,取得适应的消息发送器
* <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:
[java]
view plaincopy/**
* 功能: 消息发送器接口<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;
}
[java]
view plain copy/**
* 功能: 消息发送器接口<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:
[java]
view plaincopypublic 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);
}
[java]
view plain copypublic 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);
}
[java]
view plaincopypublic 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);
}
}
[java]
view plain copypublic 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)这个已经在上一篇实现了,大家可以返回去看一下,是不是明白了呢?
接下来我详细介绍发送短信的代码。
那好我们来时先刚刚短信的接口:
[java]
view plaincopy/**
* 功能: 短信发送服务
* <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;
}
}
[java]
view plain copy/**
* 功能: 短信发送服务
* <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文件里,这样更改更方便。