diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index bfa25fe..192e6e6 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -130,6 +130,13 @@ 4.3.6 + + + javax.mail + mail + 1.4.6 + + org.quartz-scheduler diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index bfa25fe..192e6e6 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -130,6 +130,13 @@ 4.3.6 + + + javax.mail + mail + 1.4.6 + + org.quartz-scheduler diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java new file mode 100644 index 0000000..9060e28 --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java @@ -0,0 +1,41 @@ +package com.xxl.job.controller.resolver; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerExceptionResolver; +import org.springframework.web.servlet.ModelAndView; + +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.model.ReturnT; + +/** + * common exception resolver + * @author xuxueli 2016-1-6 19:22:18 + */ +public class WebExceptionResolver implements HandlerExceptionResolver { + private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class); + + @Override + public ModelAndView resolveException(HttpServletRequest request, + HttpServletResponse response, Object handler, Exception ex) { + logger.error("system catch exception:{}", ex); + + ModelAndView mv = new ModelAndView(); + HandlerMethod method = (HandlerMethod)handler; + ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class); + if (responseBody != null) { + mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
")))); + mv.setViewName("/common/common.result"); + } else { + mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
")); + mv.setViewName("/common/common.exception"); + } + return mv; + } + +} \ No newline at end of file diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index bfa25fe..192e6e6 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -130,6 +130,13 @@ 4.3.6
+ + + javax.mail + mail + 1.4.6 + + org.quartz-scheduler diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java new file mode 100644 index 0000000..9060e28 --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java @@ -0,0 +1,41 @@ +package com.xxl.job.controller.resolver; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerExceptionResolver; +import org.springframework.web.servlet.ModelAndView; + +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.model.ReturnT; + +/** + * common exception resolver + * @author xuxueli 2016-1-6 19:22:18 + */ +public class WebExceptionResolver implements HandlerExceptionResolver { + private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class); + + @Override + public ModelAndView resolveException(HttpServletRequest request, + HttpServletResponse response, Object handler, Exception ex) { + logger.error("system catch exception:{}", ex); + + ModelAndView mv = new ModelAndView(); + HandlerMethod method = (HandlerMethod)handler; + ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class); + if (responseBody != null) { + mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
")))); + mv.setViewName("/common/common.result"); + } else { + mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
")); + mv.setViewName("/common/common.exception"); + } + return mv; + } + +} \ No newline at end of file diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java deleted file mode 100644 index 3bc58d7..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.xxl.job.core.resolver; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.method.HandlerMethod; -import org.springframework.web.servlet.HandlerExceptionResolver; -import org.springframework.web.servlet.ModelAndView; - -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; - -/** - * common exception resolver - * @author xuxueli 2016-1-6 19:22:18 - */ -public class WebExceptionResolver implements HandlerExceptionResolver { - private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class); - - @Override - public ModelAndView resolveException(HttpServletRequest request, - HttpServletResponse response, Object handler, Exception ex) { - logger.error("system catch exception:{}", ex); - - ModelAndView mv = new ModelAndView(); - HandlerMethod method = (HandlerMethod)handler; - ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class); - if (responseBody != null) { - mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
")))); - mv.setViewName("/common/common.result"); - } else { - mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
")); - mv.setViewName("/common/common.exception"); - } - return mv; - } - -} \ No newline at end of file diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index bfa25fe..192e6e6 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -130,6 +130,13 @@ 4.3.6
+ + + javax.mail + mail + 1.4.6 + + org.quartz-scheduler diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java new file mode 100644 index 0000000..9060e28 --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java @@ -0,0 +1,41 @@ +package com.xxl.job.controller.resolver; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerExceptionResolver; +import org.springframework.web.servlet.ModelAndView; + +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.model.ReturnT; + +/** + * common exception resolver + * @author xuxueli 2016-1-6 19:22:18 + */ +public class WebExceptionResolver implements HandlerExceptionResolver { + private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class); + + @Override + public ModelAndView resolveException(HttpServletRequest request, + HttpServletResponse response, Object handler, Exception ex) { + logger.error("system catch exception:{}", ex); + + ModelAndView mv = new ModelAndView(); + HandlerMethod method = (HandlerMethod)handler; + ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class); + if (responseBody != null) { + mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
")))); + mv.setViewName("/common/common.result"); + } else { + mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
")); + mv.setViewName("/common/common.exception"); + } + return mv; + } + +} \ No newline at end of file diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java deleted file mode 100644 index 3bc58d7..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.xxl.job.core.resolver; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.method.HandlerMethod; -import org.springframework.web.servlet.HandlerExceptionResolver; -import org.springframework.web.servlet.ModelAndView; - -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; - -/** - * common exception resolver - * @author xuxueli 2016-1-6 19:22:18 - */ -public class WebExceptionResolver implements HandlerExceptionResolver { - private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class); - - @Override - public ModelAndView resolveException(HttpServletRequest request, - HttpServletResponse response, Object handler, Exception ex) { - logger.error("system catch exception:{}", ex); - - ModelAndView mv = new ModelAndView(); - HandlerMethod method = (HandlerMethod)handler; - ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class); - if (responseBody != null) { - mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
")))); - mv.setViewName("/common/common.result"); - } else { - mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
")); - mv.setViewName("/common/common.exception"); - } - return mv; - } - -} \ No newline at end of file diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java new file mode 100644 index 0000000..c322d9c --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java @@ -0,0 +1,82 @@ +package com.xxl.job.core.thread; + +import java.text.MessageFormat; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.xxl.job.client.util.HttpUtil; +import com.xxl.job.core.model.XxlJobInfo; +import com.xxl.job.core.model.XxlJobLog; +import com.xxl.job.core.util.DynamicSchedulerUtil; +import com.xxl.job.core.util.MailUtil; + +/** + * job monitor helper + * @author xuxueli 2015-9-1 18:05:56 + */ +public class JobMonitorHelper { + private static Logger logger = LoggerFactory.getLogger(JobMonitorHelper.class); + + public static JobMonitorHelper helper = new JobMonitorHelper(); + private ExecutorService executor = Executors.newCachedThreadPool(); + private LinkedBlockingQueue queue = new LinkedBlockingQueue(0xfff8); + private ConcurrentHashMap countMap = new ConcurrentHashMap(); + + public JobMonitorHelper(){ + // consumer + executor.execute(new Runnable() { + @Override + public void run() { + while (true) { + logger.info(">>>>>>>>>>> job monitor run ... "); + Integer jobLogId = JobMonitorHelper.helper.queue.poll(); + if (jobLogId != null && jobLogId > 0) { + XxlJobLog log = DynamicSchedulerUtil.xxlJobLogDao.load(jobLogId); + if (log!=null) { + if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && StringUtils.isBlank(log.getHandleStatus())) { + JobMonitorHelper.monitor(jobLogId); + } + if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && HttpUtil.SUCCESS.equals(log.getHandleStatus())) { + // pass + } + if (HttpUtil.FAIL.equals(log.getTriggerStatus()) || HttpUtil.FAIL.equals(log.getHandleStatus())) { + String monotorKey = log.getJobGroup().concat("_").concat(log.getJobName()); + Integer count = countMap.get(monotorKey); + if (count == null) { + count = new Integer(0); + } + count += 1; + countMap.put(monotorKey, count); + XxlJobInfo info = DynamicSchedulerUtil.xxlJobInfoDao.load(log.getJobGroup(), log.getJobName()); + if (count >= info.getAlarmThreshold()) { + MailUtil.sendMail(info.getAlarmEmail(), "《调度平台中心-监控报警》", + MessageFormat.format("调度任务[{0}]失败报警", monotorKey), false, null); + countMap.remove(monotorKey); + } + } + } + } else { + try { + TimeUnit.SECONDS.sleep(20); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + }); + } + + // producer + public static void monitor(int jobLogId){ + JobMonitorHelper.helper.queue.offer(jobLogId); + } + +} diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index bfa25fe..192e6e6 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -130,6 +130,13 @@ 4.3.6
+ + + javax.mail + mail + 1.4.6 + + org.quartz-scheduler diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java new file mode 100644 index 0000000..9060e28 --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java @@ -0,0 +1,41 @@ +package com.xxl.job.controller.resolver; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerExceptionResolver; +import org.springframework.web.servlet.ModelAndView; + +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.model.ReturnT; + +/** + * common exception resolver + * @author xuxueli 2016-1-6 19:22:18 + */ +public class WebExceptionResolver implements HandlerExceptionResolver { + private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class); + + @Override + public ModelAndView resolveException(HttpServletRequest request, + HttpServletResponse response, Object handler, Exception ex) { + logger.error("system catch exception:{}", ex); + + ModelAndView mv = new ModelAndView(); + HandlerMethod method = (HandlerMethod)handler; + ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class); + if (responseBody != null) { + mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
")))); + mv.setViewName("/common/common.result"); + } else { + mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
")); + mv.setViewName("/common/common.exception"); + } + return mv; + } + +} \ No newline at end of file diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java deleted file mode 100644 index 3bc58d7..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.xxl.job.core.resolver; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.method.HandlerMethod; -import org.springframework.web.servlet.HandlerExceptionResolver; -import org.springframework.web.servlet.ModelAndView; - -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; - -/** - * common exception resolver - * @author xuxueli 2016-1-6 19:22:18 - */ -public class WebExceptionResolver implements HandlerExceptionResolver { - private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class); - - @Override - public ModelAndView resolveException(HttpServletRequest request, - HttpServletResponse response, Object handler, Exception ex) { - logger.error("system catch exception:{}", ex); - - ModelAndView mv = new ModelAndView(); - HandlerMethod method = (HandlerMethod)handler; - ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class); - if (responseBody != null) { - mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
")))); - mv.setViewName("/common/common.result"); - } else { - mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
")); - mv.setViewName("/common/common.exception"); - } - return mv; - } - -} \ No newline at end of file diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java new file mode 100644 index 0000000..c322d9c --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java @@ -0,0 +1,82 @@ +package com.xxl.job.core.thread; + +import java.text.MessageFormat; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.xxl.job.client.util.HttpUtil; +import com.xxl.job.core.model.XxlJobInfo; +import com.xxl.job.core.model.XxlJobLog; +import com.xxl.job.core.util.DynamicSchedulerUtil; +import com.xxl.job.core.util.MailUtil; + +/** + * job monitor helper + * @author xuxueli 2015-9-1 18:05:56 + */ +public class JobMonitorHelper { + private static Logger logger = LoggerFactory.getLogger(JobMonitorHelper.class); + + public static JobMonitorHelper helper = new JobMonitorHelper(); + private ExecutorService executor = Executors.newCachedThreadPool(); + private LinkedBlockingQueue queue = new LinkedBlockingQueue(0xfff8); + private ConcurrentHashMap countMap = new ConcurrentHashMap(); + + public JobMonitorHelper(){ + // consumer + executor.execute(new Runnable() { + @Override + public void run() { + while (true) { + logger.info(">>>>>>>>>>> job monitor run ... "); + Integer jobLogId = JobMonitorHelper.helper.queue.poll(); + if (jobLogId != null && jobLogId > 0) { + XxlJobLog log = DynamicSchedulerUtil.xxlJobLogDao.load(jobLogId); + if (log!=null) { + if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && StringUtils.isBlank(log.getHandleStatus())) { + JobMonitorHelper.monitor(jobLogId); + } + if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && HttpUtil.SUCCESS.equals(log.getHandleStatus())) { + // pass + } + if (HttpUtil.FAIL.equals(log.getTriggerStatus()) || HttpUtil.FAIL.equals(log.getHandleStatus())) { + String monotorKey = log.getJobGroup().concat("_").concat(log.getJobName()); + Integer count = countMap.get(monotorKey); + if (count == null) { + count = new Integer(0); + } + count += 1; + countMap.put(monotorKey, count); + XxlJobInfo info = DynamicSchedulerUtil.xxlJobInfoDao.load(log.getJobGroup(), log.getJobName()); + if (count >= info.getAlarmThreshold()) { + MailUtil.sendMail(info.getAlarmEmail(), "《调度平台中心-监控报警》", + MessageFormat.format("调度任务[{0}]失败报警", monotorKey), false, null); + countMap.remove(monotorKey); + } + } + } + } else { + try { + TimeUnit.SECONDS.sleep(20); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + }); + } + + // producer + public static void monitor(int jobLogId){ + JobMonitorHelper.helper.queue.offer(jobLogId); + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java index 1b06f65..ef675c7 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java @@ -67,6 +67,7 @@ } // getJobKeys + @Deprecated public static List> getJobList(){ List> jobList = new ArrayList>(); diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index bfa25fe..192e6e6 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -130,6 +130,13 @@ 4.3.6
+ + + javax.mail + mail + 1.4.6 + + org.quartz-scheduler diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java new file mode 100644 index 0000000..9060e28 --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java @@ -0,0 +1,41 @@ +package com.xxl.job.controller.resolver; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerExceptionResolver; +import org.springframework.web.servlet.ModelAndView; + +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.model.ReturnT; + +/** + * common exception resolver + * @author xuxueli 2016-1-6 19:22:18 + */ +public class WebExceptionResolver implements HandlerExceptionResolver { + private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class); + + @Override + public ModelAndView resolveException(HttpServletRequest request, + HttpServletResponse response, Object handler, Exception ex) { + logger.error("system catch exception:{}", ex); + + ModelAndView mv = new ModelAndView(); + HandlerMethod method = (HandlerMethod)handler; + ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class); + if (responseBody != null) { + mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
")))); + mv.setViewName("/common/common.result"); + } else { + mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
")); + mv.setViewName("/common/common.exception"); + } + return mv; + } + +} \ No newline at end of file diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java deleted file mode 100644 index 3bc58d7..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.xxl.job.core.resolver; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.method.HandlerMethod; -import org.springframework.web.servlet.HandlerExceptionResolver; -import org.springframework.web.servlet.ModelAndView; - -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; - -/** - * common exception resolver - * @author xuxueli 2016-1-6 19:22:18 - */ -public class WebExceptionResolver implements HandlerExceptionResolver { - private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class); - - @Override - public ModelAndView resolveException(HttpServletRequest request, - HttpServletResponse response, Object handler, Exception ex) { - logger.error("system catch exception:{}", ex); - - ModelAndView mv = new ModelAndView(); - HandlerMethod method = (HandlerMethod)handler; - ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class); - if (responseBody != null) { - mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
")))); - mv.setViewName("/common/common.result"); - } else { - mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
")); - mv.setViewName("/common/common.exception"); - } - return mv; - } - -} \ No newline at end of file diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java new file mode 100644 index 0000000..c322d9c --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java @@ -0,0 +1,82 @@ +package com.xxl.job.core.thread; + +import java.text.MessageFormat; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.xxl.job.client.util.HttpUtil; +import com.xxl.job.core.model.XxlJobInfo; +import com.xxl.job.core.model.XxlJobLog; +import com.xxl.job.core.util.DynamicSchedulerUtil; +import com.xxl.job.core.util.MailUtil; + +/** + * job monitor helper + * @author xuxueli 2015-9-1 18:05:56 + */ +public class JobMonitorHelper { + private static Logger logger = LoggerFactory.getLogger(JobMonitorHelper.class); + + public static JobMonitorHelper helper = new JobMonitorHelper(); + private ExecutorService executor = Executors.newCachedThreadPool(); + private LinkedBlockingQueue queue = new LinkedBlockingQueue(0xfff8); + private ConcurrentHashMap countMap = new ConcurrentHashMap(); + + public JobMonitorHelper(){ + // consumer + executor.execute(new Runnable() { + @Override + public void run() { + while (true) { + logger.info(">>>>>>>>>>> job monitor run ... "); + Integer jobLogId = JobMonitorHelper.helper.queue.poll(); + if (jobLogId != null && jobLogId > 0) { + XxlJobLog log = DynamicSchedulerUtil.xxlJobLogDao.load(jobLogId); + if (log!=null) { + if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && StringUtils.isBlank(log.getHandleStatus())) { + JobMonitorHelper.monitor(jobLogId); + } + if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && HttpUtil.SUCCESS.equals(log.getHandleStatus())) { + // pass + } + if (HttpUtil.FAIL.equals(log.getTriggerStatus()) || HttpUtil.FAIL.equals(log.getHandleStatus())) { + String monotorKey = log.getJobGroup().concat("_").concat(log.getJobName()); + Integer count = countMap.get(monotorKey); + if (count == null) { + count = new Integer(0); + } + count += 1; + countMap.put(monotorKey, count); + XxlJobInfo info = DynamicSchedulerUtil.xxlJobInfoDao.load(log.getJobGroup(), log.getJobName()); + if (count >= info.getAlarmThreshold()) { + MailUtil.sendMail(info.getAlarmEmail(), "《调度平台中心-监控报警》", + MessageFormat.format("调度任务[{0}]失败报警", monotorKey), false, null); + countMap.remove(monotorKey); + } + } + } + } else { + try { + TimeUnit.SECONDS.sleep(20); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + }); + } + + // producer + public static void monitor(int jobLogId){ + JobMonitorHelper.helper.queue.offer(jobLogId); + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java index 1b06f65..ef675c7 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java @@ -67,6 +67,7 @@ } // getJobKeys + @Deprecated public static List> getJobList(){ List> jobList = new ArrayList>(); diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java new file mode 100644 index 0000000..ff2204d --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java @@ -0,0 +1,181 @@ +package com.xxl.job.core.util; + +import java.io.File; +import java.util.Properties; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeUtility; + +import org.apache.commons.lang.ArrayUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.JavaMailSenderImpl; +import org.springframework.mail.javamail.MimeMessageHelper; + +/** + * 邮件发送.Util + * @author xuxueli 2016-3-12 15:06:20 + */ +public class MailUtil { + private static Logger logger = LoggerFactory.getLogger(MailUtil.class); + + private static String host; + private static String port; + private static String username; + private static String password; + private static String sendFrom; + private static String sendNick; + static{ + host = PropertiesUtil.getString("mail.host"); + port = PropertiesUtil.getString("mail.port"); + username = PropertiesUtil.getString("mail.username"); + password = PropertiesUtil.getString("mail.password"); + sendFrom = PropertiesUtil.getString("mail.sendFrom"); + sendNick = PropertiesUtil.getString("mail.sendNick"); + } + + /** + + + + + + + + + true + true + + + + + */ + /** + * 发送邮件 (完整版)(结合Spring) + * + * @param javaMailSender: 发送Bean + * @param sendFrom : 发送人邮箱 + * @param sendNick : 发送人昵称 + * @param toAddress : 收件人邮箱 + * @param mailSubject : 邮件主题 + * @param mailBody : 邮件正文 + * @param mailBodyIsHtml: 邮件正文格式,true:HTML格式;false:文本格式 + * @param files[] : 附件 + */ + @SuppressWarnings("null") + public static boolean sendMailSpring(String toAddress, String mailSubject, String mailBody, boolean mailBodyIsHtml,File[] attachments) { + JavaMailSender javaMailSender = null;//ResourceBundle.getInstance().getJavaMailSender(); + try { + MimeMessage mimeMessage = javaMailSender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, ArrayUtils.isNotEmpty(attachments), "UTF-8"); // 设置utf-8或GBK编码,否则邮件会有乱码;multipart,true表示文件上传 + + helper.setFrom(sendFrom, sendNick); + helper.setTo(toAddress); + + // 设置收件人抄送的名片和地址(相当于群发了) + //helper.setCc(InternetAddress.parse(MimeUtility.encodeText("邮箱001") + " <@163.com>," + MimeUtility.encodeText("邮箱002") + " <@foxmail.com>")); + + helper.setSubject(mailSubject); + helper.setText(mailBody, mailBodyIsHtml); + + // 添加附件 + if (ArrayUtils.isNotEmpty(attachments)) { + for (File file : attachments) { + helper.addAttachment(MimeUtility.encodeText(file.getName()), file); + } + } + + // 群发 + //MimeMessage[] mailMessages = { mimeMessage }; + + javaMailSender.send(mimeMessage); + return true; + } catch (Exception e) { + logger.info("{}", e); + } + return false; + } + + /** + * 发送邮件 (完整版) (纯JavaMail) + * + * @param toAddress : 收件人邮箱 + * @param mailSubject : 邮件主题 + * @param mailBody : 邮件正文 + * @param mailBodyIsHtml: 邮件正文格式,true:HTML格式;false:文本格式 + * @param inLineFile : 内嵌文件 + * @param files[] : 附件 + */ + public static boolean sendMail (String toAddress, String mailSubject, String mailBody, + boolean mailBodyIsHtml, File[] attachments){ + try { + // 创建邮件发送类 JavaMailSender (用于发送多元化邮件,包括附件,图片,html 等 ) + JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); + mailSender.setHost(host); // 设置邮件服务主机 + mailSender.setUsername(username); // 发送者邮箱的用户名 + mailSender.setPassword(password); // 发送者邮箱的密码 + + //配置文件,用于实例化java.mail.session + Properties pro = System.getProperties(); + pro.put("mail.smtp.auth", "true"); // 登录SMTP服务器,需要获得授权 (网易163邮箱新近注册的邮箱均不能授权,测试 sohu 的邮箱可以获得授权) + pro.put("mail.smtp.socketFactory.port", port); + pro.put("mail.smtp.socketFactory.fallback", "false"); + mailSender.setJavaMailProperties(pro); + + //创建多元化邮件 (创建 mimeMessage 帮助类,用于封装信息至 mimeMessage) + MimeMessage mimeMessage = mailSender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, ArrayUtils.isNotEmpty(attachments), "UTF-8"); + + helper.setFrom(sendFrom, sendNick); + helper.setTo(toAddress); + + helper.setSubject(mailSubject); + helper.setText(mailBody, mailBodyIsHtml); + + // 添加内嵌文件,第1个参数为cid标识这个文件,第2个参数为资源 + //helper.addInline(MimeUtility.encodeText(inLineFile.getName()), inLineFile); + + // 添加附件 + if (ArrayUtils.isNotEmpty(attachments)) { + for (File file : attachments) { + helper.addAttachment(MimeUtility.encodeText(file.getName()), file); + } + } + + mailSender.send(mimeMessage); + return true; + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } + + static int total = 0; + public static void main(String[] args) { + + ExecutorService exec = Executors.newCachedThreadPool(); + for (int i = 0; i < 20; i++) { + exec.execute(new Thread(new Runnable() { + @Override + public void run() { + while(total < 10){ + String mailBody = "

新书快递通知

你的新书快递申请已推送新书,请到空间" + + "中查看"; + + sendMail("ovono802302@163.com", "测试邮件", mailBody, false, null); + System.out.println(total); + total++; + } + } + })); + } + } + +} diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index bfa25fe..192e6e6 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -130,6 +130,13 @@ 4.3.6
+ + + javax.mail + mail + 1.4.6 + + org.quartz-scheduler diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java new file mode 100644 index 0000000..9060e28 --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java @@ -0,0 +1,41 @@ +package com.xxl.job.controller.resolver; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerExceptionResolver; +import org.springframework.web.servlet.ModelAndView; + +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.model.ReturnT; + +/** + * common exception resolver + * @author xuxueli 2016-1-6 19:22:18 + */ +public class WebExceptionResolver implements HandlerExceptionResolver { + private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class); + + @Override + public ModelAndView resolveException(HttpServletRequest request, + HttpServletResponse response, Object handler, Exception ex) { + logger.error("system catch exception:{}", ex); + + ModelAndView mv = new ModelAndView(); + HandlerMethod method = (HandlerMethod)handler; + ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class); + if (responseBody != null) { + mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
")))); + mv.setViewName("/common/common.result"); + } else { + mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
")); + mv.setViewName("/common/common.exception"); + } + return mv; + } + +} \ No newline at end of file diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java deleted file mode 100644 index 3bc58d7..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.xxl.job.core.resolver; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.method.HandlerMethod; -import org.springframework.web.servlet.HandlerExceptionResolver; -import org.springframework.web.servlet.ModelAndView; - -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; - -/** - * common exception resolver - * @author xuxueli 2016-1-6 19:22:18 - */ -public class WebExceptionResolver implements HandlerExceptionResolver { - private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class); - - @Override - public ModelAndView resolveException(HttpServletRequest request, - HttpServletResponse response, Object handler, Exception ex) { - logger.error("system catch exception:{}", ex); - - ModelAndView mv = new ModelAndView(); - HandlerMethod method = (HandlerMethod)handler; - ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class); - if (responseBody != null) { - mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
")))); - mv.setViewName("/common/common.result"); - } else { - mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
")); - mv.setViewName("/common/common.exception"); - } - return mv; - } - -} \ No newline at end of file diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java new file mode 100644 index 0000000..c322d9c --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java @@ -0,0 +1,82 @@ +package com.xxl.job.core.thread; + +import java.text.MessageFormat; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.xxl.job.client.util.HttpUtil; +import com.xxl.job.core.model.XxlJobInfo; +import com.xxl.job.core.model.XxlJobLog; +import com.xxl.job.core.util.DynamicSchedulerUtil; +import com.xxl.job.core.util.MailUtil; + +/** + * job monitor helper + * @author xuxueli 2015-9-1 18:05:56 + */ +public class JobMonitorHelper { + private static Logger logger = LoggerFactory.getLogger(JobMonitorHelper.class); + + public static JobMonitorHelper helper = new JobMonitorHelper(); + private ExecutorService executor = Executors.newCachedThreadPool(); + private LinkedBlockingQueue queue = new LinkedBlockingQueue(0xfff8); + private ConcurrentHashMap countMap = new ConcurrentHashMap(); + + public JobMonitorHelper(){ + // consumer + executor.execute(new Runnable() { + @Override + public void run() { + while (true) { + logger.info(">>>>>>>>>>> job monitor run ... "); + Integer jobLogId = JobMonitorHelper.helper.queue.poll(); + if (jobLogId != null && jobLogId > 0) { + XxlJobLog log = DynamicSchedulerUtil.xxlJobLogDao.load(jobLogId); + if (log!=null) { + if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && StringUtils.isBlank(log.getHandleStatus())) { + JobMonitorHelper.monitor(jobLogId); + } + if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && HttpUtil.SUCCESS.equals(log.getHandleStatus())) { + // pass + } + if (HttpUtil.FAIL.equals(log.getTriggerStatus()) || HttpUtil.FAIL.equals(log.getHandleStatus())) { + String monotorKey = log.getJobGroup().concat("_").concat(log.getJobName()); + Integer count = countMap.get(monotorKey); + if (count == null) { + count = new Integer(0); + } + count += 1; + countMap.put(monotorKey, count); + XxlJobInfo info = DynamicSchedulerUtil.xxlJobInfoDao.load(log.getJobGroup(), log.getJobName()); + if (count >= info.getAlarmThreshold()) { + MailUtil.sendMail(info.getAlarmEmail(), "《调度平台中心-监控报警》", + MessageFormat.format("调度任务[{0}]失败报警", monotorKey), false, null); + countMap.remove(monotorKey); + } + } + } + } else { + try { + TimeUnit.SECONDS.sleep(20); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + }); + } + + // producer + public static void monitor(int jobLogId){ + JobMonitorHelper.helper.queue.offer(jobLogId); + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java index 1b06f65..ef675c7 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java @@ -67,6 +67,7 @@ } // getJobKeys + @Deprecated public static List> getJobList(){ List> jobList = new ArrayList>(); diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java new file mode 100644 index 0000000..ff2204d --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java @@ -0,0 +1,181 @@ +package com.xxl.job.core.util; + +import java.io.File; +import java.util.Properties; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeUtility; + +import org.apache.commons.lang.ArrayUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.JavaMailSenderImpl; +import org.springframework.mail.javamail.MimeMessageHelper; + +/** + * 邮件发送.Util + * @author xuxueli 2016-3-12 15:06:20 + */ +public class MailUtil { + private static Logger logger = LoggerFactory.getLogger(MailUtil.class); + + private static String host; + private static String port; + private static String username; + private static String password; + private static String sendFrom; + private static String sendNick; + static{ + host = PropertiesUtil.getString("mail.host"); + port = PropertiesUtil.getString("mail.port"); + username = PropertiesUtil.getString("mail.username"); + password = PropertiesUtil.getString("mail.password"); + sendFrom = PropertiesUtil.getString("mail.sendFrom"); + sendNick = PropertiesUtil.getString("mail.sendNick"); + } + + /** + + + + + + + + + true + true + + + + + */ + /** + * 发送邮件 (完整版)(结合Spring) + * + * @param javaMailSender: 发送Bean + * @param sendFrom : 发送人邮箱 + * @param sendNick : 发送人昵称 + * @param toAddress : 收件人邮箱 + * @param mailSubject : 邮件主题 + * @param mailBody : 邮件正文 + * @param mailBodyIsHtml: 邮件正文格式,true:HTML格式;false:文本格式 + * @param files[] : 附件 + */ + @SuppressWarnings("null") + public static boolean sendMailSpring(String toAddress, String mailSubject, String mailBody, boolean mailBodyIsHtml,File[] attachments) { + JavaMailSender javaMailSender = null;//ResourceBundle.getInstance().getJavaMailSender(); + try { + MimeMessage mimeMessage = javaMailSender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, ArrayUtils.isNotEmpty(attachments), "UTF-8"); // 设置utf-8或GBK编码,否则邮件会有乱码;multipart,true表示文件上传 + + helper.setFrom(sendFrom, sendNick); + helper.setTo(toAddress); + + // 设置收件人抄送的名片和地址(相当于群发了) + //helper.setCc(InternetAddress.parse(MimeUtility.encodeText("邮箱001") + " <@163.com>," + MimeUtility.encodeText("邮箱002") + " <@foxmail.com>")); + + helper.setSubject(mailSubject); + helper.setText(mailBody, mailBodyIsHtml); + + // 添加附件 + if (ArrayUtils.isNotEmpty(attachments)) { + for (File file : attachments) { + helper.addAttachment(MimeUtility.encodeText(file.getName()), file); + } + } + + // 群发 + //MimeMessage[] mailMessages = { mimeMessage }; + + javaMailSender.send(mimeMessage); + return true; + } catch (Exception e) { + logger.info("{}", e); + } + return false; + } + + /** + * 发送邮件 (完整版) (纯JavaMail) + * + * @param toAddress : 收件人邮箱 + * @param mailSubject : 邮件主题 + * @param mailBody : 邮件正文 + * @param mailBodyIsHtml: 邮件正文格式,true:HTML格式;false:文本格式 + * @param inLineFile : 内嵌文件 + * @param files[] : 附件 + */ + public static boolean sendMail (String toAddress, String mailSubject, String mailBody, + boolean mailBodyIsHtml, File[] attachments){ + try { + // 创建邮件发送类 JavaMailSender (用于发送多元化邮件,包括附件,图片,html 等 ) + JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); + mailSender.setHost(host); // 设置邮件服务主机 + mailSender.setUsername(username); // 发送者邮箱的用户名 + mailSender.setPassword(password); // 发送者邮箱的密码 + + //配置文件,用于实例化java.mail.session + Properties pro = System.getProperties(); + pro.put("mail.smtp.auth", "true"); // 登录SMTP服务器,需要获得授权 (网易163邮箱新近注册的邮箱均不能授权,测试 sohu 的邮箱可以获得授权) + pro.put("mail.smtp.socketFactory.port", port); + pro.put("mail.smtp.socketFactory.fallback", "false"); + mailSender.setJavaMailProperties(pro); + + //创建多元化邮件 (创建 mimeMessage 帮助类,用于封装信息至 mimeMessage) + MimeMessage mimeMessage = mailSender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, ArrayUtils.isNotEmpty(attachments), "UTF-8"); + + helper.setFrom(sendFrom, sendNick); + helper.setTo(toAddress); + + helper.setSubject(mailSubject); + helper.setText(mailBody, mailBodyIsHtml); + + // 添加内嵌文件,第1个参数为cid标识这个文件,第2个参数为资源 + //helper.addInline(MimeUtility.encodeText(inLineFile.getName()), inLineFile); + + // 添加附件 + if (ArrayUtils.isNotEmpty(attachments)) { + for (File file : attachments) { + helper.addAttachment(MimeUtility.encodeText(file.getName()), file); + } + } + + mailSender.send(mimeMessage); + return true; + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } + + static int total = 0; + public static void main(String[] args) { + + ExecutorService exec = Executors.newCachedThreadPool(); + for (int i = 0; i < 20; i++) { + exec.execute(new Thread(new Runnable() { + @Override + public void run() { + while(total < 10){ + String mailBody = "

新书快递通知

你的新书快递申请已推送新书,请到空间" + + "中查看"; + + sendMail("ovono802302@163.com", "测试邮件", mailBody, false, null); + System.out.println(total); + total++; + } + } + })); + } + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java b/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java index 8e522f9..9b59cf5 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java @@ -19,6 +19,7 @@ import com.xxl.job.client.util.JacksonUtil; import com.xxl.job.core.model.XxlJobInfo; import com.xxl.job.core.model.XxlJobLog; +import com.xxl.job.core.thread.JobMonitorHelper; import com.xxl.job.core.util.DynamicSchedulerUtil; /** @@ -81,6 +82,7 @@ // update trigger info DynamicSchedulerUtil.xxlJobLogDao.updateTriggerInfo(jobLog); DynamicSchedulerUtil.xxlJobLogDao.updateHandleInfo(jobLog); + JobMonitorHelper.monitor(jobLog.getId()); logger.info(">>>>>>>>>>> xxl-job trigger end, jobLog.id:{}, jobLog:{}", jobLog.getId(), jobLog); } diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index bfa25fe..192e6e6 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -130,6 +130,13 @@ 4.3.6
+ + + javax.mail + mail + 1.4.6 + + org.quartz-scheduler diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java new file mode 100644 index 0000000..9060e28 --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java @@ -0,0 +1,41 @@ +package com.xxl.job.controller.resolver; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerExceptionResolver; +import org.springframework.web.servlet.ModelAndView; + +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.model.ReturnT; + +/** + * common exception resolver + * @author xuxueli 2016-1-6 19:22:18 + */ +public class WebExceptionResolver implements HandlerExceptionResolver { + private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class); + + @Override + public ModelAndView resolveException(HttpServletRequest request, + HttpServletResponse response, Object handler, Exception ex) { + logger.error("system catch exception:{}", ex); + + ModelAndView mv = new ModelAndView(); + HandlerMethod method = (HandlerMethod)handler; + ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class); + if (responseBody != null) { + mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
")))); + mv.setViewName("/common/common.result"); + } else { + mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
")); + mv.setViewName("/common/common.exception"); + } + return mv; + } + +} \ No newline at end of file diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java deleted file mode 100644 index 3bc58d7..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.xxl.job.core.resolver; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.method.HandlerMethod; -import org.springframework.web.servlet.HandlerExceptionResolver; -import org.springframework.web.servlet.ModelAndView; - -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; - -/** - * common exception resolver - * @author xuxueli 2016-1-6 19:22:18 - */ -public class WebExceptionResolver implements HandlerExceptionResolver { - private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class); - - @Override - public ModelAndView resolveException(HttpServletRequest request, - HttpServletResponse response, Object handler, Exception ex) { - logger.error("system catch exception:{}", ex); - - ModelAndView mv = new ModelAndView(); - HandlerMethod method = (HandlerMethod)handler; - ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class); - if (responseBody != null) { - mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
")))); - mv.setViewName("/common/common.result"); - } else { - mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
")); - mv.setViewName("/common/common.exception"); - } - return mv; - } - -} \ No newline at end of file diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java new file mode 100644 index 0000000..c322d9c --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java @@ -0,0 +1,82 @@ +package com.xxl.job.core.thread; + +import java.text.MessageFormat; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.xxl.job.client.util.HttpUtil; +import com.xxl.job.core.model.XxlJobInfo; +import com.xxl.job.core.model.XxlJobLog; +import com.xxl.job.core.util.DynamicSchedulerUtil; +import com.xxl.job.core.util.MailUtil; + +/** + * job monitor helper + * @author xuxueli 2015-9-1 18:05:56 + */ +public class JobMonitorHelper { + private static Logger logger = LoggerFactory.getLogger(JobMonitorHelper.class); + + public static JobMonitorHelper helper = new JobMonitorHelper(); + private ExecutorService executor = Executors.newCachedThreadPool(); + private LinkedBlockingQueue queue = new LinkedBlockingQueue(0xfff8); + private ConcurrentHashMap countMap = new ConcurrentHashMap(); + + public JobMonitorHelper(){ + // consumer + executor.execute(new Runnable() { + @Override + public void run() { + while (true) { + logger.info(">>>>>>>>>>> job monitor run ... "); + Integer jobLogId = JobMonitorHelper.helper.queue.poll(); + if (jobLogId != null && jobLogId > 0) { + XxlJobLog log = DynamicSchedulerUtil.xxlJobLogDao.load(jobLogId); + if (log!=null) { + if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && StringUtils.isBlank(log.getHandleStatus())) { + JobMonitorHelper.monitor(jobLogId); + } + if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && HttpUtil.SUCCESS.equals(log.getHandleStatus())) { + // pass + } + if (HttpUtil.FAIL.equals(log.getTriggerStatus()) || HttpUtil.FAIL.equals(log.getHandleStatus())) { + String monotorKey = log.getJobGroup().concat("_").concat(log.getJobName()); + Integer count = countMap.get(monotorKey); + if (count == null) { + count = new Integer(0); + } + count += 1; + countMap.put(monotorKey, count); + XxlJobInfo info = DynamicSchedulerUtil.xxlJobInfoDao.load(log.getJobGroup(), log.getJobName()); + if (count >= info.getAlarmThreshold()) { + MailUtil.sendMail(info.getAlarmEmail(), "《调度平台中心-监控报警》", + MessageFormat.format("调度任务[{0}]失败报警", monotorKey), false, null); + countMap.remove(monotorKey); + } + } + } + } else { + try { + TimeUnit.SECONDS.sleep(20); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + }); + } + + // producer + public static void monitor(int jobLogId){ + JobMonitorHelper.helper.queue.offer(jobLogId); + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java index 1b06f65..ef675c7 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java @@ -67,6 +67,7 @@ } // getJobKeys + @Deprecated public static List> getJobList(){ List> jobList = new ArrayList>(); diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java new file mode 100644 index 0000000..ff2204d --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java @@ -0,0 +1,181 @@ +package com.xxl.job.core.util; + +import java.io.File; +import java.util.Properties; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeUtility; + +import org.apache.commons.lang.ArrayUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.JavaMailSenderImpl; +import org.springframework.mail.javamail.MimeMessageHelper; + +/** + * 邮件发送.Util + * @author xuxueli 2016-3-12 15:06:20 + */ +public class MailUtil { + private static Logger logger = LoggerFactory.getLogger(MailUtil.class); + + private static String host; + private static String port; + private static String username; + private static String password; + private static String sendFrom; + private static String sendNick; + static{ + host = PropertiesUtil.getString("mail.host"); + port = PropertiesUtil.getString("mail.port"); + username = PropertiesUtil.getString("mail.username"); + password = PropertiesUtil.getString("mail.password"); + sendFrom = PropertiesUtil.getString("mail.sendFrom"); + sendNick = PropertiesUtil.getString("mail.sendNick"); + } + + /** + + + + + + + + + true + true + + + + + */ + /** + * 发送邮件 (完整版)(结合Spring) + * + * @param javaMailSender: 发送Bean + * @param sendFrom : 发送人邮箱 + * @param sendNick : 发送人昵称 + * @param toAddress : 收件人邮箱 + * @param mailSubject : 邮件主题 + * @param mailBody : 邮件正文 + * @param mailBodyIsHtml: 邮件正文格式,true:HTML格式;false:文本格式 + * @param files[] : 附件 + */ + @SuppressWarnings("null") + public static boolean sendMailSpring(String toAddress, String mailSubject, String mailBody, boolean mailBodyIsHtml,File[] attachments) { + JavaMailSender javaMailSender = null;//ResourceBundle.getInstance().getJavaMailSender(); + try { + MimeMessage mimeMessage = javaMailSender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, ArrayUtils.isNotEmpty(attachments), "UTF-8"); // 设置utf-8或GBK编码,否则邮件会有乱码;multipart,true表示文件上传 + + helper.setFrom(sendFrom, sendNick); + helper.setTo(toAddress); + + // 设置收件人抄送的名片和地址(相当于群发了) + //helper.setCc(InternetAddress.parse(MimeUtility.encodeText("邮箱001") + " <@163.com>," + MimeUtility.encodeText("邮箱002") + " <@foxmail.com>")); + + helper.setSubject(mailSubject); + helper.setText(mailBody, mailBodyIsHtml); + + // 添加附件 + if (ArrayUtils.isNotEmpty(attachments)) { + for (File file : attachments) { + helper.addAttachment(MimeUtility.encodeText(file.getName()), file); + } + } + + // 群发 + //MimeMessage[] mailMessages = { mimeMessage }; + + javaMailSender.send(mimeMessage); + return true; + } catch (Exception e) { + logger.info("{}", e); + } + return false; + } + + /** + * 发送邮件 (完整版) (纯JavaMail) + * + * @param toAddress : 收件人邮箱 + * @param mailSubject : 邮件主题 + * @param mailBody : 邮件正文 + * @param mailBodyIsHtml: 邮件正文格式,true:HTML格式;false:文本格式 + * @param inLineFile : 内嵌文件 + * @param files[] : 附件 + */ + public static boolean sendMail (String toAddress, String mailSubject, String mailBody, + boolean mailBodyIsHtml, File[] attachments){ + try { + // 创建邮件发送类 JavaMailSender (用于发送多元化邮件,包括附件,图片,html 等 ) + JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); + mailSender.setHost(host); // 设置邮件服务主机 + mailSender.setUsername(username); // 发送者邮箱的用户名 + mailSender.setPassword(password); // 发送者邮箱的密码 + + //配置文件,用于实例化java.mail.session + Properties pro = System.getProperties(); + pro.put("mail.smtp.auth", "true"); // 登录SMTP服务器,需要获得授权 (网易163邮箱新近注册的邮箱均不能授权,测试 sohu 的邮箱可以获得授权) + pro.put("mail.smtp.socketFactory.port", port); + pro.put("mail.smtp.socketFactory.fallback", "false"); + mailSender.setJavaMailProperties(pro); + + //创建多元化邮件 (创建 mimeMessage 帮助类,用于封装信息至 mimeMessage) + MimeMessage mimeMessage = mailSender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, ArrayUtils.isNotEmpty(attachments), "UTF-8"); + + helper.setFrom(sendFrom, sendNick); + helper.setTo(toAddress); + + helper.setSubject(mailSubject); + helper.setText(mailBody, mailBodyIsHtml); + + // 添加内嵌文件,第1个参数为cid标识这个文件,第2个参数为资源 + //helper.addInline(MimeUtility.encodeText(inLineFile.getName()), inLineFile); + + // 添加附件 + if (ArrayUtils.isNotEmpty(attachments)) { + for (File file : attachments) { + helper.addAttachment(MimeUtility.encodeText(file.getName()), file); + } + } + + mailSender.send(mimeMessage); + return true; + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } + + static int total = 0; + public static void main(String[] args) { + + ExecutorService exec = Executors.newCachedThreadPool(); + for (int i = 0; i < 20; i++) { + exec.execute(new Thread(new Runnable() { + @Override + public void run() { + while(total < 10){ + String mailBody = "

新书快递通知

你的新书快递申请已推送新书,请到空间" + + "中查看"; + + sendMail("ovono802302@163.com", "测试邮件", mailBody, false, null); + System.out.println(total); + total++; + } + } + })); + } + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java b/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java index 8e522f9..9b59cf5 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java @@ -19,6 +19,7 @@ import com.xxl.job.client.util.JacksonUtil; import com.xxl.job.core.model.XxlJobInfo; import com.xxl.job.core.model.XxlJobLog; +import com.xxl.job.core.thread.JobMonitorHelper; import com.xxl.job.core.util.DynamicSchedulerUtil; /** @@ -81,6 +82,7 @@ // update trigger info DynamicSchedulerUtil.xxlJobLogDao.updateTriggerInfo(jobLog); DynamicSchedulerUtil.xxlJobLogDao.updateHandleInfo(jobLog); + JobMonitorHelper.monitor(jobLog.getId()); logger.info(">>>>>>>>>>> xxl-job trigger end, jobLog.id:{}, jobLog:{}", jobLog.getId(), jobLog); } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java b/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java index 7ca28fc..c15aa2c 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java @@ -18,6 +18,7 @@ import com.xxl.job.client.util.JacksonUtil; import com.xxl.job.core.model.XxlJobInfo; import com.xxl.job.core.model.XxlJobLog; +import com.xxl.job.core.thread.JobMonitorHelper; import com.xxl.job.core.util.DynamicSchedulerUtil; import com.xxl.job.core.util.PropertiesUtil; @@ -85,6 +86,7 @@ // update trigger info DynamicSchedulerUtil.xxlJobLogDao.updateTriggerInfo(jobLog); + JobMonitorHelper.monitor(jobLog.getId()); logger.info(">>>>>>>>>>> xxl-job trigger end, jobLog.id:{}, jobLog:{}", jobLog.getId(), jobLog); } diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index bfa25fe..192e6e6 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -130,6 +130,13 @@ 4.3.6
+ + + javax.mail + mail + 1.4.6 + + org.quartz-scheduler diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java new file mode 100644 index 0000000..9060e28 --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java @@ -0,0 +1,41 @@ +package com.xxl.job.controller.resolver; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerExceptionResolver; +import org.springframework.web.servlet.ModelAndView; + +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.model.ReturnT; + +/** + * common exception resolver + * @author xuxueli 2016-1-6 19:22:18 + */ +public class WebExceptionResolver implements HandlerExceptionResolver { + private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class); + + @Override + public ModelAndView resolveException(HttpServletRequest request, + HttpServletResponse response, Object handler, Exception ex) { + logger.error("system catch exception:{}", ex); + + ModelAndView mv = new ModelAndView(); + HandlerMethod method = (HandlerMethod)handler; + ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class); + if (responseBody != null) { + mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
")))); + mv.setViewName("/common/common.result"); + } else { + mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
")); + mv.setViewName("/common/common.exception"); + } + return mv; + } + +} \ No newline at end of file diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java deleted file mode 100644 index 3bc58d7..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.xxl.job.core.resolver; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.method.HandlerMethod; -import org.springframework.web.servlet.HandlerExceptionResolver; -import org.springframework.web.servlet.ModelAndView; - -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; - -/** - * common exception resolver - * @author xuxueli 2016-1-6 19:22:18 - */ -public class WebExceptionResolver implements HandlerExceptionResolver { - private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class); - - @Override - public ModelAndView resolveException(HttpServletRequest request, - HttpServletResponse response, Object handler, Exception ex) { - logger.error("system catch exception:{}", ex); - - ModelAndView mv = new ModelAndView(); - HandlerMethod method = (HandlerMethod)handler; - ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class); - if (responseBody != null) { - mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
")))); - mv.setViewName("/common/common.result"); - } else { - mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
")); - mv.setViewName("/common/common.exception"); - } - return mv; - } - -} \ No newline at end of file diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java new file mode 100644 index 0000000..c322d9c --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java @@ -0,0 +1,82 @@ +package com.xxl.job.core.thread; + +import java.text.MessageFormat; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.xxl.job.client.util.HttpUtil; +import com.xxl.job.core.model.XxlJobInfo; +import com.xxl.job.core.model.XxlJobLog; +import com.xxl.job.core.util.DynamicSchedulerUtil; +import com.xxl.job.core.util.MailUtil; + +/** + * job monitor helper + * @author xuxueli 2015-9-1 18:05:56 + */ +public class JobMonitorHelper { + private static Logger logger = LoggerFactory.getLogger(JobMonitorHelper.class); + + public static JobMonitorHelper helper = new JobMonitorHelper(); + private ExecutorService executor = Executors.newCachedThreadPool(); + private LinkedBlockingQueue queue = new LinkedBlockingQueue(0xfff8); + private ConcurrentHashMap countMap = new ConcurrentHashMap(); + + public JobMonitorHelper(){ + // consumer + executor.execute(new Runnable() { + @Override + public void run() { + while (true) { + logger.info(">>>>>>>>>>> job monitor run ... "); + Integer jobLogId = JobMonitorHelper.helper.queue.poll(); + if (jobLogId != null && jobLogId > 0) { + XxlJobLog log = DynamicSchedulerUtil.xxlJobLogDao.load(jobLogId); + if (log!=null) { + if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && StringUtils.isBlank(log.getHandleStatus())) { + JobMonitorHelper.monitor(jobLogId); + } + if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && HttpUtil.SUCCESS.equals(log.getHandleStatus())) { + // pass + } + if (HttpUtil.FAIL.equals(log.getTriggerStatus()) || HttpUtil.FAIL.equals(log.getHandleStatus())) { + String monotorKey = log.getJobGroup().concat("_").concat(log.getJobName()); + Integer count = countMap.get(monotorKey); + if (count == null) { + count = new Integer(0); + } + count += 1; + countMap.put(monotorKey, count); + XxlJobInfo info = DynamicSchedulerUtil.xxlJobInfoDao.load(log.getJobGroup(), log.getJobName()); + if (count >= info.getAlarmThreshold()) { + MailUtil.sendMail(info.getAlarmEmail(), "《调度平台中心-监控报警》", + MessageFormat.format("调度任务[{0}]失败报警", monotorKey), false, null); + countMap.remove(monotorKey); + } + } + } + } else { + try { + TimeUnit.SECONDS.sleep(20); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + }); + } + + // producer + public static void monitor(int jobLogId){ + JobMonitorHelper.helper.queue.offer(jobLogId); + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java index 1b06f65..ef675c7 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java @@ -67,6 +67,7 @@ } // getJobKeys + @Deprecated public static List> getJobList(){ List> jobList = new ArrayList>(); diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java new file mode 100644 index 0000000..ff2204d --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java @@ -0,0 +1,181 @@ +package com.xxl.job.core.util; + +import java.io.File; +import java.util.Properties; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeUtility; + +import org.apache.commons.lang.ArrayUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.JavaMailSenderImpl; +import org.springframework.mail.javamail.MimeMessageHelper; + +/** + * 邮件发送.Util + * @author xuxueli 2016-3-12 15:06:20 + */ +public class MailUtil { + private static Logger logger = LoggerFactory.getLogger(MailUtil.class); + + private static String host; + private static String port; + private static String username; + private static String password; + private static String sendFrom; + private static String sendNick; + static{ + host = PropertiesUtil.getString("mail.host"); + port = PropertiesUtil.getString("mail.port"); + username = PropertiesUtil.getString("mail.username"); + password = PropertiesUtil.getString("mail.password"); + sendFrom = PropertiesUtil.getString("mail.sendFrom"); + sendNick = PropertiesUtil.getString("mail.sendNick"); + } + + /** + + + + + + + + + true + true + + + + + */ + /** + * 发送邮件 (完整版)(结合Spring) + * + * @param javaMailSender: 发送Bean + * @param sendFrom : 发送人邮箱 + * @param sendNick : 发送人昵称 + * @param toAddress : 收件人邮箱 + * @param mailSubject : 邮件主题 + * @param mailBody : 邮件正文 + * @param mailBodyIsHtml: 邮件正文格式,true:HTML格式;false:文本格式 + * @param files[] : 附件 + */ + @SuppressWarnings("null") + public static boolean sendMailSpring(String toAddress, String mailSubject, String mailBody, boolean mailBodyIsHtml,File[] attachments) { + JavaMailSender javaMailSender = null;//ResourceBundle.getInstance().getJavaMailSender(); + try { + MimeMessage mimeMessage = javaMailSender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, ArrayUtils.isNotEmpty(attachments), "UTF-8"); // 设置utf-8或GBK编码,否则邮件会有乱码;multipart,true表示文件上传 + + helper.setFrom(sendFrom, sendNick); + helper.setTo(toAddress); + + // 设置收件人抄送的名片和地址(相当于群发了) + //helper.setCc(InternetAddress.parse(MimeUtility.encodeText("邮箱001") + " <@163.com>," + MimeUtility.encodeText("邮箱002") + " <@foxmail.com>")); + + helper.setSubject(mailSubject); + helper.setText(mailBody, mailBodyIsHtml); + + // 添加附件 + if (ArrayUtils.isNotEmpty(attachments)) { + for (File file : attachments) { + helper.addAttachment(MimeUtility.encodeText(file.getName()), file); + } + } + + // 群发 + //MimeMessage[] mailMessages = { mimeMessage }; + + javaMailSender.send(mimeMessage); + return true; + } catch (Exception e) { + logger.info("{}", e); + } + return false; + } + + /** + * 发送邮件 (完整版) (纯JavaMail) + * + * @param toAddress : 收件人邮箱 + * @param mailSubject : 邮件主题 + * @param mailBody : 邮件正文 + * @param mailBodyIsHtml: 邮件正文格式,true:HTML格式;false:文本格式 + * @param inLineFile : 内嵌文件 + * @param files[] : 附件 + */ + public static boolean sendMail (String toAddress, String mailSubject, String mailBody, + boolean mailBodyIsHtml, File[] attachments){ + try { + // 创建邮件发送类 JavaMailSender (用于发送多元化邮件,包括附件,图片,html 等 ) + JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); + mailSender.setHost(host); // 设置邮件服务主机 + mailSender.setUsername(username); // 发送者邮箱的用户名 + mailSender.setPassword(password); // 发送者邮箱的密码 + + //配置文件,用于实例化java.mail.session + Properties pro = System.getProperties(); + pro.put("mail.smtp.auth", "true"); // 登录SMTP服务器,需要获得授权 (网易163邮箱新近注册的邮箱均不能授权,测试 sohu 的邮箱可以获得授权) + pro.put("mail.smtp.socketFactory.port", port); + pro.put("mail.smtp.socketFactory.fallback", "false"); + mailSender.setJavaMailProperties(pro); + + //创建多元化邮件 (创建 mimeMessage 帮助类,用于封装信息至 mimeMessage) + MimeMessage mimeMessage = mailSender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, ArrayUtils.isNotEmpty(attachments), "UTF-8"); + + helper.setFrom(sendFrom, sendNick); + helper.setTo(toAddress); + + helper.setSubject(mailSubject); + helper.setText(mailBody, mailBodyIsHtml); + + // 添加内嵌文件,第1个参数为cid标识这个文件,第2个参数为资源 + //helper.addInline(MimeUtility.encodeText(inLineFile.getName()), inLineFile); + + // 添加附件 + if (ArrayUtils.isNotEmpty(attachments)) { + for (File file : attachments) { + helper.addAttachment(MimeUtility.encodeText(file.getName()), file); + } + } + + mailSender.send(mimeMessage); + return true; + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } + + static int total = 0; + public static void main(String[] args) { + + ExecutorService exec = Executors.newCachedThreadPool(); + for (int i = 0; i < 20; i++) { + exec.execute(new Thread(new Runnable() { + @Override + public void run() { + while(total < 10){ + String mailBody = "

新书快递通知

你的新书快递申请已推送新书,请到空间" + + "中查看"; + + sendMail("ovono802302@163.com", "测试邮件", mailBody, false, null); + System.out.println(total); + total++; + } + } + })); + } + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java b/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java index 8e522f9..9b59cf5 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java @@ -19,6 +19,7 @@ import com.xxl.job.client.util.JacksonUtil; import com.xxl.job.core.model.XxlJobInfo; import com.xxl.job.core.model.XxlJobLog; +import com.xxl.job.core.thread.JobMonitorHelper; import com.xxl.job.core.util.DynamicSchedulerUtil; /** @@ -81,6 +82,7 @@ // update trigger info DynamicSchedulerUtil.xxlJobLogDao.updateTriggerInfo(jobLog); DynamicSchedulerUtil.xxlJobLogDao.updateHandleInfo(jobLog); + JobMonitorHelper.monitor(jobLog.getId()); logger.info(">>>>>>>>>>> xxl-job trigger end, jobLog.id:{}, jobLog:{}", jobLog.getId(), jobLog); } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java b/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java index 7ca28fc..c15aa2c 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java @@ -18,6 +18,7 @@ import com.xxl.job.client.util.JacksonUtil; import com.xxl.job.core.model.XxlJobInfo; import com.xxl.job.core.model.XxlJobLog; +import com.xxl.job.core.thread.JobMonitorHelper; import com.xxl.job.core.util.DynamicSchedulerUtil; import com.xxl.job.core.util.PropertiesUtil; @@ -85,6 +86,7 @@ // update trigger info DynamicSchedulerUtil.xxlJobLogDao.updateTriggerInfo(jobLog); + JobMonitorHelper.monitor(jobLog.getId()); logger.info(">>>>>>>>>>> xxl-job trigger end, jobLog.id:{}, jobLog:{}", jobLog.getId(), jobLog); } diff --git a/xxl-job-admin/src/main/resources/config.properties b/xxl-job-admin/src/main/resources/config.properties index c22c950..574549d 100644 --- a/xxl-job-admin/src/main/resources/config.properties +++ b/xxl-job-admin/src/main/resources/config.properties @@ -1 +1,10 @@ -trigger_log_url=http://localhost:8080/joblog/save \ No newline at end of file +# for trigger log callback +trigger_log_url=http://localhost:8080/joblog/save + +# for email +mail.host=smtp.163.com +mail.port=25 +mail.username=ovono802302@163.com +mail.password=asdfzxcv +mail.sendFrom=ovono802302@163.com +mail.sendNick=《任务调度中心xxl-job》 \ No newline at end of file diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index bfa25fe..192e6e6 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -130,6 +130,13 @@ 4.3.6
+ + + javax.mail + mail + 1.4.6 + + org.quartz-scheduler diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java new file mode 100644 index 0000000..9060e28 --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java @@ -0,0 +1,41 @@ +package com.xxl.job.controller.resolver; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerExceptionResolver; +import org.springframework.web.servlet.ModelAndView; + +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.model.ReturnT; + +/** + * common exception resolver + * @author xuxueli 2016-1-6 19:22:18 + */ +public class WebExceptionResolver implements HandlerExceptionResolver { + private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class); + + @Override + public ModelAndView resolveException(HttpServletRequest request, + HttpServletResponse response, Object handler, Exception ex) { + logger.error("system catch exception:{}", ex); + + ModelAndView mv = new ModelAndView(); + HandlerMethod method = (HandlerMethod)handler; + ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class); + if (responseBody != null) { + mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
")))); + mv.setViewName("/common/common.result"); + } else { + mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
")); + mv.setViewName("/common/common.exception"); + } + return mv; + } + +} \ No newline at end of file diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java deleted file mode 100644 index 3bc58d7..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.xxl.job.core.resolver; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.method.HandlerMethod; -import org.springframework.web.servlet.HandlerExceptionResolver; -import org.springframework.web.servlet.ModelAndView; - -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; - -/** - * common exception resolver - * @author xuxueli 2016-1-6 19:22:18 - */ -public class WebExceptionResolver implements HandlerExceptionResolver { - private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class); - - @Override - public ModelAndView resolveException(HttpServletRequest request, - HttpServletResponse response, Object handler, Exception ex) { - logger.error("system catch exception:{}", ex); - - ModelAndView mv = new ModelAndView(); - HandlerMethod method = (HandlerMethod)handler; - ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class); - if (responseBody != null) { - mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
")))); - mv.setViewName("/common/common.result"); - } else { - mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
")); - mv.setViewName("/common/common.exception"); - } - return mv; - } - -} \ No newline at end of file diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java new file mode 100644 index 0000000..c322d9c --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java @@ -0,0 +1,82 @@ +package com.xxl.job.core.thread; + +import java.text.MessageFormat; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.xxl.job.client.util.HttpUtil; +import com.xxl.job.core.model.XxlJobInfo; +import com.xxl.job.core.model.XxlJobLog; +import com.xxl.job.core.util.DynamicSchedulerUtil; +import com.xxl.job.core.util.MailUtil; + +/** + * job monitor helper + * @author xuxueli 2015-9-1 18:05:56 + */ +public class JobMonitorHelper { + private static Logger logger = LoggerFactory.getLogger(JobMonitorHelper.class); + + public static JobMonitorHelper helper = new JobMonitorHelper(); + private ExecutorService executor = Executors.newCachedThreadPool(); + private LinkedBlockingQueue queue = new LinkedBlockingQueue(0xfff8); + private ConcurrentHashMap countMap = new ConcurrentHashMap(); + + public JobMonitorHelper(){ + // consumer + executor.execute(new Runnable() { + @Override + public void run() { + while (true) { + logger.info(">>>>>>>>>>> job monitor run ... "); + Integer jobLogId = JobMonitorHelper.helper.queue.poll(); + if (jobLogId != null && jobLogId > 0) { + XxlJobLog log = DynamicSchedulerUtil.xxlJobLogDao.load(jobLogId); + if (log!=null) { + if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && StringUtils.isBlank(log.getHandleStatus())) { + JobMonitorHelper.monitor(jobLogId); + } + if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && HttpUtil.SUCCESS.equals(log.getHandleStatus())) { + // pass + } + if (HttpUtil.FAIL.equals(log.getTriggerStatus()) || HttpUtil.FAIL.equals(log.getHandleStatus())) { + String monotorKey = log.getJobGroup().concat("_").concat(log.getJobName()); + Integer count = countMap.get(monotorKey); + if (count == null) { + count = new Integer(0); + } + count += 1; + countMap.put(monotorKey, count); + XxlJobInfo info = DynamicSchedulerUtil.xxlJobInfoDao.load(log.getJobGroup(), log.getJobName()); + if (count >= info.getAlarmThreshold()) { + MailUtil.sendMail(info.getAlarmEmail(), "《调度平台中心-监控报警》", + MessageFormat.format("调度任务[{0}]失败报警", monotorKey), false, null); + countMap.remove(monotorKey); + } + } + } + } else { + try { + TimeUnit.SECONDS.sleep(20); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + }); + } + + // producer + public static void monitor(int jobLogId){ + JobMonitorHelper.helper.queue.offer(jobLogId); + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java index 1b06f65..ef675c7 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java @@ -67,6 +67,7 @@ } // getJobKeys + @Deprecated public static List> getJobList(){ List> jobList = new ArrayList>(); diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java new file mode 100644 index 0000000..ff2204d --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java @@ -0,0 +1,181 @@ +package com.xxl.job.core.util; + +import java.io.File; +import java.util.Properties; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeUtility; + +import org.apache.commons.lang.ArrayUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.JavaMailSenderImpl; +import org.springframework.mail.javamail.MimeMessageHelper; + +/** + * 邮件发送.Util + * @author xuxueli 2016-3-12 15:06:20 + */ +public class MailUtil { + private static Logger logger = LoggerFactory.getLogger(MailUtil.class); + + private static String host; + private static String port; + private static String username; + private static String password; + private static String sendFrom; + private static String sendNick; + static{ + host = PropertiesUtil.getString("mail.host"); + port = PropertiesUtil.getString("mail.port"); + username = PropertiesUtil.getString("mail.username"); + password = PropertiesUtil.getString("mail.password"); + sendFrom = PropertiesUtil.getString("mail.sendFrom"); + sendNick = PropertiesUtil.getString("mail.sendNick"); + } + + /** + + + + + + + + + true + true + + + + + */ + /** + * 发送邮件 (完整版)(结合Spring) + * + * @param javaMailSender: 发送Bean + * @param sendFrom : 发送人邮箱 + * @param sendNick : 发送人昵称 + * @param toAddress : 收件人邮箱 + * @param mailSubject : 邮件主题 + * @param mailBody : 邮件正文 + * @param mailBodyIsHtml: 邮件正文格式,true:HTML格式;false:文本格式 + * @param files[] : 附件 + */ + @SuppressWarnings("null") + public static boolean sendMailSpring(String toAddress, String mailSubject, String mailBody, boolean mailBodyIsHtml,File[] attachments) { + JavaMailSender javaMailSender = null;//ResourceBundle.getInstance().getJavaMailSender(); + try { + MimeMessage mimeMessage = javaMailSender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, ArrayUtils.isNotEmpty(attachments), "UTF-8"); // 设置utf-8或GBK编码,否则邮件会有乱码;multipart,true表示文件上传 + + helper.setFrom(sendFrom, sendNick); + helper.setTo(toAddress); + + // 设置收件人抄送的名片和地址(相当于群发了) + //helper.setCc(InternetAddress.parse(MimeUtility.encodeText("邮箱001") + " <@163.com>," + MimeUtility.encodeText("邮箱002") + " <@foxmail.com>")); + + helper.setSubject(mailSubject); + helper.setText(mailBody, mailBodyIsHtml); + + // 添加附件 + if (ArrayUtils.isNotEmpty(attachments)) { + for (File file : attachments) { + helper.addAttachment(MimeUtility.encodeText(file.getName()), file); + } + } + + // 群发 + //MimeMessage[] mailMessages = { mimeMessage }; + + javaMailSender.send(mimeMessage); + return true; + } catch (Exception e) { + logger.info("{}", e); + } + return false; + } + + /** + * 发送邮件 (完整版) (纯JavaMail) + * + * @param toAddress : 收件人邮箱 + * @param mailSubject : 邮件主题 + * @param mailBody : 邮件正文 + * @param mailBodyIsHtml: 邮件正文格式,true:HTML格式;false:文本格式 + * @param inLineFile : 内嵌文件 + * @param files[] : 附件 + */ + public static boolean sendMail (String toAddress, String mailSubject, String mailBody, + boolean mailBodyIsHtml, File[] attachments){ + try { + // 创建邮件发送类 JavaMailSender (用于发送多元化邮件,包括附件,图片,html 等 ) + JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); + mailSender.setHost(host); // 设置邮件服务主机 + mailSender.setUsername(username); // 发送者邮箱的用户名 + mailSender.setPassword(password); // 发送者邮箱的密码 + + //配置文件,用于实例化java.mail.session + Properties pro = System.getProperties(); + pro.put("mail.smtp.auth", "true"); // 登录SMTP服务器,需要获得授权 (网易163邮箱新近注册的邮箱均不能授权,测试 sohu 的邮箱可以获得授权) + pro.put("mail.smtp.socketFactory.port", port); + pro.put("mail.smtp.socketFactory.fallback", "false"); + mailSender.setJavaMailProperties(pro); + + //创建多元化邮件 (创建 mimeMessage 帮助类,用于封装信息至 mimeMessage) + MimeMessage mimeMessage = mailSender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, ArrayUtils.isNotEmpty(attachments), "UTF-8"); + + helper.setFrom(sendFrom, sendNick); + helper.setTo(toAddress); + + helper.setSubject(mailSubject); + helper.setText(mailBody, mailBodyIsHtml); + + // 添加内嵌文件,第1个参数为cid标识这个文件,第2个参数为资源 + //helper.addInline(MimeUtility.encodeText(inLineFile.getName()), inLineFile); + + // 添加附件 + if (ArrayUtils.isNotEmpty(attachments)) { + for (File file : attachments) { + helper.addAttachment(MimeUtility.encodeText(file.getName()), file); + } + } + + mailSender.send(mimeMessage); + return true; + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } + + static int total = 0; + public static void main(String[] args) { + + ExecutorService exec = Executors.newCachedThreadPool(); + for (int i = 0; i < 20; i++) { + exec.execute(new Thread(new Runnable() { + @Override + public void run() { + while(total < 10){ + String mailBody = "

新书快递通知

你的新书快递申请已推送新书,请到空间" + + "中查看"; + + sendMail("ovono802302@163.com", "测试邮件", mailBody, false, null); + System.out.println(total); + total++; + } + } + })); + } + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java b/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java index 8e522f9..9b59cf5 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java @@ -19,6 +19,7 @@ import com.xxl.job.client.util.JacksonUtil; import com.xxl.job.core.model.XxlJobInfo; import com.xxl.job.core.model.XxlJobLog; +import com.xxl.job.core.thread.JobMonitorHelper; import com.xxl.job.core.util.DynamicSchedulerUtil; /** @@ -81,6 +82,7 @@ // update trigger info DynamicSchedulerUtil.xxlJobLogDao.updateTriggerInfo(jobLog); DynamicSchedulerUtil.xxlJobLogDao.updateHandleInfo(jobLog); + JobMonitorHelper.monitor(jobLog.getId()); logger.info(">>>>>>>>>>> xxl-job trigger end, jobLog.id:{}, jobLog:{}", jobLog.getId(), jobLog); } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java b/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java index 7ca28fc..c15aa2c 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java @@ -18,6 +18,7 @@ import com.xxl.job.client.util.JacksonUtil; import com.xxl.job.core.model.XxlJobInfo; import com.xxl.job.core.model.XxlJobLog; +import com.xxl.job.core.thread.JobMonitorHelper; import com.xxl.job.core.util.DynamicSchedulerUtil; import com.xxl.job.core.util.PropertiesUtil; @@ -85,6 +86,7 @@ // update trigger info DynamicSchedulerUtil.xxlJobLogDao.updateTriggerInfo(jobLog); + JobMonitorHelper.monitor(jobLog.getId()); logger.info(">>>>>>>>>>> xxl-job trigger end, jobLog.id:{}, jobLog:{}", jobLog.getId(), jobLog); } diff --git a/xxl-job-admin/src/main/resources/config.properties b/xxl-job-admin/src/main/resources/config.properties index c22c950..574549d 100644 --- a/xxl-job-admin/src/main/resources/config.properties +++ b/xxl-job-admin/src/main/resources/config.properties @@ -1 +1,10 @@ -trigger_log_url=http://localhost:8080/joblog/save \ No newline at end of file +# for trigger log callback +trigger_log_url=http://localhost:8080/joblog/save + +# for email +mail.host=smtp.163.com +mail.port=25 +mail.username=ovono802302@163.com +mail.password=asdfzxcv +mail.sendFrom=ovono802302@163.com +mail.sendNick=《任务调度中心xxl-job》 \ No newline at end of file diff --git a/xxl-job-admin/src/main/resources/springmvc-context.xml b/xxl-job-admin/src/main/resources/springmvc-context.xml index 4f16544..2107680 100644 --- a/xxl-job-admin/src/main/resources/springmvc-context.xml +++ b/xxl-job-admin/src/main/resources/springmvc-context.xml @@ -38,7 +38,7 @@ - + \ No newline at end of file