聪明文档网

聪明文档网

最新最全的文档下载
当前位置: 首页> Quartz使用手记

Quartz使用手记

时间:2010-12-25 11:33:13    下载该word文档

Quartz使用手记

概述

这篇文章是英文教程的中文翻译,有些认为暂时使用不到的特性有省略,英文文档参见http://www.opensymphony.com/quartz/wikidocs/TutorialLesson1.html

如何使用

使用QUARTZ调试程序之前,必须使用SchedlerFactory实例化Scheduler。一旦实例化Scheduler后可以启动或者停止,需要注意的是一旦Scheduler关闭,必须重新实例化后才能够重启。任务只有在Scheduler启动后才会执行。

下面的代码片断实例化并启动Scheduler,然后执行一个任务。

java 代码

1. SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();   

2. Scheduler sched = schedFact.getScheduler();   

3. sched.start();   

4. JobDetail jobDetail = new JobDetail("myJob", null, DumbJob.class);   

5. Trigger trigger = TriggerUtils.makeHourlyTrigger(); // fire every hour   

6. trigger.setStartTime(TriggerUtils.getEvenHourDate(new Date()));   

7. trigger.setName("myTrigger");   

8. sched.scheduleJob(jobDetail, trigger);  

任务/触发器

要定义一个任务,只需要实现Job接口即可,Job接口如下:

java 代码

1. package org.quartz;public interface Job {  public void execute(JobExecutionContext context)      

2.       throws JobExecutionException;      

3. }    

当任务被触发时将调用execute方法,JobExecutionContext 参数提供关于任务的运行时环境,包括一个Scheduler的引用,触发这个任务的触发器的引用,任务的JobDetail实例和一些别的信息。

JobDetail 对象在添加任务到Scheduler时创建,这个对象和*JobDataMap* 都用来保存Job实例的状态信息。

Trigger 用来触发任务。要计划一个任务,需要实例化一个触发器并设置相关的属性,触发器也有一个关联的JobDataMap用来传递参数给指定的任务。Quartz提供几个不同的触发器实例,比较常用的是SimpleTriggerCronTrigger

如果需要在一个指定的时间,或者指定的时间后以一个指定的间隔对一个任务重复执行多次,使用SimpleTrigger。如果需要基于日历安排任务,使用CronTrigger,比如每个星期五中午。

很多任务调用器没有分离任务和触发器,Quartz这样做有很多好处。比如一个任务可以和多个触发器关联,可以更改或替换一个触发器,而不必重新定义任务。

任务和触发器都有唯一标识名称,也可以进行分组,在一个组中任务和触发器的名称必须是唯一的,这意味着任务和触发器是使用名称+组名唯一标识的。如果不指定组名,相当于使用缺省的组名: Scheduler.DEFAULT_GROUP

任务

以前的Quartz要求具体的Job实现类通过get/set方法传递数据,现在使用JobDetail类来传递数据。

我们先来看一个实例: 

java 代码

1. JobDetail jobDetail = new JobDetail("myJob", // job name                               

2.                                     sched.DEFAULT_GROUP, // job group (you can also specify 'null' to use the default group)   

3.                                     DumbJob.class);               // the java class to executeTrigger trigger = TriggerUtils.makeDailyTrigger(8, 30);   

4. trigger.setStartTime(new Date());   

5. trigger.setName("myTrigger");sched.scheduleJob(jobDetail, trigger);  

如下是DumbJob类的代码:

java 代码

1. public class DumbJob implements Job {   

2.        public DumbJob() {   

3.        }   

4.        public void execute(JobExecutionContext context)   

5.            throws JobExecutionException   

6.        {   

7.            System.err.println("DumbJob is executing.");   

8.        }   

9.    }  

注意在添加一个任务时,传递了一个JobDetail实例作为参数,构建这个JobDetail实例时需要一个任务类参数。每次调用程序执行任务时,创建一个新的任务类实例并执行其execute方法,但是这种方法有一些限制,首先是所有的任务实现必须提供一个无参数的构造函数,还有就是任务实现不应该包含成员字段,因为在每次执行后这些值都会被消除。

那么应该如何给一个任务提供属性或者配置呢?如何在任务的不同执行过程中保存或跟踪任务的状态呢?这是通过JobDetailJobDataMap来实现。

JobDataMap

JobDataMap可以用来保存任何需要传递给任务实例的对象(这些对象要求是可序列化的),JobDataMapjavaMap接口的实现,添加了一些便利方法,下面的代码片断描述了如何使用JobDataMap保存数据:

java 代码

1. jobDetail.getJobDataMap().put("jobSays", "Hello World!");   

2. jobDetail.getJobDataMap().put("myFloatValue", 3.141f);   

3. jobDetail.getJobDataMap().put("myStateData", new List());  

下面的示例描述了如何在任务执行过程中从JobDataMap获取数据:

1. public class DumbJob implements Job {          

2.        public DumbJob() {   

3.        }          

4.   

5.        public void execute(JobExecutionContext context)   

6.            throws JobExecutionException   

7.        {   

8.            String instName = context.getJobDetail().getName();   

9.            String instGroup = context.getJobDetail().getGroup();              

10.           JobDataMap dataMap = context.getJobDetail().getJobDataMap();              

11.            String jobSays = dataMap.getString("jobSays");   

12.            float myFloatValue = dataMap.getFloat("myFloatValue");   

13.            List state = (List)dataMap.get("myStateData");   

14.            state.add(new Date());              

15.            System.err.println("Instance " + instName + " of DumbJob says: " + jobSays);   

16.        }   

17.    }   

java 代码

如果使用可持久化的JobStore(随后会有讨论),需要小心决定将JobDataMap保存在什么地方,因为JobDataMap对象中保存的对象是可序列化的,因此可能会遇到类版本问题。

有状态/无状态

触发器也可以使用JobDataMap保存数据。当需要使用多个触发器重用保存在Scheduler中的单个任务实例时,并且针对每个触发器希望提供任务不同的数据时,这是比较有用的。

JobDataMap在任务执行过程中,可以在JobExecutionContext中找到,这里的JobDataMapJobDetail中的JobDataMap和触发器中的JobDataMap合并的结果,如果遇到命名相同的元素,后者会重写前者。

如下是从JobExecutionContext中获取JobDataMap的代码片断:

java 代码

1. public class DumbJob implements Job {             

2.     public DumbJob() {   

3.     }            

4.     public void execute(JobExecutionContext context)   

5.                 throws JobExecutionException   

6.      {   

7.                 String instName = context.getJobDetail().getName();   

8.                 String instGroup = context.getJobDetail().getGroup();                   

9.                 JobDataMap dataMap = context.getJobDataMap();    // Note the difference from the previous example                   

10.                  String jobSays = dataMap.getString("jobSays");   

11.                 float myFloatValue = dataMap.getFloat("myFloatValue");   

12.                 List state = (List)dataMap.get("myStateData");   

13.                 state.add(new Date());                   

14.                  System.err.println("Instance " + instName + " of DumbJob says: " + jobSays);   

15.           }   

16.     }  

有状态任务

任务可以被定义成有状态或无状态的,无状态任务仅仅通过JobDataMap传递数据,这意味着每次任务执行后对JobDataMap的改变都会丢失,而有状态任务恰恰相反,每次任务执行后JobDataMap都被恢复。有状态任务不能并发执行。

实现*StatefulJob*接口的任务是有状态的

任务属性

下面是通过JobDetail对象定义的一些任务属性:

Durability - 如果这个值为false,每次任务没有活动的触发器关联时都将从Scheduler中删除。

Volatility - 如果任务是暂态的,在每次重启Scheduler时将不会被持久化

RequestsRecovery - 如果任务是"requests recovery",当他在Scheduler关闭的时间正在执行时,当Scheduler再次启动时将再次被执行。

JobListeners - 任务可以添加多个JobListener实例,当任务执行时,这些监听器将接收到通知。

JobExecutionException

Jobexecute方法只能抛出JobExecutionException,这就意味着通常你需要try-catch方法中的所有代码。详细信息可以参考JAVADOC

触发器

Calendars

Quartz Calendar 对象 (不是 java.util.Calendar对象) 可以和触发器关联,当需要从触发器中排除一些时间时,Calendar是比较有用的。比如你希望创建一个触发器,在每个星期三的上午九点激活一个任务,然后通过加一个Calendar实例排除所有的节假日。Calendar接口如下:

java 代码

1. package org.quartz;        

2. public interface Calendar    

3. {                

4.     public boolean isTimeIncluded(long timeStamp);    

5.     public long getNextIncludedTime(long timeStamp);        

6. }  

注意这些方法的参数单位是微秒,这意味着Calendar可以精确到微秒,但是通常我们只关心天,Quartz提供一个org.quartz.impl.HolidayCalendar类用来简化Calendar的使用。

Calendar必须使用ScheduleraddCalendar方法进行注册。如果使用HolidayCalendar,实例化后应该调用addExcludedDate(Date date)添加那些需要排除的日期,同一个Calendar可以用于多个触发器。

java 代码

1. HolidayCalendar cal = new HolidayCalendar();   

2. cal.addExcludedDate( someDate );       

3. sched.addCalendar("myHolidays", cal, false);       

4.   

5. Trigger trigger = TriggerUtils.makeHourlyTrigger(); // fire every one hour interval   

6. trigger.setStartTime(TriggerUtils.getEvenHourDate(new Date()));    // start on the next even hour   

7. trigger.setName("myTrigger1");      

8. trigger.setCalendarName("myHolidays");    // .. schedule job with trigger       

9.   

10. Trigger trigger2 = TriggerUtils.makeDailyTrigger(8, 0); // fire every day at 08:00   

11. trigger.setStartTime(new Date()); // begin immediately   

12. trigger2.setName("myTrigger2");      

13. trigger2.setCalendarName("myHolidays");    // .. schedule job with trigger2  

优先级

待补充。

Misfire指令

待补充。

TriggerUtils

TriggerUtils 类包含一些创建触发器和日期的便利方法。使用这个类可以很容易的创建基于分钟,小时,天,星期,月的触发器。

TriggerListener

触发器也可以注册监听器,监听器必须实现*TriggerListener* 接口。

SimpleTrigger

如果需要计划一个任务在指定的时间执行,或者在指定的时间后以指定的间隔连续执行多次,比如希望在2005112号上午11:22:54开始执行一个任务,在这之后每隔20分钟执行一次,共执行一次,这种情况下可以使用SimpleTrigger

SimpleTrigger包含几个属性:开始时间,结束时间,重复次数和间隔。

重复次数可以是大于等于0,或者是常量值SimpleTrigger.REPEAT_INDEFINITELY,间隔必须大于等于0的长整数,单位是微秒。如果间隔为0表示并发执行重复次数。

如果不熟悉java.util.Calendar类,可能经常需要根据开始时间计算触发时间,org.quartz.helpers.TriggerUtils 可以帮助完成这些任务。

结束时间属性重写重复次数属性。如果希望创建一个触发器,每隔10秒执行一次,直到一个指定的时间,可以简单的指定结束时间, 重复次数值为REPEAT_INDEFINITELY

SimpleTrigger有几个构造函数,下面是其中一个:

java 代码

1. public SimpleTrigger(String name,   

2.                        String group,   

3.                        Date startTime,   

4.                        Date endTime,   

5.                        int repeatCount,   

6.                        long repeatInterval)   

创建一个10秒钟后只执行一次的触发器:

java 代码

1. long startTime = System.currentTimeMillis() + 10000L;   

2.   

3. SimpleTrigger trigger = new SimpleTrigger("myTrigger",   

4.                                             null,   

5.                                             new Date(startTime),   

6.                                             null,   

7.                                             0,   

8.                                             0L);   

创建一个每隔60秒重复执行的触发器:

1. SimpleTrigger trigger = new SimpleTrigger("myTrigger",   

2.                                             null,   

3.                                             new Date(),   

4.                                             null,   

5.                                             SimpleTrigger.REPEAT_INDEFINITELY,   

6.                                             60L * 1000L);  

java 代码

创建一个40秒后开始执行,每隔10秒执行一次的触发器:

java 代码

1. long endTime = System.currentTimeMillis() + 40000L;   

2.   

3. SimpleTrigger trigger = new SimpleTrigger("myTrigger",   

4.                                             "myGroup",   

5.                                             new Date(),   

6.                                             new Date(endTime),   

7.                                             SimpleTrigger.REPEAT_INDEFINITELY,   

8.                                             10L * 1000L);   

创建一个触发器,在2002317日开始执行,重复5次,每次间隔为30:

java 代码

 

1. java.util.Calendar cal = new java.util.GregorianCalendar(2002, cal.MARCH, 17);   

2.   cal.set(cal.HOUR, 10);   

3.   cal.set(cal.MINUTE, 30);   

4.   cal.set(cal.SECOND, 0);   

5.   cal.set(cal.MILLISECOND, 0);  Data startTime = cal.getTime()  SimpleTrigger trigger = new SimpleTrigger("myTrigger",   

6.                                             null,   

7.                                             startTime,   

8.                                             null,   

9.                                             5,   

10.                                             30L * 1000L);  

CronTrigger



如果需要基于日历指定触发器,可以使用CronTrigger。使用CronTrigger可以实现类似的触发器,比如:每个星期五的下午。比如每个星期一,三和五的上午9点到10点之间每隔5分钟。

CronTrigger也有一个开始时间和结束时间属性,用来指定什么时候任务开始和结束。

Cron表达式

*Cron*表达式用来配置CronTriggerCron表达式是一个由七个部分组成的字符串,这七个部分用空隔进行分隔:

Seconds

Minutes

Hours

Day-of-Month

Month

Day-of-Week

Year (可选字段)

'*'字符表示指定字段的所有可能值,比如Day-Of-Week字段的*表示每天。

每个字段都有一些有效值。比如秒和分可以取值0-59,小时可以取值0-23Day-of-Month可以取值0-31,需要注意一个月有多少天。 月可以取值0-11,或者通过使用JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV DEC Days-of-Week可以取值1-7(1==Sunday)或者SUN, MON, TUE, WED, THU, FRI SAT

'/' 字符可以用来指定增量,比如如果指定Minute字段为"0/15"表示在第0分钟启动,每隔15分钟的间隔;"3/20"表示每三分钟启动,每隔20分钟的间隔。

'?' 字符可以在day-of-monthday-of-week 字段中使用,用来表示没有指定值。

'L'字符可以在day-of-monthday-of-week 字段中使用,这个字符表示最后一个的意思。比如在day-of-month字段中表示这个月的最后一天,如果在day-of-week字段表示"7"或者"SAT",但是如果在day-of-week字段L在另一个值后面,意味着这个月的最后XXX天,比如"6L"表示这个月的最后一个星期五。使用这个字符,不能指定列表,范围值。

'W'字符用来指定离指定天最近的星期XXX,比如如果day-of-month字段值为"15W",表示离这个月15号最近的一个weekday

'#'字符用来表示这个月的第几个XXX,比如day-of-week字段的"6#3"表示这个月的第三个星期五。

下面是一些示例:

创建一个每五分钟激活一次的触发器:

java 代码

1. "0 0/5 * * * ?"   

创建一个触发器在当前分钟的第10秒后,每五分钟执行一次,比如上午10:00:10 am,上午10:05:10

java 代码

1. "10 0/5 * * * ?"   

创建一个触发器,在每个星期三和星期五的10:30, 11:30, 12:30, 13:30执行。

java 代码

1. "0 30 10-13 ? * WED,FRI"   

创建一个触发器,在每个月的第5天和第20天的上午8点到10点执行,每隔半小时执行一次,注意上午10:00不会执行:

java 代码

1. "0 0/30 8-9 5,20 * ?"  

监听器



基于触发器的监听器接口如下:

1. public interface TriggerListener {   

2.   

3.     public String getName();   

4.   

5.     public void triggerFired(Trigger trigger, JobExecutionContext context);   

6.   

7.     public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context);   

8.   

9.     public void triggerMisfired(Trigger trigger);   

10.   

11.     public void triggerComplete(Trigger trigger, JobExecutionContext context,   

12.             int triggerInstructionCode);   

13. }   

java 代码

基于任务的监听器接口如下:

java 代码

1. public interface JobListener {   

2.   

3.     public String getName();   

4.   

5.     public void jobToBeExecuted(JobExecutionContext context);   

6.   

7.     public void jobExecutionVetoed(JobExecutionContext context);   

8.   

9.     public void jobWasExecuted(JobExecutionContext context,   

10.             JobExecutionException jobException);   

11.   

12. }   

注册监听器

要创建一个监听器,只需要实现相应的接口就可以了。监听器需要在Scheduler中注册,监听器可以被注册为全局的或者本地的,注册监听器时必须指定一个名字,或者监听器本身的getName方法返回一个值。

java 代码

1. scheduler.addGlobalJobListener(myJobListener);   

2. or   

3. scheduler.addJobListener(myJobListener);   

quartz配置总结收藏

新一篇:  quartzhibernate集成 | 旧一篇使用domapiajax开发

 quartz配置总结

由于项目需要,这2天在spring中添加了quartz计划任务,目的是自动检测某个目录是否接收到了新文件。

需要的配置有如下几项:

1.spring包里有quartz的扩展,但是没有包含quartz的包,不要忘了一起放到lib目录下。

2.spring的配置文件中,添加计划任务。



   

     

 

 

   

 ------定时运行taskBean类的taskMethod方法。

   

     

     

     

    

    

     

   

 ----定时运行方式的一种,server启动10秒后就运行,并且每隔50秒循环一次

   

 

 

   

 ----定时的另一种,和linux下的cron方式差不多,意思是每个小时的3840分钟运行一次。

   

 

  

  

  

  

 

   

 ----这个是定时任务的监视器,加到list列表里的任务才会被执行。

3.一开始我以为配置到此结束,server启动后就可以enjoy myself了,但是在我的环境下还不行。

分析了一下原因,spring里的Bean是需要手工调用才会生效的,也就是说,虽然quartzCronBean已经有了,但是server启动时没有人给初始调用。

一种办法是设置lazy-init="false";另一种办法是用servlet初始化“quartzCronBean”。至于用哪一个就看个人需要的,我的项目的servlet不会轻易改动,

我就新建了另外一个servlet专门启动“quartzCronBean”



上面是servlet,下面是在web.xml里的配置:



     quartz cron start servlet

      quartz cron start servlet

      StartupServlet

      xxx.CronTaskServlet

     3

   

这就是全过程,server启动就可以用了。

 QuartzOpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EEJ2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的日程序表。Jobs可以做成标准的Java组件或 EJBs

实例:

package  example.quartz;



import  org.quartz.CronTrigger;

import  org.quartz.Job;

import  org.quartz.JobDetail;

import  org.quartz.JobExecutionContext;

import  org.quartz.JobExecutionException;

import  org.quartz.Scheduler;

import  org.quartz.SchedulerFactory;



import  java.util.Date;



/** */ /**

 *  @author  starsiday

  */

/**/ /*  实现Job  */

public   class  QuartzReport  implements  Job  {



     /**/ /*  重载该函数  */

     public   void  execute(JobExecutionContext cntxt)  throws  JobExecutionException  {

        System.out.println( " Generating report -  "

                         +  cntxt.getJobDetail().getJobDataMap().get( " type " )

                         +   new  Date());

    }



     public   static   void  main(String[] args)  {

         try   {

            SchedulerFactory schedFact  =   new  org.quartz.impl.StdSchedulerFactory();

            Scheduler sched  =  schedFact.getScheduler();

            sched.start();

            JobDetail jobDetail  =   new  JobDetail( " Income Report " ,

                     " Report Generation " , QuartzReport. class );

            jobDetail.getJobDataMap().put( " type " ,  " FULL " );

            CronTrigger trigger  =   new  CronTrigger( " Income Report " ,

                     " Report Generation " );

             /**/ /*  1分钟执行一次  */

            trigger.setCronExpression( " 0 0/1 * * * ? " );

            sched.scheduleJob(jobDetail, trigger);

        }   catch  (Exception e)  {

            e.printStackTrace();

        }

    }

}



Quartz的配置文件:quartz.properties

# Configure Main Scheduler Properties

org.quartz.scheduler.instanceName = TestScheduler

org.quartz.scheduler.instanceId = one

# Configure ThreadPool

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool

org.quartz.threadPool.threadCount =  5

org.quartz.threadPool.threadPriority = 4

# Configure JobStore

org.quartz.jobStore.misfireThreshold = 5000

org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

附:cronExpression配置说明

字段

 

允许值

 

允许的特殊字符

 

0-59

 

, - * /

 

0-59

 

, - * /

小时

 

0-23

 

, - * /

日期

 

1-31

 

, - * ? / L W C

月份

 

1-12 或者 JAN-DEC

 

, - * /

星期

 

1-7 或者 SUN-SAT

 

, - * ? / L C #

年(可选)

 

留空, 1970-2099

 

, - * /

表达式

 

意义

"0 0 12 * * ?"

 

每天中午12点触发

"0 15 10 ? * *"

 

每天上午10:15触发

"0 15 10 * * ?"

 

每天上午10:15触发

"0 15 10 * * ? *"

 

每天上午10:15触发

"0 15 10 * * ? 2005"

 

2005年的每天上午10:15触发

"0 * 14 * * ?"

 

在每天下午2点到下午2:59期间的每1分钟触发

"0 0/5 14 * * ?"

 

在每天下午2点到下午2:55期间的每5分钟触发

"0 0/5 14,18 * * ?"

 

在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发

"0 0-5 14 * * ?"

 

在每天下午2点到下午2:05期间的每1分钟触发

"0 10,44 14 ? 3 WED"

 

每年三月的星期三的下午2:102:44触发

"0 15 10 ? * MON-FRI"

 

周一至周五的上午10:15触发

"0 15 10 15 * ?"

 

每月15日上午10:15触发

"0 15 10 L * ?"

 

每月最后一日的上午10:15触发

"0 15 10 ? * 6L"

 

每月的最后一个星期五上午10:15触发 

"0 15 10 ? * 6L 2002-2005"

 

2002年至2005年的每月的最后一个星期五上午10:15触发

"0 15 10 ? * 6#3"

 

每月的第三个星期五上午10:15触发

特殊字符

 

意义

*

 

表示所有值;

?

 

表示未说明的值,即不关心它为何值;

-

 

表示一个指定的范围;

,

 

表示附加一个可能值;

/

 

符号前表示开始时间,符号后表示每次递增的值;

L("last")

 

("last") "L" 用在day-of-month字段意思是 "这个月最后一天";用在 day-of-week字段, 它简单意思是 "7" or "SAT" 如果在day-of-week字段里和数字联合使用,它的意思就是 "这个月的最后一个星期几" – 例如: "6L" means "这个月的最后一个星期五". 当我们用L”时,不指明一个列表值或者范围是很重要的,不然的话,我们会得到一些意想不到的结果。

W("weekday")

 

只能用在day-of-month字段。用来描叙最接近指定天的工作日(周一到周五)。例如:在day-of-month字段用15W”指最接近这个月第15天的工作日,即如果这个月第15天是周六,那么触发器将会在这个月第14天即周五触发;如果这个月第15天是周日,那么触发器将会在这个月第16天即周一触发;如果这个月第15天是周二,那么就在触发器这天触发。注意一点:这个用法只会在当前月计算值,不会越过当前月。W”字符仅能在day-of-month指明一天,不能是一个范围或列表。也可以用LW”来指定这个月的最后一个工作日。

#

 

只能用在day-of-week字段。用来指定这个月的第几个周几。例:在day-of-week字段用"6#3"指这个月第3个周五(6指周五,3指第3个)。如果指定的日期不存在,触发器就不会触发。

C

 

指和calendar联系后计算过的值。例:在day-of-month 字段用5C”指在这个月第5天或之后包括calendar的第一天;在day-of-week字段用1C”指在这周日或之后包括calendar的第一天。

MONTHDay Of Week字段里对字母大小写不敏感。

免费下载 Word文档免费下载: Quartz使用手记

  • 29.8

    ¥45 每天只需1.0元
    1个月 推荐
  • 9.9

    ¥15
    1天
  • 59.8

    ¥90
    3个月

选择支付方式

  • 微信付款
郑重提醒:支付后,系统自动为您完成注册

请使用微信扫码支付(元)

订单号:
支付后,系统自动为您完成注册
遇到问题请联系 在线客服

常用手机号:
用于找回密码
图片验证码:
看不清?点击更换
短信验证码:
新密码:
 
绑定后可用手机号登录
请不要关闭本页面,支付完成后请点击【支付完成】按钮
遇到问题请联系 在线客服