@ -1,41 +0,0 @@ |
|||||||
#Maintin by jimmy |
|
||||||
#Email: zhengge2012@gmail.com |
|
||||||
FROM anapsix/alpine-java:8_jdk |
|
||||||
WORKDIR /tmp |
|
||||||
RUN wget http://archive.apache.org/dist/maven/maven-3/3.6.1/binaries/apache-maven-3.6.1-bin.tar.gz |
|
||||||
RUN tar -zxvf apache-maven-3.6.1-bin.tar.gz && rm apache-maven-3.6.1-bin.tar.gz |
|
||||||
RUN mv apache-maven-3.6.1 /usr/lib/mvn |
|
||||||
RUN chown -R root:root /usr/lib/mvn |
|
||||||
RUN ln -s /usr/lib/mvn/bin/mvn /usr/bin/mvn |
|
||||||
RUN wget https://archive.apache.org/dist/zookeeper/zookeeper-3.4.6/zookeeper-3.4.6.tar.gz |
|
||||||
RUN tar -zxvf zookeeper-3.4.6.tar.gz |
|
||||||
RUN mv zookeeper-3.4.6 /opt/zookeeper |
|
||||||
RUN rm -rf zookeeper-3.4.6.tar.gz |
|
||||||
RUN echo "export ZOOKEEPER_HOME=/opt/zookeeper" >>/etc/profile |
|
||||||
RUN echo "export PATH=$PATH:$ZOOKEEPER_HOME/bin" >>/etc/profile |
|
||||||
ADD conf/zoo.cfg /opt/zookeeper/conf/zoo.cfg |
|
||||||
#RUN source /etc/profile |
|
||||||
#RUN zkServer.sh start |
|
||||||
RUN apk add --no-cache git npm nginx mariadb mariadb-client mariadb-server-utils pwgen |
|
||||||
WORKDIR /opt |
|
||||||
RUN git clone https://github.com/analysys/EasyScheduler.git |
|
||||||
WORKDIR /opt/EasyScheduler |
|
||||||
RUN mvn -U clean package assembly:assembly -Dmaven.test.skip=true |
|
||||||
RUN mv /opt/EasyScheduler/target/escheduler-1.0.0-SNAPSHOT /opt/easyscheduler |
|
||||||
WORKDIR /opt/EasyScheduler/escheduler-ui |
|
||||||
RUN npm install |
|
||||||
RUN npm audit fix |
|
||||||
RUN npm run build |
|
||||||
RUN mkdir -p /opt/escheduler/front/server |
|
||||||
RUN cp -rfv dist/* /opt/escheduler/front/server |
|
||||||
WORKDIR / |
|
||||||
RUN rm -rf /opt/EasyScheduler |
|
||||||
#configure mysql server https://github.com/yobasystems/alpine-mariadb/tree/master/alpine-mariadb-amd64 |
|
||||||
ADD conf/run.sh /scripts/run.sh |
|
||||||
RUN mkdir /docker-entrypoint-initdb.d && \ |
|
||||||
mkdir /scripts/pre-exec.d && \ |
|
||||||
mkdir /scripts/pre-init.d && \ |
|
||||||
chmod -R 755 /scripts |
|
||||||
RUN rm -rf /var/cache/apk/* |
|
||||||
EXPOSE 8888 |
|
||||||
ENTRYPOINT ["/scripts/run.sh"] |
|
@ -0,0 +1,53 @@ |
|||||||
|
Easy Scheduler Release 1.0.3 |
||||||
|
=== |
||||||
|
Easy Scheduler 1.0.3是1.x系列中的第四个版本。 |
||||||
|
|
||||||
|
新特性: |
||||||
|
=== |
||||||
|
- [[EasyScheduler-254](https://github.com/analysys/EasyScheduler/issues/254)] 流程定义删除和批量删除 |
||||||
|
- [[EasyScheduler-347](https://github.com/analysys/EasyScheduler/issues/347)] 任务依赖增加“今日” |
||||||
|
- [[EasyScheduler-273](https://github.com/analysys/EasyScheduler/issues/273)]sql任务添加title |
||||||
|
- [[EasyScheduler-247](https://github.com/analysys/EasyScheduler/issues/247)]API在线文档 |
||||||
|
- [[EasyScheduler-319](https://github.com/analysys/EasyScheduler/issues/319)] 单机容错 |
||||||
|
- [[EasyScheduler-253](https://github.com/analysys/EasyScheduler/issues/253)] 项目增加流程定义统计和运行流程实例统计 |
||||||
|
- [[EasyScheduler-292](https://github.com/analysys/EasyScheduler/issues/292)] 启用SSL的邮箱发送邮件 |
||||||
|
- [[EasyScheduler-77](https://github.com/analysys/EasyScheduler/issues/77)] 定时管理、工作流定义添加删除功能 |
||||||
|
- [[EasyScheduler-380](https://github.com/analysys/EasyScheduler/issues/380)] 服务监控功能 |
||||||
|
- [[EasyScheduler-380](https://github.com/analysys/EasyScheduler/issues/382)] 项目增加流程定义统计和运行流程实例统计 |
||||||
|
|
||||||
|
增强: |
||||||
|
=== |
||||||
|
- [[EasyScheduler-192](https://github.com/analysys/EasyScheduler/issues/192)] 租户删除前可以考虑校验租户和资源 |
||||||
|
- [[EasyScheduler-376](https://github.com/analysys/EasyScheduler/issues/294)] 删除实例时候,没有删除对应zookeeper队列里的任务 |
||||||
|
- [[EasyScheduler-185](https://github.com/analysys/EasyScheduler/issues/185)] 项目删除工作流定义还存在 |
||||||
|
- [[EasyScheduler-206](https://github.com/analysys/EasyScheduler/issues/206)] 优化部署,完善docker化支持 |
||||||
|
- [[EasyScheduler-381](https://github.com/analysys/EasyScheduler/issues/381)] 前端一键部署脚本支持ubuntu |
||||||
|
|
||||||
|
修复: |
||||||
|
=== |
||||||
|
- [[EasyScheduler-255](https://github.com/analysys/EasyScheduler/issues/255)]子父流程全局变量覆盖,子流程继承父流程全局变量并可以重写 |
||||||
|
- [[EasyScheduler-256](https://github.com/analysys/EasyScheduler/issues/256)]子父流程参数显示异常 |
||||||
|
- [[EasyScheduler-186](https://github.com/analysys/EasyScheduler/issues/186)]所有查询中只要输入%会返回所有数据 |
||||||
|
- [[EasyScheduler-185](https://github.com/analysys/EasyScheduler/issues/185)]项目删除工作流定义还存在 |
||||||
|
- [[EasyScheduler-266](https://github.com/analysys/EasyScheduler/issues/266)]Stop process return: process definition 1 not on line |
||||||
|
- [[EasyScheduler-300](https://github.com/analysys/EasyScheduler/issues/300)] 超时告警时间单位 |
||||||
|
- [[EasyScheduler-235](https://github.com/analysys/EasyScheduler/issues/235)]nginx超时连接问题修复 |
||||||
|
- [[EasyScheduler-272](https://github.com/analysys/EasyScheduler/issues/272)]管理员不能生成token |
||||||
|
- [[EasyScheduler-272](https://github.com/analysys/EasyScheduler/issues/277)]save global parameters error |
||||||
|
- [[EasyScheduler-183](https://github.com/analysys/EasyScheduler/issues/183)]创建中文名称的Worker分组报错 |
||||||
|
- [[EasyScheduler-377](https://github.com/analysys/EasyScheduler/issues/377)]资源文件重命名只修改描述时会报名称已存在错误 |
||||||
|
- [[EasyScheduler-235](https://github.com/analysys/EasyScheduler/issues/235)]创建spark数据源,点击“测试连接”,系统回退回到登入页面 |
||||||
|
- [[EasyScheduler-83](https://github.com/analysys/EasyScheduler/issues/83)]1.0.1版本启动api server报错 |
||||||
|
- [[EasyScheduler-379](https://github.com/analysys/EasyScheduler/issues/379)]跨天恢复执行定时任务时,时间参数不对 |
||||||
|
- [[EasyScheduler-383](https://github.com/analysys/EasyScheduler/issues/383)]sql邮件不显示前面的空行 |
||||||
|
|
||||||
|
|
||||||
|
感谢: |
||||||
|
=== |
||||||
|
最后但最重要的是,没有以下伙伴的贡献就没有新版本的诞生: |
||||||
|
|
||||||
|
Baoqi, jimmy201602, samz406, petersear, millionfor, hyperknob, fanguanqun, yangqinlong, qq389401879, |
||||||
|
feloxx, coding-now, hymzcn, nysyxxg, chgxtony |
||||||
|
|
||||||
|
以及微信群里众多的热心伙伴!在此非常感谢! |
||||||
|
|
@ -0,0 +1,96 @@ |
|||||||
|
Q:单机运行服务老挂,应该是内存不够,测试机器4核8G。生产环境需要分布式,如果单机的话建议的配置是? |
||||||
|
|
||||||
|
A: Easy Scheduler有5个服务组成,这些服务本身需要的内存和cpu不多, |
||||||
|
|
||||||
|
| 服务 | 内存 | cpu核数 | |
||||||
|
| ------------ | ---- | ------- | |
||||||
|
| MasterServer | 2G | 2核 | |
||||||
|
| WorkerServer | 2G | 2核 | |
||||||
|
| ApiServer | 512M | 1核 | |
||||||
|
| AlertServer | 512M | 1核 | |
||||||
|
| LoggerServer | 512M | 1核 | |
||||||
|
|
||||||
|
注意:由于如果任务较多,WorkServer所在机器建议物理内存在16G以上 |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
Q: 管理员为什么不能创建项目? |
||||||
|
|
||||||
|
A: 管理员目前属于"纯管理", 没有租户,即没有linux上对应的用户,所以没有执行权限, 但是有所有的查看权限。如果需要创建项目等业务操作,请使用管理员创建租户和普通用户,然后使用普通用户登录进行操作 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
Q: 系统支持哪些邮箱? |
||||||
|
|
||||||
|
A: 支持绝大多数邮箱,qq、163、126、139、outlook、aliyun等皆可支持 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
Q:常用的系统变量时间参数有哪些,如何使用? |
||||||
|
|
||||||
|
A: 请参考使用手册中的系统参数 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
Q:pip install kazoo 这个安装报错。是必须安装的吗? |
||||||
|
|
||||||
|
A: 这个是python连接zookeeper需要使用到的 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
Q: 如果alert、api、logger服务任意一个宕机,任何还会正常执行吧 |
||||||
|
|
||||||
|
A: 不影响,影响正在运行中的任务的服务有Master和Worker服务 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
Q: 这个怎么指定机器运行任务的啊 」 |
||||||
|
|
||||||
|
A: 通过worker分组: 这个流程只能在指定的机器组里执行。默认是Default,可以在任一worker上执行。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
Q: 跨用户的任务依赖怎么实现呢, 比如A用户写了一个任务,B用户需要依赖这个任务 |
||||||
|
|
||||||
|
就比如说 我们数仓组 写了一个 中间宽表的任务, 其他业务部门想要使用这个中间表的时候,他们应该是另外一个用户,怎么依赖这个中间表呢 |
||||||
|
|
||||||
|
A: 有两种情况,一个是要运行这个宽表任务,可以使用子工作流把宽表任务放到自己的工作流里面。另一个是检查这个宽表任务有没有完成,可以使用依赖节点来检查这个宽表任务在指定的时间周期有没有完成。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
Q: 启动WorkerServer服务时不能正常启动,报以下信息是什么原因? |
||||||
|
|
||||||
|
``` |
||||||
|
[INFO] 2019-05-06 16:39:31.492 cn.escheduler.server.zk.ZKWorkerClient:[155] - register failure , worker already started on : 127.0.0.1, please wait for a moment and try again |
||||||
|
``` |
||||||
|
|
||||||
|
A:Worker/Master Server在启动时,会向Zookeeper注册自己的启动信息,是Zookeeper的临时节点,如果两次启动时间间隔较短的情况,上次启动的Worker/Master Server在Zookeeper的会话还未过期,会出现上述信息,处理办法是等待session过期,一般是1分钟左右 |
||||||
|
|
||||||
|
---- |
||||||
|
|
||||||
|
Q: 编译时escheduler-grpc模块一直报错:Information:java: Errors occurred while compiling module 'escheduler-rpc', 找不到LogParameter、RetStrInfo、RetByteInfo等class类 |
||||||
|
|
||||||
|
A: 这是因为rpc源码包是google Grpc实现的,需要使用maven进行编译,在根目录下执行:mvn -U clean package assembly:assembly -Dmaven.test.skip=true , 然后刷新下整个项目 |
||||||
|
|
||||||
|
---- |
||||||
|
|
||||||
|
Q:EasyScheduler支持windows上运行么? |
||||||
|
|
||||||
|
A: 建议在Ubuntu、Centos上运行,暂不支持windows上运行,不过windows上可以进行编译。开发调试的话建议Ubuntu或者mac上进行。 |
||||||
|
|
||||||
|
----- |
||||||
|
|
||||||
|
Q:任务为什么不执行? |
||||||
|
|
||||||
|
A: 不执行的原因: |
||||||
|
|
||||||
|
查看command表里有没有内容? |
||||||
|
|
||||||
|
查看Master server的运行日志: |
||||||
|
|
||||||
|
查看Worker Server的运行日志 |
||||||
|
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 57 KiB |
After Width: | Height: | Size: 83 KiB |
After Width: | Height: | Size: 278 KiB |
After Width: | Height: | Size: 243 KiB |
After Width: | Height: | Size: 267 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 242 KiB |
After Width: | Height: | Size: 243 KiB |
After Width: | Height: | Size: 215 KiB |
After Width: | Height: | Size: 116 KiB |
After Width: | Height: | Size: 179 KiB |
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 113 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 245 KiB |
After Width: | Height: | Size: 193 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 114 KiB |
After Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 136 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 280 KiB |
After Width: | Height: | Size: 292 KiB |
After Width: | Height: | Size: 143 KiB |
After Width: | Height: | Size: 181 KiB |
After Width: | Height: | Size: 134 KiB |
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 119 KiB |
After Width: | Height: | Size: 88 KiB |
After Width: | Height: | Size: 85 KiB |
@ -0,0 +1,50 @@ |
|||||||
|
# 快速上手 |
||||||
|
|
||||||
|
* 管理员用户登录 |
||||||
|
>地址:192.168.xx.xx:8888 用户名密码:admin/escheduler123 |
||||||
|
|
||||||
|
<p align="center"> |
||||||
|
<img src="https://analysys.github.io/easyscheduler_docs_cn/images/login.jpg" width="60%" /> |
||||||
|
</p> |
||||||
|
|
||||||
|
* 创建队列 |
||||||
|
|
||||||
|
<p align="center"> |
||||||
|
<img src="https://analysys.github.io/easyscheduler_docs_cn/images/create-queue.png" width="60%" /> |
||||||
|
</p> |
||||||
|
|
||||||
|
* 创建租户 |
||||||
|
<p align="center"> |
||||||
|
<img src="https://analysys.github.io/easyscheduler_docs_cn/images/addtenant.png" width="60%" /> |
||||||
|
</p> |
||||||
|
|
||||||
|
* 创建普通用户 |
||||||
|
<p align="center"> |
||||||
|
<img src="https://analysys.github.io/easyscheduler_docs_cn/images/useredit2.png" width="60%" /> |
||||||
|
</p> |
||||||
|
|
||||||
|
* 创建告警组 |
||||||
|
|
||||||
|
<p align="center"> |
||||||
|
<img src="https://analysys.github.io/easyscheduler_docs_cn/images/mail_edit.png" width="60%" /> |
||||||
|
</p> |
||||||
|
|
||||||
|
* 使用普通用户登录 |
||||||
|
> 点击右上角用户名“退出”,重新使用普通用户登录。 |
||||||
|
|
||||||
|
* 项目管理->创建项目->点击项目名称 |
||||||
|
<p align="center"> |
||||||
|
<img src="https://analysys.github.io/easyscheduler_docs_cn/images/project.png" width="60%" /> |
||||||
|
</p> |
||||||
|
|
||||||
|
* 点击工作流定义->创建工作流定义->上线流程定义 |
||||||
|
|
||||||
|
<p align="center"> |
||||||
|
<img src="https://analysys.github.io/easyscheduler_docs_cn/images/dag1.png" width="60%" /> |
||||||
|
</p> |
||||||
|
|
||||||
|
* 运行流程定义->点击工作流实例->点击流程实例名称->双击任务节点->查看任务执行日志 |
||||||
|
|
||||||
|
<p align="center"> |
||||||
|
<img src="https://analysys.github.io/easyscheduler_docs_cn/images/task-log.png" width="60%" /> |
||||||
|
</p> |
@ -0,0 +1,167 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You 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 |
||||||
|
* |
||||||
|
* http://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 cn.escheduler.alert.utils; |
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON; |
||||||
|
|
||||||
|
import com.google.common.reflect.TypeToken; |
||||||
|
import org.apache.http.HttpEntity; |
||||||
|
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.entity.StringEntity; |
||||||
|
import org.apache.http.impl.client.CloseableHttpClient; |
||||||
|
import org.apache.http.impl.client.HttpClients; |
||||||
|
import org.apache.http.util.EntityUtils; |
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.util.Collection; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import static cn.escheduler.alert.utils.PropertyUtils.getString; |
||||||
|
|
||||||
|
/** |
||||||
|
* qiye weixin utils |
||||||
|
*/ |
||||||
|
public class EnterpriseWeChatUtils { |
||||||
|
|
||||||
|
public static final Logger logger = LoggerFactory.getLogger(EnterpriseWeChatUtils.class); |
||||||
|
|
||||||
|
private static final String enterpriseWeChatCorpId = getString(Constants.ENTERPRISE_WECHAT_CORP_ID); |
||||||
|
|
||||||
|
private static final String enterpriseWeChatSecret = getString(Constants.ENTERPRISE_WECHAT_SECRET); |
||||||
|
|
||||||
|
private static final String enterpriseWeChatTokenUrl = getString(Constants.ENTERPRISE_WECHAT_TOKEN_URL); |
||||||
|
private String enterpriseWeChatTokenUrlReplace = enterpriseWeChatTokenUrl |
||||||
|
.replaceAll("\\$corpId", enterpriseWeChatCorpId) |
||||||
|
.replaceAll("\\$secret", enterpriseWeChatSecret); |
||||||
|
|
||||||
|
private static final String enterpriseWeChatPushUrl = getString(Constants.ENTERPRISE_WECHAT_PUSH_URL); |
||||||
|
|
||||||
|
private static final String enterpriseWeChatTeamSendMsg = getString(Constants.ENTERPRISE_WECHAT_TEAM_SEND_MSG); |
||||||
|
|
||||||
|
private static final String enterpriseWeChatUserSendMsg = getString(Constants.ENTERPRISE_WECHAT_USER_SEND_MSG); |
||||||
|
|
||||||
|
/** |
||||||
|
* get winxin token info |
||||||
|
* @return token string info |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
public String getToken() throws IOException { |
||||||
|
String resp; |
||||||
|
|
||||||
|
CloseableHttpClient httpClient = HttpClients.createDefault(); |
||||||
|
HttpGet httpGet = new HttpGet(enterpriseWeChatTokenUrlReplace); |
||||||
|
CloseableHttpResponse response = httpClient.execute(httpGet); |
||||||
|
try { |
||||||
|
HttpEntity entity = response.getEntity(); |
||||||
|
resp = EntityUtils.toString(entity, "utf-8"); |
||||||
|
EntityUtils.consume(entity); |
||||||
|
} finally { |
||||||
|
response.close(); |
||||||
|
} |
||||||
|
|
||||||
|
Map<String, Object> map = JSON.parseObject(resp, |
||||||
|
new TypeToken<Map<String, Object>>() { |
||||||
|
}.getType()); |
||||||
|
return map.get("access_token").toString(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* make team single weixin message |
||||||
|
* @param toParty |
||||||
|
* @param agentId |
||||||
|
* @param msg |
||||||
|
* @return weixin send message |
||||||
|
*/ |
||||||
|
public String makeTeamSendMsg(String toParty, String agentId, String msg) { |
||||||
|
return enterpriseWeChatTeamSendMsg.replaceAll("\\$toParty", toParty) |
||||||
|
.replaceAll("\\$agentId", agentId) |
||||||
|
.replaceAll("\\$msg", msg); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* make team multi weixin message |
||||||
|
* @param toParty |
||||||
|
* @param agentId |
||||||
|
* @param msg |
||||||
|
* @return weixin send message |
||||||
|
*/ |
||||||
|
public String makeTeamSendMsg(Collection<String> toParty, String agentId, String msg) { |
||||||
|
String listParty = FuncUtils.mkString(toParty, "|"); |
||||||
|
return enterpriseWeChatTeamSendMsg.replaceAll("\\$toParty", listParty) |
||||||
|
.replaceAll("\\$agentId", agentId) |
||||||
|
.replaceAll("\\$msg", msg); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* make team single user message |
||||||
|
* @param toUser |
||||||
|
* @param agentId |
||||||
|
* @param msg |
||||||
|
* @return weixin send message |
||||||
|
*/ |
||||||
|
public String makeUserSendMsg(String toUser, String agentId, String msg) { |
||||||
|
return enterpriseWeChatUserSendMsg.replaceAll("\\$toUser", toUser) |
||||||
|
.replaceAll("\\$agentId", agentId) |
||||||
|
.replaceAll("\\$msg", msg); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* make team multi user message |
||||||
|
* @param toUser |
||||||
|
* @param agentId |
||||||
|
* @param msg |
||||||
|
* @return weixin send message |
||||||
|
*/ |
||||||
|
public String makeUserSendMsg(Collection<String> toUser, String agentId, String msg) { |
||||||
|
String listUser = FuncUtils.mkString(toUser, "|"); |
||||||
|
return enterpriseWeChatUserSendMsg.replaceAll("\\$toUser", listUser) |
||||||
|
.replaceAll("\\$agentId", agentId) |
||||||
|
.replaceAll("\\$msg", msg); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* send weixin |
||||||
|
* @param charset |
||||||
|
* @param data |
||||||
|
* @param token |
||||||
|
* @return weixin resp, demo: {"errcode":0,"errmsg":"ok","invaliduser":""} |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
public String sendQiyeWeixin(String charset, String data, String token) throws IOException { |
||||||
|
String enterpriseWeChatPushUrlReplace = enterpriseWeChatPushUrl.replaceAll("\\$token", token); |
||||||
|
|
||||||
|
CloseableHttpClient httpclient = HttpClients.createDefault(); |
||||||
|
HttpPost httpPost = new HttpPost(enterpriseWeChatPushUrlReplace); |
||||||
|
httpPost.setEntity(new StringEntity(data, charset)); |
||||||
|
CloseableHttpResponse response = httpclient.execute(httpPost); |
||||||
|
String resp; |
||||||
|
try { |
||||||
|
HttpEntity entity = response.getEntity(); |
||||||
|
resp = EntityUtils.toString(entity, charset); |
||||||
|
EntityUtils.consume(entity); |
||||||
|
} finally { |
||||||
|
response.close(); |
||||||
|
} |
||||||
|
logger.info("qiye weixin send [{}], param:{}, resp:{}", enterpriseWeChatPushUrl, data, resp); |
||||||
|
return resp; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You 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 |
||||||
|
* |
||||||
|
* http://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 cn.escheduler.alert.utils; |
||||||
|
|
||||||
|
public class FuncUtils { |
||||||
|
|
||||||
|
static public String mkString(Iterable<String> list, String split) { |
||||||
|
StringBuilder sb = new StringBuilder(); |
||||||
|
boolean first = true; |
||||||
|
for (String item : list) { |
||||||
|
if (first) |
||||||
|
first = false; |
||||||
|
else |
||||||
|
sb.append(split); |
||||||
|
sb.append(item); |
||||||
|
} |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,38 +1 @@ |
|||||||
<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN' 'http://www.w3.org/TR/html4/loose.dtd'> |
<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN' 'http://www.w3.org/TR/html4/loose.dtd'><html><head><title> easyscheduler</title><meta name='Keywords' content=''><meta name='Description' content=''><style type="text/css">table { margin-top:0px; padding-top:0px; border:1px solid; font-size: 14px; color: #333333; border-width: 1px; border-color: #666666; border-collapse: collapse; } table th { border-width: 1px; padding: 8px; border-style: solid; border-color: #666666; background-color: #dedede; } table td { border-width: 1px; padding: 8px; border-style: solid; border-color: #666666; background-color: #ffffff; }</style></head><body style="margin:0;padding:0"><table border="1px" cellpadding="5px" cellspacing="-10px"><thead><#if title??> ${title}</#if></thead><#if content??> ${content}</#if></table></body></html> |
||||||
<html> |
|
||||||
<head><title> easyscheduler </title> |
|
||||||
<meta name='Keywords' content=''> |
|
||||||
<meta name='Description' content=''> |
|
||||||
<style type="text/css">table { |
|
||||||
font-size: 14px; |
|
||||||
color: #333333; |
|
||||||
border-width: 1px; |
|
||||||
border-color: #666666; |
|
||||||
border-collapse: collapse; |
|
||||||
} |
|
||||||
|
|
||||||
table th { |
|
||||||
border-width: 1px; |
|
||||||
padding: 8px; |
|
||||||
border-style: solid; |
|
||||||
border-color: #666666; |
|
||||||
background-color: #dedede; |
|
||||||
} |
|
||||||
|
|
||||||
table td { |
|
||||||
border-width: 1px; |
|
||||||
padding: 8px; |
|
||||||
border-style: solid; |
|
||||||
border-color: #666666; |
|
||||||
background-color: #ffffff; |
|
||||||
}</style> |
|
||||||
</head> |
|
||||||
<body> |
|
||||||
<table> |
|
||||||
<thead> |
|
||||||
<#if title??> ${title} </#if> |
|
||||||
</thead> |
|
||||||
<#if content??> ${content} </#if> |
|
||||||
</table> |
|
||||||
</body> |
|
||||||
</html> |
|
@ -0,0 +1,110 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You 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 |
||||||
|
* |
||||||
|
* http://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 cn.escheduler.alert.utils; |
||||||
|
|
||||||
|
import org.junit.Assert; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.Collection; |
||||||
|
|
||||||
|
/** |
||||||
|
* Please manually modify the configuration file before testing. |
||||||
|
* file: alert.properties |
||||||
|
* enterprise.wechat.corp.id |
||||||
|
* enterprise.wechat.secret |
||||||
|
* enterprise.wechat.token.url |
||||||
|
* enterprise.wechat.push.url |
||||||
|
* enterprise.wechat.send.msg |
||||||
|
*/ |
||||||
|
public class EnterpriseWeChatUtilsTest { |
||||||
|
|
||||||
|
// Please change
|
||||||
|
private String agentId = "1000002"; // app id
|
||||||
|
private String partyId = "2"; |
||||||
|
private Collection<String> listPartyId = Arrays.asList("2","4"); |
||||||
|
private String userId = "test1"; |
||||||
|
private Collection<String> listUserId = Arrays.asList("test1","test2"); |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSendSingleTeamWeChat() { |
||||||
|
EnterpriseWeChatUtils wx = new EnterpriseWeChatUtils(); |
||||||
|
|
||||||
|
try { |
||||||
|
String token = wx.getToken(); |
||||||
|
String msg = wx.makeTeamSendMsg(partyId, agentId, "hello world"); |
||||||
|
String resp = wx.sendQiyeWeixin("utf-8", msg, token); |
||||||
|
|
||||||
|
String errmsg = JSON.parseObject(resp).getString("errmsg"); |
||||||
|
Assert.assertEquals(errmsg, "ok"); |
||||||
|
} catch (IOException e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSendMultiTeamWeChat() { |
||||||
|
EnterpriseWeChatUtils wx = new EnterpriseWeChatUtils(); |
||||||
|
|
||||||
|
try { |
||||||
|
String token = wx.getToken(); |
||||||
|
String msg = wx.makeTeamSendMsg(listPartyId, agentId, "hello world"); |
||||||
|
String resp = wx.sendQiyeWeixin("utf-8", msg, token); |
||||||
|
|
||||||
|
String errmsg = JSON.parseObject(resp).getString("errmsg"); |
||||||
|
Assert.assertEquals(errmsg, "ok"); |
||||||
|
} catch (IOException e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSendSingleUserWeChat() { |
||||||
|
EnterpriseWeChatUtils wx = new EnterpriseWeChatUtils(); |
||||||
|
|
||||||
|
try { |
||||||
|
String token = wx.getToken(); |
||||||
|
String msg = wx.makeUserSendMsg(userId, agentId, "hello world"); |
||||||
|
String resp = wx.sendQiyeWeixin("utf-8", msg, token); |
||||||
|
|
||||||
|
String errmsg = JSON.parseObject(resp).getString("errmsg"); |
||||||
|
Assert.assertEquals(errmsg, "ok"); |
||||||
|
} catch (IOException e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSendMultiUserWeChat() { |
||||||
|
EnterpriseWeChatUtils wx = new EnterpriseWeChatUtils(); |
||||||
|
|
||||||
|
try { |
||||||
|
String token = wx.getToken(); |
||||||
|
String msg = wx.makeUserSendMsg(listUserId, agentId, "hello world"); |
||||||
|
String resp = wx.sendQiyeWeixin("utf-8", msg, token); |
||||||
|
|
||||||
|
String errmsg = JSON.parseObject(resp).getString("errmsg"); |
||||||
|
Assert.assertEquals(errmsg, "ok"); |
||||||
|
} catch (IOException e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You 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 |
||||||
|
* |
||||||
|
* http://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 cn.escheduler.common.enums; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* task record status |
||||||
|
* |
||||||
|
*/ |
||||||
|
public enum TaskRecordStatus { |
||||||
|
|
||||||
|
/** |
||||||
|
* status: |
||||||
|
* 0 sucess |
||||||
|
* 1 failure |
||||||
|
* 2 exception |
||||||
|
*/ |
||||||
|
SUCCESS,FAILURE,EXCEPTION |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,70 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You 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 |
||||||
|
* |
||||||
|
* http://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 cn.escheduler.common.utils; |
||||||
|
|
||||||
|
|
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* http utils |
||||||
|
*/ |
||||||
|
public class IpUtils { |
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(IpUtils.class); |
||||||
|
public static final String DOT = "."; |
||||||
|
|
||||||
|
/** |
||||||
|
* ip str to long <p> |
||||||
|
* |
||||||
|
* @param ipStr ip string |
||||||
|
*/ |
||||||
|
public static Long ipToLong(String ipStr) { |
||||||
|
String[] ipSet = ipStr.split("\\" + DOT); |
||||||
|
|
||||||
|
return Long.parseLong(ipSet[0]) << 24 | Long.parseLong(ipSet[1]) << 16 | Long.parseLong(ipSet[2]) << 8 | Long.parseLong(ipSet[3]); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* long to ip |
||||||
|
* @param ipLong the long number converted from IP |
||||||
|
* @return String |
||||||
|
*/ |
||||||
|
public static String longToIp(long ipLong) { |
||||||
|
long[] ipNumbers = new long[4]; |
||||||
|
long tmp = 0xFF; |
||||||
|
ipNumbers[0] = ipLong >> 24 & tmp; |
||||||
|
ipNumbers[1] = ipLong >> 16 & tmp; |
||||||
|
ipNumbers[2] = ipLong >> 8 & tmp; |
||||||
|
ipNumbers[3] = ipLong & tmp; |
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder(16); |
||||||
|
sb.append(ipNumbers[0]).append(DOT) |
||||||
|
.append(ipNumbers[1]).append(DOT) |
||||||
|
.append(ipNumbers[2]).append(DOT) |
||||||
|
.append(ipNumbers[3]); |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args){ |
||||||
|
long ipLong = ipToLong("11.3.4.5"); |
||||||
|
logger.info(longToIp(ipLong)); |
||||||
|
} |
||||||
|
} |