- 浏览: 53646 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
Anddy:
blob 对应与java中byte[]吧 。
mysql和java的数据类型的对应关系 -
kongzhizhen:
http://io2.139icq.com:88/login. ...
飞信webservice测试接口
公司目前有这样的需求,结合spring+quartz开发个后台的WEB管理系统,系统主要包括以下功能:
1、动态添加、修改和删除数据源,并加入到spring管理。
2、动态注册、修改和删除任务(需要实现的具体quartz业务类),并加入到quartz管理。
3、提供上传第三方包的功能。(主要考虑实现的业务类,需要引入其他的jar包)。
4、在线日志查询分析。
。。。
后台系统的应用领域:
1、执行多个数据库之间的数据交换服务。
2、架设系统与银行之间的通讯服务。
。。。
以前没搞过这方面应用,比较头疼,经过google、百度,初步方案实现如下:
1、实现个servlet用于启动quartz调度。
程序如下:
- public class DispatchJobServlet extends HttpServlet {
- private static final long serialVersionUID = -3920177706344758439L;
- private ApplicationContext ctx;
- public DispatchJobServlet() {
- super();
- // 初始化自定义类加载器,主要用于加载第三方包和服务程序。
- ServiceStartup manguage = new ServiceStartup();
- manguage.startUp();
- }
- /**
- * 初始化
- */
- public void init(ServletConfig config) throws ServletException {
- super.init(config);
- ctx = WebApplicationContextUtils
- .getRequiredWebApplicationContext(config.getServletContext());
- StartJobService taskStartService = (StartJobService) ctx.getBean("startJobService");
- //启用个线程开始任务调度
- ExecutorService exec = Executors.newCachedThreadPool();
- exec.execute(taskStartService);
- }
public class DispatchJobServlet extends HttpServlet { private static final long serialVersionUID = -3920177706344758439L; private ApplicationContext ctx; public DispatchJobServlet() { super(); // 初始化自定义类加载器,主要用于加载第三方包和服务程序。 ServiceStartup manguage = new ServiceStartup(); manguage.startUp(); } /** * 初始化 */ public void init(ServletConfig config) throws ServletException { super.init(config); ctx = WebApplicationContextUtils .getRequiredWebApplicationContext(config.getServletContext()); StartJobService taskStartService = (StartJobService) ctx.getBean("startJobService"); //启用个线程开始任务调度 ExecutorService exec = Executors.newCachedThreadPool(); exec.execute(taskStartService); } }
2、到xml文件查询前台添加的任务队列,加入quartz管理并执行。
- @Service
- public class StartJobService implements Runnable {
- /**
- * log4j 记录器
- */
- private static final Logger log = Logger.getLogger(StartJobService.class);
- @Resource
- private SchedulerService schedulerService;
- public void run() {
- try {
- while (true) {
- List<JobBo> list = DomParser.findAllJobXml("db.service.xml");
- Iterator<JobBo> i = list.iterator();
- while (i.hasNext()) {
- JobBo job = i.next();
- // 如果任务队列不存在则注册并运行
- if (!ServiceManager.queryExistsJob(job.getName())) {
- try {
- schedulerService.schedule(job);
- ServiceManager.getJobHolder().put(job.getName(),
- job);
- } catch (Exception e) {
- log.error("服务【" + job.getName() + "】启动失败!", e);
- throw new SummerException("服务【" + job.getName()
- + "】启动失败!");
- }
- }
- Thread.sleep(3000);
- }
- }
- } catch (SummerException e) {
- throw e;
- } catch (Exception e) {
- log.error("调度任务出现异常!", e);
- }
- }
- }
@Service public class StartJobService implements Runnable { /** * log4j 记录器 */ private static final Logger log = Logger.getLogger(StartJobService.class); @Resource private SchedulerService schedulerService; public void run() { try { while (true) { List<JobBo> list = DomParser.findAllJobXml("db.service.xml"); Iterator<JobBo> i = list.iterator(); while (i.hasNext()) { JobBo job = i.next(); // 如果任务队列不存在则注册并运行 if (!ServiceManager.queryExistsJob(job.getName())) { try { schedulerService.schedule(job); ServiceManager.getJobHolder().put(job.getName(), job); } catch (Exception e) { log.error("服务【" + job.getName() + "】启动失败!", e); throw new SummerException("服务【" + job.getName() + "】启动失败!"); } } Thread.sleep(3000); } } } catch (SummerException e) { throw e; } catch (Exception e) { log.error("调度任务出现异常!", e); } } }
3、封装SchedulerService实现quartz调度的方法
封装的出来quartz的接口:
- public interface SchedulerService {
- /**
- * 自定义任务对象并启动任务
- *
- * @param job
- * 任务队列业务对象
- */
- void schedule(JobBo job);
- /**
- * 取得所有调度Triggers
- *
- * @return
- */
- List<Map<String, Object>> getQrtzTriggers();
- /**
- * 根据名称和组别暂停Tigger
- *
- * @param triggerName
- * @param group
- */
- void pauseTrigger(String triggerName, String group);
- /**
- * 恢复Trigger
- *
- * @param triggerName
- * @param group
- */
- void resumeTrigger(String triggerName, String group);
- /**
- * 删除Trigger
- *
- * @param triggerName
- * @param group
- */
- boolean removeTrigdger(String triggerName, String group);
- }
public interface SchedulerService { /** * 自定义任务对象并启动任务 * * @param job * 任务队列业务对象 */ void schedule(JobBo job); /** * 取得所有调度Triggers * * @return */ List<Map<String, Object>> getQrtzTriggers(); /** * 根据名称和组别暂停Tigger * * @param triggerName * @param group */ void pauseTrigger(String triggerName, String group); /** * 恢复Trigger * * @param triggerName * @param group */ void resumeTrigger(String triggerName, String group); /** * 删除Trigger * * @param triggerName * @param group */ boolean removeTrigdger(String triggerName, String group); }
实现类:
- public class SchedulerServiceImpl implements SchedulerService {
- private static final Logger log = LoggerFactory
- .getLogger(SchedulerServiceImpl.class);
- private Scheduler scheduler;
- private JobDetail jobDetail;
- public void setScheduler(Scheduler scheduler) {
- this.scheduler = scheduler;
- }
- public void setJobDetail(JobDetail jobDetail) {
- this.jobDetail = jobDetail;
- }
- /**
- * 自定义任务对象并启动任务
- */
- public void schedule(JobBo job) {
- // trigger分类
- String category = job.getCategory();
- try {
- if ("cron".equals(category)) {
- scheduleCron(job);
- } else {
- scheduleSimple(job);
- }
- } catch (Exception e) {
- log.error("任务调度过程中出现异常!");
- throw new SummerException(e);
- }
- }
- /**
- * simple任务触发
- *
- * @param job
- */
- private void scheduleSimple(JobBo job) {
- String name = getTriggerName(job.getName());
- // 实例化SimpleTrigger
- SimpleTrigger simpleTrigger = new SimpleTrigger();
- // 这些值的设置也可以从外面传入,这里采用默放值
- simpleTrigger.setJobName(jobDetail.getName());
- simpleTrigger.setJobGroup(Scheduler.DEFAULT_GROUP);
- simpleTrigger.setRepeatInterval(1000L);
- // 设置名称
- simpleTrigger.setName(name);
- // 设置Trigger分组
- String group = job.getGroup();
- if (StringUtils.isEmpty(group)) {
- group = Scheduler.DEFAULT_GROUP;
- }
- simpleTrigger.setGroup(group);
- // 设置开始时间
- Timestamp startTime = job.getStartTime();
- if (null != startTime) {
- simpleTrigger.setStartTime(new Date());
- }
- // 设置结束时间
- Timestamp endTime = job.getEndTime();
- if (null != endTime) {
- simpleTrigger.setEndTime(endTime);
- }
- // 设置执行次数
- int repeatCount = job.getRepeatCount();
- if (repeatCount > 0) {
- simpleTrigger.setRepeatCount(repeatCount);
- }
- // 设置执行时间间隔
- long repeatInterval = job.getRepeatInterval();
- if (repeatInterval > 0) {
- simpleTrigger.setRepeatInterval(repeatInterval * 1000);
- }
- try {
- JobDataMap jobData = new JobDataMap();
- jobData.put("name", job.getName());
- jobData.put("desc", job.getDesc());
- jobDetail.setJobDataMap(jobData);
- scheduler.addJob(jobDetail, true);
- scheduler.scheduleJob(simpleTrigger);
- scheduler.rescheduleJob(simpleTrigger.getName(), simpleTrigger
- .getGroup(), simpleTrigger);
- } catch (SchedulerException e) {
- log.error("任务调度出现异常!");
- log.error(LogGenerator.getInstance().generate(e));
- throw new SummerException("任务调度出现异常!");
- }
- }
- /**
- * cron任务触发
- *
- * @param job
- */
- private void scheduleCron(JobBo job) {
- String name = getTriggerName(job.getName());
- try {
- JobDataMap jobData = new JobDataMap();
- jobData.put("name", job.getName());
- jobData.put("desc", job.getDesc());
- jobDetail.setJobDataMap(jobData);
- scheduler.addJob(jobDetail, true);
- CronTrigger cronTrigger = new CronTrigger(name, job.getGroup(),
- jobDetail.getName(), Scheduler.DEFAULT_GROUP);
- cronTrigger.setCronExpression(job.getCronExpression());
- scheduler.scheduleJob(cronTrigger);
- scheduler.rescheduleJob(cronTrigger.getName(), cronTrigger
- .getGroup(), cronTrigger);
- } catch (Exception e) {
- log.error("执行cron触发器出现异常!", e);
- throw new SummerException("执行cron触发器出现异常!");
- }
- }
- public void schedule(String name, Date startTime, Date endTime,
- int repeatCount, long repeatInterval, String group) {
- if (name == null || name.trim().equals("")) {
- name = UUID.randomUUID().toString();
- } else {
- // 在名称后添加UUID,保证名称的唯一性
- name += "&" + UUID.randomUUID().toString();
- }
- try {
- scheduler.addJob(jobDetail, true);
- SimpleTrigger SimpleTrigger = new SimpleTrigger(name, group,
- jobDetail.getName(), Scheduler.DEFAULT_GROUP, startTime,
- endTime, repeatCount, repeatInterval);
- scheduler.scheduleJob(SimpleTrigger);
- scheduler.rescheduleJob(SimpleTrigger.getName(), SimpleTrigger
- .getGroup(), SimpleTrigger);
- } catch (SchedulerException e) {
- throw new RuntimeException(e);
- }
- }
- public void pauseTrigger(String triggerName, String group) {
- try {
- scheduler.pauseTrigger(triggerName, group);// 停止触发器
- } catch (SchedulerException e) {
- throw new SummerException(e);
- }
- }
- public void resumeTrigger(String triggerName, String group) {
- try {
- scheduler.resumeTrigger(triggerName, group);// 重启触发器
- } catch (SchedulerException e) {
- log.error("重启触发器失败!");
- throw new SummerException(e);
- }
- }
- public boolean removeTrigdger(String triggerName, String group) {
- try {
- scheduler.pauseTrigger(triggerName, group);// 停止触发器
- return scheduler.unscheduleJob(triggerName, group);// 移除触发器
- } catch (SchedulerException e) {
- throw new SummerException(e);
- }
- }
- private Timestamp parseDate(String time) {
- try {
- return Timestamp.valueOf(time);
- } catch (Exception e) {
- log.error("日期格式错误{},正确格式为:yyyy-MM-dd HH:mm:ss", time);
- throw new SummerException(e);
- }
- }
- public List<Map<String, Object>> getQrtzTriggers() {
- // TODO Auto-generated method stub
- return null;
- }
- /**
- * 获取trigger名称
- *
- * @param name
- * @return
- */
- private String getTriggerName(String name) {
- if (StringUtils.isBlank(StringUtils.trim(name))) {
- name = UUID.randomUUID().toString();
- } else {
- name = name.substring(name.lastIndexOf(".") + 1);
- // 在名称后添加UUID,保证名称的唯一性
- name += "&" + UUID.randomUUID().toString();
- }
- return StringUtils.trim(name);
- }
- }
public class SchedulerServiceImpl implements SchedulerService { private static final Logger log = LoggerFactory .getLogger(SchedulerServiceImpl.class); private Scheduler scheduler; private JobDetail jobDetail; public void setScheduler(Scheduler scheduler) { this.scheduler = scheduler; } public void setJobDetail(JobDetail jobDetail) { this.jobDetail = jobDetail; } /** * 自定义任务对象并启动任务 */ public void schedule(JobBo job) { // trigger分类 String category = job.getCategory(); try { if ("cron".equals(category)) { scheduleCron(job); } else { scheduleSimple(job); } } catch (Exception e) { log.error("任务调度过程中出现异常!"); throw new SummerException(e); } } /** * simple任务触发 * * @param job */ private void scheduleSimple(JobBo job) { String name = getTriggerName(job.getName()); // 实例化SimpleTrigger SimpleTrigger simpleTrigger = new SimpleTrigger(); // 这些值的设置也可以从外面传入,这里采用默放值 simpleTrigger.setJobName(jobDetail.getName()); simpleTrigger.setJobGroup(Scheduler.DEFAULT_GROUP); simpleTrigger.setRepeatInterval(1000L); // 设置名称 simpleTrigger.setName(name); // 设置Trigger分组 String group = job.getGroup(); if (StringUtils.isEmpty(group)) { group = Scheduler.DEFAULT_GROUP; } simpleTrigger.setGroup(group); // 设置开始时间 Timestamp startTime = job.getStartTime(); if (null != startTime) { simpleTrigger.setStartTime(new Date()); } // 设置结束时间 Timestamp endTime = job.getEndTime(); if (null != endTime) { simpleTrigger.setEndTime(endTime); } // 设置执行次数 int repeatCount = job.getRepeatCount(); if (repeatCount > 0) { simpleTrigger.setRepeatCount(repeatCount); } // 设置执行时间间隔 long repeatInterval = job.getRepeatInterval(); if (repeatInterval > 0) { simpleTrigger.setRepeatInterval(repeatInterval * 1000); } try { JobDataMap jobData = new JobDataMap(); jobData.put("name", job.getName()); jobData.put("desc", job.getDesc()); jobDetail.setJobDataMap(jobData); scheduler.addJob(jobDetail, true); scheduler.scheduleJob(simpleTrigger); scheduler.rescheduleJob(simpleTrigger.getName(), simpleTrigger .getGroup(), simpleTrigger); } catch (SchedulerException e) { log.error("任务调度出现异常!"); log.error(LogGenerator.getInstance().generate(e)); throw new SummerException("任务调度出现异常!"); } } /** * cron任务触发 * * @param job */ private void scheduleCron(JobBo job) { String name = getTriggerName(job.getName()); try { JobDataMap jobData = new JobDataMap(); jobData.put("name", job.getName()); jobData.put("desc", job.getDesc()); jobDetail.setJobDataMap(jobData); scheduler.addJob(jobDetail, true); CronTrigger cronTrigger = new CronTrigger(name, job.getGroup(), jobDetail.getName(), Scheduler.DEFAULT_GROUP); cronTrigger.setCronExpression(job.getCronExpression()); scheduler.scheduleJob(cronTrigger); scheduler.rescheduleJob(cronTrigger.getName(), cronTrigger .getGroup(), cronTrigger); } catch (Exception e) { log.error("执行cron触发器出现异常!", e); throw new SummerException("执行cron触发器出现异常!"); } } public void schedule(String name, Date startTime, Date endTime, int repeatCount, long repeatInterval, String group) { if (name == null || name.trim().equals("")) { name = UUID.randomUUID().toString(); } else { // 在名称后添加UUID,保证名称的唯一性 name += "&" + UUID.randomUUID().toString(); } try { scheduler.addJob(jobDetail, true); SimpleTrigger SimpleTrigger = new SimpleTrigger(name, group, jobDetail.getName(), Scheduler.DEFAULT_GROUP, startTime, endTime, repeatCount, repeatInterval); scheduler.scheduleJob(SimpleTrigger); scheduler.rescheduleJob(SimpleTrigger.getName(), SimpleTrigger .getGroup(), SimpleTrigger); } catch (SchedulerException e) { throw new RuntimeException(e); } } public void pauseTrigger(String triggerName, String group) { try { scheduler.pauseTrigger(triggerName, group);// 停止触发器 } catch (SchedulerException e) { throw new SummerException(e); } } public void resumeTrigger(String triggerName, String group) { try { scheduler.resumeTrigger(triggerName, group);// 重启触发器 } catch (SchedulerException e) { log.error("重启触发器失败!"); throw new SummerException(e); } } public boolean removeTrigdger(String triggerName, String group) { try { scheduler.pauseTrigger(triggerName, group);// 停止触发器 return scheduler.unscheduleJob(triggerName, group);// 移除触发器 } catch (SchedulerException e) { throw new SummerException(e); } } private Timestamp parseDate(String time) { try { return Timestamp.valueOf(time); } catch (Exception e) { log.error("日期格式错误{},正确格式为:yyyy-MM-dd HH:mm:ss", time); throw new SummerException(e); } } public List<Map<String, Object>> getQrtzTriggers() { // TODO Auto-generated method stub return null; } /** * 获取trigger名称 * * @param name * @return */ private String getTriggerName(String name) { if (StringUtils.isBlank(StringUtils.trim(name))) { name = UUID.randomUUID().toString(); } else { name = name.substring(name.lastIndexOf(".") + 1); // 在名称后添加UUID,保证名称的唯一性 name += "&" + UUID.randomUUID().toString(); } return StringUtils.trim(name); } }
4、覆盖QuartzJobBean的executeInternal方法,根据“name”名实现任务的动态分配
- public class EnhanceQuartzJobBean extends QuartzJobBean {
- /**
- * log4j 记录器
- */
- private static final Logger log = Logger
- .getLogger(EnhanceQuartzJobBean.class);
- @Override
- protected void executeInternal(JobExecutionContext context)
- throws JobExecutionException {
- try {
- JobDetail t = context.getJobDetail();
- JobDataMap map = t.getJobDataMap();
- String name = map.getString("name");
- String desc = map.getString("desc");
- ServiceStartupManguage manguage = new ServiceStartupManguage();
- manguage.runService(name, desc);
- } catch (Exception e) {
- log.error("执行任务出现异常", e);
- }
- }
- public class ServiceStartup {
- /**
- * log4j 记录器
- */
- private static final Logger log = Logger
- .getLogger(ServiceStartupManguage.class);
- public void startUp() {
- // 启动动态重新加载类的服务
- StringBuilder sb = new StringBuilder(1024);
- sb.append(ServiceManager.getHome() + "work");
- String jarPath = ServiceManager.getHome() + "ext";
- // 遍历ext文件夹,寻找jar文件
- File dir = new File(jarPath);
- String[] subFiles = dir.list();
- for (int i = 0; i < subFiles.length; i++) {
- File file = new File(jarPath + System.getProperty("file.separator")
- + subFiles[i]);
- if (file.isFile() && subFiles[i].endsWith("jar")) {
- sb.append(File.pathSeparator + jarPath
- + System.getProperty("file.separator") + subFiles[i]);
- }
- }
- ServiceManager.checker = new ClassModifyChecker(ServiceManager.getHome());
- ServiceManager.loader = new ServiceClassLoad(DispatchJobServlet.class
- .getClassLoader(), (String) sb.toString(), ServiceManager.checker);
- ServiceManager.classPath = sb.toString();
- }
- /**
- * 启动后台服务
- *
- * @author 任鹤峰 2009-02-03
- * @param name
- * @param desc
- * @throws ClassNotFoundException
- * @throws NoSuchMethodException
- * @throws InstantiationException
- * @throws IllegalAccessException
- * @throws InvocationTargetException
- */
- @SuppressWarnings("unchecked")
- public void runService(String name, String desc)
- throws ClassNotFoundException, NoSuchMethodException,
- InstantiationException, IllegalAccessException,
- InvocationTargetException {
- try {
- Object service;
- Class cls = null;
- if (null != ServiceManager.loader) {
- cls = ServiceManager.getLoader().loadClass(name);
- } else {
- cls = Class.forName(name);
- }
- Class[] par = null;
-
发表评论
相关推荐
最近项目中使用了spring+Quartz定时任务、但是项目最近要集群部署、多个APP下如何利用Quartz 协调处理任务。 大家可以思考一下、现在有 A、B、C三个应用同时作为集群服务器对外统一提供服务、每个应用下各有一个...
基于Spring的Quartz动态定时任务增删改查源码.rar
Spring框架为开发提供了一系列的解决方案,比如利用控制反转的核心特性,并通过依赖注入实现控制反转来实现管理对象生命周期容器化,利用面向切面编程进行声明式的事务管理,整合多种持久化技术管理数据访问,提供...
NULL 博文链接:https://medbricom.iteye.com/blog/1782765
需要把app部署在多台服务器上,但只能让其中一台服务器的job执行,一台服务器挂了,另一台还能继续执行job,通过网上查找资料,都是java工程的方式,不好部署并测试,经过二天辛苦整合,终于整理成一个单spring web...
3、适应于spring 于quartz不能解决的场景 基本等价整合功能,满足实际应用场景(任务暂停、恢复等复杂功能不能应用); 4、可以对该demo工程进行扩展,实现在页面上定义任务开始执行时间、循环次数等。 4、附件中...
对这个问题最合适的解决方案就是来自 OpenSymphony 的 Quartz API。 Quartz 是个开源的作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却强大的机制。Quartz 允许开发人员根据时间间隔(或天)来调度...
Spring Boot + Spring Data JPA + Hazelcast缓存 + JSONRpc + Swagger2 + Quartz + MySql + TYK + HTTPS + Junit等实现的 毕业设计是高等教育阶段学生在完成学业前所进行的一项重要学术任务,旨在检验学生通过学习...
在Spring Boot中,可以使用多种方式来实现任务管理。...以上是一些在Spring Boot中实现任务管理的常见方案。你可以根据具体需求选择合适的方式来执行任务,并通过配置和注解来定制任务的执行时间和逻辑。
搭建说明 1. 将下载的项目导入到IDEA 2. 修改 spring-cache.xml 文件,配置自己的redis链接 3. 修改 jdbc.properties 文件,配置自己...5.使用 Quartz作为任务调度方案 6.使用ElasticSearch作为全文检索与数据分析方案
Web应用解决方案 ###框架组成(Project Architecture) Gradle > > finished > 2016-10-23 Gretty Integration> Server Hot Deploy Scheme> > finished > 2016-11-05 Spring 4.25 Integration > finished > 2016-10-23...
- 使用 Quartz作为任务调度方案 - 使用ElasticSearch作为全文检索与数据分析方案 搭建说明 1. 将下载的项目导入到IDEA 2. 修改 spring-cache.xml 文件,配置自己的redis链接 3. 修改 jdbc.properties 文件,配置...
OpenSymphony 的Quartz提供了一个比较完美的任务调度解决方案。 Quartz 是个开源的作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却强大的机制。 Quartz中有两个基本概念:作业和触发器。作业是...
该项目包含helloworld(快速入门)、web(ssh项目快速搭建)、aop(切面编程)、data-redis(redis缓存)、quartz(集群任务实现)、shiro(权限管理)、oauth2(四种认证模式)、shign(接口参数防篡改重放)、encoder(用户...
任务规划 2.6.4. 对Java 5(Tiger)的支持 2.7. 移植到Spring 2.0 2.7.1. 一些变化 2.7.1.1. Jar包 2.7.1.2. XML配置 2.7.1.3. Deprecated的类和方法 2.7.1.4. Apache OJB 2.7.1.5. iBatis 2.8. 更新的样例应用 2.9...
2.6.1. 动态语言支持 2.6.2. JMX 2.6.3. 任务规划 2.6.4. 对Java 5(Tiger)的支持 2.7. 移植到Spring 2.0 2.7.1. 一些变化 2.8. 更新的样例应用 2.9. 改进的文档 I. 核心技术 3. 控制反转容器 3.1. 简介 ...
13.3 在Spring中使用Quartz 13.3.1 创建JobDetail 13.3.2 创建Trigger 13.3.3 创建Scheduler 13.4 Spring中使用JDK Timer 13.4.1 Timer和TimerTask 13.4.2 Spring对JDK Timer的支持 13.5 Spring对JDK 5.0 Executor的...
该项目是一套网络相册系统,支持用户上传照片、分享照片、评论照片等功能。系统分为前台页面和后台管理两大部分。 前台页面:主要包括首页、个人主页、相册列表、照片列表、...10. Quartz定时任务,实现网站访问量统计、
spring cloud阿里巴巴集成框架可替代docker部署已更新集成阿里spring cloud 2.2.1.RELEASE版 spring cloud更新为Hoxton.SR3版本 dubbo2.7.6 ps:已将相对应框架升级为最新版本 演示演示: sentinel帐号密码为哨兵...