Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
7025b92d2c | |||
e0162e100e | |||
3600c0980e | |||
ef85b53283 | |||
3e0ac9fc2e | |||
605fee50dd | |||
d78b9dbcd2 | |||
e74ffafe18 | |||
32527e321e |
66
README.md
Normal file
66
README.md
Normal file
@ -0,0 +1,66 @@
|
||||
# 消息通知组件
|
||||
|
||||
## 如何使用
|
||||
|
||||
`com.simaek.notify.NotifyConfigManager`
|
||||
|
||||
实现getNotifyConfig(NotifyType notifyType, String id),从数据库或者配置文件读取通知器配置
|
||||
|
||||
|
||||
`com.simaek.notify.template.AbstractTemplateManager`
|
||||
|
||||
实现方法getProperties(NotifyType notifyType, String id),从数据库或者配置文件读取模板配置
|
||||
|
||||
`com.simaek.notify.AbstractNotifierManager`
|
||||
|
||||
默认实现所有的方法,直接继承,有需要再覆写。
|
||||
|
||||
## 消息发送
|
||||
|
||||
需要实现或者覆写的功能全都完成了,直接使用即可,有两种发送方式。
|
||||
|
||||
1、使用预配置的模板发送信息(适用于定时提醒、验证码等较为常用的信息)
|
||||
|
||||
需要提供两个参数:notifierId,templateId。
|
||||
|
||||
```
|
||||
// 通过配置信息的ID,和通知类型获取通知器
|
||||
Notifier<Template> notifier = notifierManager.getNotifier(DefaultNotifyType.email, notifierId);
|
||||
// 通过模板管理器获取模板
|
||||
Template template = templateManager.getTemplate(DefaultNotifyType.email, templateId);
|
||||
// 指定使用的消息模板和上下文,上下文用于对模板中的形如${name}的变量进行提换
|
||||
notifier.send(template, new HashMap<>());
|
||||
```
|
||||
|
||||
2、使用自定义模板发送信息(适用于自定义消息),以短信为例。
|
||||
|
||||
需要提供一个参数:notifierId。
|
||||
|
||||
```
|
||||
// 创建短信模板
|
||||
TelecomSmsTemplate smsTemplate = new TelecomSmsTemplate();
|
||||
smsTemplate.setMobile("18605120786,13047986669");
|
||||
smsTemplate.setContent("你好,您的验证码是:${code},验证码有效期5分钟。");
|
||||
|
||||
// 创建模板配置文件
|
||||
TemplateProperties templateProperties = new TemplateProperties();
|
||||
// 定义模板类型为短信
|
||||
templateProperties.setType(DefaultNotifyType.sms.getId());
|
||||
// 选择短信服务提供商
|
||||
templateProperties.setProvider(SmsProvider.js139.getId());
|
||||
// 配置文件为了兼容不同模板,是使用JSON字符串进行存储的,需要转换一下
|
||||
templateProperties.setTemplate(JSON.toJSONString(smsTemplate));
|
||||
|
||||
// 使用通知管理器创建模板,这一步会对模板进行渲染
|
||||
Template template = templateManager.createTemplate(DefaultNotifyType.sms, templateProperties);
|
||||
Map<String, Object> context = new HashMap<>();
|
||||
context.put("code", "123456");
|
||||
|
||||
// 获取短信通知器并发送信息
|
||||
Notifier<Template> notifier = notifierManager.getNotifier(DefaultNotifyType.sms, notifierId);
|
||||
notifier.send(template, context);
|
||||
```
|
||||
|
||||
## 其他
|
||||
|
||||
目前对接的通知服务有钉钉、微信公众号、企业微信、阿里云短信、云信通短信、电子邮件。如果想实现自己的通知器,实现core模块中的接口即可。
|
@ -3,9 +3,9 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>notify</artifactId>
|
||||
<groupId>com.cicdi</groupId>
|
||||
<version>0.1.0</version>
|
||||
<artifactId>notify-parent</artifactId>
|
||||
<groupId>com.simaek</groupId>
|
||||
<version>0.1.1</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@ -21,20 +21,16 @@
|
||||
<dependency>
|
||||
<groupId>commons-beanutils</groupId>
|
||||
<artifactId>commons-beanutils</artifactId>
|
||||
<version>1.9.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>1.14</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-expression</artifactId>
|
||||
<version>5.2.15.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.cicdi.notify;
|
||||
package com.simaek.notify;
|
||||
|
||||
import com.cicdi.notify.template.Template;
|
||||
import com.simaek.notify.template.Template;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
@ -1,4 +1,4 @@
|
||||
package com.cicdi.notify;
|
||||
package com.simaek.notify;
|
||||
|
||||
/**
|
||||
* 默认支持的通知类型
|
@ -1,6 +1,6 @@
|
||||
package com.cicdi.notify;
|
||||
package com.simaek.notify;
|
||||
|
||||
import com.cicdi.notify.template.Template;
|
||||
import com.simaek.notify.template.Template;
|
||||
|
||||
import java.util.Map;
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.cicdi.notify;
|
||||
package com.simaek.notify;
|
||||
|
||||
import com.cicdi.notify.template.Template;
|
||||
import com.simaek.notify.template.Template;
|
||||
|
||||
/**
|
||||
* 通知器管理器,用于获取获取通知器
|
@ -1,4 +1,4 @@
|
||||
package com.cicdi.notify;
|
||||
package com.simaek.notify;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
@ -1,6 +1,6 @@
|
||||
package com.cicdi.notify;
|
||||
package com.simaek.notify;
|
||||
|
||||
import com.cicdi.notify.template.Template;
|
||||
import com.simaek.notify.template.Template;
|
||||
|
||||
/**
|
||||
* 通知服务商
|
@ -1,4 +1,4 @@
|
||||
package com.cicdi.notify;
|
||||
package com.simaek.notify;
|
||||
|
||||
/**
|
||||
* 通知配置属性管理器,用于统一管理通知配置属性
|
@ -1,4 +1,4 @@
|
||||
package com.cicdi.notify;
|
||||
package com.simaek.notify;
|
||||
|
||||
/**
|
||||
* 通知类型,通常使用枚举实现,枚举支持的通知类型
|
@ -1,4 +1,4 @@
|
||||
package com.cicdi.notify;
|
||||
package com.simaek.notify;
|
||||
|
||||
/**
|
||||
* 服务商标识,通常使用枚举实现,枚举支持的服务商
|
@ -1,7 +1,7 @@
|
||||
package com.cicdi.notify.template;
|
||||
package com.simaek.notify.template;
|
||||
|
||||
import com.cicdi.notify.DefaultNotifyType;
|
||||
import com.cicdi.notify.NotifyType;
|
||||
import com.simaek.notify.DefaultNotifyType;
|
||||
import com.simaek.notify.NotifyType;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
@ -1,6 +1,6 @@
|
||||
package com.cicdi.notify.template;
|
||||
package com.simaek.notify.template;
|
||||
|
||||
import com.cicdi.notify.NotifierProvider;
|
||||
import com.simaek.notify.NotifierProvider;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.cicdi.notify.template;
|
||||
package com.simaek.notify.template;
|
||||
|
||||
import com.cicdi.notify.NotifyType;
|
||||
import com.simaek.notify.NotifyType;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.cicdi.notify.template;
|
||||
package com.simaek.notify.template;
|
||||
|
||||
import com.cicdi.notify.NotifierProvider;
|
||||
import com.cicdi.notify.NotifyType;
|
||||
import com.simaek.notify.NotifierProvider;
|
||||
import com.simaek.notify.NotifyType;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.cicdi.notify.template;
|
||||
package com.simaek.notify.template;
|
||||
|
||||
import com.cicdi.notify.DefaultNotifyType;
|
||||
import com.cicdi.notify.NotifyType;
|
||||
import com.cicdi.notify.Provider;
|
||||
import com.simaek.notify.DefaultNotifyType;
|
||||
import com.simaek.notify.NotifyType;
|
||||
import com.simaek.notify.Provider;
|
||||
|
||||
/**
|
||||
* 通知模板服务商
|
@ -1,7 +1,7 @@
|
||||
package com.cicdi.notify.util;
|
||||
package com.simaek.notify.util;
|
||||
|
||||
import com.cicdi.notify.util.script.engine.DynamicScriptEngine;
|
||||
import com.cicdi.notify.util.script.engine.spel.SpelParserEngine;
|
||||
import com.simaek.notify.util.script.engine.DynamicScriptEngine;
|
||||
import com.simaek.notify.util.script.engine.spel.SpelParserEngine;
|
||||
import org.apache.commons.beanutils.BeanUtilsBean2;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
|
@ -0,0 +1,33 @@
|
||||
package com.simaek.notify.util;
|
||||
|
||||
/**
|
||||
* @author Yaser Hsueh
|
||||
*/
|
||||
public abstract class StringUtils {
|
||||
|
||||
public static boolean isEmpty(Object str) {
|
||||
return (str == null || "".equals(str));
|
||||
}
|
||||
|
||||
public static boolean hasLength(CharSequence str) {
|
||||
return (str != null && str.length() > 0);
|
||||
}
|
||||
|
||||
public static boolean hasLength(String str) {
|
||||
return (str != null && !str.isEmpty());
|
||||
}
|
||||
|
||||
public static boolean isBlank(String str) {
|
||||
int strLen;
|
||||
if (str == null || (strLen = str.length()) == 0) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < strLen; i++) {
|
||||
if ((!Character.isWhitespace(str.charAt(i)))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.cicdi.notify.util;
|
||||
package com.simaek.notify.util;
|
||||
|
||||
import org.apache.commons.beanutils.BeanUtilsBean;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.cicdi.notify.util.script.engine;
|
||||
package com.simaek.notify.util.script.engine;
|
||||
|
||||
import java.util.Map;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.cicdi.notify.util.script.engine;
|
||||
package com.simaek.notify.util.script.engine;
|
||||
|
||||
import javax.script.ScriptException;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.cicdi.notify.util.script.engine;
|
||||
package com.simaek.notify.util.script.engine;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
@ -1,4 +1,4 @@
|
||||
package com.cicdi.notify.util.script.engine;
|
||||
package com.simaek.notify.util.script.engine;
|
||||
|
||||
public class ScriptContext {
|
||||
private final String id;
|
@ -1,8 +1,8 @@
|
||||
package com.cicdi.notify.util.script.engine.spel;
|
||||
package com.simaek.notify.util.script.engine.spel;
|
||||
|
||||
import com.cicdi.notify.util.script.engine.ExecuteResult;
|
||||
import com.cicdi.notify.util.script.engine.ListenerSupportEngine;
|
||||
import com.cicdi.notify.util.script.engine.ScriptContext;
|
||||
import com.simaek.notify.util.script.engine.ExecuteResult;
|
||||
import com.simaek.notify.util.script.engine.ListenerSupportEngine;
|
||||
import com.simaek.notify.util.script.engine.ScriptContext;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ExpressionParser;
|
@ -3,9 +3,9 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>notify</artifactId>
|
||||
<groupId>com.cicdi</groupId>
|
||||
<version>0.1.0</version>
|
||||
<artifactId>notify-parent</artifactId>
|
||||
<groupId>com.simaek</groupId>
|
||||
<version>0.1.1</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@ -19,9 +19,8 @@
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.cicdi</groupId>
|
||||
<groupId>com.simaek</groupId>
|
||||
<artifactId>notify-core</artifactId>
|
||||
<version>0.1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@ -30,8 +29,8 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
@ -1,128 +0,0 @@
|
||||
package com.cicdi.notify.dingtalk;
|
||||
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.cicdi.notify.DefaultNotifyType;
|
||||
import com.cicdi.notify.Notifier;
|
||||
import com.cicdi.notify.NotifyType;
|
||||
import com.cicdi.notify.Provider;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class DingTalkNotifier implements Notifier<DingTalkMessageTemplate> {
|
||||
|
||||
private final AtomicReference<String> accessToken = new AtomicReference<>();
|
||||
|
||||
private long refreshTokenTime;
|
||||
|
||||
private final long tokenTimeOut = Duration.ofSeconds(7000).toMillis();
|
||||
|
||||
private static final String tokenApi = "https://oapi.dingtalk.com/gettoken";
|
||||
|
||||
private static final String notifyApi = "https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2";
|
||||
|
||||
private final DingTalkProperties properties;
|
||||
|
||||
private final String notifierId;
|
||||
|
||||
@Override
|
||||
public String getNotifierId() {
|
||||
return notifierId;
|
||||
}
|
||||
|
||||
public DingTalkNotifier(String id, DingTalkProperties properties) {
|
||||
this.properties = properties;
|
||||
this.notifierId = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotifyType getType() {
|
||||
return DefaultNotifyType.dingTalk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Provider getProvider() {
|
||||
return DingTalkProvider.dingTalkMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(DingTalkMessageTemplate template, Map<String, Object> context) {
|
||||
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
|
||||
List<NameValuePair> params = new ArrayList<>();
|
||||
params.add(new BasicNameValuePair("access_token", getToken()));
|
||||
|
||||
try {
|
||||
HttpPost httpPost = new HttpPost(new URIBuilder(notifyApi).setParameters(params).build());
|
||||
String formInserter = template.createFormInserter(context);
|
||||
StringEntity entity = new StringEntity(template.createFormInserter(context));
|
||||
httpPost.setEntity(entity);
|
||||
CloseableHttpResponse response = httpClient.execute(httpPost);
|
||||
JSONObject responseJson = JSON.parseObject(EntityUtils.toString(response.getEntity()));
|
||||
System.out.println(responseJson);
|
||||
} catch (URISyntaxException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkResult(String msg) {
|
||||
if ("0".equals(msg)) {
|
||||
// log.info("发送钉钉通知成功");
|
||||
} else {
|
||||
// log.warn("发送钉钉通知失败:{}", map);
|
||||
// throw new BusinessException("发送钉钉通知失败:" + map.get("errmsg"), code);
|
||||
}
|
||||
}
|
||||
|
||||
private String getToken() {
|
||||
if (System.currentTimeMillis() - refreshTokenTime > tokenTimeOut || accessToken.get() == null) {
|
||||
return requestToken();
|
||||
}
|
||||
return accessToken.get();
|
||||
}
|
||||
|
||||
private String requestToken() {
|
||||
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
|
||||
List<NameValuePair> params = new ArrayList<>();
|
||||
params.add(new BasicNameValuePair("appkey", properties.getAppKey()));
|
||||
params.add(new BasicNameValuePair("appsecret", properties.getAppSecret()));
|
||||
try {
|
||||
HttpGet httpGet = new HttpGet(new URIBuilder(tokenApi).setParameters(params).build());
|
||||
CloseableHttpResponse response = httpClient.execute(httpGet);
|
||||
JSONObject responseJson = JSON.parseObject(EntityUtils.toString(response.getEntity()));
|
||||
if (responseJson.containsKey("access_token")) {
|
||||
String access_token = responseJson.get("access_token").toString();
|
||||
refreshTokenTime = System.currentTimeMillis();
|
||||
accessToken.set(access_token);
|
||||
return access_token;
|
||||
} else {
|
||||
// throw new BusinessException("获取Token失败:" + map.get("errmsg"), String.valueOf(map.get("errcode")));
|
||||
}
|
||||
} catch (URISyntaxException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
accessToken.set(null);
|
||||
refreshTokenTime = 0;
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package com.cicdi.notify.dingtalk;
|
||||
package com.simaek.notify.dingtalk;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.cicdi.notify.template.Template;
|
||||
import com.simaek.notify.template.Template;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
@ -0,0 +1,122 @@
|
||||
package com.simaek.notify.dingtalk;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.simaek.notify.DefaultNotifyType;
|
||||
import com.simaek.notify.Notifier;
|
||||
import com.simaek.notify.NotifyType;
|
||||
import com.simaek.notify.Provider;
|
||||
import okhttp3.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class DingTalkNotifier implements Notifier<DingTalkMessageTemplate> {
|
||||
|
||||
private final AtomicReference<String> accessToken = new AtomicReference<>();
|
||||
|
||||
private long refreshTokenTime;
|
||||
|
||||
private final long tokenTimeOut = Duration.ofSeconds(7000).toMillis();
|
||||
|
||||
private static final String tokenApi = "https://oapi.dingtalk.com/gettoken";
|
||||
|
||||
private static final String notifyApi = "https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2";
|
||||
|
||||
private final DingTalkProperties properties;
|
||||
|
||||
private final String notifierId;
|
||||
|
||||
private final OkHttpClient httpClient;
|
||||
|
||||
@Override
|
||||
public String getNotifierId() {
|
||||
return notifierId;
|
||||
}
|
||||
|
||||
public DingTalkNotifier(String id, DingTalkProperties properties) {
|
||||
this.properties = properties;
|
||||
this.notifierId = id;
|
||||
this.httpClient = new OkHttpClient.Builder().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotifyType getType() {
|
||||
return DefaultNotifyType.dingTalk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Provider getProvider() {
|
||||
return DingTalkProvider.dingTalkMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(DingTalkMessageTemplate template, Map<String, Object> context) {
|
||||
HttpUrl url = Objects.requireNonNull(HttpUrl.parse(notifyApi)).newBuilder()
|
||||
.addQueryParameter("access_token", getToken())
|
||||
.build();
|
||||
String formInserter = template.createFormInserter(context);
|
||||
RequestBody requestBody = RequestBody.create(formInserter, MediaType.get("application/json"));
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.post(requestBody)
|
||||
.build();
|
||||
Call call = httpClient.newCall(request);
|
||||
try {
|
||||
Response response = call.execute();
|
||||
checkResult(Objects.requireNonNull(response.body()).string());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkResult(String msg) {
|
||||
JSONObject jsonObject = JSON.parseObject(msg);
|
||||
int errorCode = jsonObject.getIntValue("errcode");
|
||||
if (errorCode != 0) {
|
||||
throw new RuntimeException("发送钉钉通知失败:" + jsonObject.get("errmsg"));
|
||||
}
|
||||
}
|
||||
|
||||
private String getToken() {
|
||||
if (System.currentTimeMillis() - refreshTokenTime > tokenTimeOut || accessToken.get() == null) {
|
||||
return requestToken();
|
||||
}
|
||||
return accessToken.get();
|
||||
}
|
||||
|
||||
private String requestToken() {
|
||||
HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(tokenApi)).newBuilder();
|
||||
urlBuilder.addQueryParameter("appkey", properties.getAppKey());
|
||||
urlBuilder.addQueryParameter("appsecret", properties.getAppSecret());
|
||||
Request request = new Request.Builder()
|
||||
.url(urlBuilder.build())
|
||||
.get()
|
||||
.build();
|
||||
Call call = httpClient.newCall(request);
|
||||
try {
|
||||
Response response = call.execute();
|
||||
JSONObject responseJson = JSON.parseObject(Objects.requireNonNull(response.body()).string());
|
||||
if (responseJson.containsKey("access_token")) {
|
||||
String access_token = responseJson.get("access_token").toString();
|
||||
refreshTokenTime = System.currentTimeMillis();
|
||||
accessToken.set(access_token);
|
||||
return access_token;
|
||||
} else {
|
||||
throw new RuntimeException("获取Token失败:" + responseJson.get("errmsg"));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
accessToken.set(null);
|
||||
refreshTokenTime = 0;
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
package com.cicdi.notify.dingtalk;
|
||||
package com.simaek.notify.dingtalk;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cicdi.notify.*;
|
||||
import com.cicdi.notify.template.TemplateProperties;
|
||||
import com.cicdi.notify.template.TemplateProvider;
|
||||
import com.simaek.notify.*;
|
||||
import com.simaek.notify.template.TemplateProperties;
|
||||
import com.simaek.notify.template.TemplateProvider;
|
||||
|
||||
import java.util.Objects;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.cicdi.notify.dingtalk;
|
||||
package com.simaek.notify.dingtalk;
|
||||
|
||||
/**
|
||||
* 钉钉通知属性
|
@ -1,6 +1,6 @@
|
||||
package com.cicdi.notify.dingtalk;
|
||||
package com.simaek.notify.dingtalk;
|
||||
|
||||
import com.cicdi.notify.Provider;
|
||||
import com.simaek.notify.Provider;
|
||||
|
||||
/**
|
||||
* 钉钉通知提供商
|
@ -1,11 +1,11 @@
|
||||
package com.cicdi.notify.dingtalk;
|
||||
package com.simaek.notify.dingtalk;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cicdi.notify.*;
|
||||
import com.cicdi.notify.template.AbstractTemplateManager;
|
||||
import com.cicdi.notify.template.Template;
|
||||
import com.cicdi.notify.template.TemplateManager;
|
||||
import com.cicdi.notify.template.TemplateProperties;
|
||||
import com.simaek.notify.*;
|
||||
import com.simaek.notify.template.AbstractTemplateManager;
|
||||
import com.simaek.notify.template.Template;
|
||||
import com.simaek.notify.template.TemplateManager;
|
||||
import com.simaek.notify.template.TemplateProperties;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@ -3,9 +3,9 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>notify</artifactId>
|
||||
<groupId>com.cicdi</groupId>
|
||||
<version>0.1.0</version>
|
||||
<artifactId>notify-parent</artifactId>
|
||||
<groupId>com.simaek</groupId>
|
||||
<version>0.1.1</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@ -19,15 +19,8 @@
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.cicdi</groupId>
|
||||
<groupId>com.simaek</groupId>
|
||||
<artifactId>notify-core</artifactId>
|
||||
<version>0.1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
<version>5.2.15.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@ -38,24 +31,16 @@
|
||||
<dependency>
|
||||
<groupId>com.sun.mail</groupId>
|
||||
<artifactId>jakarta.mail</artifactId>
|
||||
<version>1.6.7</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<version>5.2.10.RELEASE</version>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jsoup</groupId>
|
||||
<artifactId>jsoup</artifactId>
|
||||
<version>1.11.3</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.cicdi.notify.email;
|
||||
package com.simaek.notify.email;
|
||||
|
||||
import com.cicdi.notify.Provider;
|
||||
import com.simaek.notify.Provider;
|
||||
|
||||
/**
|
||||
* 邮件通知提供商
|
@ -1,6 +1,6 @@
|
||||
package com.cicdi.notify.email;
|
||||
package com.simaek.notify.email;
|
||||
|
||||
import com.cicdi.notify.template.Template;
|
||||
import com.simaek.notify.template.Template;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.cicdi.notify.email;
|
||||
package com.simaek.notify.email;
|
||||
|
||||
import java.util.Map;
|
||||
|
@ -1,25 +1,24 @@
|
||||
package com.cicdi.notify.email.embedded;
|
||||
package com.simaek.notify.email.embedded;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.cicdi.notify.*;
|
||||
import com.cicdi.notify.email.EmailProvider;
|
||||
import com.cicdi.notify.email.EmailTemplate;
|
||||
import com.cicdi.notify.email.EmailTemplateParsed;
|
||||
import com.cicdi.notify.util.ExpressionUtils;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import com.simaek.notify.*;
|
||||
import com.simaek.notify.email.EmailProvider;
|
||||
import com.simaek.notify.email.EmailTemplate;
|
||||
import com.simaek.notify.email.EmailTemplateParsed;
|
||||
import com.simaek.notify.email.embedded.mail.javamail.JavaMailSender;
|
||||
import com.simaek.notify.email.embedded.mail.javamail.JavaMailSenderImpl;
|
||||
import com.simaek.notify.email.embedded.mail.javamail.MimeMessageHelper;
|
||||
import com.simaek.notify.util.ExpressionUtils;
|
||||
import com.simaek.notify.util.StringUtils;
|
||||
import okhttp3.Call;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.core.io.InputStreamSource;
|
||||
import org.springframework.mail.javamail.JavaMailSender;
|
||||
import org.springframework.mail.javamail.JavaMailSenderImpl;
|
||||
import org.springframework.mail.javamail.MimeMessageHelper;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
@ -57,6 +56,8 @@ public class DefaultEmailNotifier implements Notifier<EmailTemplate> {
|
||||
|
||||
private final String notifierId;
|
||||
|
||||
private final OkHttpClient httpClient;
|
||||
|
||||
@Override
|
||||
public String getNotifierId() {
|
||||
return notifierId;
|
||||
@ -75,6 +76,7 @@ public class DefaultEmailNotifier implements Notifier<EmailTemplate> {
|
||||
mailSender.setJavaMailProperties(emailProperties.createJavaMailProperties());
|
||||
this.sender = emailProperties.getSender();
|
||||
this.javaMailSender = mailSender;
|
||||
this.httpClient = new OkHttpClient.Builder().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -124,12 +126,15 @@ public class DefaultEmailNotifier implements Notifier<EmailTemplate> {
|
||||
|
||||
protected InputStreamSource convertResource(String resource) {
|
||||
if (resource.startsWith("http://") || resource.startsWith("https://")) {
|
||||
HttpClient httpClient = HttpClientBuilder.create().build();
|
||||
HttpGet httpGet = new HttpGet(resource);
|
||||
httpGet.setHeader(HttpHeaders.ACCEPT, "application/octet-stream");
|
||||
Request request = new Request.Builder()
|
||||
.url(resource)
|
||||
.get()
|
||||
.header("Accept", "application/octet-stream")
|
||||
.build();
|
||||
Call call = httpClient.newCall(request);
|
||||
try {
|
||||
HttpResponse response = httpClient.execute(httpGet);
|
||||
InputStream inputStream = response.getEntity().getContent();
|
||||
Response response = call.execute();
|
||||
InputStream inputStream = Objects.requireNonNull(response.body()).byteStream();
|
||||
new InputStreamResource(inputStream);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
@ -1,11 +1,11 @@
|
||||
package com.cicdi.notify.email.embedded;
|
||||
package com.simaek.notify.email.embedded;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cicdi.notify.*;
|
||||
import com.cicdi.notify.email.EmailProvider;
|
||||
import com.cicdi.notify.email.EmailTemplate;
|
||||
import com.cicdi.notify.template.TemplateProperties;
|
||||
import com.cicdi.notify.template.TemplateProvider;
|
||||
import com.simaek.notify.*;
|
||||
import com.simaek.notify.email.EmailProvider;
|
||||
import com.simaek.notify.email.EmailTemplate;
|
||||
import com.simaek.notify.template.TemplateProperties;
|
||||
import com.simaek.notify.template.TemplateProvider;
|
||||
|
||||
public class DefaultEmailNotifierProvider implements NotifierProvider, TemplateProvider {
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.cicdi.notify.email.embedded;
|
||||
package com.simaek.notify.email.embedded;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
@ -0,0 +1,39 @@
|
||||
package com.simaek.notify.email.embedded.mail;
|
||||
|
||||
/**
|
||||
* Exception thrown on failed authentication.
|
||||
*
|
||||
* @author Dmitriy Kopylenko
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class MailAuthenticationException extends MailException {
|
||||
|
||||
/**
|
||||
* Constructor for MailAuthenticationException.
|
||||
*
|
||||
* @param msg message
|
||||
*/
|
||||
public MailAuthenticationException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for MailAuthenticationException.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param cause the root cause from the mail API in use
|
||||
*/
|
||||
public MailAuthenticationException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for MailAuthenticationException.
|
||||
*
|
||||
* @param cause the root cause from the mail API in use
|
||||
*/
|
||||
public MailAuthenticationException(Throwable cause) {
|
||||
super("Authentication failed", cause);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.simaek.notify.email.embedded.mail;
|
||||
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Base class for all mail exceptions.
|
||||
*
|
||||
* @author Dmitriy Kopylenko
|
||||
*/
|
||||
public abstract class MailException extends NestedRuntimeException {
|
||||
|
||||
/**
|
||||
* Constructor for MailException.
|
||||
*
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public MailException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for MailException.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param cause the root cause from the mail API in use
|
||||
*/
|
||||
public MailException(@Nullable String msg, @Nullable Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package com.simaek.notify.email.embedded.mail;
|
||||
|
||||
import com.simaek.notify.email.embedded.mail.javamail.MimeMessageHelper;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* This is a common interface for mail messages, allowing a user to set key
|
||||
* values required in assembling a mail message, without needing to know if
|
||||
* the underlying message is a simple text message or a more sophisticated
|
||||
* MIME message.
|
||||
*
|
||||
* <p>Implemented by both SimpleMailMessage and MimeMessageHelper,
|
||||
* to let message population code interact with a simple message or a
|
||||
* MIME message through a common interface.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @see SimpleMailMessage
|
||||
* @see MimeMessageHelper
|
||||
* @since 1.1.5
|
||||
*/
|
||||
public interface MailMessage {
|
||||
|
||||
void setFrom(String from) throws MailParseException;
|
||||
|
||||
void setReplyTo(String replyTo) throws MailParseException;
|
||||
|
||||
void setTo(String to) throws MailParseException;
|
||||
|
||||
void setTo(String... to) throws MailParseException;
|
||||
|
||||
void setCc(String cc) throws MailParseException;
|
||||
|
||||
void setCc(String... cc) throws MailParseException;
|
||||
|
||||
void setBcc(String bcc) throws MailParseException;
|
||||
|
||||
void setBcc(String... bcc) throws MailParseException;
|
||||
|
||||
void setSentDate(Date sentDate) throws MailParseException;
|
||||
|
||||
void setSubject(String subject) throws MailParseException;
|
||||
|
||||
void setText(String text) throws MailParseException;
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package com.simaek.notify.email.embedded.mail;
|
||||
|
||||
/**
|
||||
* Exception thrown if illegal message properties are encountered.
|
||||
*
|
||||
* @author Dmitriy Kopylenko
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class MailParseException extends MailException {
|
||||
|
||||
/**
|
||||
* Constructor for MailParseException.
|
||||
*
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public MailParseException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for MailParseException.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param cause the root cause from the mail API in use
|
||||
*/
|
||||
public MailParseException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for MailParseException.
|
||||
*
|
||||
* @param cause the root cause from the mail API in use
|
||||
*/
|
||||
public MailParseException(Throwable cause) {
|
||||
super("Could not parse mail", cause);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.simaek.notify.email.embedded.mail;
|
||||
|
||||
/**
|
||||
* Exception to be thrown by user code if a mail cannot be prepared properly,
|
||||
* for example when a FreeMarker template cannot be rendered for the mail text.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1
|
||||
*/
|
||||
public class MailPreparationException extends MailException {
|
||||
|
||||
/**
|
||||
* Constructor for MailPreparationException.
|
||||
*
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public MailPreparationException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for MailPreparationException.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param cause the root cause from the mail API in use
|
||||
*/
|
||||
public MailPreparationException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
public MailPreparationException(Throwable cause) {
|
||||
super("Could not prepare mail", cause);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,184 @@
|
||||
package com.simaek.notify.email.embedded.mail;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Exception thrown when a mail sending error is encountered.
|
||||
* Can register failed messages with their exceptions.
|
||||
*
|
||||
* @author Dmitriy Kopylenko
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class MailSendException extends MailException {
|
||||
|
||||
private final transient Map<Object, Exception> failedMessages;
|
||||
|
||||
@Nullable
|
||||
private final Exception[] messageExceptions;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for MailSendException.
|
||||
*
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public MailSendException(String msg) {
|
||||
this(msg, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for MailSendException.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param cause the root cause from the mail API in use
|
||||
*/
|
||||
public MailSendException(String msg, @Nullable Throwable cause) {
|
||||
super(msg, cause);
|
||||
this.failedMessages = new LinkedHashMap<>();
|
||||
this.messageExceptions = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for registration of failed messages, with the
|
||||
* messages that failed as keys, and the thrown exceptions as values.
|
||||
* <p>The messages should be the same that were originally passed
|
||||
* to the invoked send method.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param cause the root cause from the mail API in use
|
||||
* @param failedMessages a Map of failed messages as keys and thrown
|
||||
* exceptions as values
|
||||
*/
|
||||
public MailSendException(@Nullable String msg, @Nullable Throwable cause, Map<Object, Exception> failedMessages) {
|
||||
super(msg, cause);
|
||||
this.failedMessages = new LinkedHashMap<>(failedMessages);
|
||||
this.messageExceptions = failedMessages.values().toArray(new Exception[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for registration of failed messages, with the
|
||||
* messages that failed as keys, and the thrown exceptions as values.
|
||||
* <p>The messages should be the same that were originally passed
|
||||
* to the invoked send method.
|
||||
*
|
||||
* @param failedMessages a Map of failed messages as keys and thrown
|
||||
* exceptions as values
|
||||
*/
|
||||
public MailSendException(Map<Object, Exception> failedMessages) {
|
||||
this(null, null, failedMessages);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a Map with the failed messages as keys, and the thrown exceptions
|
||||
* as values.
|
||||
* <p>Note that a general mail server connection failure will not result
|
||||
* in failed messages being returned here: A message will only be
|
||||
* contained here if actually sending it was attempted but failed.
|
||||
* <p>The messages will be the same that were originally passed to the
|
||||
* invoked send method, that is, SimpleMailMessages in case of using
|
||||
* the generic MailSender interface.
|
||||
* <p>In case of sending MimeMessage instances via JavaMailSender,
|
||||
* the messages will be of type MimeMessage.
|
||||
* <p><b>NOTE:</b> This Map will not be available after serialization.
|
||||
* Use {@link #getMessageExceptions()} in such a scenario, which will
|
||||
* be available after serialization as well.
|
||||
*
|
||||
* @return the Map of failed messages as keys and thrown exceptions as values
|
||||
* @see SimpleMailMessage
|
||||
* @see javax.mail.internet.MimeMessage
|
||||
*/
|
||||
public final Map<Object, Exception> getFailedMessages() {
|
||||
return this.failedMessages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array with thrown message exceptions.
|
||||
* <p>Note that a general mail server connection failure will not result
|
||||
* in failed messages being returned here: A message will only be
|
||||
* contained here if actually sending it was attempted but failed.
|
||||
*
|
||||
* @return the array of thrown message exceptions,
|
||||
* or an empty array if no failed messages
|
||||
*/
|
||||
public final Exception[] getMessageExceptions() {
|
||||
return (this.messageExceptions != null ? this.messageExceptions : new Exception[0]);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getMessage() {
|
||||
if (ObjectUtils.isEmpty(this.messageExceptions)) {
|
||||
return super.getMessage();
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String baseMessage = super.getMessage();
|
||||
if (baseMessage != null) {
|
||||
sb.append(baseMessage).append(". ");
|
||||
}
|
||||
sb.append("Failed messages: ");
|
||||
for (int i = 0; i < this.messageExceptions.length; i++) {
|
||||
Exception subEx = this.messageExceptions[i];
|
||||
sb.append(subEx.toString());
|
||||
if (i < this.messageExceptions.length - 1) {
|
||||
sb.append("; ");
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (ObjectUtils.isEmpty(this.messageExceptions)) {
|
||||
return super.toString();
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder(super.toString());
|
||||
sb.append("; message exceptions (").append(this.messageExceptions.length).append(") are:");
|
||||
for (int i = 0; i < this.messageExceptions.length; i++) {
|
||||
Exception subEx = this.messageExceptions[i];
|
||||
sb.append('\n').append("Failed message ").append(i + 1).append(": ");
|
||||
sb.append(subEx);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printStackTrace(PrintStream ps) {
|
||||
if (ObjectUtils.isEmpty(this.messageExceptions)) {
|
||||
super.printStackTrace(ps);
|
||||
} else {
|
||||
ps.println(super.toString() + "; message exception details (" +
|
||||
this.messageExceptions.length + ") are:");
|
||||
for (int i = 0; i < this.messageExceptions.length; i++) {
|
||||
Exception subEx = this.messageExceptions[i];
|
||||
ps.println("Failed message " + (i + 1) + ":");
|
||||
subEx.printStackTrace(ps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printStackTrace(PrintWriter pw) {
|
||||
if (ObjectUtils.isEmpty(this.messageExceptions)) {
|
||||
super.printStackTrace(pw);
|
||||
} else {
|
||||
pw.println(super.toString() + "; message exception details (" +
|
||||
this.messageExceptions.length + ") are:");
|
||||
for (int i = 0; i < this.messageExceptions.length; i++) {
|
||||
Exception subEx = this.messageExceptions[i];
|
||||
pw.println("Failed message " + (i + 1) + ":");
|
||||
subEx.printStackTrace(pw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package com.simaek.notify.email.embedded.mail;
|
||||
|
||||
import com.simaek.notify.email.embedded.mail.javamail.JavaMailSender;
|
||||
|
||||
/**
|
||||
* This interface defines a strategy for sending simple mails. Can be
|
||||
* implemented for a variety of mailing systems due to the simple requirements.
|
||||
* For richer functionality like MIME messages, consider JavaMailSender.
|
||||
*
|
||||
* <p>Allows for easy testing of clients, as it does not depend on JavaMail's
|
||||
* infrastructure classes: no mocking of JavaMail Session or Transport necessary.
|
||||
*
|
||||
* @author Dmitriy Kopylenko
|
||||
* @author Juergen Hoeller
|
||||
* @see JavaMailSender
|
||||
* @since 10.09.2003
|
||||
*/
|
||||
public interface MailSender {
|
||||
|
||||
/**
|
||||
* Send the given simple mail message.
|
||||
*
|
||||
* @param simpleMessage the message to send
|
||||
* @throws MailParseException in case of failure when parsing the message
|
||||
* @throws MailAuthenticationException in case of authentication failure
|
||||
* @throws MailSendException in case of failure when sending the message
|
||||
*/
|
||||
void send(SimpleMailMessage simpleMessage) throws MailException;
|
||||
|
||||
/**
|
||||
* Send the given array of simple mail messages in batch.
|
||||
*
|
||||
* @param simpleMessages the messages to send
|
||||
* @throws MailParseException in case of failure when parsing a message
|
||||
* @throws MailAuthenticationException in case of authentication failure
|
||||
* @throws MailSendException in case of failure when sending a message
|
||||
*/
|
||||
void send(SimpleMailMessage... simpleMessages) throws MailException;
|
||||
|
||||
}
|
@ -0,0 +1,270 @@
|
||||
package com.simaek.notify.email.embedded.mail;
|
||||
|
||||
import com.simaek.notify.email.embedded.mail.javamail.JavaMailSender;
|
||||
import com.simaek.notify.email.embedded.mail.javamail.MimeMailMessage;
|
||||
import com.simaek.notify.email.embedded.mail.javamail.MimeMessageHelper;
|
||||
import com.simaek.notify.email.embedded.mail.javamail.MimeMessagePreparator;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Models a simple mail message, including data such as the from, to, cc, subject,
|
||||
* and text fields.
|
||||
*
|
||||
* <p>Consider {@code JavaMailSender} and JavaMail {@code MimeMessages} for creating
|
||||
* more sophisticated messages, for example messages with attachments, special
|
||||
* character encodings, or personal names that accompany mail addresses.
|
||||
*
|
||||
* @author Dmitriy Kopylenko
|
||||
* @author Juergen Hoeller
|
||||
* @see MailSender
|
||||
* @see JavaMailSender
|
||||
* @see MimeMessagePreparator
|
||||
* @see MimeMessageHelper
|
||||
* @see MimeMailMessage
|
||||
* @since 10.09.2003
|
||||
*/
|
||||
public class SimpleMailMessage implements MailMessage, Serializable {
|
||||
|
||||
@Nullable
|
||||
private String from;
|
||||
|
||||
@Nullable
|
||||
private String replyTo;
|
||||
|
||||
@Nullable
|
||||
private String[] to;
|
||||
|
||||
@Nullable
|
||||
private String[] cc;
|
||||
|
||||
@Nullable
|
||||
private String[] bcc;
|
||||
|
||||
@Nullable
|
||||
private Date sentDate;
|
||||
|
||||
@Nullable
|
||||
private String subject;
|
||||
|
||||
@Nullable
|
||||
private String text;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code SimpleMailMessage}.
|
||||
*/
|
||||
public SimpleMailMessage() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor for creating a new {@code SimpleMailMessage} from the state
|
||||
* of an existing {@code SimpleMailMessage} instance.
|
||||
*/
|
||||
public SimpleMailMessage(SimpleMailMessage original) {
|
||||
Assert.notNull(original, "'original' message argument must not be null");
|
||||
this.from = original.getFrom();
|
||||
this.replyTo = original.getReplyTo();
|
||||
this.to = copyOrNull(original.getTo());
|
||||
this.cc = copyOrNull(original.getCc());
|
||||
this.bcc = copyOrNull(original.getBcc());
|
||||
this.sentDate = original.getSentDate();
|
||||
this.subject = original.getSubject();
|
||||
this.text = original.getText();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setFrom(String from) {
|
||||
this.from = from;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getFrom() {
|
||||
return this.from;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReplyTo(String replyTo) {
|
||||
this.replyTo = replyTo;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getReplyTo() {
|
||||
return this.replyTo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTo(String to) {
|
||||
this.to = new String[]{to};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTo(String... to) {
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String[] getTo() {
|
||||
return this.to;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCc(String cc) {
|
||||
this.cc = new String[]{cc};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCc(String... cc) {
|
||||
this.cc = cc;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String[] getCc() {
|
||||
return this.cc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBcc(String bcc) {
|
||||
this.bcc = new String[]{bcc};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBcc(String... bcc) {
|
||||
this.bcc = bcc;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String[] getBcc() {
|
||||
return this.bcc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSentDate(Date sentDate) {
|
||||
this.sentDate = sentDate;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Date getSentDate() {
|
||||
return this.sentDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSubject(String subject) {
|
||||
this.subject = subject;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getSubject() {
|
||||
return this.subject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getText() {
|
||||
return this.text;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copy the contents of this message to the given target message.
|
||||
*
|
||||
* @param target the {@code MailMessage} to copy to
|
||||
*/
|
||||
public void copyTo(MailMessage target) {
|
||||
Assert.notNull(target, "'target' MailMessage must not be null");
|
||||
if (getFrom() != null) {
|
||||
target.setFrom(getFrom());
|
||||
}
|
||||
if (getReplyTo() != null) {
|
||||
target.setReplyTo(getReplyTo());
|
||||
}
|
||||
if (getTo() != null) {
|
||||
target.setTo(copy(getTo()));
|
||||
}
|
||||
if (getCc() != null) {
|
||||
target.setCc(copy(getCc()));
|
||||
}
|
||||
if (getBcc() != null) {
|
||||
target.setBcc(copy(getBcc()));
|
||||
}
|
||||
if (getSentDate() != null) {
|
||||
target.setSentDate(getSentDate());
|
||||
}
|
||||
if (getSubject() != null) {
|
||||
target.setSubject(getSubject());
|
||||
}
|
||||
if (getText() != null) {
|
||||
target.setText(getText());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof SimpleMailMessage)) {
|
||||
return false;
|
||||
}
|
||||
SimpleMailMessage otherMessage = (SimpleMailMessage) other;
|
||||
return (ObjectUtils.nullSafeEquals(this.from, otherMessage.from) &&
|
||||
ObjectUtils.nullSafeEquals(this.replyTo, otherMessage.replyTo) &&
|
||||
ObjectUtils.nullSafeEquals(this.to, otherMessage.to) &&
|
||||
ObjectUtils.nullSafeEquals(this.cc, otherMessage.cc) &&
|
||||
ObjectUtils.nullSafeEquals(this.bcc, otherMessage.bcc) &&
|
||||
ObjectUtils.nullSafeEquals(this.sentDate, otherMessage.sentDate) &&
|
||||
ObjectUtils.nullSafeEquals(this.subject, otherMessage.subject) &&
|
||||
ObjectUtils.nullSafeEquals(this.text, otherMessage.text));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = ObjectUtils.nullSafeHashCode(this.from);
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.replyTo);
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.to);
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.cc);
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.bcc);
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.sentDate);
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.subject);
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("SimpleMailMessage: ");
|
||||
sb.append("from=").append(this.from).append("; ");
|
||||
sb.append("replyTo=").append(this.replyTo).append("; ");
|
||||
sb.append("to=").append(StringUtils.arrayToCommaDelimitedString(this.to)).append("; ");
|
||||
sb.append("cc=").append(StringUtils.arrayToCommaDelimitedString(this.cc)).append("; ");
|
||||
sb.append("bcc=").append(StringUtils.arrayToCommaDelimitedString(this.bcc)).append("; ");
|
||||
sb.append("sentDate=").append(this.sentDate).append("; ");
|
||||
sb.append("subject=").append(this.subject).append("; ");
|
||||
sb.append("text=").append(this.text);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private static String[] copyOrNull(@Nullable String[] state) {
|
||||
if (state == null) {
|
||||
return null;
|
||||
}
|
||||
return copy(state);
|
||||
}
|
||||
|
||||
private static String[] copy(String[] state) {
|
||||
return state.clone();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,159 @@
|
||||
package com.simaek.notify.email.embedded.mail.javamail;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import javax.activation.FileTypeMap;
|
||||
import javax.activation.MimetypesFileTypeMap;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Spring-configurable {@code FileTypeMap} implementation that will read
|
||||
* MIME type to file extension mappings from a standard JavaMail MIME type
|
||||
* mapping file, using a standard {@code MimetypesFileTypeMap} underneath.
|
||||
*
|
||||
* <p>The mapping file should be in the following format, as specified by the
|
||||
* Java Activation Framework:
|
||||
*
|
||||
* <pre class="code">
|
||||
* # map text/html to .htm and .html files
|
||||
* text/html html htm HTML HTM</pre>
|
||||
* <p>
|
||||
* Lines starting with {@code #} are treated as comments and are ignored. All
|
||||
* other lines are treated as mappings. Each mapping line should contain the MIME
|
||||
* type as the first entry and then each file extension to map to that MIME type
|
||||
* as subsequent entries. Each entry is separated by spaces or tabs.
|
||||
*
|
||||
* <p>By default, the mappings in the {@code mime.types} file located in the
|
||||
* same package as this class are used, which cover many common file extensions
|
||||
* (in contrast to the out-of-the-box mappings in {@code activation.jar}).
|
||||
* This can be overridden using the {@code mappingLocation} property.
|
||||
*
|
||||
* <p>Additional mappings can be added via the {@code mappings} bean property,
|
||||
* as lines that follow the {@code mime.types} file format.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
* @see #setMappingLocation
|
||||
* @see #setMappings
|
||||
* @see MimetypesFileTypeMap
|
||||
* @since 1.2
|
||||
*/
|
||||
public class ConfigurableMimeFileTypeMap extends FileTypeMap {
|
||||
|
||||
/**
|
||||
* The {@code Resource} to load the mapping file from.
|
||||
*/
|
||||
private Resource mappingLocation = new ClassPathResource("mime.types", getClass());
|
||||
|
||||
/**
|
||||
* Used to configure additional mappings.
|
||||
*/
|
||||
@Nullable
|
||||
private String[] mappings;
|
||||
|
||||
/**
|
||||
* The delegate FileTypeMap, compiled from the mappings in the mapping file
|
||||
* and the entries in the {@code mappings} property.
|
||||
*/
|
||||
@Nullable
|
||||
private FileTypeMap fileTypeMap;
|
||||
|
||||
|
||||
/**
|
||||
* Specify the {@code Resource} from which mappings are loaded.
|
||||
* <p>Needs to follow the {@code mime.types} file format, as specified
|
||||
* by the Java Activation Framework, containing lines such as:<br>
|
||||
* {@code text/html html htm HTML HTM}
|
||||
*/
|
||||
public void setMappingLocation(Resource mappingLocation) {
|
||||
this.mappingLocation = mappingLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify additional MIME type mappings as lines that follow the
|
||||
* {@code mime.types} file format, as specified by the
|
||||
* Java Activation Framework. For example:<br>
|
||||
* {@code text/html html htm HTML HTM}
|
||||
*/
|
||||
public void setMappings(String... mappings) {
|
||||
this.mappings = mappings;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the delegate FileTypeMap, compiled from the mappings in the mapping file
|
||||
* and the entries in the {@code mappings} property.
|
||||
*
|
||||
* @see #setMappingLocation
|
||||
* @see #setMappings
|
||||
* @see #createFileTypeMap
|
||||
*/
|
||||
protected final FileTypeMap getFileTypeMap() {
|
||||
if (this.fileTypeMap == null) {
|
||||
try {
|
||||
this.fileTypeMap = createFileTypeMap(this.mappingLocation, this.mappings);
|
||||
} catch (IOException ex) {
|
||||
throw new IllegalStateException(
|
||||
"Could not load specified MIME type mapping file: " + this.mappingLocation, ex);
|
||||
}
|
||||
}
|
||||
return this.fileTypeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile a {@link FileTypeMap} from the mappings in the given mapping file
|
||||
* and the given mapping entries.
|
||||
* <p>The default implementation creates an Activation Framework {@link MimetypesFileTypeMap},
|
||||
* passing in an InputStream from the mapping resource (if any) and registering
|
||||
* the mapping lines programmatically.
|
||||
*
|
||||
* @param mappingLocation a {@code mime.types} mapping resource (can be {@code null})
|
||||
* @param mappings an array of MIME type mapping lines (can be {@code null})
|
||||
* @return the compiled FileTypeMap
|
||||
* @throws IOException if resource access failed
|
||||
* @see MimetypesFileTypeMap#MimetypesFileTypeMap(InputStream)
|
||||
* @see MimetypesFileTypeMap#addMimeTypes(String)
|
||||
*/
|
||||
protected FileTypeMap createFileTypeMap(@Nullable Resource mappingLocation, @Nullable String[] mappings) throws IOException {
|
||||
MimetypesFileTypeMap fileTypeMap = null;
|
||||
if (mappingLocation != null) {
|
||||
try (InputStream is = mappingLocation.getInputStream()) {
|
||||
fileTypeMap = new MimetypesFileTypeMap(is);
|
||||
}
|
||||
} else {
|
||||
fileTypeMap = new MimetypesFileTypeMap();
|
||||
}
|
||||
if (mappings != null) {
|
||||
for (String mapping : mappings) {
|
||||
fileTypeMap.addMimeTypes(mapping);
|
||||
}
|
||||
}
|
||||
return fileTypeMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delegates to the underlying FileTypeMap.
|
||||
*
|
||||
* @see #getFileTypeMap()
|
||||
*/
|
||||
@Override
|
||||
public String getContentType(File file) {
|
||||
return getFileTypeMap().getContentType(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to the underlying FileTypeMap.
|
||||
*
|
||||
* @see #getFileTypeMap()
|
||||
*/
|
||||
@Override
|
||||
public String getContentType(String fileName) {
|
||||
return getFileTypeMap().getContentType(fileName);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.simaek.notify.email.embedded.mail.javamail;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.mail.internet.AddressException;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import java.beans.PropertyEditorSupport;
|
||||
|
||||
/**
|
||||
* Editor for {@code java.mail.internet.InternetAddress},
|
||||
* to directly populate an InternetAddress property.
|
||||
*
|
||||
* <p>Expects the same syntax as InternetAddress's constructor with
|
||||
* a String argument. Converts empty Strings into null values.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2.3
|
||||
* @see InternetAddress
|
||||
*/
|
||||
public class InternetAddressEditor extends PropertyEditorSupport {
|
||||
|
||||
@Override
|
||||
public void setAsText(String text) throws IllegalArgumentException {
|
||||
if (StringUtils.hasText(text)) {
|
||||
try {
|
||||
setValue(new InternetAddress(text));
|
||||
}
|
||||
catch (AddressException ex) {
|
||||
throw new IllegalArgumentException("Could not parse mail address: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
else {
|
||||
setValue(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAsText() {
|
||||
InternetAddress value = (InternetAddress) getValue();
|
||||
return (value != null ? value.toUnicodeString() : "");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
package com.simaek.notify.email.embedded.mail.javamail;
|
||||
|
||||
import com.simaek.notify.email.embedded.mail.*;
|
||||
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Extended {@link MailSender} interface for JavaMail,
|
||||
* supporting MIME messages both as direct arguments and through preparation
|
||||
* callbacks. Typically used in conjunction with the {@link MimeMessageHelper}
|
||||
* class for convenient creation of JavaMail {@link MimeMessage MimeMessages},
|
||||
* including attachments etc.
|
||||
*
|
||||
* <p>Clients should talk to the mail sender through this interface if they need
|
||||
* mail functionality beyond {@link SimpleMailMessage}.
|
||||
* The production implementation is {@link JavaMailSenderImpl}; for testing,
|
||||
* mocks can be created based on this interface. Clients will typically receive
|
||||
* the JavaMailSender reference through dependency injection.
|
||||
*
|
||||
* <p>The recommended way of using this interface is the {@link MimeMessagePreparator}
|
||||
* mechanism, possibly using a {@link MimeMessageHelper} for populating the message.
|
||||
* See {@link MimeMessageHelper MimeMessageHelper's javadoc} for an example.
|
||||
*
|
||||
* <p>The entire JavaMail {@link javax.mail.Session} management is abstracted
|
||||
* by the JavaMailSender. Client code should not deal with a Session in any way,
|
||||
* rather leave the entire JavaMail configuration and resource handling to the
|
||||
* JavaMailSender implementation. This also increases testability.
|
||||
*
|
||||
* <p>A JavaMailSender client is not as easy to test as a plain
|
||||
* {@link MailSender} client, but still straightforward
|
||||
* compared to traditional JavaMail code: Just let {@link #createMimeMessage()}
|
||||
* return a plain {@link MimeMessage} created with a
|
||||
* {@code Session.getInstance(new Properties())} call, and check the passed-in
|
||||
* messages in your mock implementations of the various {@code send} methods.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @see MimeMessage
|
||||
* @see javax.mail.Session
|
||||
* @see JavaMailSenderImpl
|
||||
* @see MimeMessagePreparator
|
||||
* @see MimeMessageHelper
|
||||
* @since 07.10.2003
|
||||
*/
|
||||
public interface JavaMailSender extends MailSender {
|
||||
|
||||
/**
|
||||
* Create a new JavaMail MimeMessage for the underlying JavaMail Session
|
||||
* of this sender. Needs to be called to create MimeMessage instances
|
||||
* that can be prepared by the client and passed to send(MimeMessage).
|
||||
*
|
||||
* @return the new MimeMessage instance
|
||||
* @see #send(MimeMessage)
|
||||
* @see #send(MimeMessage[])
|
||||
*/
|
||||
MimeMessage createMimeMessage();
|
||||
|
||||
/**
|
||||
* Create a new JavaMail MimeMessage for the underlying JavaMail Session
|
||||
* of this sender, using the given input stream as the message source.
|
||||
*
|
||||
* @param contentStream the raw MIME input stream for the message
|
||||
* @return the new MimeMessage instance
|
||||
* @throws MailParseException in case of message creation failure
|
||||
*/
|
||||
MimeMessage createMimeMessage(InputStream contentStream) throws MailException;
|
||||
|
||||
/**
|
||||
* Send the given JavaMail MIME message.
|
||||
* The message needs to have been created with {@link #createMimeMessage()}.
|
||||
*
|
||||
* @param mimeMessage message to send
|
||||
* @throws MailAuthenticationException in case of authentication failure
|
||||
* @throws MailSendException in case of failure when sending the message
|
||||
* @see #createMimeMessage
|
||||
*/
|
||||
void send(MimeMessage mimeMessage) throws MailException;
|
||||
|
||||
/**
|
||||
* Send the given array of JavaMail MIME messages in batch.
|
||||
* The messages need to have been created with {@link #createMimeMessage()}.
|
||||
*
|
||||
* @param mimeMessages messages to send
|
||||
* @throws MailAuthenticationException in case of authentication failure
|
||||
* @throws MailSendException in case of failure when sending a message
|
||||
* @see #createMimeMessage
|
||||
*/
|
||||
void send(MimeMessage... mimeMessages) throws MailException;
|
||||
|
||||
/**
|
||||
* Send the JavaMail MIME message prepared by the given MimeMessagePreparator.
|
||||
* <p>Alternative way to prepare MimeMessage instances, instead of
|
||||
* {@link #createMimeMessage()} and {@link #send(MimeMessage)} calls.
|
||||
* Takes care of proper exception conversion.
|
||||
*
|
||||
* @param mimeMessagePreparator the preparator to use
|
||||
* @throws MailPreparationException in case of failure when preparing the message
|
||||
* @throws MailParseException in case of failure when parsing the message
|
||||
* @throws MailAuthenticationException in case of authentication failure
|
||||
* @throws MailSendException in case of failure when sending the message
|
||||
*/
|
||||
void send(MimeMessagePreparator mimeMessagePreparator) throws MailException;
|
||||
|
||||
/**
|
||||
* Send the JavaMail MIME messages prepared by the given MimeMessagePreparators.
|
||||
* <p>Alternative way to prepare MimeMessage instances, instead of
|
||||
* {@link #createMimeMessage()} and {@link #send(MimeMessage[])} calls.
|
||||
* Takes care of proper exception conversion.
|
||||
*
|
||||
* @param mimeMessagePreparators the preparator to use
|
||||
* @throws MailPreparationException in case of failure when preparing a message
|
||||
* @throws MailParseException in case of failure when parsing a message
|
||||
* @throws MailAuthenticationException in case of authentication failure
|
||||
* @throws MailSendException in case of failure when sending a message
|
||||
*/
|
||||
void send(MimeMessagePreparator... mimeMessagePreparators) throws MailException;
|
||||
|
||||
}
|
@ -0,0 +1,507 @@
|
||||
package com.simaek.notify.email.embedded.mail.javamail;
|
||||
|
||||
import com.simaek.notify.email.embedded.mail.*;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.activation.FileTypeMap;
|
||||
import javax.mail.*;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Production implementation of the {@link JavaMailSender} interface,
|
||||
* supporting both JavaMail {@link MimeMessage MimeMessages} and Spring
|
||||
* {@link SimpleMailMessage SimpleMailMessages}. Can also be used as a
|
||||
* plain {@link MailSender} implementation.
|
||||
*
|
||||
* <p>Allows for defining all settings locally as bean properties.
|
||||
* Alternatively, a pre-configured JavaMail {@link Session} can be
|
||||
* specified, possibly pulled from an application server's JNDI environment.
|
||||
*
|
||||
* <p>Non-default properties in this object will always override the settings
|
||||
* in the JavaMail {@code Session}. Note that if overriding all values locally,
|
||||
* there is no added value in setting a pre-configured {@code Session}.
|
||||
*
|
||||
* @author Dmitriy Kopylenko
|
||||
* @author Juergen Hoeller
|
||||
* @see MimeMessage
|
||||
* @see Session
|
||||
* @see #setSession
|
||||
* @see #setJavaMailProperties
|
||||
* @see #setHost
|
||||
* @see #setPort
|
||||
* @see #setUsername
|
||||
* @see #setPassword
|
||||
* @since 10.09.2003
|
||||
*/
|
||||
public class JavaMailSenderImpl implements JavaMailSender {
|
||||
|
||||
/**
|
||||
* The default protocol: 'smtp'.
|
||||
*/
|
||||
public static final String DEFAULT_PROTOCOL = "smtp";
|
||||
|
||||
/**
|
||||
* The default port: -1.
|
||||
*/
|
||||
public static final int DEFAULT_PORT = -1;
|
||||
|
||||
private static final String HEADER_MESSAGE_ID = "Message-ID";
|
||||
|
||||
|
||||
private Properties javaMailProperties = new Properties();
|
||||
|
||||
@Nullable
|
||||
private Session session;
|
||||
|
||||
@Nullable
|
||||
private String protocol;
|
||||
|
||||
@Nullable
|
||||
private String host;
|
||||
|
||||
private int port = DEFAULT_PORT;
|
||||
|
||||
@Nullable
|
||||
private String username;
|
||||
|
||||
@Nullable
|
||||
private String password;
|
||||
|
||||
@Nullable
|
||||
private String defaultEncoding;
|
||||
|
||||
@Nullable
|
||||
private FileTypeMap defaultFileTypeMap;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@code JavaMailSenderImpl} class.
|
||||
* <p>Initializes the {@link #setDefaultFileTypeMap "defaultFileTypeMap"}
|
||||
* property with a default {@link ConfigurableMimeFileTypeMap}.
|
||||
*/
|
||||
public JavaMailSenderImpl() {
|
||||
ConfigurableMimeFileTypeMap fileTypeMap = new ConfigurableMimeFileTypeMap();
|
||||
// fileTypeMap.afterPropertiesSet();
|
||||
this.defaultFileTypeMap = fileTypeMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set JavaMail properties for the {@code Session}.
|
||||
* <p>A new {@code Session} will be created with those properties.
|
||||
* Use either this method or {@link #setSession}, but not both.
|
||||
* <p>Non-default properties in this instance will override given
|
||||
* JavaMail properties.
|
||||
*/
|
||||
public void setJavaMailProperties(Properties javaMailProperties) {
|
||||
this.javaMailProperties = javaMailProperties;
|
||||
synchronized (this) {
|
||||
this.session = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow {code Map} access to the JavaMail properties of this sender,
|
||||
* with the option to add or override specific entries.
|
||||
* <p>Useful for specifying entries directly, for example via
|
||||
* {code javaMailProperties[mail.smtp.auth]}.
|
||||
*/
|
||||
public Properties getJavaMailProperties() {
|
||||
return this.javaMailProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JavaMail {@code Session}, possibly pulled from JNDI.
|
||||
* <p>Default is a new {@code Session} without defaults, that is
|
||||
* completely configured via this instance's properties.
|
||||
* <p>If using a pre-configured {@code Session}, non-default properties
|
||||
* in this instance will override the settings in the {@code Session}.
|
||||
*
|
||||
* @see #setJavaMailProperties
|
||||
*/
|
||||
public synchronized void setSession(Session session) {
|
||||
Assert.notNull(session, "Session must not be null");
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JavaMail {@code Session},
|
||||
* lazily initializing it if it hasn't been specified explicitly.
|
||||
*/
|
||||
public synchronized Session getSession() {
|
||||
if (this.session == null) {
|
||||
this.session = Session.getInstance(this.javaMailProperties);
|
||||
}
|
||||
return this.session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mail protocol. Default is "smtp".
|
||||
*/
|
||||
public void setProtocol(@Nullable String protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mail protocol.
|
||||
*/
|
||||
@Nullable
|
||||
public String getProtocol() {
|
||||
return this.protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mail server host, typically an SMTP host.
|
||||
* <p>Default is the default host of the underlying JavaMail Session.
|
||||
*/
|
||||
public void setHost(@Nullable String host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mail server host.
|
||||
*/
|
||||
@Nullable
|
||||
public String getHost() {
|
||||
return this.host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mail server port.
|
||||
* <p>Default is {@link #DEFAULT_PORT}, letting JavaMail use the default
|
||||
* SMTP port (25).
|
||||
*/
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mail server port.
|
||||
*/
|
||||
public int getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the username for the account at the mail host, if any.
|
||||
* <p>Note that the underlying JavaMail {@code Session} has to be
|
||||
* configured with the property {@code "mail.smtp.auth"} set to
|
||||
* {@code true}, else the specified username will not be sent to the
|
||||
* mail server by the JavaMail runtime. If you are not explicitly passing
|
||||
* in a {@code Session} to use, simply specify this setting via
|
||||
* {@link #setJavaMailProperties}.
|
||||
*
|
||||
* @see #setSession
|
||||
* @see #setPassword
|
||||
*/
|
||||
public void setUsername(@Nullable String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the username for the account at the mail host.
|
||||
*/
|
||||
@Nullable
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the password for the account at the mail host, if any.
|
||||
* <p>Note that the underlying JavaMail {@code Session} has to be
|
||||
* configured with the property {@code "mail.smtp.auth"} set to
|
||||
* {@code true}, else the specified password will not be sent to the
|
||||
* mail server by the JavaMail runtime. If you are not explicitly passing
|
||||
* in a {@code Session} to use, simply specify this setting via
|
||||
* {@link #setJavaMailProperties}.
|
||||
*
|
||||
* @see #setSession
|
||||
* @see #setUsername
|
||||
*/
|
||||
public void setPassword(@Nullable String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the password for the account at the mail host.
|
||||
*/
|
||||
@Nullable
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default encoding to use for {@link MimeMessage MimeMessages}
|
||||
* created by this instance.
|
||||
* <p>Such an encoding will be auto-detected by {@link MimeMessageHelper}.
|
||||
*/
|
||||
public void setDefaultEncoding(@Nullable String defaultEncoding) {
|
||||
this.defaultEncoding = defaultEncoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default encoding for {@link MimeMessage MimeMessages},
|
||||
* or {@code null} if none.
|
||||
*/
|
||||
@Nullable
|
||||
public String getDefaultEncoding() {
|
||||
return this.defaultEncoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default Java Activation {@link FileTypeMap} to use for
|
||||
* {@link MimeMessage MimeMessages} created by this instance.
|
||||
* <p>A {@code FileTypeMap} specified here will be autodetected by
|
||||
* {@link MimeMessageHelper}, avoiding the need to specify the
|
||||
* {@code FileTypeMap} for each {@code MimeMessageHelper} instance.
|
||||
* <p>For example, you can specify a custom instance of Spring's
|
||||
* {@link ConfigurableMimeFileTypeMap} here. If not explicitly specified,
|
||||
* a default {@code ConfigurableMimeFileTypeMap} will be used, containing
|
||||
* an extended set of MIME type mappings (as defined by the
|
||||
* {@code mime.types} file contained in the Spring jar).
|
||||
*
|
||||
* @see MimeMessageHelper#setFileTypeMap
|
||||
*/
|
||||
public void setDefaultFileTypeMap(@Nullable FileTypeMap defaultFileTypeMap) {
|
||||
this.defaultFileTypeMap = defaultFileTypeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default Java Activation {@link FileTypeMap} for
|
||||
* {@link MimeMessage MimeMessages}, or {@code null} if none.
|
||||
*/
|
||||
@Nullable
|
||||
public FileTypeMap getDefaultFileTypeMap() {
|
||||
return this.defaultFileTypeMap;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Implementation of MailSender
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void send(SimpleMailMessage simpleMessage) throws MailException {
|
||||
send(new SimpleMailMessage[]{simpleMessage});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(SimpleMailMessage... simpleMessages) throws MailException {
|
||||
List<MimeMessage> mimeMessages = new ArrayList<>(simpleMessages.length);
|
||||
for (SimpleMailMessage simpleMessage : simpleMessages) {
|
||||
MimeMailMessage message = new MimeMailMessage(createMimeMessage());
|
||||
simpleMessage.copyTo(message);
|
||||
mimeMessages.add(message.getMimeMessage());
|
||||
}
|
||||
doSend(mimeMessages.toArray(new MimeMessage[0]), simpleMessages);
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Implementation of JavaMailSender
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This implementation creates a SmartMimeMessage, holding the specified
|
||||
* default encoding and default FileTypeMap. This special defaults-carrying
|
||||
* message will be autodetected by {@link MimeMessageHelper}, which will use
|
||||
* the carried encoding and FileTypeMap unless explicitly overridden.
|
||||
*
|
||||
* @see #setDefaultEncoding
|
||||
* @see #setDefaultFileTypeMap
|
||||
*/
|
||||
@Override
|
||||
public MimeMessage createMimeMessage() {
|
||||
return new SmartMimeMessage(getSession(), getDefaultEncoding(), getDefaultFileTypeMap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public MimeMessage createMimeMessage(InputStream contentStream) throws MailException {
|
||||
try {
|
||||
return new MimeMessage(getSession(), contentStream);
|
||||
} catch (Exception ex) {
|
||||
throw new MailParseException("Could not parse raw MIME content", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(MimeMessage mimeMessage) throws MailException {
|
||||
send(new MimeMessage[]{mimeMessage});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(MimeMessage... mimeMessages) throws MailException {
|
||||
doSend(mimeMessages, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(MimeMessagePreparator mimeMessagePreparator) throws MailException {
|
||||
send(new MimeMessagePreparator[]{mimeMessagePreparator});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(MimeMessagePreparator... mimeMessagePreparators) throws MailException {
|
||||
try {
|
||||
List<MimeMessage> mimeMessages = new ArrayList<>(mimeMessagePreparators.length);
|
||||
for (MimeMessagePreparator preparator : mimeMessagePreparators) {
|
||||
MimeMessage mimeMessage = createMimeMessage();
|
||||
preparator.prepare(mimeMessage);
|
||||
mimeMessages.add(mimeMessage);
|
||||
}
|
||||
send(mimeMessages.toArray(new MimeMessage[0]));
|
||||
} catch (MailException ex) {
|
||||
throw ex;
|
||||
} catch (MessagingException ex) {
|
||||
throw new MailParseException(ex);
|
||||
} catch (Exception ex) {
|
||||
throw new MailPreparationException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that this instance can connect to the server that it is configured
|
||||
* for. Throws a {@link MessagingException} if the connection attempt failed.
|
||||
*/
|
||||
public void testConnection() throws MessagingException {
|
||||
Transport transport = null;
|
||||
try {
|
||||
transport = connectTransport();
|
||||
} finally {
|
||||
if (transport != null) {
|
||||
transport.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually send the given array of MimeMessages via JavaMail.
|
||||
*
|
||||
* @param mimeMessages the MimeMessage objects to send
|
||||
* @param originalMessages corresponding original message objects
|
||||
* that the MimeMessages have been created from (with same array
|
||||
* length and indices as the "mimeMessages" array), if any
|
||||
* @throws MailAuthenticationException in case of authentication failure
|
||||
* @throws MailSendException in case of failure when sending a message
|
||||
*/
|
||||
protected void doSend(MimeMessage[] mimeMessages, @Nullable Object[] originalMessages) throws MailException {
|
||||
Map<Object, Exception> failedMessages = new LinkedHashMap<>();
|
||||
Transport transport = null;
|
||||
|
||||
try {
|
||||
for (int i = 0; i < mimeMessages.length; i++) {
|
||||
|
||||
// Check transport connection first...
|
||||
if (transport == null || !transport.isConnected()) {
|
||||
if (transport != null) {
|
||||
try {
|
||||
transport.close();
|
||||
} catch (Exception ex) {
|
||||
// Ignore - we're reconnecting anyway
|
||||
}
|
||||
transport = null;
|
||||
}
|
||||
try {
|
||||
transport = connectTransport();
|
||||
} catch (AuthenticationFailedException ex) {
|
||||
throw new MailAuthenticationException(ex);
|
||||
} catch (Exception ex) {
|
||||
// Effectively, all remaining messages failed...
|
||||
for (int j = i; j < mimeMessages.length; j++) {
|
||||
Object original = (originalMessages != null ? originalMessages[j] : mimeMessages[j]);
|
||||
failedMessages.put(original, ex);
|
||||
}
|
||||
throw new MailSendException("Mail server connection failed", ex, failedMessages);
|
||||
}
|
||||
}
|
||||
|
||||
// Send message via current transport...
|
||||
MimeMessage mimeMessage = mimeMessages[i];
|
||||
try {
|
||||
if (mimeMessage.getSentDate() == null) {
|
||||
mimeMessage.setSentDate(new Date());
|
||||
}
|
||||
String messageId = mimeMessage.getMessageID();
|
||||
mimeMessage.saveChanges();
|
||||
if (messageId != null) {
|
||||
// Preserve explicitly specified message id...
|
||||
mimeMessage.setHeader(HEADER_MESSAGE_ID, messageId);
|
||||
}
|
||||
Address[] addresses = mimeMessage.getAllRecipients();
|
||||
transport.sendMessage(mimeMessage, (addresses != null ? addresses : new Address[0]));
|
||||
} catch (Exception ex) {
|
||||
Object original = (originalMessages != null ? originalMessages[i] : mimeMessage);
|
||||
failedMessages.put(original, ex);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
if (transport != null) {
|
||||
transport.close();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
if (!failedMessages.isEmpty()) {
|
||||
throw new MailSendException("Failed to close server connection after message failures", ex,
|
||||
failedMessages);
|
||||
} else {
|
||||
throw new MailSendException("Failed to close server connection after message sending", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!failedMessages.isEmpty()) {
|
||||
throw new MailSendException(failedMessages);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain and connect a Transport from the underlying JavaMail Session,
|
||||
* passing in the specified host, port, username, and password.
|
||||
*
|
||||
* @return the connected Transport object
|
||||
* @throws MessagingException if the connect attempt failed
|
||||
* @see #getTransport
|
||||
* @see #getHost()
|
||||
* @see #getPort()
|
||||
* @see #getUsername()
|
||||
* @see #getPassword()
|
||||
* @since 4.1.2
|
||||
*/
|
||||
protected Transport connectTransport() throws MessagingException {
|
||||
String username = getUsername();
|
||||
String password = getPassword();
|
||||
if ("".equals(username)) { // probably from a placeholder
|
||||
username = null;
|
||||
if ("".equals(password)) { // in conjunction with "" username, this means no password to use
|
||||
password = null;
|
||||
}
|
||||
}
|
||||
|
||||
Transport transport = getTransport(getSession());
|
||||
transport.connect(getHost(), getPort(), username, password);
|
||||
return transport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a Transport object from the given JavaMail Session,
|
||||
* using the configured protocol.
|
||||
* <p>Can be overridden in subclasses, e.g. to return a mock Transport object.
|
||||
*
|
||||
* @see Session#getTransport(String)
|
||||
* @see #getSession()
|
||||
* @see #getProtocol()
|
||||
*/
|
||||
protected Transport getTransport(Session session) throws NoSuchProviderException {
|
||||
String protocol = getProtocol();
|
||||
if (protocol == null) {
|
||||
protocol = session.getProperty("mail.transport.protocol");
|
||||
if (protocol == null) {
|
||||
protocol = DEFAULT_PROTOCOL;
|
||||
}
|
||||
}
|
||||
return session.getTransport(protocol);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,160 @@
|
||||
package com.simaek.notify.email.embedded.mail.javamail;
|
||||
|
||||
import com.simaek.notify.email.embedded.mail.MailMessage;
|
||||
import com.simaek.notify.email.embedded.mail.MailParseException;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Implementation of the MailMessage interface for a JavaMail MIME message,
|
||||
* to let message population code interact with a simple message or a MIME
|
||||
* message through a common interface.
|
||||
*
|
||||
* <p>Uses a MimeMessageHelper underneath. Can either be created with a
|
||||
* MimeMessageHelper instance or with a JavaMail MimeMessage instance.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @see MimeMessageHelper
|
||||
* @see MimeMessage
|
||||
* @since 1.1.5
|
||||
*/
|
||||
public class MimeMailMessage implements MailMessage {
|
||||
|
||||
private final MimeMessageHelper helper;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new MimeMailMessage based on the given MimeMessageHelper.
|
||||
*
|
||||
* @param mimeMessageHelper the MimeMessageHelper
|
||||
*/
|
||||
public MimeMailMessage(MimeMessageHelper mimeMessageHelper) {
|
||||
this.helper = mimeMessageHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new MimeMailMessage based on the given JavaMail MimeMessage.
|
||||
*
|
||||
* @param mimeMessage the JavaMail MimeMessage
|
||||
*/
|
||||
public MimeMailMessage(MimeMessage mimeMessage) {
|
||||
this.helper = new MimeMessageHelper(mimeMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the MimeMessageHelper that this MimeMailMessage is based on.
|
||||
*/
|
||||
public final MimeMessageHelper getMimeMessageHelper() {
|
||||
return this.helper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JavaMail MimeMessage that this MimeMailMessage is based on.
|
||||
*/
|
||||
public final MimeMessage getMimeMessage() {
|
||||
return this.helper.getMimeMessage();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setFrom(String from) throws MailParseException {
|
||||
try {
|
||||
this.helper.setFrom(from);
|
||||
} catch (MessagingException ex) {
|
||||
throw new MailParseException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReplyTo(String replyTo) throws MailParseException {
|
||||
try {
|
||||
this.helper.setReplyTo(replyTo);
|
||||
} catch (MessagingException ex) {
|
||||
throw new MailParseException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTo(String to) throws MailParseException {
|
||||
try {
|
||||
this.helper.setTo(to);
|
||||
} catch (MessagingException ex) {
|
||||
throw new MailParseException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTo(String... to) throws MailParseException {
|
||||
try {
|
||||
this.helper.setTo(to);
|
||||
} catch (MessagingException ex) {
|
||||
throw new MailParseException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCc(String cc) throws MailParseException {
|
||||
try {
|
||||
this.helper.setCc(cc);
|
||||
} catch (MessagingException ex) {
|
||||
throw new MailParseException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCc(String... cc) throws MailParseException {
|
||||
try {
|
||||
this.helper.setCc(cc);
|
||||
} catch (MessagingException ex) {
|
||||
throw new MailParseException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBcc(String bcc) throws MailParseException {
|
||||
try {
|
||||
this.helper.setBcc(bcc);
|
||||
} catch (MessagingException ex) {
|
||||
throw new MailParseException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBcc(String... bcc) throws MailParseException {
|
||||
try {
|
||||
this.helper.setBcc(bcc);
|
||||
} catch (MessagingException ex) {
|
||||
throw new MailParseException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSentDate(Date sentDate) throws MailParseException {
|
||||
try {
|
||||
this.helper.setSentDate(sentDate);
|
||||
} catch (MessagingException ex) {
|
||||
throw new MailParseException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSubject(String subject) throws MailParseException {
|
||||
try {
|
||||
this.helper.setSubject(subject);
|
||||
} catch (MessagingException ex) {
|
||||
throw new MailParseException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setText(String text) throws MailParseException {
|
||||
try {
|
||||
this.helper.setText(text);
|
||||
} catch (MessagingException ex) {
|
||||
throw new MailParseException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,39 @@
|
||||
package com.simaek.notify.email.embedded.mail.javamail;
|
||||
|
||||
import javax.mail.internet.MimeMessage;
|
||||
|
||||
/**
|
||||
* Callback interface for the preparation of JavaMail MIME messages.
|
||||
*
|
||||
* <p>The corresponding {@code send} methods of {@link JavaMailSender}
|
||||
* will take care of the actual creation of a {@link MimeMessage} instance,
|
||||
* and of proper exception conversion.
|
||||
*
|
||||
* <p>It is often convenient to use a {@link MimeMessageHelper} for populating
|
||||
* the passed-in MimeMessage, in particular when working with attachments or
|
||||
* special character encodings.
|
||||
* See {@link MimeMessageHelper MimeMessageHelper's javadoc} for an example.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @see JavaMailSender#send(MimeMessagePreparator)
|
||||
* @see JavaMailSender#send(MimeMessagePreparator[])
|
||||
* @see MimeMessageHelper
|
||||
* @since 07.10.2003
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface MimeMessagePreparator {
|
||||
|
||||
/**
|
||||
* Prepare the given new MimeMessage instance.
|
||||
*
|
||||
* @param mimeMessage the message to prepare
|
||||
* @throws javax.mail.MessagingException passing any exceptions thrown by MimeMessage
|
||||
* methods through for automatic conversion to the MailException hierarchy
|
||||
* @throws java.io.IOException passing any exceptions thrown by MimeMessage methods
|
||||
* through for automatic conversion to the MailException hierarchy
|
||||
* @throws Exception if mail preparation failed, for example when a
|
||||
* FreeMarker template cannot be rendered for the mail text
|
||||
*/
|
||||
void prepare(MimeMessage mimeMessage) throws Exception;
|
||||
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package com.simaek.notify.email.embedded.mail.javamail;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import javax.activation.FileTypeMap;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
|
||||
/**
|
||||
* Special subclass of the standard JavaMail {@link MimeMessage}, carrying a
|
||||
* default encoding to be used when populating the message and a default Java
|
||||
* Activation {@link FileTypeMap} to be used for resolving attachment types.
|
||||
*
|
||||
* <p>Created by {@link JavaMailSenderImpl} in case of a specified default encoding
|
||||
* and/or default FileTypeMap. Autodetected by {@link MimeMessageHelper}, which
|
||||
* will use the carried encoding and FileTypeMap unless explicitly overridden.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @see JavaMailSenderImpl#createMimeMessage()
|
||||
* @see MimeMessageHelper#getDefaultEncoding(MimeMessage)
|
||||
* @see MimeMessageHelper#getDefaultFileTypeMap(MimeMessage)
|
||||
* @since 1.2
|
||||
*/
|
||||
class SmartMimeMessage extends MimeMessage {
|
||||
|
||||
@Nullable
|
||||
private final String defaultEncoding;
|
||||
|
||||
@Nullable
|
||||
private final FileTypeMap defaultFileTypeMap;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new SmartMimeMessage.
|
||||
*
|
||||
* @param session the JavaMail Session to create the message for
|
||||
* @param defaultEncoding the default encoding, or {@code null} if none
|
||||
* @param defaultFileTypeMap the default FileTypeMap, or {@code null} if none
|
||||
*/
|
||||
public SmartMimeMessage(
|
||||
Session session, @Nullable String defaultEncoding, @Nullable FileTypeMap defaultFileTypeMap) {
|
||||
|
||||
super(session);
|
||||
this.defaultEncoding = defaultEncoding;
|
||||
this.defaultFileTypeMap = defaultFileTypeMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the default encoding of this message, or {@code null} if none.
|
||||
*/
|
||||
@Nullable
|
||||
public final String getDefaultEncoding() {
|
||||
return this.defaultEncoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default FileTypeMap of this message, or {@code null} if none.
|
||||
*/
|
||||
@Nullable
|
||||
public final FileTypeMap getDefaultFileTypeMap() {
|
||||
return this.defaultFileTypeMap;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,326 @@
|
||||
################################################################################
|
||||
# Copyright 2002-2019 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
################################################################################
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# Defaults for the Java Activation Framework (revised).
|
||||
#
|
||||
# Modified extensions registered in this file:
|
||||
# text/plain java c c++ cpp pl cc h
|
||||
# image/png png
|
||||
# image/svg+xml svg
|
||||
#
|
||||
################################################################################
|
||||
|
||||
text/html html htm HTML HTM
|
||||
text/plain txt text TXT TEXT java c c++ cpp pl cc h
|
||||
image/gif gif GIF
|
||||
image/ief ief
|
||||
image/jpeg jpeg jpg jpe JPG
|
||||
image/tiff tiff tif
|
||||
image/x-xwindowdump xwd
|
||||
application/postscript ai eps ps
|
||||
application/rtf rtf
|
||||
application/x-tex tex
|
||||
application/x-texinfo texinfo texi
|
||||
application/x-troff t tr roff
|
||||
audio/basic au
|
||||
audio/midi midi mid
|
||||
audio/x-aifc aifc
|
||||
audio/x-aiff aif aiff
|
||||
audio/x-mpeg mpeg mpg
|
||||
audio/x-wav wav
|
||||
video/mpeg mpeg mpg mpe
|
||||
video/quicktime qt mov
|
||||
video/x-msvideo avi
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# Additional file types adapted from
|
||||
# http://sites.utoronto.ca/webdocs/HTMLdocs/Book/Book-3ed/appb/mimetype.html
|
||||
# kindly re-licensed to Apache Software License 2.0 by Ian Graham.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
# TEXT TYPES
|
||||
|
||||
text/x-speech talk
|
||||
text/css css
|
||||
text/csv csv
|
||||
|
||||
# IMAGE TYPES
|
||||
|
||||
# X-Windows bitmap (b/w)
|
||||
image/x-xbitmap xbm
|
||||
# X-Windows pixelmap (8-bit color)
|
||||
image/x-xpixmap xpm
|
||||
# Portable Network Graphics
|
||||
image/png png
|
||||
# Scalable Vector Graphics
|
||||
image/svg+xml svg
|
||||
# Image Exchange Format (RFC 1314)
|
||||
image/ief ief
|
||||
# RGB
|
||||
image/rgb rgb
|
||||
# Group III Fax (RFC 1494)
|
||||
image/g3fax g3f
|
||||
# X Windowdump format
|
||||
image/x-xwindowdump xwd
|
||||
# Macintosh PICT format
|
||||
image/x-pict pict
|
||||
# PPM (UNIX PPM package)
|
||||
image/x-portable-pixmap ppm
|
||||
# PGM (UNIX PPM package)
|
||||
image/x-portable-graymap pgm
|
||||
# PBM (UNIX PPM package)
|
||||
image/x-portable-bitmap pbm
|
||||
# PNM (UNIX PPM package)
|
||||
image/x-portable-anymap pnm
|
||||
# Microsoft Windows bitmap
|
||||
image/x-ms-bmp bmp
|
||||
# CMU raster
|
||||
image/x-cmu-raster ras
|
||||
# Kodak Photo-CD
|
||||
image/x-photo-cd pcd
|
||||
# Computer Graphics Metafile
|
||||
image/cgm cgm
|
||||
# CALS Type 1 or 2
|
||||
image/x-cals mil cal
|
||||
# Fractal Image Format (Iterated Systems)
|
||||
image/fif fif
|
||||
# QuickSilver active image (Micrografx)
|
||||
image/x-mgx-dsf dsf
|
||||
# CMX vector image (Corel)
|
||||
image/x-cmx cmx
|
||||
# Wavelet-compressed (Summus)
|
||||
image/wavelet wi
|
||||
# AutoCad Drawing (SoftSource)
|
||||
image/vnd.dwg dwg
|
||||
# AutoCad DXF file (SoftSource)
|
||||
image/vnd.dxf dxf
|
||||
# Simple Vector Format (SoftSource)
|
||||
image/vnd.svf svf
|
||||
|
||||
# AUDIO/VOICE/MUSIC RELATED TYPES
|
||||
|
||||
# """basic""audio - 8-bit u-law PCM"
|
||||
audio/basic au snd
|
||||
# Macintosh audio format (AIpple)
|
||||
audio/x-aiff aif aiff aifc
|
||||
# Microsoft audio
|
||||
audio/x-wav wav
|
||||
# MPEG audio
|
||||
audio/x-mpeg mpa abs mpega
|
||||
# MPEG-2 audio
|
||||
audio/x-mpeg-2 mp2a mpa2
|
||||
# compressed speech (Echo Speech Corp.)
|
||||
audio/echospeech es
|
||||
# Toolvox speech audio (Voxware)
|
||||
audio/voxware vox
|
||||
# RapidTransit compressed audio (Fast Man)
|
||||
application/fastman lcc
|
||||
# Realaudio (Progressive Networks)
|
||||
application/x-pn-realaudio ra ram
|
||||
# MIDI music data
|
||||
x-music/x-midi mmid
|
||||
# Koan music data (SSeyo)
|
||||
application/vnd.koan skp
|
||||
# Speech synthesis data (MVP Solutions)
|
||||
text/x-speech talk
|
||||
|
||||
# VIDEO TYPES
|
||||
|
||||
# MPEG video
|
||||
video/mpeg mpeg mpg mpe
|
||||
# MPEG-2 video
|
||||
video/mpeg-2 mpv2 mp2v
|
||||
# Macintosh Quicktime
|
||||
video/quicktime qt mov
|
||||
# Microsoft video
|
||||
video/x-msvideo avi
|
||||
# SGI Movie format
|
||||
video/x-sgi-movie movie
|
||||
# VDOlive streaming video (VDOnet)
|
||||
video/vdo vdo
|
||||
# Vivo streaming video (Vivo software)
|
||||
video/vnd.vivo viv
|
||||
|
||||
# SPECIAL HTTP/WEB APPLICATION TYPES
|
||||
|
||||
# Proxy autoconfiguration (Netscape browsers)
|
||||
application/x-ns-proxy-autoconfig pac
|
||||
# Netscape Cooltalk chat data (Netscape)
|
||||
x-conference/x-cooltalk ice
|
||||
|
||||
# TEXT-RELATED
|
||||
|
||||
# PostScript
|
||||
application/postscript ai eps ps
|
||||
# Microsoft Rich Text Format
|
||||
application/rtf rtf
|
||||
# Adobe Acrobat PDF
|
||||
application/pdf pdf
|
||||
# Maker Interchange Format (FrameMaker)
|
||||
application/vnd.mif mif
|
||||
# Troff document
|
||||
application/x-troff t tr roff
|
||||
# Troff document with MAN macros
|
||||
application/x-troff-man man
|
||||
# Troff document with ME macros
|
||||
application/x-troff-me me
|
||||
# Troff document with MS macros
|
||||
application/x-troff-ms ms
|
||||
# LaTeX document
|
||||
application/x-latex latex
|
||||
# Tex/LateX document
|
||||
application/x-tex tex
|
||||
# GNU TexInfo document
|
||||
application/x-texinfo texinfo texi
|
||||
# TeX dvi format
|
||||
application/x-dvi dvi
|
||||
# MS word document
|
||||
application/msword doc DOC
|
||||
# Office Document Architecture
|
||||
application/oda oda
|
||||
# Envoy Document
|
||||
application/envoy evy
|
||||
|
||||
# ARCHIVE/COMPRESSED ARCHIVES
|
||||
|
||||
# Gnu tar format
|
||||
application/x-gtar gtar
|
||||
# 4.3BSD tar format
|
||||
application/x-tar tar
|
||||
# POSIX tar format
|
||||
application/x-ustar ustar
|
||||
# Old CPIO format
|
||||
application/x-bcpio bcpio
|
||||
# POSIX CPIO format
|
||||
application/x-cpio cpio
|
||||
# UNIX sh shell archive
|
||||
application/x-shar shar
|
||||
# DOS/PC - Pkzipped archive
|
||||
application/zip zip
|
||||
# Macintosh Binhexed archive
|
||||
application/mac-binhex40 hqx
|
||||
# Macintosh Stuffit Archive
|
||||
application/x-stuffit sit sea
|
||||
# Fractal Image Format
|
||||
application/fractals fif
|
||||
# "Binary UUencoded"
|
||||
application/octet-stream bin uu
|
||||
# PC executable
|
||||
application/octet-stream exe
|
||||
# "WAIS ""sources"""
|
||||
application/x-wais-source src wsrc
|
||||
# NCSA HDF data format
|
||||
application/hdf hdf
|
||||
|
||||
# DOWNLOADABLE PROGRAM/SCRIPTS
|
||||
|
||||
# Javascript program
|
||||
text/javascript js ls mocha
|
||||
# UNIX bourne shell program
|
||||
application/x-sh sh
|
||||
# UNIX c-shell program
|
||||
application/x-csh csh
|
||||
# Perl program
|
||||
application/x-perl pl
|
||||
# Tcl (Tool Control Language) program
|
||||
application/x-tcl tcl
|
||||
|
||||
# ANIMATION/MULTIMEDIA
|
||||
|
||||
# FutureSplash vector animation (FutureWave)
|
||||
application/futuresplash spl
|
||||
# mBED multimedia data (mBED)
|
||||
application/mbedlet mbd
|
||||
# PowerMedia multimedia (RadMedia)
|
||||
application/x-rad-powermedia rad
|
||||
|
||||
# PRESENTATION
|
||||
|
||||
# PowerPoint presentation (Microsoft)
|
||||
application/mspowerpoint ppz
|
||||
# ASAP WordPower (Software Publishing Corp.)
|
||||
application/x-asap asp
|
||||
# Astound Web Player multimedia data (GoldDisk)
|
||||
application/astound asn
|
||||
|
||||
# SPECIAL EMBEDDED OBJECT
|
||||
|
||||
# OLE script e.g. Visual Basic (Ncompass)
|
||||
application/x-olescript axs
|
||||
# OLE Object (Microsoft/NCompass)
|
||||
application/x-oleobject ods
|
||||
# OpenScape OLE/OCX objects (Business@Web)
|
||||
x-form/x-openscape opp
|
||||
# Visual Basic objects (Amara)
|
||||
application/x-webbasic wba
|
||||
# Specialized data entry forms (Alpha Software)
|
||||
application/x-alpha-form frm
|
||||
# client-server objects (Wayfarer Communications)
|
||||
x-script/x-wfxclient wfx
|
||||
|
||||
# GENERAL APPLICATIONS
|
||||
|
||||
# Undefined binary data (often executable progs)
|
||||
application/octet-stream exe com
|
||||
# Pointcast news data (Pointcast)
|
||||
application/x-pcn pcn
|
||||
# Excel spreadsheet (Microsoft)
|
||||
application/vnd.ms-excel xls
|
||||
# PowerPoint (Microsoft)
|
||||
application/vnd.ms-powerpoint ppt
|
||||
# Microsoft Project (Microsoft)
|
||||
application/vnd.ms-project mpp
|
||||
# SourceView document (Dataware Electronics)
|
||||
application/vnd.svd svd
|
||||
# Net Install - software install (20/20 Software)
|
||||
application/x-net-install ins
|
||||
# Carbon Copy - remote control/access (Microcom)
|
||||
application/ccv ccv
|
||||
# Spreadsheets (Visual Components)
|
||||
workbook/formulaone vts
|
||||
|
||||
# 2D/3D DATA/VIRTUAL REALITY TYPES
|
||||
|
||||
# VRML data file
|
||||
x-world/x-vrml wrl vrml
|
||||
# WIRL - VRML data (VREAM)
|
||||
x-world/x-vream vrw
|
||||
# Play3D 3d scene data (Play3D)
|
||||
application/x-p3d p3d
|
||||
# Viscape Interactive 3d world data (Superscape)
|
||||
x-world/x-svr svr
|
||||
# WebActive 3d data (Plastic Thought)
|
||||
x-world/x-wvr wvr
|
||||
# QuickDraw3D scene data (Apple)
|
||||
x-world/x-3dmf 3dmf
|
||||
|
||||
# SCIENTIFIC/MATH/CAD TYPES
|
||||
|
||||
# Mathematica notebook
|
||||
application/mathematica ma
|
||||
# Computational meshes for numerical simulations
|
||||
x-model/x-mesh msh
|
||||
# Vis5D 5-dimensional data
|
||||
application/vis5d v5d
|
||||
# IGES models -- CAD/CAM (CGM) data
|
||||
application/iges igs
|
||||
# Autocad WHIP vector drawings
|
||||
drawing/x-dwf dwf
|
||||
|
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* JavaMail support for Spring's mail infrastructure.
|
||||
* Provides an extended JavaMailSender interface and a MimeMessageHelper
|
||||
* class for convenient population of a JavaMail MimeMessage.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package com.simaek.notify.email.embedded.mail.javamail;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Spring's generic mail infrastructure.
|
||||
* Concrete implementations are provided in the subpackages.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package com.simaek.notify.email.embedded.mail;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
@ -1,12 +1,12 @@
|
||||
package com.cicdi.notify.email;
|
||||
package com.simaek.notify.email;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cicdi.notify.*;
|
||||
import com.cicdi.notify.template.AbstractTemplateManager;
|
||||
import com.cicdi.notify.template.Template;
|
||||
import com.cicdi.notify.template.TemplateManager;
|
||||
import com.cicdi.notify.template.TemplateProperties;
|
||||
import com.cicdi.notify.email.embedded.DefaultEmailNotifierProvider;
|
||||
import com.simaek.notify.*;
|
||||
import com.simaek.notify.template.AbstractTemplateManager;
|
||||
import com.simaek.notify.template.Template;
|
||||
import com.simaek.notify.template.TemplateManager;
|
||||
import com.simaek.notify.template.TemplateProperties;
|
||||
import com.simaek.notify.email.embedded.DefaultEmailNotifierProvider;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
@ -23,9 +23,7 @@ public class DefaultEmailTest {
|
||||
@Test
|
||||
public void testSend() {
|
||||
// 通知器配置管理器
|
||||
NotifyConfigManager notifyConfigManager = new NotifyConfigManager() {
|
||||
@Override
|
||||
public NotifierProperties getNotifyConfig(NotifyType notifyType, String configId) {
|
||||
NotifyConfigManager notifyConfigManager = (notifyType, configId) -> {
|
||||
NotifierProperties notifierProperties = new NotifierProperties();
|
||||
notifierProperties.setType(DefaultNotifyType.email.getId());
|
||||
notifierProperties.setProvider(EmailProvider.embedded.getId());
|
||||
@ -47,7 +45,6 @@ public class DefaultEmailTest {
|
||||
config.put("properties", Arrays.asList(p1, p2));
|
||||
notifierProperties.setConfiguration(config);
|
||||
return notifierProperties;
|
||||
}
|
||||
};
|
||||
|
||||
// 模板管理器
|
@ -3,9 +3,9 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>notify</artifactId>
|
||||
<groupId>com.cicdi</groupId>
|
||||
<version>0.1.0</version>
|
||||
<artifactId>notify-parent</artifactId>
|
||||
<groupId>com.simaek</groupId>
|
||||
<version>0.1.1</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@ -19,9 +19,8 @@
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.cicdi</groupId>
|
||||
<groupId>com.simaek</groupId>
|
||||
<artifactId>notify-core</artifactId>
|
||||
<version>0.1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@ -32,12 +31,11 @@
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>aliyun-java-sdk-core</artifactId>
|
||||
<version>4.5.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.cicdi.notify.sms;
|
||||
package com.simaek.notify.sms;
|
||||
|
||||
import com.cicdi.notify.Provider;
|
||||
import com.simaek.notify.Provider;
|
||||
|
||||
/**
|
||||
* @author xueye
|
@ -1,6 +1,6 @@
|
||||
package com.cicdi.notify.sms;
|
||||
package com.simaek.notify.sms;
|
||||
|
||||
import com.cicdi.notify.template.Template;
|
||||
import com.simaek.notify.template.Template;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
@ -1,4 +1,4 @@
|
||||
package com.cicdi.notify.sms.aliyun;
|
||||
package com.simaek.notify.sms.aliyun;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
@ -9,8 +9,8 @@ import com.aliyuncs.IAcsClient;
|
||||
import com.aliyuncs.http.MethodType;
|
||||
import com.aliyuncs.profile.DefaultProfile;
|
||||
import com.aliyuncs.profile.IClientProfile;
|
||||
import com.cicdi.notify.*;
|
||||
import com.cicdi.notify.sms.SmsProvider;
|
||||
import com.simaek.notify.*;
|
||||
import com.simaek.notify.sms.SmsProvider;
|
||||
|
||||
|
||||
import java.util.Map;
|
@ -1,12 +1,11 @@
|
||||
package com.cicdi.notify.sms.aliyun;
|
||||
package com.simaek.notify.sms.aliyun;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cicdi.notify.*;
|
||||
import com.cicdi.notify.sms.SmsProvider;
|
||||
import com.cicdi.notify.template.Template;
|
||||
import com.cicdi.notify.template.TemplateManager;
|
||||
import com.cicdi.notify.template.TemplateProperties;
|
||||
import com.cicdi.notify.template.TemplateProvider;
|
||||
import com.simaek.notify.*;
|
||||
import com.simaek.notify.sms.SmsProvider;
|
||||
import com.simaek.notify.template.Template;
|
||||
import com.simaek.notify.template.TemplateProperties;
|
||||
import com.simaek.notify.template.TemplateProvider;
|
||||
|
||||
/**
|
||||
* 阿里云短信通知服务
|
@ -1,7 +1,7 @@
|
||||
package com.cicdi.notify.sms.aliyun;
|
||||
package com.simaek.notify.sms.aliyun;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cicdi.notify.template.Template;
|
||||
import com.simaek.notify.template.Template;
|
||||
|
||||
import java.util.Map;
|
||||
|
@ -1,21 +1,14 @@
|
||||
package com.cicdi.notify.sms.telecom;
|
||||
package com.simaek.notify.sms.telecom;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.cicdi.notify.*;
|
||||
import com.cicdi.notify.sms.SmsProvider;
|
||||
import com.cicdi.notify.template.TemplateManager;
|
||||
import com.cicdi.notify.util.ExpressionUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import com.simaek.notify.*;
|
||||
import com.simaek.notify.sms.SmsProvider;
|
||||
import com.simaek.notify.util.ExpressionUtils;
|
||||
import okhttp3.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 云信通短信通知平台通知器
|
||||
@ -30,12 +23,12 @@ public class TelecomSmsNotifier implements Notifier<TelecomSmsTemplate> {
|
||||
|
||||
private final String notifierId;
|
||||
|
||||
private final CloseableHttpClient httpClient;
|
||||
private final OkHttpClient httpClient;
|
||||
|
||||
public TelecomSmsNotifier(NotifierProperties properties) {
|
||||
this.httpClient = HttpClientBuilder.create().build();
|
||||
this.notifierId = properties.getId();
|
||||
this.configuration = new JSONObject(properties.getConfiguration()).toJavaObject(TelecomSmsNotifierConfiguration.class);
|
||||
this.httpClient = new OkHttpClient.Builder().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -56,21 +49,23 @@ public class TelecomSmsNotifier implements Notifier<TelecomSmsTemplate> {
|
||||
@Override
|
||||
public void send(TelecomSmsTemplate template, Map<String, Object> context) {
|
||||
try {
|
||||
URI sendMsgURI = new URIBuilder(notifyApi).addParameter("userId", configuration.getUserId())
|
||||
.addParameter("password", configuration.getPassword())
|
||||
.addParameter("content", render(template.getContent(), context))
|
||||
.addParameter("mobile", template.getMobile())
|
||||
HttpUrl url = Objects.requireNonNull(HttpUrl.parse(notifyApi)).newBuilder()
|
||||
.addQueryParameter("userId", configuration.getUserId())
|
||||
.addQueryParameter("password", configuration.getPassword())
|
||||
.addQueryParameter("content", render(template.getContent(), context))
|
||||
.addQueryParameter("mobile", template.getMobile())
|
||||
.build();
|
||||
HttpPost httpPost = new HttpPost(sendMsgURI);
|
||||
CloseableHttpResponse response = httpClient.execute(httpPost);
|
||||
String responseString = EntityUtils.toString(response.getEntity());
|
||||
Map<String, String> resultMap = handleResponse(responseString);
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.post(RequestBody.create(new byte[0]))
|
||||
.build();
|
||||
Call call = httpClient.newCall(request);
|
||||
Response response = call.execute();
|
||||
Map<String, String> resultMap = handleResponse(Objects.requireNonNull(response.body()).string());
|
||||
String resultCodeKey = "rspCode";
|
||||
if (resultMap.containsKey(resultCodeKey)) {
|
||||
if (!"0".equals(resultMap.get(resultCodeKey)) && !"DELIVRD".equalsIgnoreCase(resultMap.get(resultCodeKey))) {
|
||||
if (!resultMap.containsKey(resultCodeKey) || (!"0".equals(resultMap.get(resultCodeKey)) && !"DELIVRD".equalsIgnoreCase(resultMap.get(resultCodeKey)))) {
|
||||
throw new RuntimeException("短信发送失败:" + resultMap.get("rspDesc"));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -78,11 +73,6 @@ public class TelecomSmsNotifier implements Notifier<TelecomSmsTemplate> {
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
httpClient.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
@ -1,4 +1,4 @@
|
||||
package com.cicdi.notify.sms.telecom;
|
||||
package com.simaek.notify.sms.telecom;
|
||||
|
||||
/**
|
||||
* 云信通短信通知平台配置信息
|
@ -1,11 +1,11 @@
|
||||
package com.cicdi.notify.sms.telecom;
|
||||
package com.simaek.notify.sms.telecom;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cicdi.notify.*;
|
||||
import com.cicdi.notify.sms.SmsProvider;
|
||||
import com.cicdi.notify.template.Template;
|
||||
import com.cicdi.notify.template.TemplateProperties;
|
||||
import com.cicdi.notify.template.TemplateProvider;
|
||||
import com.simaek.notify.*;
|
||||
import com.simaek.notify.sms.SmsProvider;
|
||||
import com.simaek.notify.template.Template;
|
||||
import com.simaek.notify.template.TemplateProperties;
|
||||
import com.simaek.notify.template.TemplateProvider;
|
||||
|
||||
/**
|
||||
* @author xueye
|
@ -1,6 +1,6 @@
|
||||
package com.cicdi.notify.sms.telecom;
|
||||
package com.simaek.notify.sms.telecom;
|
||||
|
||||
import com.cicdi.notify.template.Template;
|
||||
import com.simaek.notify.template.Template;
|
||||
|
||||
/**
|
||||
* @author xueye
|
@ -1,11 +1,11 @@
|
||||
package com.cicdi.notify.sms;
|
||||
package com.simaek.notify.sms;
|
||||
|
||||
import com.cicdi.notify.*;
|
||||
import com.cicdi.notify.sms.aliyun.AliyunSmsNotifierProvider;
|
||||
import com.cicdi.notify.template.AbstractTemplateManager;
|
||||
import com.cicdi.notify.template.Template;
|
||||
import com.cicdi.notify.template.TemplateManager;
|
||||
import com.cicdi.notify.template.TemplateProperties;
|
||||
import com.simaek.notify.*;
|
||||
import com.simaek.notify.sms.aliyun.AliyunSmsNotifierProvider;
|
||||
import com.simaek.notify.template.AbstractTemplateManager;
|
||||
import com.simaek.notify.template.Template;
|
||||
import com.simaek.notify.template.TemplateManager;
|
||||
import com.simaek.notify.template.TemplateProperties;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
@ -1,13 +1,13 @@
|
||||
package com.cicdi.notify.sms;
|
||||
package com.simaek.notify.sms;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cicdi.notify.*;
|
||||
import com.cicdi.notify.sms.telecom.TelecomSmsNotifierProvider;
|
||||
import com.cicdi.notify.sms.telecom.TelecomSmsTemplate;
|
||||
import com.cicdi.notify.template.AbstractTemplateManager;
|
||||
import com.cicdi.notify.template.Template;
|
||||
import com.cicdi.notify.template.TemplateManager;
|
||||
import com.cicdi.notify.template.TemplateProperties;
|
||||
import com.simaek.notify.*;
|
||||
import com.simaek.notify.sms.telecom.TelecomSmsNotifierProvider;
|
||||
import com.simaek.notify.sms.telecom.TelecomSmsTemplate;
|
||||
import com.simaek.notify.template.AbstractTemplateManager;
|
||||
import com.simaek.notify.template.Template;
|
||||
import com.simaek.notify.template.TemplateManager;
|
||||
import com.simaek.notify.template.TemplateProperties;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
@ -45,7 +45,7 @@ public class TelecomSmsTest {
|
||||
|
||||
TelecomSmsTemplate template = new TelecomSmsTemplate();
|
||||
template.setContent("${code},有效期为5分钟。");
|
||||
template.setMobile("13047689449,18605120786");
|
||||
template.setMobile("18605120786");
|
||||
|
||||
templateProperties.setTemplate(JSON.toJSONString(template));
|
||||
|
@ -3,9 +3,9 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>notify</artifactId>
|
||||
<groupId>com.cicdi</groupId>
|
||||
<version>0.1.0</version>
|
||||
<artifactId>notify-parent</artifactId>
|
||||
<groupId>com.simaek</groupId>
|
||||
<version>0.1.1</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@ -19,26 +19,20 @@
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.cicdi</groupId>
|
||||
<groupId>com.simaek</groupId>
|
||||
<artifactId>notify-core</artifactId>
|
||||
<version>0.1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -1,6 +1,6 @@
|
||||
package com.cicdi.notify.wechat;
|
||||
package com.simaek.notify.wechat;
|
||||
|
||||
import com.cicdi.notify.Provider;
|
||||
import com.simaek.notify.Provider;
|
||||
|
||||
public enum WechatProvider implements Provider {
|
||||
corpMessage("微信企业消息通知"),
|
@ -1,28 +1,18 @@
|
||||
package com.cicdi.notify.wechat.corp;
|
||||
package com.simaek.notify.wechat.corp;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.cicdi.notify.DefaultNotifyType;
|
||||
import com.cicdi.notify.Notifier;
|
||||
import com.cicdi.notify.NotifyType;
|
||||
import com.cicdi.notify.Provider;
|
||||
import com.cicdi.notify.wechat.WechatProvider;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import com.simaek.notify.DefaultNotifyType;
|
||||
import com.simaek.notify.Notifier;
|
||||
import com.simaek.notify.NotifyType;
|
||||
import com.simaek.notify.Provider;
|
||||
import com.simaek.notify.wechat.WechatProvider;
|
||||
import okhttp3.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class WechatCorpNotifier implements Notifier<WechatCorpTemplate> {
|
||||
|
||||
@ -40,9 +30,12 @@ public class WechatCorpNotifier implements Notifier<WechatCorpTemplate> {
|
||||
|
||||
private final String notifierId;
|
||||
|
||||
private final OkHttpClient httpClient;
|
||||
|
||||
public WechatCorpNotifier(String id, WechatCorpProperties properties) {
|
||||
this.properties = properties;
|
||||
this.notifierId = id;
|
||||
this.httpClient = new OkHttpClient.Builder().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -62,17 +55,18 @@ public class WechatCorpNotifier implements Notifier<WechatCorpTemplate> {
|
||||
|
||||
@Override
|
||||
public void send(WechatCorpTemplate template, Map<String, Object> context) {
|
||||
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
|
||||
HttpPost httpPost = new HttpPost(notifyApi + "?access_token=" + getToken());
|
||||
httpPost.setHeader("Content-Type", "application/json;charset=utf8");
|
||||
|
||||
StringEntity stringEntity = new StringEntity(template.createJsonRequest(context), "UTF-8");
|
||||
httpPost.setEntity(stringEntity);
|
||||
|
||||
HttpUrl url = Objects.requireNonNull(HttpUrl.parse(notifyApi)).newBuilder()
|
||||
.addQueryParameter("access_token", getToken())
|
||||
.build();
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.post(RequestBody.create(template.createJsonRequest(context), MediaType.get("application/json")))
|
||||
.header("Content-Type", "application/json;charset=utf8")
|
||||
.build();
|
||||
try {
|
||||
CloseableHttpResponse response = httpClient.execute(httpPost);
|
||||
String result = EntityUtils.toString(response.getEntity());
|
||||
System.out.println(result);
|
||||
Call call = httpClient.newCall(request);
|
||||
Response response = call.execute();
|
||||
String result = Objects.requireNonNull(response.body()).string();
|
||||
JSONObject jsonObject = JSON.parseObject(result);
|
||||
if (!"0".equals(jsonObject.get("errcode").toString())) {
|
||||
throw new RuntimeException("发送微信企业通知失败:" + jsonObject.get("errmsg"));
|
||||
@ -90,15 +84,18 @@ public class WechatCorpNotifier implements Notifier<WechatCorpTemplate> {
|
||||
}
|
||||
|
||||
private String requestToken() {
|
||||
List<NameValuePair> params = new ArrayList<>();
|
||||
params.add(new BasicNameValuePair("corpId", properties.getCorpId()));
|
||||
params.add(new BasicNameValuePair("corpSecret", properties.getCorpSecret()));
|
||||
|
||||
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
|
||||
HttpUrl url = Objects.requireNonNull(HttpUrl.parse(tokenApi)).newBuilder()
|
||||
.addQueryParameter("corpId", properties.getCorpId())
|
||||
.addQueryParameter("corpSecret", properties.getCorpSecret())
|
||||
.build();
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.get()
|
||||
.build();
|
||||
try {
|
||||
HttpGet httpGet = new HttpGet(new URIBuilder(tokenApi).setParameters(params).build());
|
||||
CloseableHttpResponse response = httpClient.execute(httpGet);
|
||||
JSONObject responseJson = JSON.parseObject(EntityUtils.toString(response.getEntity()));
|
||||
Call call = httpClient.newCall(request);
|
||||
Response response = call.execute();
|
||||
JSONObject responseJson = JSON.parseObject(Objects.requireNonNull(response.body()).string());
|
||||
if (responseJson.containsKey("access_token")) {
|
||||
String access_token = responseJson.get("access_token").toString();
|
||||
accessToken = access_token;
|
@ -1,11 +1,11 @@
|
||||
package com.cicdi.notify.wechat.corp;
|
||||
package com.simaek.notify.wechat.corp;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cicdi.notify.*;
|
||||
import com.cicdi.notify.template.Template;
|
||||
import com.cicdi.notify.template.TemplateProperties;
|
||||
import com.cicdi.notify.template.TemplateProvider;
|
||||
import com.cicdi.notify.wechat.WechatProvider;
|
||||
import com.simaek.notify.*;
|
||||
import com.simaek.notify.template.Template;
|
||||
import com.simaek.notify.template.TemplateProperties;
|
||||
import com.simaek.notify.template.TemplateProvider;
|
||||
import com.simaek.notify.wechat.WechatProvider;
|
||||
|
||||
import java.util.Map;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.cicdi.notify.wechat.corp;
|
||||
package com.simaek.notify.wechat.corp;
|
||||
|
||||
public class WechatCorpProperties {
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.cicdi.notify.wechat.corp;
|
||||
package com.simaek.notify.wechat.corp;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.cicdi.notify.template.Template;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import com.simaek.notify.template.Template;
|
||||
import com.simaek.notify.util.StringUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
@ -68,10 +68,10 @@ public class WechatCorpTemplate implements Template {
|
||||
json.put("msgtype", "text");
|
||||
json.put("text", Collections.singletonMap("content", message));
|
||||
|
||||
if (StringUtils.isNotBlank(toUser)) {
|
||||
if (!StringUtils.isBlank(toUser)) {
|
||||
json.put("touser", this.createUserIdList(context));
|
||||
}
|
||||
if (StringUtils.isNotBlank(toParty)) {
|
||||
if (!StringUtils.isBlank(toParty)) {
|
||||
json.put("toparty", this.createDepartmentIdList(context));
|
||||
}
|
||||
|
@ -1,30 +1,15 @@
|
||||
package com.cicdi.notify.wechat.subscription;
|
||||
package com.simaek.notify.wechat.subscription;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.cicdi.notify.*;
|
||||
import com.cicdi.notify.wechat.WechatProvider;
|
||||
import org.apache.http.Consts;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import com.simaek.notify.*;
|
||||
import com.simaek.notify.wechat.WechatProvider;
|
||||
import okhttp3.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
@ -65,11 +50,11 @@ public class WechatSubscriptionNotifier implements Notifier<WechatSubscriptionTe
|
||||
*/
|
||||
private long refreshTokenTime;
|
||||
|
||||
private final CloseableHttpClient httpClient;
|
||||
private final OkHttpClient httpClient;
|
||||
|
||||
public WechatSubscriptionNotifier(NotifierProperties properties) {
|
||||
this.properties = properties;
|
||||
this.httpClient = HttpClientBuilder.create().build();
|
||||
this.httpClient = new OkHttpClient.Builder().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -89,21 +74,23 @@ public class WechatSubscriptionNotifier implements Notifier<WechatSubscriptionTe
|
||||
|
||||
@Override
|
||||
public void send(WechatSubscriptionTemplate template, Map<String, Object> context) {
|
||||
try {
|
||||
URI sendMessageURI = new URIBuilder(notifyApi)
|
||||
.addParameter("access_token", getToken())
|
||||
HttpUrl url = Objects.requireNonNull(HttpUrl.parse(notifyApi)).newBuilder()
|
||||
.addQueryParameter("access_token", getToken())
|
||||
.build();
|
||||
HttpPost httpPost = new HttpPost(sendMessageURI);
|
||||
httpPost.setHeader("Content-Type", "application/json; charset=UTF-8");
|
||||
StringEntity requestBody = new StringEntity(template.createJsonRequest(), ContentType.APPLICATION_JSON);
|
||||
httpPost.setEntity(requestBody);
|
||||
CloseableHttpResponse response = httpClient.execute(httpPost);
|
||||
JSONObject responseJson = JSON.parseObject(EntityUtils.toString(response.getEntity()));
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.header("Content-Type", "application/json; charset=UTF-8")
|
||||
.post(RequestBody.create(template.createJsonRequest(), MediaType.get("application/json")))
|
||||
.build();
|
||||
try {
|
||||
Call call = httpClient.newCall(request);
|
||||
Response response = call.execute();
|
||||
JSONObject responseJson = JSON.parseObject(Objects.requireNonNull(response.body()).string());
|
||||
System.out.println(responseJson);
|
||||
if (!responseJson.containsKey("errcode") || responseJson.getIntValue("errcode") != 0) {
|
||||
throw new RuntimeException(responseJson.get("errmsg").toString());
|
||||
}
|
||||
} catch (URISyntaxException | IOException e) {
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
@ -112,11 +99,6 @@ public class WechatSubscriptionNotifier implements Notifier<WechatSubscriptionTe
|
||||
public void close() {
|
||||
accessToken.set(null);
|
||||
refreshTokenTime = 0;
|
||||
try {
|
||||
httpClient.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private String getToken() {
|
||||
@ -131,22 +113,25 @@ public class WechatSubscriptionNotifier implements Notifier<WechatSubscriptionTe
|
||||
*/
|
||||
private void refreshToken() {
|
||||
WechatSubscriptionProperties config = new JSONObject(properties.getConfiguration()).toJavaObject(WechatSubscriptionProperties.class);
|
||||
try {
|
||||
URI getTokenURI = new URIBuilder(tokenApi)
|
||||
.addParameter("grant_type", config.getGrantType())
|
||||
.addParameter("appid", config.getAppId())
|
||||
.addParameter("secret", config.getSecret())
|
||||
HttpUrl url = HttpUrl.parse(tokenApi).newBuilder()
|
||||
.addQueryParameter("grant_type", config.getGrantType())
|
||||
.addQueryParameter("appid", config.getAppId())
|
||||
.addQueryParameter("secret", config.getSecret())
|
||||
.build();
|
||||
HttpGet httpGet = new HttpGet(getTokenURI);
|
||||
CloseableHttpResponse response = httpClient.execute(httpGet);
|
||||
String responseString = EntityUtils.toString(response.getEntity());
|
||||
JSONObject responseJson = JSON.parseObject(responseString);
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.get()
|
||||
.build();
|
||||
try {
|
||||
Call call = httpClient.newCall(request);
|
||||
Response response = call.execute();
|
||||
JSONObject responseJson = JSON.parseObject(Objects.requireNonNull(response.body()).string());
|
||||
if (responseJson.containsKey("access_token")) {
|
||||
accessToken.set(responseJson.get("access_token").toString());
|
||||
} else if (responseJson.containsKey("errcode")) {
|
||||
throw new RuntimeException(responseJson.get("errmsg").toString());
|
||||
}
|
||||
} catch (URISyntaxException | IOException e) {
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
@ -1,13 +1,11 @@
|
||||
package com.cicdi.notify.wechat.subscription;
|
||||
package com.simaek.notify.wechat.subscription;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cicdi.notify.*;
|
||||
import com.cicdi.notify.template.Template;
|
||||
import com.cicdi.notify.template.TemplateProperties;
|
||||
import com.cicdi.notify.template.TemplateProvider;
|
||||
import com.cicdi.notify.wechat.WechatProvider;
|
||||
|
||||
import java.util.Map;
|
||||
import com.simaek.notify.*;
|
||||
import com.simaek.notify.template.Template;
|
||||
import com.simaek.notify.template.TemplateProperties;
|
||||
import com.simaek.notify.template.TemplateProvider;
|
||||
import com.simaek.notify.wechat.WechatProvider;
|
||||
|
||||
/**
|
||||
* 微信公众号通知器提供商
|
@ -1,6 +1,6 @@
|
||||
package com.cicdi.notify.wechat.subscription;
|
||||
package com.simaek.notify.wechat.subscription;
|
||||
|
||||
import com.cicdi.notify.NotifierProperties;
|
||||
import com.simaek.notify.NotifierProperties;
|
||||
|
||||
/**
|
||||
* 微信公众号通知器配置信息
|
@ -1,7 +1,7 @@
|
||||
package com.cicdi.notify.wechat.subscription;
|
||||
package com.simaek.notify.wechat.subscription;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.cicdi.notify.template.Template;
|
||||
import com.simaek.notify.template.Template;
|
||||
|
||||
import java.util.Map;
|
||||
|
@ -1,14 +1,13 @@
|
||||
package com.cicdi.notify.wechat;
|
||||
package com.simaek.notify.wechat;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.cicdi.notify.*;
|
||||
import com.cicdi.notify.template.AbstractTemplateManager;
|
||||
import com.cicdi.notify.template.Template;
|
||||
import com.cicdi.notify.template.TemplateManager;
|
||||
import com.cicdi.notify.template.TemplateProperties;
|
||||
import com.cicdi.notify.wechat.corp.WechatCorpNotifierProvider;
|
||||
import com.cicdi.notify.wechat.subscription.WechatSubscriptionNotifierProvider;
|
||||
import com.simaek.notify.*;
|
||||
import com.simaek.notify.template.AbstractTemplateManager;
|
||||
import com.simaek.notify.template.Template;
|
||||
import com.simaek.notify.template.TemplateManager;
|
||||
import com.simaek.notify.template.TemplateProperties;
|
||||
import com.simaek.notify.wechat.subscription.WechatSubscriptionNotifierProvider;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
@ -1,13 +1,13 @@
|
||||
package com.cicdi.notify.wechat;
|
||||
package com.simaek.notify.wechat;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cicdi.notify.*;
|
||||
import com.cicdi.notify.template.AbstractTemplateManager;
|
||||
import com.cicdi.notify.template.Template;
|
||||
import com.cicdi.notify.template.TemplateManager;
|
||||
import com.cicdi.notify.template.TemplateProperties;
|
||||
import com.cicdi.notify.wechat.corp.WechatCorpNotifierProvider;
|
||||
import com.cicdi.notify.wechat.corp.WechatCorpTemplate;
|
||||
import com.simaek.notify.*;
|
||||
import com.simaek.notify.template.AbstractTemplateManager;
|
||||
import com.simaek.notify.template.Template;
|
||||
import com.simaek.notify.template.TemplateManager;
|
||||
import com.simaek.notify.template.TemplateProperties;
|
||||
import com.simaek.notify.wechat.corp.WechatCorpNotifierProvider;
|
||||
import com.simaek.notify.wechat.corp.WechatCorpTemplate;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
@ -27,8 +27,8 @@ public class WechatTest {
|
||||
notifierProperties.setId("12");
|
||||
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.put("corpId", "wwbd49ae2419a55a9f");
|
||||
config.put("corpSecret", "TXDRQw_H8gpVKX0E01EmwMXJ4VooXmj65I-mDe0wQ1k");
|
||||
config.put("corpId", "ww27a579a37932f608");
|
||||
config.put("corpSecret", "V3e3ore5zuiZmZZ1qYweebr6N1MFo37uGN4xoDwtnu8");
|
||||
|
||||
notifierProperties.setConfiguration(config);
|
||||
|
||||
@ -44,8 +44,8 @@ public class WechatTest {
|
||||
templateProperties.setProvider(WechatProvider.corpMessage.getId());
|
||||
|
||||
WechatCorpTemplate template = new WechatCorpTemplate();
|
||||
template.setAgentId("3010084");
|
||||
template.setToUser("XueYe");
|
||||
template.setAgentId("1000002");
|
||||
template.setToUser("Hsueh");
|
||||
template.setToParty("");
|
||||
template.setToTag("");
|
||||
template.setMessage("Hello");
|
106
pom.xml
106
pom.xml
@ -4,10 +4,10 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.cicdi</groupId>
|
||||
<artifactId>notify</artifactId>
|
||||
<groupId>com.simaek</groupId>
|
||||
<artifactId>notify-parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>0.1.0</version>
|
||||
<version>0.1.1</version>
|
||||
<modules>
|
||||
<module>notify-core</module>
|
||||
<module>notify-email</module>
|
||||
@ -25,6 +25,44 @@
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.simaek</groupId>
|
||||
<artifactId>notify-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.simaek</groupId>
|
||||
<artifactId>notify-dingtalk</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.simaek</groupId>
|
||||
<artifactId>notify-email</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.simaek</groupId>
|
||||
<artifactId>notify-sms</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.simaek</groupId>
|
||||
<artifactId>notify-wechat</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>2.7.3</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
@ -38,18 +76,48 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<version>2.6</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.13</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>aliyun-java-sdk-core</artifactId>
|
||||
<version>4.6.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-beanutils</groupId>
|
||||
<artifactId>commons-beanutils</artifactId>
|
||||
<version>1.9.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>1.14</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jsoup</groupId>
|
||||
<artifactId>jsoup</artifactId>
|
||||
<version>1.11.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.mail</groupId>
|
||||
<artifactId>jakarta.mail</artifactId>
|
||||
<version>1.6.7</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>4.9.3</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</dependencyManagement>
|
||||
@ -73,7 +141,6 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<configuration>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
@ -82,7 +149,6 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<source>8</source>
|
||||
<target>8</target>
|
||||
@ -93,7 +159,6 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.2</version>
|
||||
<configuration>
|
||||
<skipTests>true</skipTests>
|
||||
</configuration>
|
||||
@ -119,7 +184,6 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<configuration>
|
||||
<attach>true</attach>
|
||||
<encoding>UTF-8</encoding>
|
||||
@ -170,9 +234,9 @@
|
||||
<developers>
|
||||
|
||||
<developer>
|
||||
<name>xueye</name>
|
||||
<name>Yaser Hsueh</name>
|
||||
<email>xueye404@qq.com</email>
|
||||
<url>https://www.simaek.com</url>
|
||||
<email>master@simaek.com</email>
|
||||
</developer>
|
||||
|
||||
</developers>
|
||||
@ -180,15 +244,15 @@
|
||||
<distributionManagement>
|
||||
|
||||
<repository>
|
||||
<id>nexus-bigdata-releases</id>
|
||||
<name>Cicdi Nexus Repository Release</name>
|
||||
<url>http://172.16.243.137:8081/repository/maven-releases/</url>
|
||||
<id>simaek-nexus</id>
|
||||
<name>release</name>
|
||||
<url>https://nas.xueye.io:8081/repository/maven-releases/</url>
|
||||
</repository>
|
||||
|
||||
<snapshotRepository>
|
||||
<id>nexus-bigdata-snapshots</id>
|
||||
<name>Bigdata Nexus Repository Snapshot</name>
|
||||
<url>http://172.16.243.137:8081/repository/maven-snapshots/</url>
|
||||
<id>simaek-nexus</id>
|
||||
<name>snapshots</name>
|
||||
<url>https://nas.xueye.io:8081/repository/maven-snapshots/</url>
|
||||
</snapshotRepository>
|
||||
|
||||
</distributionManagement>
|
||||
|
Loading…
Reference in New Issue
Block a user