Browse Source

精简项目,取消第三方依赖 ommons-lang3

xuxueli 5 years ago
parent
commit
9d92fa7578

+ 2 - 1
doc/XXL-JOB官方文档.md

@@ -1432,7 +1432,7 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
 - 8、调度中心告警邮件发送组件改为 “spring-boot-starter-mail”;
 - 9、记住密码功能优化,选中时永久记住;非选中时关闭浏览器即登出;
 - 10、项目依赖升级至较新稳定版本,如quartz、spring、jackson、groovy、xxl-rpc等等;
-- 11、精简项目,取消第三方依赖,如 commons-collections4 ;
+- 11、精简项目,取消第三方依赖,如 commons-collections4、commons-lang3 ;
 - 12、执行器回调日志落盘方案复用RPC序列化方案,并移除Jackson依赖;
 - 13、底层Log调优,应用正常终止取消异常栈信息打印;
 - 14、交互优化,尽量避免新开页面窗口;仅WebIDE支持新开页,并提供窗口快速关闭按钮;任务启、停、删除、触发等轻操作提示改为toast方式,
@@ -1493,6 +1493,7 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
 - 34、批量调度:调度请求入queue,调度线程批量获取调度请求并发起远程调度;提高线程效率;
 - 35、执行器端口复用,http通讯自动添加相对地址 "/xxl-job":
 - 36、多语言执行器:约定跨语言通讯方案,以及通讯接口;
+- 37、移除commons-exec,采用原生实现;
 
 
 ## 七、其他

+ 0 - 1
pom.xml

@@ -37,7 +37,6 @@
 		<junit.version>4.12</junit.version>
 
 		<commons-exec.version>1.3</commons-exec.version>
-		<commons-lang3.version>3.8.1</commons-lang3.version>
 
 		<groovy.version>2.5.6</groovy.version>
 		<quartz.version>2.3.1</quartz.version>

+ 0 - 8
xxl-job-admin/pom.xml

@@ -60,14 +60,6 @@
 			<version>${mysql-connector-java.version}</version>
 		</dependency>
 
-		<!-- commons-lang3 -->
-		<dependency>
-			<groupId>org.apache.commons</groupId>
-			<artifactId>commons-lang3</artifactId>
-			<version>${commons-lang3.version}</version>
-		</dependency>
-
-
 		<!-- quartz :quartz-2.2.3/c3p0-0.9.1.1/slf4j-api-1.6.6 -->
 		<dependency>
 			<groupId>org.quartz-scheduler</groupId>

+ 2 - 3
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/IndexController.java

@@ -5,7 +5,6 @@ import com.xxl.job.admin.controller.interceptor.PermissionInterceptor;
 import com.xxl.job.admin.core.util.I18nUtil;
 import com.xxl.job.admin.service.XxlJobService;
 import com.xxl.job.core.biz.model.ReturnT;
-import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.propertyeditors.CustomDateEditor;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
@@ -67,10 +66,10 @@ public class IndexController {
 		}
 
 		// param
-		if (StringUtils.isBlank(userName) || StringUtils.isBlank(password)){
+		if (userName==null || userName.trim().length()==0 || password==null || password.trim().length()==0){
 			return new ReturnT<String>(500, I18nUtil.getString("login_param_empty"));
 		}
-		boolean ifRem = (StringUtils.isNotBlank(ifRemember) && "on".equals(ifRemember))?true:false;
+		boolean ifRem = (ifRemember!=null && ifRemember.trim().length()>0 && "on".equals(ifRemember))?true:false;
 
 		// do login
 		boolean loginRet = PermissionInterceptor.login(response, userName, password, ifRem);

+ 13 - 10
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobGroupController.java

@@ -8,7 +8,6 @@ import com.xxl.job.admin.dao.XxlJobGroupDao;
 import com.xxl.job.admin.dao.XxlJobInfoDao;
 import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.enums.RegistryConfig;
-import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -48,22 +47,22 @@ public class JobGroupController {
 	public ReturnT<String> save(XxlJobGroup xxlJobGroup){
 
 		// valid
-		if (xxlJobGroup.getAppName()==null || StringUtils.isBlank(xxlJobGroup.getAppName())) {
+		if (xxlJobGroup.getAppName()==null || xxlJobGroup.getAppName().trim().length()==0) {
 			return new ReturnT<String>(500, (I18nUtil.getString("system_please_input")+"AppName") );
 		}
 		if (xxlJobGroup.getAppName().length()<4 || xxlJobGroup.getAppName().length()>64) {
 			return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_appName_length") );
 		}
-		if (xxlJobGroup.getTitle()==null || StringUtils.isBlank(xxlJobGroup.getTitle())) {
+		if (xxlJobGroup.getTitle()==null || xxlJobGroup.getTitle().trim().length()==0) {
 			return new ReturnT<String>(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobgroup_field_title")) );
 		}
 		if (xxlJobGroup.getAddressType()!=0) {
-			if (StringUtils.isBlank(xxlJobGroup.getAddressList())) {
+			if (xxlJobGroup.getAddressList()==null || xxlJobGroup.getAddressList().trim().length()==0) {
 				return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_addressType_limit") );
 			}
 			String[] addresss = xxlJobGroup.getAddressList().split(",");
 			for (String item: addresss) {
-				if (StringUtils.isBlank(item)) {
+				if (item==null || item.trim().length()==0) {
 					return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_registryList_unvalid") );
 				}
 			}
@@ -77,13 +76,13 @@ public class JobGroupController {
 	@ResponseBody
 	public ReturnT<String> update(XxlJobGroup xxlJobGroup){
 		// valid
-		if (xxlJobGroup.getAppName()==null || StringUtils.isBlank(xxlJobGroup.getAppName())) {
+		if (xxlJobGroup.getAppName()==null || xxlJobGroup.getAppName().trim().length()==0) {
 			return new ReturnT<String>(500, (I18nUtil.getString("system_please_input")+"AppName") );
 		}
 		if (xxlJobGroup.getAppName().length()<4 || xxlJobGroup.getAppName().length()>64) {
 			return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_appName_length") );
 		}
-		if (xxlJobGroup.getTitle()==null || StringUtils.isBlank(xxlJobGroup.getTitle())) {
+		if (xxlJobGroup.getTitle()==null || xxlJobGroup.getTitle().trim().length()==0) {
 			return new ReturnT<String>(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobgroup_field_title")) );
 		}
 		if (xxlJobGroup.getAddressType() == 0) {
@@ -92,17 +91,21 @@ public class JobGroupController {
 			String addressListStr = null;
 			if (registryList!=null && !registryList.isEmpty()) {
 				Collections.sort(registryList);
-				addressListStr = StringUtils.join(registryList, ",");
+				addressListStr = "";
+				for (String item:registryList) {
+					addressListStr += item + ",";
+				}
+				addressListStr = addressListStr.substring(0, addressListStr.length()-1);
 			}
 			xxlJobGroup.setAddressList(addressListStr);
 		} else {
 			// 1=手动录入
-			if (StringUtils.isBlank(xxlJobGroup.getAddressList())) {
+			if (xxlJobGroup.getAddressList()==null || xxlJobGroup.getAddressList().trim().length()==0) {
 				return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_addressType_limit") );
 			}
 			String[] addresss = xxlJobGroup.getAddressList().split(",");
 			for (String item: addresss) {
-				if (StringUtils.isBlank(item)) {
+				if (item==null || item.trim().length()==0) {
 					return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_registryList_unvalid") );
 				}
 			}

+ 8 - 11
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java

@@ -11,8 +11,7 @@ import com.xxl.job.admin.dao.XxlJobLogDao;
 import com.xxl.job.core.biz.ExecutorBiz;
 import com.xxl.job.core.biz.model.LogResult;
 import com.xxl.job.core.biz.model.ReturnT;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.time.DateUtils;
+import com.xxl.job.core.util.DateUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Controller;
@@ -76,13 +75,11 @@ public class JobLogController {
 		// parse param
 		Date triggerTimeStart = null;
 		Date triggerTimeEnd = null;
-		if (StringUtils.isNotBlank(filterTime)) {
+		if (filterTime!=null && filterTime.trim().length()>0) {
 			String[] temp = filterTime.split(" - ");
 			if (temp!=null && temp.length == 2) {
-				try {
-					triggerTimeStart = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"});
-					triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"});
-				} catch (ParseException e) {	}
+				triggerTimeStart = DateUtil.parseDateTime(temp[0]);
+				triggerTimeEnd = DateUtil.parseDateTime(temp[1]);
 			}
 		}
 		
@@ -179,13 +176,13 @@ public class JobLogController {
 		Date clearBeforeTime = null;
 		int clearBeforeNum = 0;
 		if (type == 1) {
-			clearBeforeTime = DateUtils.addMonths(new Date(), -1);	// 清理一个月之前日志数据
+			clearBeforeTime = DateUtil.addMonths(new Date(), -1);	// 清理一个月之前日志数据
 		} else if (type == 2) {
-			clearBeforeTime = DateUtils.addMonths(new Date(), -3);	// 清理三个月之前日志数据
+			clearBeforeTime = DateUtil.addMonths(new Date(), -3);	// 清理三个月之前日志数据
 		} else if (type == 3) {
-			clearBeforeTime = DateUtils.addMonths(new Date(), -6);	// 清理六个月之前日志数据
+			clearBeforeTime = DateUtil.addMonths(new Date(), -6);	// 清理六个月之前日志数据
 		} else if (type == 4) {
-			clearBeforeTime = DateUtils.addYears(new Date(), -1);	// 清理一年之前日志数据
+			clearBeforeTime = DateUtil.addYears(new Date(), -1);	// 清理一年之前日志数据
 		} else if (type == 5) {
 			clearBeforeNum = 1000;		// 清理一千条以前日志数据
 		} else if (type == 6) {

+ 1 - 2
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/CookieInterceptor.java

@@ -2,7 +2,6 @@ package com.xxl.job.admin.controller.interceptor;
 
 import com.xxl.job.admin.core.util.FtlUtil;
 import com.xxl.job.admin.core.util.I18nUtil;
-import org.apache.commons.lang3.ArrayUtils;
 import org.springframework.stereotype.Component;
 import org.springframework.web.servlet.ModelAndView;
 import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
@@ -25,7 +24,7 @@ public class CookieInterceptor extends HandlerInterceptorAdapter {
 			ModelAndView modelAndView) throws Exception {
 
 		// cookie
-		if (modelAndView!=null && ArrayUtils.isNotEmpty(request.getCookies())) {
+		if (modelAndView!=null && request.getCookies()!=null && request.getCookies().length>0) {
 			HashMap<String, Cookie> cookieMap = new HashMap<String, Cookie>();
 			for (Cookie ck : request.getCookies()) {
 				cookieMap.put(ck.getName(), ck);

+ 1 - 3
xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobGroup.java

@@ -1,7 +1,5 @@
 package com.xxl.job.admin.core.model;
 
-import org.apache.commons.lang3.StringUtils;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -21,7 +19,7 @@ public class XxlJobGroup {
     // registry list
     private List<String> registryList;  // 执行器地址列表(系统注册)
     public List<String> getRegistryList() {
-        if (StringUtils.isNotBlank(addressList)) {
+        if (addressList!=null && addressList.trim().length()>0) {
             registryList = new ArrayList<String>(Arrays.asList(addressList.split(",")));
         }
         return registryList;

+ 5 - 2
xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobRegistryMonitorHelper.java

@@ -4,7 +4,6 @@ import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
 import com.xxl.job.admin.core.model.XxlJobGroup;
 import com.xxl.job.admin.core.model.XxlJobRegistry;
 import com.xxl.job.core.enums.RegistryConfig;
-import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -67,7 +66,11 @@ public class JobRegistryMonitorHelper {
 								String addressListStr = null;
 								if (registryList!=null && !registryList.isEmpty()) {
 									Collections.sort(registryList);
-									addressListStr = StringUtils.join(registryList, ",");
+									addressListStr = "";
+									for (String item:registryList) {
+										addressListStr += item + ",";
+									}
+									addressListStr = addressListStr.substring(0, addressListStr.length()-1);
 								}
 								group.setAddressList(addressListStr);
 								XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().update(group);

+ 10 - 2
xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java

@@ -13,7 +13,6 @@ import com.xxl.job.core.biz.model.TriggerParam;
 import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
 import com.xxl.rpc.util.IpUtil;
 import com.xxl.rpc.util.ThrowableUtil;
-import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -56,7 +55,7 @@ public class XxlJobTrigger {
         int[] shardingParam = null;
         if (executorShardingParam!=null){
             String[] shardingArr = executorShardingParam.split("/");
-            if (shardingArr.length==2 && StringUtils.isNumeric(shardingArr[0]) && StringUtils.isNumeric(shardingArr[1])) {
+            if (shardingArr.length==2 && isNumeric(shardingArr[0]) && isNumeric(shardingArr[1])) {
                 shardingParam = new int[2];
                 shardingParam[0] = Integer.valueOf(shardingArr[0]);
                 shardingParam[1] = Integer.valueOf(shardingArr[1]);
@@ -77,6 +76,15 @@ public class XxlJobTrigger {
 
     }
 
+    private static boolean isNumeric(String str){
+        try {
+            int result = Integer.valueOf(str);
+            return true;
+        } catch (NumberFormatException e) {
+            return false;
+        }
+    }
+
     /**
      * @param group                     job group, registry list may be empty
      * @param jobInfo

+ 1 - 2
xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/I18nUtil.java

@@ -1,7 +1,6 @@
 package com.xxl.job.admin.core.util;
 
 import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
-import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.core.io.ClassPathResource;
@@ -31,7 +30,7 @@ public class I18nUtil {
         try {
             // build i18n prop
             String i18n = XxlJobAdminConfig.getAdminConfig().getI18n();
-            i18n = StringUtils.isNotBlank(i18n)?("_"+i18n):i18n;
+            i18n = (i18n!=null && i18n.trim().length()>0)?("_"+i18n):i18n;
             String i18nFile = MessageFormat.format("i18n/message{0}.properties", i18n);
 
             // load prop

+ 3 - 5
xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/LocalCacheUtil.java

@@ -1,7 +1,5 @@
 package com.xxl.job.admin.core.util;
 
-import org.apache.commons.lang3.StringUtils;
-
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
@@ -67,7 +65,7 @@ public class LocalCacheUtil {
         cleanTimeutCache();
 
         // set new cache
-        if (StringUtils.isBlank(key)) {
+        if (key==null || key.trim().length()==0) {
             return false;
         }
         if (val == null) {
@@ -89,7 +87,7 @@ public class LocalCacheUtil {
      * @return
      */
     public static boolean remove(String key){
-        if (StringUtils.isBlank(key)) {
+        if (key==null || key.trim().length()==0) {
             return false;
         }
         cacheRepository.remove(key);
@@ -103,7 +101,7 @@ public class LocalCacheUtil {
      * @return
      */
     public static Object get(String key){
-        if (StringUtils.isBlank(key)) {
+        if (key==null || key.trim().length()==0) {
             return null;
         }
         LocalCacheData localCacheData = cacheRepository.get(key);

+ 11 - 3
xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java

@@ -13,7 +13,6 @@ import com.xxl.job.core.biz.model.HandleCallbackParam;
 import com.xxl.job.core.biz.model.RegistryParam;
 import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.handler.IJobHandler;
-import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
@@ -63,12 +62,12 @@ public class AdminBizImpl implements AdminBiz {
         String callbackMsg = null;
         if (IJobHandler.SUCCESS.getCode() == handleCallbackParam.getExecuteResult().getCode()) {
             XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(log.getJobId());
-            if (xxlJobInfo!=null && StringUtils.isNotBlank(xxlJobInfo.getChildJobId())) {
+            if (xxlJobInfo!=null && xxlJobInfo.getChildJobId()!=null && xxlJobInfo.getChildJobId().trim().length()>0) {
                 callbackMsg = "<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_child_run") +"<<<<<<<<<<< </span><br>";
 
                 String[] childJobIds = xxlJobInfo.getChildJobId().split(",");
                 for (int i = 0; i < childJobIds.length; i++) {
-                    int childJobId = (StringUtils.isNotBlank(childJobIds[i]) && StringUtils.isNumeric(childJobIds[i]))?Integer.valueOf(childJobIds[i]):-1;
+                    int childJobId = (childJobIds[i]!=null && childJobIds[i].trim().length()>0 && isNumeric(childJobIds[i]))?Integer.valueOf(childJobIds[i]):-1;
                     if (childJobId > 0) {
 
                         JobTriggerPoolHelper.trigger(childJobId, TriggerTypeEnum.PARENT, -1, null, null);
@@ -113,6 +112,15 @@ public class AdminBizImpl implements AdminBiz {
         return ReturnT.SUCCESS;
     }
 
+    private boolean isNumeric(String str){
+        try {
+            int result = Integer.valueOf(str);
+            return true;
+        } catch (NumberFormatException e) {
+            return false;
+        }
+    }
+
     @Override
     public ReturnT<String> registry(RegistryParam registryParam) {
         int ret = xxlJobRegistryDao.registryUpdate(registryParam.getRegistGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue());

+ 38 - 17
xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java

@@ -13,9 +13,7 @@ import com.xxl.job.admin.service.XxlJobService;
 import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
 import com.xxl.job.core.glue.GlueTypeEnum;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.time.DateUtils;
-import org.apache.commons.lang3.time.FastDateFormat;
+import com.xxl.job.core.util.DateUtil;
 import org.quartz.CronExpression;
 import org.quartz.SchedulerException;
 import org.slf4j.Logger;
@@ -75,10 +73,10 @@ public class XxlJobServiceImpl implements XxlJobService {
 		if (!CronExpression.isValidExpression(jobInfo.getJobCron())) {
 			return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("jobinfo_field_cron_unvalid") );
 		}
-		if (StringUtils.isBlank(jobInfo.getJobDesc())) {
+		if (jobInfo.getJobDesc()==null || jobInfo.getJobDesc().trim().length()==0) {
 			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_jobdesc")) );
 		}
-		if (StringUtils.isBlank(jobInfo.getAuthor())) {
+		if (jobInfo.getAuthor()==null || jobInfo.getAuthor().trim().length()==0) {
 			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_author")) );
 		}
 		if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {
@@ -90,7 +88,7 @@ public class XxlJobServiceImpl implements XxlJobService {
 		if (GlueTypeEnum.match(jobInfo.getGlueType()) == null) {
 			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_gluetype")+I18nUtil.getString("system_unvalid")) );
 		}
-		if (GlueTypeEnum.BEAN==GlueTypeEnum.match(jobInfo.getGlueType()) && StringUtils.isBlank(jobInfo.getExecutorHandler())) {
+		if (GlueTypeEnum.BEAN==GlueTypeEnum.match(jobInfo.getGlueType()) && (jobInfo.getExecutorHandler()==null || jobInfo.getExecutorHandler().trim().length()==0) ) {
 			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+"JobHandler") );
 		}
 
@@ -100,10 +98,10 @@ public class XxlJobServiceImpl implements XxlJobService {
 		}
 
 		// ChildJobId valid
-		if (StringUtils.isNotBlank(jobInfo.getChildJobId())) {
-			String[] childJobIds = StringUtils.split(jobInfo.getChildJobId(), ",");
+		if (jobInfo.getChildJobId()!=null && jobInfo.getChildJobId().trim().length()>0) {
+			String[] childJobIds = jobInfo.getChildJobId().split(",");
 			for (String childJobIdItem: childJobIds) {
-				if (StringUtils.isNotBlank(childJobIdItem) && StringUtils.isNumeric(childJobIdItem)) {
+				if (childJobIdItem!=null && childJobIdItem.trim().length()>0 && isNumeric(childJobIdItem)) {
 					XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobIdItem));
 					if (childJobInfo==null) {
 						return new ReturnT<String>(ReturnT.FAIL_CODE,
@@ -114,7 +112,14 @@ public class XxlJobServiceImpl implements XxlJobService {
 							MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_unvalid")), childJobIdItem));
 				}
 			}
-			jobInfo.setChildJobId(StringUtils.join(childJobIds, ","));
+
+			String temp = "";	// join ,
+			for (String item:childJobIds) {
+				temp += item + ",";
+			}
+			temp = temp.substring(0, temp.length()-1);
+
+			jobInfo.setChildJobId(temp);
 		}
 
 		// add in db
@@ -126,6 +131,15 @@ public class XxlJobServiceImpl implements XxlJobService {
 		return new ReturnT<String>(String.valueOf(jobInfo.getId()));
 	}
 
+	private boolean isNumeric(String str){
+		try {
+			int result = Integer.valueOf(str);
+			return true;
+		} catch (NumberFormatException e) {
+			return false;
+		}
+	}
+
 	@Override
 	public ReturnT<String> update(XxlJobInfo jobInfo) {
 
@@ -133,10 +147,10 @@ public class XxlJobServiceImpl implements XxlJobService {
 		if (!CronExpression.isValidExpression(jobInfo.getJobCron())) {
 			return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("jobinfo_field_cron_unvalid") );
 		}
-		if (StringUtils.isBlank(jobInfo.getJobDesc())) {
+		if (jobInfo.getJobDesc()==null || jobInfo.getJobDesc().trim().length()==0) {
 			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_jobdesc")) );
 		}
-		if (StringUtils.isBlank(jobInfo.getAuthor())) {
+		if (jobInfo.getAuthor()==null || jobInfo.getAuthor().trim().length()==0) {
 			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_author")) );
 		}
 		if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {
@@ -147,10 +161,10 @@ public class XxlJobServiceImpl implements XxlJobService {
 		}
 
 		// ChildJobId valid
-		if (StringUtils.isNotBlank(jobInfo.getChildJobId())) {
-			String[] childJobIds = StringUtils.split(jobInfo.getChildJobId(), ",");
+		if (jobInfo.getChildJobId()!=null && jobInfo.getChildJobId().trim().length()>0) {
+			String[] childJobIds = jobInfo.getChildJobId().split(",");
 			for (String childJobIdItem: childJobIds) {
-				if (StringUtils.isNotBlank(childJobIdItem) && StringUtils.isNumeric(childJobIdItem)) {
+				if (childJobIdItem!=null && childJobIdItem.trim().length()>0 && isNumeric(childJobIdItem)) {
 					XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobIdItem));
 					if (childJobInfo==null) {
 						return new ReturnT<String>(ReturnT.FAIL_CODE,
@@ -161,7 +175,14 @@ public class XxlJobServiceImpl implements XxlJobService {
 							MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_unvalid")), childJobIdItem));
 				}
 			}
-			jobInfo.setChildJobId(StringUtils.join(childJobIds, ","));
+
+			String temp = "";	// join ,
+			for (String item:childJobIds) {
+				temp += item + ",";
+			}
+			temp = temp.substring(0, temp.length()-1);
+
+			jobInfo.setChildJobId(temp);
 		}
 
 		// group valid
@@ -348,7 +369,7 @@ public class XxlJobServiceImpl implements XxlJobService {
 			}
 		} else {
             for (int i = 4; i > -1; i--) {
-                triggerDayList.add(FastDateFormat.getInstance("yyyy-MM-dd").format(DateUtils.addDays(new Date(), -i)));
+                triggerDayList.add(DateUtil.formatDate(DateUtil.addDays(new Date(), -i)));
 				triggerDayCountRunningList.add(0);
                 triggerDayCountSucList.add(0);
                 triggerDayCountFailList.add(0);

+ 1 - 2
xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobLogDaoTest.java

@@ -1,7 +1,6 @@
 package com.xxl.job.admin.dao;
 
 import com.xxl.job.admin.core.model.XxlJobLog;
-import org.apache.commons.lang3.time.DateUtils;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.test.context.ContextConfiguration;
@@ -48,7 +47,7 @@ public class XxlJobLogDaoTest {
         dto = xxlJobLogDao.load(log.getId());
 
 
-        List<Map<String, Object>> list2 = xxlJobLogDao.triggerCountByDay(DateUtils.addDays(new Date(), 30), new Date());
+        List<Map<String, Object>> list2 = xxlJobLogDao.triggerCountByDay(new Date(new Date().getTime() + 30*24*60*60*1000), new Date());
 
         int ret4 = xxlJobLogDao.clearLog(1, 1, new Date(), 100);
 

+ 1 - 1
xxl-job-core/src/main/java/com/xxl/job/core/log/XxlJobLogger.java

@@ -30,7 +30,7 @@ public class XxlJobLogger {
         StackTraceElement callInfo = stackTraceElements[1];*/
 
         StringBuffer stringBuffer = new StringBuffer();
-        stringBuffer.append(DateUtil.format(new Date())).append(" ")
+        stringBuffer.append(DateUtil.formatDateTime(new Date())).append(" ")
             .append("["+ callInfo.getClassName() + "#" + callInfo.getMethodName() +"]").append("-")
             .append("["+ callInfo.getLineNumber() +"]").append("-")
             .append("["+ Thread.currentThread().getName() +"]").append(" ")

+ 129 - 11
xxl-job-core/src/main/java/com/xxl/job/core/util/DateUtil.java

@@ -1,8 +1,15 @@
 package com.xxl.job.core.util;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.text.DateFormat;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
+import java.util.Calendar;
 import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * date util
@@ -10,21 +17,132 @@ import java.util.Date;
  * @author xuxueli 2018-08-19 01:24:11
  */
 public class DateUtil {
-    private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
 
-    private static ThreadLocal<SimpleDateFormat> threadLocal = new ThreadLocal<SimpleDateFormat>() {
-        @Override
-        protected synchronized SimpleDateFormat initialValue() {
-            //return super.initialValue();
-            return new SimpleDateFormat(DATE_FORMAT);
+    // ---------------------- format parse ----------------------
+    private static Logger logger = LoggerFactory.getLogger(DateUtil.class);
+
+    private static final String DATE_FORMAT = "yyyy-MM-dd";
+    private static final String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
+
+    private static ThreadLocal<Map<String, DateFormat>> dateFormatThreadLocal = new ThreadLocal<Map<String, DateFormat>>();
+    private static DateFormat getDateFormat(String pattern) {
+        if (pattern==null || pattern.trim().length()==0) {
+            throw new IllegalArgumentException("pattern cannot be empty.");
+        }
+
+        Map<String, DateFormat> dateFormatMap = dateFormatThreadLocal.get();
+        if(dateFormatMap!=null && dateFormatMap.containsKey(pattern)){
+            return dateFormatMap.get(pattern);
+        }
+
+        synchronized (dateFormatThreadLocal) {
+            if (dateFormatMap == null) {
+                dateFormatMap = new HashMap<String, DateFormat>();
+            }
+            dateFormatMap.put(pattern, new SimpleDateFormat(pattern));
+            dateFormatThreadLocal.set(dateFormatMap);
+        }
+
+        return dateFormatMap.get(pattern);
+    }
+
+    /**
+     * format datetime. like "yyyy-MM-dd"
+     *
+     * @param date
+     * @return
+     * @throws ParseException
+     */
+    public static String formatDate(Date date) {
+        return format(date, DATE_FORMAT);
+    }
+
+    /**
+     * format date. like "yyyy-MM-dd HH:mm:ss"
+     *
+     * @param date
+     * @return
+     * @throws ParseException
+     */
+    public static String formatDateTime(Date date) {
+        return format(date, DATETIME_FORMAT);
+    }
+
+    /**
+     * format date
+     *
+     * @param date
+     * @param patten
+     * @return
+     * @throws ParseException
+     */
+    public static String format(Date date, String patten) {
+        return getDateFormat(patten).format(date);
+    }
+
+    /**
+     * parse date string, like "yyyy-MM-dd HH:mm:s"
+     *
+     * @param dateString
+     * @return
+     * @throws ParseException
+     */
+    public static Date parseDate(String dateString){
+        return parse(dateString, DATE_FORMAT);
+    }
+
+    /**
+     * parse datetime string, like "yyyy-MM-dd HH:mm:ss"
+     *
+     * @param dateString
+     * @return
+     * @throws ParseException
+     */
+    public static Date parseDateTime(String dateString) {
+        return parse(dateString, DATETIME_FORMAT);
+    }
+
+    /**
+     * parse date
+     *
+     * @param dateString
+     * @param pattern
+     * @return
+     * @throws ParseException
+     */
+    public static Date parse(String dateString, String pattern) {
+        try {
+            Date date = getDateFormat(pattern).parse(dateString);
+            return date;
+        } catch (Exception e) {
+            logger.warn("parse date error, dateString = {}, pattern={}; errorMsg = ", dateString, pattern, e.getMessage());
+            return null;
         }
-    };
+    }
+
 
-    public static String format(Date date) {
-        return threadLocal.get().format(date);
+    // ---------------------- add date ----------------------
+
+    public static Date addDays(final Date date, final int amount) {
+        return add(date, Calendar.DAY_OF_MONTH, amount);
+    }
+
+    public static Date addYears(final Date date, final int amount) {
+        return add(date, Calendar.YEAR, amount);
     }
 
-    public static Date parse(String textDate) throws ParseException {
-        return threadLocal.get().parse(textDate);
+    public static Date addMonths(final Date date, final int amount) {
+        return add(date, Calendar.MONTH, amount);
     }
+
+    private static Date add(final Date date, final int calendarField, final int amount) {
+        if (date == null) {
+            return null;
+        }
+        final Calendar c = Calendar.getInstance();
+        c.setTime(date);
+        c.add(calendarField, amount);
+        return c.getTime();
+    }
+
 }