执行器新增"注册方式"和"机器地址"属性,支持手动录入机器地址;

This commit is contained in:
xueli.xue 2017-03-10 20:40:03 +08:00
parent a057b2d00e
commit 338d3b62a5
9 changed files with 139 additions and 27 deletions

View File

@ -732,12 +732,12 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
- 8、GLUE依赖注入逻辑优化支持别名注入 - 8、GLUE依赖注入逻辑优化支持别名注入
#### 6.11 版本 V1.6.0 特性(CODING) #### 6.11 版本 V1.6.0 特性(CODING)
- 1、通讯hex 通讯调整为 http-rpc 模式 - 1、通讯方案升级原基于HEX的通讯模型调整为基于HTTP的二进制RPC的通讯模型
- 2、线程模型统一 - 2、规范线程模型统一,统一线程销毁方案
- 3、执行器支持手动设置执行地址列表,提供开关切换使用注册地址还是手动设置的地址 - 3、CleanCode清理无效的历史参数
- 4、执行器路由规则:第一个、循环、随机、顺序故障(默认)转移 - 4、规范系统配置数据,通过配置文件统一管理
- 5、CleanCode清理无效的历史参数 - 5、执行器支持手动设置执行地址列表,提供开关切换使用注册地址还是手动设置的地址
- 6、规范系统配置数据,通过配置文件统一管理 - 6、执行器路由规则:第一个、循环、随机、顺序故障(默认)转移
#### TODO LIST #### TODO LIST
- 1、支持脚本JOB(源码或指定路径), 即shell/python/php等, 日志实时输出并支持在线监控定制JobHandler实现; - 1、支持脚本JOB(源码或指定路径), 即shell/python/php等, 日志实时输出并支持在线监控定制JobHandler实现;

View File

@ -201,14 +201,17 @@ CREATE TABLE XXL_JOB_QRTZ_TRIGGER_REGISTRY (
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE XXL_JOB_QRTZ_TRIGGER_GROUP ( CREATE TABLE `XXL_JOB_QRTZ_TRIGGER_GROUP` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`app_name` varchar(64) NOT NULL, `app_name` varchar(64) NOT NULL COMMENT '执行器AppName',
`title` varchar(12) NOT NULL, `title` varchar(12) NOT NULL COMMENT '执行器名称',
`order` tinyint(4) NOT NULL, `order` tinyint(4) NOT NULL DEFAULT '0' COMMENT '排序',
`address_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '执行器地址类型0=自动注册、1=手动录入',
`address_list` varchar(200) DEFAULT NULL COMMENT '执行器地址列表,多地址逗号分隔',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `XXL_JOB_QRTZ_TRIGGER_GROUP` VALUES ('1', 'xxl-job-executor-example', '示例执行器', '1');
INSERT INTO `XXL_JOB_QRTZ_TRIGGER_GROUP` ( `app_name`, `title`, `order`, `address_type`, `address_list`) values ( 'xxl-job-executor-example', '示例执行器', '1', '0', null);
commit; commit;

View File

@ -14,6 +14,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List; import java.util.List;
/** /**
@ -40,7 +41,14 @@ public class JobGroupController {
if (CollectionUtils.isNotEmpty(list)) { if (CollectionUtils.isNotEmpty(list)) {
for (XxlJobGroup group: list) { for (XxlJobGroup group: list) {
List<String> registryList = JobRegistryHelper.discover(RegistHelper.RegistType.EXECUTOR.name(), group.getAppName()); List<String> registryList = null;
if (group.getAddressType() == 0) {
registryList = JobRegistryHelper.discover(RegistHelper.RegistType.EXECUTOR.name(), group.getAppName());
} else {
if (StringUtils.isNotBlank(group.getAddressList())) {
registryList = Arrays.asList(group.getAddressList().split(","));
}
}
group.setRegistryList(registryList); group.setRegistryList(registryList);
} }
} }
@ -64,6 +72,17 @@ public class JobGroupController {
if (xxlJobGroup.getTitle()==null || StringUtils.isBlank(xxlJobGroup.getTitle())) { if (xxlJobGroup.getTitle()==null || StringUtils.isBlank(xxlJobGroup.getTitle())) {
return new ReturnT<String>(500, "请输入名称"); return new ReturnT<String>(500, "请输入名称");
} }
if (xxlJobGroup.getAddressType()!=0) {
if (StringUtils.isBlank(xxlJobGroup.getAddressList())) {
return new ReturnT<String>(500, "手动录入注册方式,机器地址不可为空");
}
String[] addresss = xxlJobGroup.getAddressList().split(",");
for (String item: addresss) {
if (StringUtils.isBlank(item)) {
return new ReturnT<String>(500, "机器地址非法");
}
}
}
int ret = xxlJobGroupDao.save(xxlJobGroup); int ret = xxlJobGroupDao.save(xxlJobGroup);
return (ret>0)?ReturnT.SUCCESS:ReturnT.FAIL; return (ret>0)?ReturnT.SUCCESS:ReturnT.FAIL;
@ -82,6 +101,17 @@ public class JobGroupController {
if (xxlJobGroup.getTitle()==null || StringUtils.isBlank(xxlJobGroup.getTitle())) { if (xxlJobGroup.getTitle()==null || StringUtils.isBlank(xxlJobGroup.getTitle())) {
return new ReturnT<String>(500, "请输入名称"); return new ReturnT<String>(500, "请输入名称");
} }
if (xxlJobGroup.getAddressType()!=0) {
if (StringUtils.isBlank(xxlJobGroup.getAddressList())) {
return new ReturnT<String>(500, "手动录入注册方式,机器地址不可为空");
}
String[] addresss = xxlJobGroup.getAddressList().split(",");
for (String item: addresss) {
if (StringUtils.isBlank(item)) {
return new ReturnT<String>(500, "机器地址非法");
}
}
}
int ret = xxlJobGroupDao.update(xxlJobGroup); int ret = xxlJobGroupDao.update(xxlJobGroup);
return (ret>0)?ReturnT.SUCCESS:ReturnT.FAIL; return (ret>0)?ReturnT.SUCCESS:ReturnT.FAIL;

View File

@ -11,9 +11,11 @@ public class XxlJobGroup {
private String appName; private String appName;
private String title; private String title;
private int order; private int order;
private int addressType; // 执行器地址类型0=自动注册1=手动录入
private String addressList; // 执行器地址列表多地址逗号分隔(手动录入)
// registry list // registry list
private List<String> registryList; private List<String> registryList; // 执行器地址列表(系统注册)
public int getId() { public int getId() {
return id; return id;
@ -54,4 +56,20 @@ public class XxlJobGroup {
public void setRegistryList(List<String> registryList) { public void setRegistryList(List<String> registryList) {
this.registryList = registryList; this.registryList = registryList;
} }
public int getAddressType() {
return addressType;
}
public void setAddressType(int addressType) {
this.addressType = addressType;
}
public String getAddressList() {
return addressList;
}
public void setAddressList(String addressList) {
this.addressList = addressList;
}
} }

View File

@ -39,9 +39,11 @@ public class JobRegistryHelper {
XxlJobDynamicScheduler.xxlJobRegistryDao.registrySave(RegistHelper.RegistType.ADMIN.name(), RegistHelper.RegistType.ADMIN.name(), XxlJobDynamicScheduler.getCallbackAddress()); XxlJobDynamicScheduler.xxlJobRegistryDao.registrySave(RegistHelper.RegistType.ADMIN.name(), RegistHelper.RegistType.ADMIN.name(), XxlJobDynamicScheduler.getCallbackAddress());
} }
// remove dead admin/executor
XxlJobDynamicScheduler.xxlJobRegistryDao.removeDead(RegistHelper.TIMEOUT*2);
// fresh registry map // fresh registry map
ConcurrentHashMap<String, List<String>> temp = new ConcurrentHashMap<String, List<String>>(); ConcurrentHashMap<String, List<String>> temp = new ConcurrentHashMap<String, List<String>>();
XxlJobDynamicScheduler.xxlJobRegistryDao.removeDead(RegistHelper.TIMEOUT*2);
List<XxlJobRegistry> list = XxlJobDynamicScheduler.xxlJobRegistryDao.findAll(RegistHelper.TIMEOUT*2); List<XxlJobRegistry> list = XxlJobDynamicScheduler.xxlJobRegistryDao.findAll(RegistHelper.TIMEOUT*2);
if (list != null) { if (list != null) {
for (XxlJobRegistry item: list) { for (XxlJobRegistry item: list) {

View File

@ -8,13 +8,17 @@
<result column="app_name" property="appName" /> <result column="app_name" property="appName" />
<result column="title" property="title" /> <result column="title" property="title" />
<result column="order" property="order" /> <result column="order" property="order" />
<result column="address_type" property="addressType" />
<result column="address_list" property="addressList" />
</resultMap> </resultMap>
<sql id="Base_Column_List"> <sql id="Base_Column_List">
t.id, t.id,
t.app_name, t.app_name,
t.title, t.title,
t.order t.order,
t.address_type,
t.address_list
</sql> </sql>
<select id="findAll" parameterType="java.lang.Integer" resultMap="XxlJobGroup"> <select id="findAll" parameterType="java.lang.Integer" resultMap="XxlJobGroup">
@ -24,15 +28,17 @@
</select> </select>
<insert id="save" parameterType="com.xxl.job.admin.core.model.XxlJobGroup" > <insert id="save" parameterType="com.xxl.job.admin.core.model.XxlJobGroup" >
INSERT INTO XXL_JOB_QRTZ_TRIGGER_GROUP ( `app_name`, `title`, `order`) INSERT INTO XXL_JOB_QRTZ_TRIGGER_GROUP ( `app_name`, `title`, `order`, `address_type`, `address_list`)
values ( #{appName}, #{title}, #{order}); values ( #{appName}, #{title}, #{order}, #{addressType}, #{addressList});
</insert> </insert>
<update id="update" parameterType="com.xxl.job.admin.core.model.XxlJobGroup" > <update id="update" parameterType="com.xxl.job.admin.core.model.XxlJobGroup" >
UPDATE XXL_JOB_QRTZ_TRIGGER_GROUP UPDATE XXL_JOB_QRTZ_TRIGGER_GROUP
SET `app_name` = #{appName}, SET `app_name` = #{appName},
`title` = #{title}, `title` = #{title},
`order` = #{order} `order` = #{order},
`address_type` = #{addressType},
`address_list` = #{addressList}
WHERE id = #{id} WHERE id = #{id}
</update> </update>

View File

@ -33,16 +33,17 @@
<h3 class="box-title">执行器列表</h3>&nbsp;&nbsp; <h3 class="box-title">执行器列表</h3>&nbsp;&nbsp;
<button class="btn btn-info btn-xs pull-left2 add" >+新增执行器</button> <button class="btn btn-info btn-xs pull-left2 add" >+新增执行器</button>
&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;
调度中心OnLine<#if adminAddressList?exists><#list adminAddressList as item><span class="badge bg-green">${item}</span></#list></#if> 调度中心OnLine机器<#if adminAddressList?exists><#list adminAddressList as item><span class="badge bg-green">${item}</span></#list></#if>
</div> </div>
<div class="box-body"> <div class="box-body">
<table id="joblog_list" class="table table-bordered table-striped display" width="100%" > <table id="joblog_list" class="table table-bordered table-striped display" width="100%" >
<thead> <thead>
<tr> <tr>
<th name="id" >ID</th> <#--<th name="id" >ID</th>-->
<th name="order" >排序</th>
<th name="appName" >AppName</th> <th name="appName" >AppName</th>
<th name="title" >名称</th> <th name="title" >名称</th>
<th name="order" >排序</th> <th name="addressType" >注册方式</th>
<th name="registryList" >OnLine 机器</th> <th name="registryList" >OnLine 机器</th>
<th name="operate" >操作</th> <th name="operate" >操作</th>
</tr> </tr>
@ -51,13 +52,20 @@
<#if list?exists && list?size gt 0> <#if list?exists && list?size gt 0>
<#list list as group> <#list list as group>
<tr> <tr>
<td>${group.id}</td> <#--<td>${group.id}</td>-->
<td>${group.order}</td>
<td>${group.appName}</td> <td>${group.appName}</td>
<td>${group.title}</td> <td>${group.title}</td>
<td>${group.order}</td> <td><#if group.addressType==0>自动注册<#else>手动录入</#if></td>
<td><#if group.registryList?exists><#list group.registryList as item><span class="badge bg-green">${item}</span><br></#list></#if></td> <td><#if group.registryList?exists><#list group.registryList as item><span class="badge bg-green">${item}</span><br></#list></#if></td>
<td> <td>
<button class="btn btn-warning btn-xs update" id="${group.id}" appName="${group.appName}" title="${group.title}" order="${group.order}" >编辑</button> <button class="btn btn-warning btn-xs update"
id="${group.id}"
appName="${group.appName}"
title="${group.title}"
order="${group.order}"
addressType="${group.addressType}"
addressList="${group.addressList}" >编辑</button>
<button class="btn btn-danger btn-xs remove" id="${group.id}" >删除</button> <button class="btn btn-danger btn-xs remove" id="${group.id}" >删除</button>
</td> </td>
</tr> </tr>
@ -93,6 +101,18 @@
<label for="lastname" class="col-sm-2 control-label">排序<font color="red">*</font></label> <label for="lastname" class="col-sm-2 control-label">排序<font color="red">*</font></label>
<div class="col-sm-10"><input type="text" class="form-control" name="order" placeholder="请输入“排序”" maxlength="50" ></div> <div class="col-sm-10"><input type="text" class="form-control" name="order" placeholder="请输入“排序”" maxlength="50" ></div>
</div> </div>
<div class="form-group">
<label for="lastname" class="col-sm-2 control-label">注册方式<font color="red">*</font></label>
<div class="col-sm-10">
<input type="radio" name="addressType" value="0" checked />自动注册
&nbsp;&nbsp;&nbsp;&nbsp;
<input type="radio" name="addressType" value="1" />手动录入
</div>
</div>
<div class="form-group">
<label for="lastname" class="col-sm-2 control-label">机器地址<font color="red">*</font></label>
<div class="col-sm-10"><input type="text" class="form-control" name="addressList" placeholder="请输入执行器地址列表,多地址逗号分隔" maxlength="200" readonly="readonly" ></div>
</div>
<hr> <hr>
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-3 col-sm-6"> <div class="col-sm-offset-3 col-sm-6">
@ -127,6 +147,18 @@
<label for="lastname" class="col-sm-2 control-label">排序<font color="red">*</font></label> <label for="lastname" class="col-sm-2 control-label">排序<font color="red">*</font></label>
<div class="col-sm-10"><input type="text" class="form-control" name="order" placeholder="请输入“排序”" maxlength="50" ></div> <div class="col-sm-10"><input type="text" class="form-control" name="order" placeholder="请输入“排序”" maxlength="50" ></div>
</div> </div>
<div class="form-group">
<label for="lastname" class="col-sm-2 control-label">注册方式<font color="red">*</font></label>
<div class="col-sm-10">
<input type="radio" name="addressType" value="0" />自动注册
&nbsp;&nbsp;&nbsp;&nbsp;
<input type="radio" name="addressType" value="1" />手动录入
</div>
</div>
<div class="form-group">
<label for="lastname" class="col-sm-2 control-label">机器地址<font color="red">*</font></label>
<div class="col-sm-10"><input type="text" class="form-control" name="addressList" placeholder="请输入执行器地址列表,多地址逗号分隔" maxlength="200" readonly="readonly" ></div>
</div>
<hr> <hr>
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-3 col-sm-6"> <div class="col-sm-offset-3 col-sm-6">

View File

@ -107,12 +107,33 @@ $(function() {
$("#addModal .form .form-group").removeClass("has-error"); $("#addModal .form .form-group").removeClass("has-error");
}); });
// 注册方式,切换
$("#addModal input[name=addressType], #updateModal input[name=addressType]").click(function(){
var addressType = $(this).val();
var $addressList = $(this).parents("form").find("input[name=addressList]");
if (addressType == 0) {
$addressList.val("");
$addressList.attr("readonly","readonly");
} else {
$addressList.removeAttr("readonly");
}
});
// update
$('.update').on('click', function(){ $('.update').on('click', function(){
$("#updateModal .form input[name='id']").val($(this).attr("id")); $("#updateModal .form input[name='id']").val($(this).attr("id"));
$("#updateModal .form input[name='appName']").val($(this).attr("appName")); $("#updateModal .form input[name='appName']").val($(this).attr("appName"));
$("#updateModal .form input[name='title']").val($(this).attr("title")); $("#updateModal .form input[name='title']").val($(this).attr("title"));
$("#updateModal .form input[name='order']").val($(this).attr("order")); $("#updateModal .form input[name='order']").val($(this).attr("order"));
// 注册方式
var addressType = $(this).attr("addressType");
$("#updateModal .form input[name='addressType']").removeAttr('checked');
//$("#updateModal .form input[name='addressType'][value='"+ addressType +"']").attr('checked', 'true');
$("#updateModal .form input[name='addressType'][value='"+ addressType +"']").click();
// 机器地址
$("#updateModal .form input[name='addressList']").val($(this).attr("addressList"));
$('#updateModal').modal({backdrop: false, keyboard: false}).modal('show'); $('#updateModal').modal({backdrop: false, keyboard: false}).modal('show');
}); });
var updateModalValidate = $("#updateModal .form").validate({ var updateModalValidate = $("#updateModal .form").validate({

View File

@ -16,9 +16,9 @@ import java.util.regex.Pattern;
public class IpUtil { public class IpUtil {
private static final Logger logger = LoggerFactory.getLogger(IpUtil.class); private static final Logger logger = LoggerFactory.getLogger(IpUtil.class);
public static final String ANYHOST = "0.0.0.0"; private static final String ANYHOST = "0.0.0.0";
public static final String LOCALHOST = "127.0.0.1"; private static final String LOCALHOST = "127.0.0.1";
private static final Pattern IP_PATTERN = Pattern.compile("\\d{1,3}(\\.\\d{1,3}){3,5}$"); public static final Pattern IP_PATTERN = Pattern.compile("\\d{1,3}(\\.\\d{1,3}){3,5}$");
private static volatile InetAddress LOCAL_ADDRESS = null; private static volatile InetAddress LOCAL_ADDRESS = null;