Browse Source

提交开源任务材料

10.0
LAPTOP-SB56SG4Q\86185 3 years ago
parent
commit
abd55b43d1
  1. BIN
      JSD-8688需求确认书.docx
  2. 5
      README.md
  3. 26
      plugin.xml
  4. 43
      src/main/java/com/fr/plugin/dingding/webhook/OutputDBAccess.java
  5. 45
      src/main/java/com/fr/plugin/dingding/webhook/OutputPluginLifecycleMonitor.java
  6. 11
      src/main/java/com/fr/plugin/dingding/webhook/PluginConstants.java
  7. 21
      src/main/java/com/fr/plugin/dingding/webhook/dao/WebHookDao.java
  8. 62
      src/main/java/com/fr/plugin/dingding/webhook/entity/OutputWebHook.java
  9. 48
      src/main/java/com/fr/plugin/dingding/webhook/entity/WebHookEntity.java
  10. 40
      src/main/java/com/fr/plugin/dingding/webhook/format/PNGOutputFormat.java
  11. 66
      src/main/java/com/fr/plugin/dingding/webhook/fun/TicketFun.java
  12. 116
      src/main/java/com/fr/plugin/dingding/webhook/handle/WebHookHandle.java
  13. 54
      src/main/java/com/fr/plugin/dingding/webhook/js/FileDef.java
  14. 25
      src/main/java/com/fr/plugin/dingding/webhook/js/JSCSSBridge.java
  15. 66
      src/main/java/com/fr/plugin/dingding/webhook/util/DesECBUtil.java
  16. 133
      src/main/java/com/fr/plugin/dingding/webhook/util/HttpUtil.java
  17. 346
      src/main/java/com/fr/plugin/dingding/webhook/util/HttpsUtil.java
  18. 71
      src/main/resources/com/fr/plugin/dingding/webhook/theme.js

BIN
JSD-8688需求确认书.docx

Binary file not shown.

5
README.md

@ -1,3 +1,6 @@
# open-JSD-8688
JSD-8688 开源任务材料
JSD-8688 钉钉webhook推送 开源任务材料\
免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\
仅作为开发者学习参考使用!禁止用于任何商业用途!\
为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系hugh处理。

26
plugin.xml

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><plugin>
<id>com.fr.plugin.dingding.webhook</id>
<name><![CDATA[钉钉webhook]]></name>
<active>yes</active>
<version>1.4</version>
<env-version>10.0</env-version>
<jartime>2018-07-31</jartime>
<vendor>fr.open</vendor>
<description><![CDATA[钉钉webhook]]></description>
<change-notes><![CDATA[
[2021-09-06]【1.0】初始化插件<br/>
[2021-09-14]【1.1】重新打包<br/>
[2021-09-15]【1.2】增加定时调度链接传参<br/>
[2021-09-15]【1.3】增加获取默认图片<br/>
[2021-09-15]【1.4】增加授权和增加获取ticket的函数<br/>
]]></change-notes>
<lifecycle-monitor class="com.fr.plugin.dingding.webhook.OutputPluginLifecycleMonitor"/>
<extra-core>
<FunctionDefineProvider class="com.fr.plugin.dingding.webhook.fun.TicketFun" name="GetTableauTicket" description="获取ticket的函数。"/>
</extra-core>
<extra-decision>
<WebResourceProvider class="com.fr.plugin.dingding.webhook.js.JSCSSBridge"/>
<DecisionDBAccessProvider class="com.fr.plugin.dingding.webhook.OutputDBAccess"/>
</extra-decision>
<function-recorder class="com.fr.plugin.dingding.webhook.js.JSCSSBridge"/>
</plugin>

43
src/main/java/com/fr/plugin/dingding/webhook/OutputDBAccess.java

@ -0,0 +1,43 @@
package com.fr.plugin.dingding.webhook;
import com.fr.decision.plugin.db.AbstractDecisionDBAccessProvider;
import com.fr.plugin.dingding.webhook.dao.WebHookDao;
import com.fr.plugin.dingding.webhook.entity.WebHookEntity;
import com.fr.stable.db.accessor.DBAccessor;
import com.fr.stable.db.dao.BaseDAO;
import com.fr.stable.db.dao.DAOProvider;
/**
* @Author fr.open
* @Date 2020/9/15
* @Description
**/
public class OutputDBAccess extends AbstractDecisionDBAccessProvider {
private static DBAccessor dbAccessor;
public DBAccessor getDbAccessor() {
return dbAccessor;
}
@Override
public DAOProvider[] registerDAO() {
return new DAOProvider[]{
new DAOProvider() {
@Override
public Class getEntityClass() {
return WebHookEntity.class;
}
@Override
public Class<? extends BaseDAO> getDAOClass() {
return WebHookDao.class;
}
}
};
}
@Override
public void onDBAvailable(DBAccessor dbAccessor) {
OutputDBAccess.dbAccessor = dbAccessor;
}
}

45
src/main/java/com/fr/plugin/dingding/webhook/OutputPluginLifecycleMonitor.java

@ -0,0 +1,45 @@
package com.fr.plugin.dingding.webhook;
import com.fr.intelli.record.Focus;
import com.fr.intelli.record.Original;
import com.fr.plugin.context.PluginContext;
import com.fr.plugin.context.PluginContexts;
import com.fr.plugin.dingding.webhook.entity.OutputWebHook;
import com.fr.plugin.dingding.webhook.entity.WebHookEntity;
import com.fr.plugin.dingding.webhook.format.PNGOutputFormat;
import com.fr.plugin.dingding.webhook.handle.WebHookHandle;
import com.fr.plugin.observer.inner.AbstractPluginLifecycleMonitor;
import com.fr.schedule.extension.report.job.output.BaseOutputFormat;
import com.fr.schedule.feature.ScheduleOutputActionEntityRegister;
import com.fr.schedule.feature.output.OutputActionHandler;
import com.fr.stable.fun.Authorize;
/**
* @Author fr.open
* @Date 2020/9/15
* @Description
**/
@Authorize(callSignKey = PluginConstants.PLUGIN_ID)
public class OutputPluginLifecycleMonitor extends AbstractPluginLifecycleMonitor {
@Override
@Focus(id = PluginConstants.PLUGIN_ID, text = "钉钉webhook", source = Original.PLUGIN)
public void afterRun(PluginContext pluginContext) {
if (!PluginContexts.currentContext().isAvailable()) {
return;
}
BaseOutputFormat.registerOutputFormat(new PNGOutputFormat());
OutputActionHandler.registerHandler(new WebHookHandle(), OutputWebHook.class.getName());
ScheduleOutputActionEntityRegister.getInstance().addClass(WebHookEntity.class);
}
@Override
@Focus(id = PluginConstants.PLUGIN_ID, text = "钉钉webhook", source = Original.PLUGIN)
public void beforeStop(PluginContext pluginContext) {
if (!PluginContexts.currentContext().isAvailable()) {
return;
}
BaseOutputFormat.removeOutputFormat(PNGOutputFormat.CONVERT_TO_PNG);
OutputActionHandler.removeOutputHandler(OutputWebHook.class.getName());
ScheduleOutputActionEntityRegister.getInstance().removeClass(WebHookEntity.class);
}
}

11
src/main/java/com/fr/plugin/dingding/webhook/PluginConstants.java

@ -0,0 +1,11 @@
package com.fr.plugin.dingding.webhook;
/**
* @Author fr.open
* @Date 2021/3/1
* @Description
**/
public class PluginConstants {
public static final String PLUGIN_ID = "com.fr.plugin.dingding.webhook";
}

21
src/main/java/com/fr/plugin/dingding/webhook/dao/WebHookDao.java

@ -0,0 +1,21 @@
package com.fr.plugin.dingding.webhook.dao;
import com.fr.plugin.dingding.webhook.entity.WebHookEntity;
import com.fr.stable.db.dao.BaseDAO;
import com.fr.stable.db.session.DAOSession;
/**
* @Author fr.open
* @Date 2020/9/15
* @Description
**/
public class WebHookDao extends BaseDAO<WebHookEntity> {
public WebHookDao(DAOSession daoSession) {
super(daoSession);
}
@Override
protected Class<WebHookEntity> getEntityClass() {
return WebHookEntity.class;
}
}

62
src/main/java/com/fr/plugin/dingding/webhook/entity/OutputWebHook.java

@ -0,0 +1,62 @@
package com.fr.plugin.dingding.webhook.entity;
import com.fr.schedule.base.bean.output.BaseOutputAction;
import com.fr.schedule.base.entity.AbstractScheduleEntity;
import com.fr.schedule.base.type.RunType;
import com.fr.third.fasterxml.jackson.annotation.JsonSubTypes;
/**
* @Author fr.open
* @Date 2020/9/15
* @Description
**/
@JsonSubTypes.Type(value = OutputWebHook.class, name = "OutputWebHook")
public class OutputWebHook extends BaseOutputAction {
private static final long serialVersionUID = 8921116228585639504L;
private String hookUrl = null;
public OutputWebHook() {
super();
}
@Override
public boolean willExecuteByUser() {
return false;
}
@Override
public RunType runType() {
return RunType.SEND_FILE;
}
@Override
public Class<? extends AbstractScheduleEntity> outputActionEntityClass() {
return WebHookEntity.class;
}
@Override
public AbstractScheduleEntity createOutputActionEntity() {
return (new WebHookEntity()).id(this.getId()).hookUrl(this.hookUrl);
}
@Override
public OutputWebHook id(String id) {
setId(id);
return this;
}
public String getHookUrl() {
return hookUrl;
}
public void setHookUrl(String hookUrl) {
this.hookUrl = hookUrl;
}
public OutputWebHook hookUrl(String hookUrl) {
setHookUrl(hookUrl);
return this;
}
}

48
src/main/java/com/fr/plugin/dingding/webhook/entity/WebHookEntity.java

@ -0,0 +1,48 @@
package com.fr.plugin.dingding.webhook.entity;
import com.fr.schedule.base.bean.BaseBean;
import com.fr.schedule.base.entity.AbstractScheduleEntity;
import com.fr.stable.db.entity.TableAssociation;
import com.fr.third.javax.persistence.Column;
import com.fr.third.javax.persistence.Entity;
import com.fr.third.javax.persistence.Table;
/**
* @Author fr.open
* @Date 2020/9/15
* @Description
**/
@Entity
@Table(name = "fine_output_dingding_webHook") //表名
@TableAssociation(associated = true)
public class WebHookEntity extends AbstractScheduleEntity {
@Column(name = "hookUrl")
private String hookUrl;
public WebHookEntity() {
}
@Override
public BaseBean createBean() {
return new OutputWebHook().id(this.getId()).hookUrl(this.hookUrl);
}
public String getHookUrl() {
return hookUrl;
}
public void setHookUrl(String hookUrl) {
this.hookUrl = hookUrl;
}
public WebHookEntity hookUrl(String hookUrl) {
setHookUrl(hookUrl);
return this;
}
public WebHookEntity id(String id) {
setId(id);
return this;
}
}

40
src/main/java/com/fr/plugin/dingding/webhook/format/PNGOutputFormat.java

@ -0,0 +1,40 @@
package com.fr.plugin.dingding.webhook.format;
import com.fr.io.exporter.ImageExporter;
import com.fr.main.workbook.ResultWorkBook;
import com.fr.schedule.extension.report.job.output.BaseOutputFormat;
import java.io.OutputStream;
import java.util.List;
/**
* @Author fr.open
* @Date 2020/9/15
* @Description
**/
public class PNGOutputFormat extends BaseOutputFormat {
public static final int CONVERT_TO_PNG = 64;
public PNGOutputFormat() {
}
@Override
public int getFormat() {
return CONVERT_TO_PNG;
}
@Override
public String getFileSuffix() {
return ".png";
}
@Override
public boolean withParentPath() {
return true;
}
@Override
public void flushWithParentPath(OutputStream var1, ResultWorkBook var2, String var3, final List<String> var4) throws Exception {
new ImageExporter("png", 96).export(var1, var2);
}
}

66
src/main/java/com/fr/plugin/dingding/webhook/fun/TicketFun.java

@ -0,0 +1,66 @@
package com.fr.plugin.dingding.webhook.fun;
import com.fr.general.http.HttpRequest;
import com.fr.general.http.HttpToolbox;
import com.fr.intelli.record.Focus;
import com.fr.intelli.record.Original;
import com.fr.log.FineLoggerFactory;
import com.fr.plugin.context.PluginContexts;
import com.fr.plugin.dingding.webhook.PluginConstants;
import com.fr.script.AbstractFunction;
import com.fr.stable.ArrayUtils;
import com.fr.stable.Primitive;
import com.fr.stable.StringUtils;
import com.fr.stable.exception.FormulaException;
import com.fr.stable.fun.Authorize;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* @Author fr.open
* @Date 2021/9/15
* @Description
**/
@Authorize(callSignKey = PluginConstants.PLUGIN_ID)
public class TicketFun extends AbstractFunction {
@Override
@Focus(id = PluginConstants.PLUGIN_ID, text = "钉钉webhook", source = Original.PLUGIN)
public Object run(Object[] args) throws FormulaException {
if (!PluginContexts.currentContext().isAvailable()) {
return null;
}
int len = ArrayUtils.getLength(args);
if (len == 0) {
return Primitive.ERROR_VALUE;
}
String user = (String) args[0];
String target = (String) args[1];
if(StringUtils.isBlank(user) || StringUtils.isBlank(target)){
return Primitive.ERROR_VALUE;
}
String url =StringUtils.EMPTY;
if(args.length < 3){
url = "http://1xxxx/trusted";
}else {
url = (String) args[2];
if(StringUtils.isBlank(url)){
url = "http://xxxx/trusted";
}
}
Map<String, String> param = new HashMap<>();
param.put("username",user);
param.put("target_site",target);
try {
String execute = HttpToolbox.executeAndParse(HttpRequest.custom().post(param).url(url).build());
return execute;
} catch (IOException e) {
FineLoggerFactory.getLogger().error(e.getMessage(),e);
}
return null;
}
}

116
src/main/java/com/fr/plugin/dingding/webhook/handle/WebHookHandle.java

@ -0,0 +1,116 @@
package com.fr.plugin.dingding.webhook.handle;
import com.fr.base.Formula;
import com.fr.base.PropertiesUtils;
import com.fr.io.utils.ResourceIOUtils;
import com.fr.json.JSONObject;
import com.fr.log.FineLoggerFactory;
import com.fr.plugin.dingding.webhook.entity.OutputWebHook;
import com.fr.plugin.dingding.webhook.util.DesECBUtil;
import com.fr.plugin.dingding.webhook.util.HttpUtil;
import com.fr.schedule.base.constant.ScheduleConstants;
import com.fr.schedule.feature.output.OutputActionHandler;
import com.fr.stable.CodeUtils;
import com.fr.stable.StringUtils;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
/**
* @Author fr.open
* @Date 2020/9/15
* @Description
**/
public class WebHookHandle extends OutputActionHandler<OutputWebHook> {
private static final String key = "xxxx";
private static final String file = "/resources/Robot.png";
@Override
public void doAction(OutputWebHook outputWebHook, Map<String, Object> map) throws Exception {
String[] files = (String[]) map.get(ScheduleConstants.OUTPUT_FILES);
getUrl(outputWebHook, map);
String mediaId = StringUtils.EMPTY;
String imageFile = StringUtils.EMPTY;
if(ResourceIOUtils.exist(file)){
FineLoggerFactory.getLogger().info("read default image {}",file);
imageFile = file;
}else {
for (String file : files) {
if (file.endsWith("png")) {
imageFile = file;
continue;
}
}
}
JSONObject object = HttpUtil.uploadMedia(imageFile);
FineLoggerFactory.getLogger().info("upload media res is {}", object);
if (HttpUtil.isOk(object)) {
mediaId = object.getJSONObject("url").getString("media_id");
}
if (StringUtils.isBlank(mediaId)) {
throw new Exception("not contain media or upload failed");
}
String taskName = CodeUtils.encodeURIComponent((String) map.get(ScheduleConstants.TASK_NAME));
String path = CodeUtils.encodeURIComponent((String) map.get(ScheduleConstants.SAVE_DIRECTORY));
path = path.replaceAll("\\+", "%20");
String showType = (String) map.get(ScheduleConstants.SHOW_TYPE);
int taskType = (Integer) map.get(ScheduleConstants.TASK_TYPE);
String scheduleUsername = (String) map.get(ScheduleConstants.USERNAME);
String resultUrl = getParam(map, "resultUrl");
String mobileUrl = outputWebHook.getResultURL()+"/url/mobile/schedule/result?taskName=" + taskName + "&username=" + scheduleUsername + "&path=" + path + "&showType=" + showType + "&taskType=" + taskType;
HttpUtil.sendWebhook(mediaId, outputWebHook.getHookUrl(), getParam(map, "title"), getParam(map, "text"), delaSign(StringUtils.isNotBlank(resultUrl)?resultUrl:mobileUrl));
}
private String delaSign(String url) {
String path = url;
try {
String user = PropertiesUtils.getProperties("dingtalk").getProperty("resultUser");
String encode = URLEncoder.encode(DesECBUtil.encryptDES(user, key), "UTF-8");
if (path.indexOf("?") != -1) {
path += "&result_sign=" + encode;
} else {
path += "?result_sign=" + encode;
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
FineLoggerFactory.getLogger().info("push dingding url is {}",path);
return path+"&op=h5";
}
private String getParam(Map<String, Object> map, String p) {
List<Map> list = (List) map.get(ScheduleConstants.RECORD_LIST);
Object title = StringUtils.EMPTY;
Object param = list.get(0).get(p);
if (param instanceof Formula) {
Formula formula = (Formula) param;
title = formula.getResult();
} else {
title = param.toString();
}
return title.toString();
}
private String getUrl(OutputWebHook outputWebHook, Map<String, Object> map) {
String taskName = CodeUtils.encodeURIComponent((String) map.get(ScheduleConstants.TASK_NAME));
String path = CodeUtils.encodeURIComponent((String) map.get(ScheduleConstants.SAVE_DIRECTORY));
path = path.replaceAll("\\+", "%20");
String showType = (String) map.get(ScheduleConstants.SHOW_TYPE);
int taskType = (Integer) map.get(ScheduleConstants.TASK_TYPE);
String scheduleUsername = (String) map.get(ScheduleConstants.USERNAME);
return outputWebHook.getResultURL() + "/url/mobile/schedule/result?taskName=" + taskName + "&username=" + scheduleUsername + "&path=" + path + "&showType=" + showType + "&taskType=" + taskType;
}
private JSONObject getJSONObject(String md5, String base) {
JSONObject obj = JSONObject.create();
obj.put("msgtype", "image");
JSONObject image = JSONObject.create();
image.put("base64", base);
image.put("md5", md5);
obj.put("image", image);
return obj;
}
}

54
src/main/java/com/fr/plugin/dingding/webhook/js/FileDef.java

@ -0,0 +1,54 @@
package com.fr.plugin.dingding.webhook.js;
import com.fr.plugin.transform.ExecuteFunctionRecord;
import com.fr.web.struct.Component;
import com.fr.web.struct.Filter;
import com.fr.web.struct.browser.RequestClient;
import com.fr.web.struct.category.ScriptPath;
import com.fr.web.struct.category.StylePath;
/**
* @author fr.open
* @date 2021/9/15
*/
public class FileDef extends Component {
public static final FileDef KEY = new FileDef();
private FileDef(){}
/**
* 返回需要引入的JS脚本路径
* @param client 请求客户端描述
* @return JS脚本路径
*/
@Override
public ScriptPath script(RequestClient client ) {
//如果不需要就直接返回 ScriptPath.EMPTY
return ScriptPath.build("com/fr/plugin/dingding/webhook/theme.js");
}
/**
* 返回需要引入的CSS样式路径
* @param client 请求客户端描述
* @return CSS样式路径
*/
@Override
public StylePath style(RequestClient client ) {
//如果不需要就直接返回 StylePath.EMPTY;
return StylePath.EMPTY;
}
/**
* 通过给定的资源过滤器控制是否加载这个资源
* @return 资源过滤器
*/
@ExecuteFunctionRecord
@Override
public Filter filter() {
return new Filter(){
@Override
public boolean accept() {
//任何情况下我们都在平台组件加载时加载我们的组件
return true;
}
};
}
}

25
src/main/java/com/fr/plugin/dingding/webhook/js/JSCSSBridge.java

@ -0,0 +1,25 @@
package com.fr.plugin.dingding.webhook.js;
import com.fr.decision.fun.impl.AbstractWebResourceProvider;
import com.fr.decision.web.MainComponent;
import com.fr.plugin.transform.FunctionRecorder;
import com.fr.web.struct.Atom;
/**
* @author open
* @date 2021/9/15
*/
@FunctionRecorder
public class JSCSSBridge extends AbstractWebResourceProvider {
@Override
public Atom attach() {
//在平台主组件加载时添加我们自己的组件
return MainComponent.KEY;
}
@Override
public Atom client() {
//我们自己要引入的组件
return FileDef.KEY;
}
}

66
src/main/java/com/fr/plugin/dingding/webhook/util/DesECBUtil.java

@ -0,0 +1,66 @@
package com.fr.plugin.dingding.webhook.util;
import com.fr.third.org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
/**
* @Author fr.open
* @Date 2020/9/15
* @Description
**/
public class DesECBUtil {
/**
* 加密数据
*
* @param encryptString
* @param encryptKey
* @return
* @throws Exception
*/
public static String encryptDES(String encryptString, String encryptKey) throws Exception {
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(getKey(encryptKey), "DES"));
byte[] encryptedData = cipher.doFinal(encryptString.getBytes("UTF-8"));
return Base64.encodeBase64String(encryptedData);
}
/**
* key 不足8位补位
*
* @param
*/
public static byte[] getKey(String keyRule) {
Key key = null;
byte[] keyByte = keyRule.getBytes();
// 创建一个空的八位数组,默认情况下为0
byte[] byteTemp = new byte[8];
// 将用户指定的规则转换成八位数组
for (int i = 0; i < byteTemp.length && i < keyByte.length; i++) {
byteTemp[i] = keyByte[i];
}
key = new SecretKeySpec(byteTemp, "DES");
return key.getEncoded();
}
/***
* 解密数据
* @param decryptString
* @param decryptKey
* @return
* @throws Exception
*/
public static String decryptDES(String decryptString, String decryptKey) throws Exception {
byte[] sourceBytes = Base64.decodeBase64(decryptString);
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(getKey(decryptKey), "DES"));
byte[] decoded = cipher.doFinal(sourceBytes);
return new String(decoded, "UTF-8");
}
}

133
src/main/java/com/fr/plugin/dingding/webhook/util/HttpUtil.java

@ -0,0 +1,133 @@
package com.fr.plugin.dingding.webhook.util;
import com.fr.general.PropertiesUtils;
import com.fr.io.utils.ResourceIOUtils;
import com.fr.json.JSONObject;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.StringUtils;
import com.fr.third.org.apache.http.NameValuePair;
import com.fr.third.org.apache.http.client.entity.UrlEncodedFormEntity;
import com.fr.third.org.apache.http.entity.ContentType;
import com.fr.third.org.apache.http.entity.mime.HttpMultipartMode;
import com.fr.third.org.apache.http.entity.mime.MultipartEntityBuilder;
import com.fr.third.org.apache.http.message.BasicNameValuePair;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Author fr.open
* @Date 2020/9/15
* @Description
**/
public class HttpUtil {
public static JSONObject uploadMedia(String path) {
JSONObject result = null;
InputStream fileInputStream = ResourceIOUtils.read(path);
String fileName = ResourceIOUtils.getName(path);
// 定时调度图片没有后缀名,用钉钉上传文件接口以type=image的方式传会返回错误,这里伪造一个后缀
fileName = addSuffixToScheduleImage(fileName, ".jpg");
if (fileInputStream == null || StringUtils.isEmpty(fileName)) {
FineLoggerFactory.getLogger().warn(String.format("%s路径下未能找到文件!", path));
} else {
try {
MultipartEntityBuilder builder = MultipartEntityBuilder.create()
.setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
.setContentType(ContentType.MULTIPART_FORM_DATA)
.addBinaryBody("media", ResourceIOUtils.read(path), ContentType.MULTIPART_FORM_DATA, new String(fileName.getBytes("UTF-8"), "ISO_8859_1"));
Map<String,Object> header = new HashMap();
header.put("Content-type", "multipart/form-data");
String res = HttpsUtil.doEntityPost(uploadMediaUrl("image"),null,builder.build());
result = new JSONObject(res);
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(),e);
}
}
return result;
}
public static String uploadMediaUrl(String type) {
return String.format(getBaseUrl() + "/xxxx=%s&type=%s", getCode(), type);
}
private static String getCode() {
String property = PropertiesUtils.getProperties("dingtalk").getProperty("yuyuan_syscode");
return property;
}
private static String getBaseUrl() {
String property = PropertiesUtils.getProperties("dingtalk").getProperty("host");
return property;
}
public static String addSuffixToScheduleImage(String fileName, String suffix) {
if (!StringUtils.contains(fileName, ".")) {
return fileName + suffix;
}
return fileName;
}
public static boolean isOk(JSONObject result) {
return result != null && result.optInt("code", -999)
==1;
}
public static String sendMessageUrl(String token) {
return getBaseUrl() + "/xxxx=" + token;
}
public static String sendWebhook( String meadia, String hookUrl,String title, String text, String url) throws IOException {
String path = String.format(getBaseUrl() + "/xxxx=%s", getCode());
String result = null;
try {
List<NameValuePair> params = new ArrayList();
params.add(new BasicNameValuePair("webhook", hookUrl));
params.add(new BasicNameValuePair("x_yuyuan_sc", getCode()));
params.add(new BasicNameValuePair("msgtype", "card"));
params.add(new BasicNameValuePair("media_id", meadia));
params.add(new BasicNameValuePair("title", title));
params.add(new BasicNameValuePair("text", text));
params.add(new BasicNameValuePair("singleURL", url));
UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(params, "UTF-8");
Map<String,Object> header = new HashMap();
header.put("Content-type", "application/x-www-form-urlencoded");
result = HttpsUtil.doEntityPost(path,header,urlEncodedFormEntity);
FineLoggerFactory.getLogger().info("send webhook result is {}", result);
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
throw e;
}
return result;
}
public static void getMessage(String msgid) throws Exception {
List<NameValuePair> params = new ArrayList();
params.add(new BasicNameValuePair("msg_id", msgid));
UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(params, "UTF-8");
Map<String,Object> header = new HashMap();
header.put("Content-type", "application/x-www-form-urlencoded");
String result = null;
try {
result = HttpsUtil.doEntityPost(messageUrl(getCode()),header,urlEncodedFormEntity);
FineLoggerFactory.getLogger().info("query message result is {}", result);
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
throw e;
}
JSONObject res = new JSONObject(result);
if (res.getInt("code") == 0) {
throw new Exception("get message error is" + res.getString("msg"));
}
}
private static String messageUrl(String token) {
return getBaseUrl() + "/xxxx=" + token;
}
}

346
src/main/java/com/fr/plugin/dingding/webhook/util/HttpsUtil.java

@ -0,0 +1,346 @@
package com.fr.plugin.dingding.webhook.util;
import com.fr.json.JSONObject;
import com.fr.log.FineLoggerFactory;
import com.fr.third.org.apache.http.HttpEntity;
import com.fr.third.org.apache.http.HttpResponse;
import com.fr.third.org.apache.http.HttpStatus;
import com.fr.third.org.apache.http.client.HttpClient;
import com.fr.third.org.apache.http.client.methods.HttpPost;
import com.fr.third.org.apache.http.config.Registry;
import com.fr.third.org.apache.http.config.RegistryBuilder;
import com.fr.third.org.apache.http.conn.socket.ConnectionSocketFactory;
import com.fr.third.org.apache.http.conn.socket.PlainConnectionSocketFactory;
import com.fr.third.org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import com.fr.third.org.apache.http.entity.StringEntity;
import com.fr.third.org.apache.http.impl.client.HttpClients;
import com.fr.third.org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import com.fr.third.org.apache.http.util.EntityUtils;
import javax.net.ssl.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.cert.CertificateException;
import java.util.Iterator;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @Author fr.open
* @Date 2020/9/15
* @Description
**/
public class HttpsUtil {
private static HostnameVerifier hv = new HostnameVerifier() {
@Override
public boolean verify(String urlHostName, SSLSession session) {
System.out.println("Warning: URL Host: " + urlHostName + " vs. "
+ session.getPeerHost());
return true;
}
};
/**
* 发送get请求
*
* @param url
* @param param
* @param header
* @return
* @throws IOException
*/
public static String sendGet(String url, Map<String, String> param, Map<String, String> header) {
String result = "";
BufferedReader in = null;
String urlNameString = url;
try {
if (param != null) {
urlNameString += "?";
urlNameString += param.entrySet()
.stream()
.map(entry -> entry.getKey() + "=" + entry.getValue())
.collect(Collectors.joining("&"));
}
URL realUrl = new URL(urlNameString);
// 打开和URL之间的连接
HttpURLConnection connection;
if (url.startsWith("https")) {
trustAllHttpsCertificates();
HttpsURLConnection.setDefaultHostnameVerifier(hv);
connection = (HttpURLConnection) realUrl.openConnection();
} else {
connection = (HttpURLConnection) realUrl.openConnection();
}
//设置超时时间
connection.setDoInput(true);
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
connection.setReadTimeout(15000);
// 设置通用的请求属性
if (header != null) {
Iterator<Map.Entry<String, String>> it = header.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
System.out.println(entry.getKey() + ":::" + entry.getValue());
connection.setRequestProperty(entry.getKey(), entry.getValue());
}
}
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 建立实际的连接
connection.connect();
// 定义 BufferedReader输入流来读取URL的响应,设置utf8防止中文乱码
in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
if (in != null) {
in.close();
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e, "get url error ,url is:{},error is {}", urlNameString, e.getMessage());
}
return result;
}
public static String sendPost(String url, Map<String, Object> header, JSONObject body) {
PrintWriter out = null;
BufferedReader in = null;
String result = null;
String res = null;
try {
String urlNameString = url;
URL realUrl = new URL(urlNameString);
// 打开和URL之间的连接
HttpURLConnection conn;
if (url.startsWith("https")) {
trustAllHttpsCertificates();
HttpsURLConnection.setDefaultHostnameVerifier(hv);
conn = (HttpURLConnection) realUrl.openConnection();
} else {
conn = (HttpURLConnection) realUrl.openConnection();
}
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
// conn.setRequestProperty("user-agent",
// "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
if (header != null) {
header.forEach((k, v) -> {
conn.setRequestProperty(k, String.valueOf(v));
});
}
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
//获取请求头
// 获取URLConnection对象对应的输出流
out = new PrintWriter(conn.getOutputStream());
// 发送请求参数
if (body != null) {
FineLoggerFactory.getLogger().error("content data: {}", body.toString());
FineLoggerFactory.getLogger().error("content cover data: {}", new String(body.toString().getBytes("UTF-8"), "UTF-8"));
out.print(new String(body.toString().getBytes("UTF-8"), "UTF-8"));
}
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
res = result;
if (res.startsWith("null")) {
res = res.replace("null", "");
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
//使用finally块来关闭输出流、输入流
finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
return res;
}
public static String doPost(String url, Map<String, Object> header, JSONObject json) {
HttpClient client = HttpClients.createDefault();
if (url.startsWith("https")) {
SSLContext sslcontext = createIgnoreVerifySSL();
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", new SSLConnectionSocketFactory(sslcontext))
.build();
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
HttpClients.custom().setConnectionManager(connManager);
client = HttpClients.custom().setConnectionManager(connManager).build();
}
HttpPost post = new HttpPost(url);
post.setHeader("accept", "*/*");
post.setHeader("connection", "Keep-Alive");
post.setHeader("Content-Type", "application/json");
if (header != null) {
header.forEach((k, v) -> {
post.setHeader(k, String.valueOf(v));
});
}
try {
StringEntity s = new StringEntity(json.toString(),"UTF-8");
s.setContentEncoding("UTF-8");
s.setContentType("application/json; charset=UTF-8");//发送json数据需要设置contentType
post.setEntity(s);
HttpResponse res = client.execute(post);
if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
String result = EntityUtils.toString(res.getEntity());// 返回json格式:
return result;
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(),e);
}
return null;
}
public static String doEntityPost(String url, Map<String, Object> header, HttpEntity entity) {
HttpClient client = HttpClients.createDefault();
if (url.startsWith("https")) {
SSLContext sslcontext = createIgnoreVerifySSL();
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", new SSLConnectionSocketFactory(sslcontext))
.build();
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
HttpClients.custom().setConnectionManager(connManager);
client = HttpClients.custom().setConnectionManager(connManager).build();
}
HttpPost post = new HttpPost(url);
post.setHeader("accept", "*/*");
post.setHeader("connection", "Keep-Alive");
if (header != null) {
header.forEach((k, v) -> {
post.setHeader(k, String.valueOf(v));
});
}
try {
post.setEntity(entity);
HttpResponse res = client.execute(post);
if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
String result = EntityUtils.toString(res.getEntity());// 返回json格式:
return result;
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(),e);
}
return null;
}
private static void trustAllHttpsCertificates() throws Exception {
TrustManager[] trustAllCerts = new TrustManager[1];
TrustManager tm = new miTM();
trustAllCerts[0] = tm;
SSLContext sc = SSLContext.getInstance("SSL", "SunJSSE");
sc.init(null, trustAllCerts, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
/**
* encode url by UTF-8
*
* @param url url before encoding
* @return url after encoding
*/
public static String encodeUrl(String url) {
String eurl = url;
try {
eurl = URLEncoder.encode(url, "UTF-8");
} catch (UnsupportedEncodingException e) {
}
return eurl;
}
private static class miTM implements TrustManager,
X509TrustManager {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public boolean isServerTrusted(
java.security.cert.X509Certificate[] certs) {
return true;
}
public boolean isClientTrusted(
java.security.cert.X509Certificate[] certs) {
return true;
}
@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType)
throws CertificateException {
return;
}
@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType)
throws CertificateException {
return;
}
}
public static SSLContext createIgnoreVerifySSL() {
try {
SSLContext sc = SSLContext.getInstance("SSLv3");
// 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法
X509TrustManager trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) throws CertificateException {
}
@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sc.init(null, new TrustManager[]{trustManager}, null);
return sc;
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
return null;
}
}

71
src/main/resources/com/fr/plugin/dingding/webhook/theme.js

@ -0,0 +1,71 @@
!(function () {
BI.config("dec.provider.schedule", function (provider) {
provider.registerTaskAttached({
value: 64,
text: "png"
}, [DecCst.Schedule.TaskType.REPORT, DecCst.Schedule.TaskType.BI]);
});
var Plugin = BI.inherit(BI.Widget, {
props: {
baseCls: "",
value: {
hookUrl: null,
}
},
render: function () {
var t = this,
e = this.options.value[0]==undefined?{hookUrl: null}: this.options.value[0];
return {
type: "bi.flex_vertical",
tgap: 15,
items: [{
type: "dec.label.editor.item",
errorTop: 16,
textCls: "dec-font-weight-bold",
text: "webHookUrl",
textWidth: 115,
editorWidth: 300,
value: e.hookUrl,
ref: function(e) {
t.hookUrl = e
}
}]
};
},
/**
*
*
* @returns {boolean}
*/
validation: function () {
var e = !0,
t = this.isVisible();
return BI.isEmpty(this.hookUrl.getValue()) && (t && this.hookUrl.showError(BI.i18nText("Dec-Error_Null")), e = !1),
e
},
/**
*
* outputActionList
* @returns {{}}
*/
getValue: function() {
var _self= this;
return {OutputWebHook: BI.extend(_self.value,{
"@class": "com.fr.plugin.dingding.webhook.entity.OutputWebHook",
actionName: "com.fr.plugin.dingding.webhook.entity.OutputWebHook",
hookUrl: _self.hookUrl.getValue(),
})}
},
});
BI.shortcut("dec.schedule.task.file.handling.plugin", Plugin);
BI.config("dec.provider.schedule", function (provider) {
provider.registerHandingWay({
text: "webHook",
value: "com.fr.plugin.dingding.webhook.entity.OutputWebHook", // actionName
cardType: "dec.schedule.task.file.handling.plugin",
actions: [] // action
}, [DecCst.Schedule.TaskType.DEFAULT, DecCst.Schedule.TaskType.REPORT, DecCst.Schedule.TaskType.BI]);
});
}());
Loading…
Cancel
Save