Quartz

来源:互联网 发布:openwrt nginx l2tp 编辑:程序博客网 时间:2024/06/10 20:00

Quartz 是一个功能强大的作业调度工具,相当于数据库中的 Job、Windows 的计划任务、Unix/Linux 下的 Cron,但 Quartz 可以把排程控制的更精细。也许大多数人听说 Quartz 是在学习或使用 Spring 的时候,也就是 Spring 整合了Quartz。由于项目中使用了Quartz来实现定时通过接口请求数据的功能,这几天自己查阅资料学习Quartz,在此记录一下。现在分三个步骤演示一下Quartz的使用:在控制台使用Quartz、整合Spring与Quartz、将Quartz任务信息持久化到数据库中。

  我的开发环境:Eclipse3.6+jdk1.6.0_26+Tomcat6.0.20,现在Quartz最新版本是2.0.2,下载地址 http://quartz-scheduler.org/downloads/catalog。创建一个Web应用程序,将Quartz2.0.2解压后lib文件夹下的jar包(quartz依赖的包)以及quartz-2.0.2.jar和quartz-oracle-2.0.2.jar(支持Oracle的)拷贝到WEB-INF/lib下,这样即完成示例的准备工作。

一、在控制台使用Quartz

首先创建一个简单的Job,ExampleJob.java代码如下:

[java] view plaincopy
  1. package com.petrochina.job;  
  2. import org.quartz.Job;  
  3. import org.quartz.JobDataMap;  
  4. import org.quartz.JobExecutionContext;  
  5. import org.quartz.JobExecutionException;  
  6. import org.slf4j.Logger;  
  7. import org.slf4j.LoggerFactory;  
  8. public class ExampleJob implements Job {  
  9.     private Logger logger = LoggerFactory.getLogger(ExampleJob.class);  
  10.     @Override  
  11.     public void execute(JobExecutionContext context) throws JobExecutionException {  
  12.         System.out.print("I can count to 10 ->");  
  13.         // 输出1-10  
  14.         for (int i = 1; i <= 10; i++) {  
  15.             System.out.print(" | " + i + " ");  
  16.             try {  
  17.                 Thread.sleep(1000);  
  18.             } catch (InterruptedException ie) {  
  19.             }  
  20.         }  
  21.         System.out.println("<- See I did it.");  
  22.         JobDataMap properties = context.getJobDetail().getJobDataMap();  
  23.         System.out.println("Previous Fire Time: " + context.getPreviousFireTime());// 上次执行时间  
  24.         System.out.println("Current Fire Time: " + context.getFireTime());// 本次执行时间  
  25.         System.out.println("Next Fire Time: " + context.getNextFireTime());// 下一次执行时间  
  26.     }  
  27. }  

控制台程序如下:

[java] view plaincopy
  1. package com.petrochina.job;  
  2. import static org.quartz.JobBuilder.newJob;  
  3. import static org.quartz.SimpleScheduleBuilder.simpleSchedule;  
  4. import static org.quartz.TriggerBuilder.newTrigger;  
  5. import java.util.Date;  
  6. import org.quartz.JobDetail;  
  7. import org.quartz.Scheduler;  
  8. import org.quartz.SchedulerException;  
  9. import org.quartz.SchedulerFactory;  
  10. import org.quartz.SchedulerMetaData;  
  11. import org.quartz.Trigger;  
  12. import org.quartz.impl.StdSchedulerFactory;  
  13. public class Console {  
  14.     public static void main(String[] args) {  
  15.         try {  
  16.             testJob();  
  17.         } catch (Exception e) {  
  18.             e.printStackTrace();  
  19.         }  
  20.     }  
  21.     // 测试使用quartz实现的调度任务  
  22.     public static void testJob() throws SchedulerException, InterruptedException {  
  23.         // 创建调度者工厂  
  24.         SchedulerFactory sfc = new StdSchedulerFactory();  
  25.         // 通过工厂创建一个调度者  
  26.         Scheduler scheduler = sfc.getScheduler();  
  27.          /*//----------Quartz1.8.4的写法---------------// 
  28.  
  29.          // 创建一个任务,命名“myjob”,组名“group1”,对应工作类“ExampleJob” 
  30.          JobDetail myJob = new JobDetail("myjob", "group1", ExampleJob.class); 
  31.          // 使用触发器工具类创建一个每隔15秒执行一次的触发器 
  32.          Trigger trigger = TriggerUtils.makeSecondlyTrigger(15); 
  33.          trigger.setName("mytrigger"); 
  34.          trigger.setStartTime(new Date()); 
  35.          */  
  36.         //----------Quartz 2.0.2的写法---------------//  
  37.         JobDetail myJob = newJob(ExampleJob.class).withIdentity("myJob""job-group").build();  
  38.         Trigger trigger = newTrigger().withIdentity("mytrigger""trigger-group").startAt(new Date())  
  39.                 .withSchedule(simpleSchedule().withIntervalInSeconds(15).repeatForever()).build();nbsp;       // 调度任务  
  40.         Date startDate = scheduler.scheduleJob(myJob, trigger);  
  41.         System.out.println(myJob.getKey() + " will start at:" + startDate.toLocaleString());  
  42.         // 开始运行调度程序  
  43.         scheduler.start();        Thread.sleep(20000);// 等待20秒  
  44.         scheduler.shutdown();// 关闭调度程序        SchedulerMetaData metaData = scheduler.getMetaData();  
  45.         System.out.println("Executed " + metaData.getNumberOfJobsExecuted() + " jobs.");  
  46.         System.out.println("Test end------>");    }}  

执行结果如下:

job-group.myJob will start at:2011-9-2 15:15:02
2011-09-02 15:15:02,046 [main] INFO  [org.quartz.core.QuartzScheduler] - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
I can count to 10 -> | 1  | 2  | 3  | 4  | 5  | 6  | 7  | 8  | 9  | 10 <- See I did it.
Previous Fire Time: null
Current Fire Time: Fri Sep 02 15:15:02 CST 2011
Next Fire Time: Fri Sep 02 15:15:17 CST 2011
I can count to 10 -> | 1  | 2  | 3  | 4  | 5  | 6 2011-09-02 15:15:22,046 [main] INFO  [org.quartz.core.QuartzScheduler] - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutting down. //sleep20秒后关闭调度程序
2011-09-02 15:15:22,046 [main] INFO  [org.quartz.core.QuartzScheduler] - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED paused.  
 | 7  | 8  | 9  | 10 <- See I did it.  //已经启动的Job继续执行完成
Previous Fire Time: Fri Sep 02 15:15:02 CST 2011
Current Fire Time: Fri Sep 02 15:15:17 CST 2011
Next Fire Time: Fri Sep 02 15:15:32 CST 2011
2011-09-02 15:15:27,031 [main] INFO  [org.quartz.core.QuartzScheduler] - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutdown complete.
Executed 2 jobs.
Test end------>

二、整合Spring与Quartz

    spring增加了对Quartz的支持,可以方便的在spring中配置调度程序,而不需要编写代码。首先要添加spring的支持:可以到官网http://www.springsource.org/download下载spring 的jar包,我使用的是3.0.5.RELEASE版本的,将下面的jar包拷贝到WEB-INF/lib下,同时这里的Quartz要使用1.8.5及其以下版本,而不能使用2.0.2版,原因后面讲。

commons-logging.jar

spring-core-3.0.5.RELEASE.jar

spring-beans-3.0.5.RELEASE.jar

spring-context-3.0.5.RELEASE.jar

spring-context-support-3.0.5.RELEASE.jar

spring-asm-3.0.5.RELEASE.jar

spring-expression-3.0.5.RELEASE.jar

spring.transaction-3.0.5.RELEASE.jar

spring-web-3.0.5.RELEASE.jar

添加spring配置文件applicationContext.xml

[html] view plaincopy
  1. <!-- 配置调度程序quartz ,其中配置JobDetail有两种方式    -->  
  2.     <!--方式一:使用JobDetailBean,任务类必须实现Job接口  
  3.     <bean id="myjob" class="org.springframework.scheduling.quartz.JobDetailBean">  
  4.      <property name="name" value="exampleJob"></property>  
  5.      <property name="group" value="group1"></property>  
  6.      <property name="jobClass" value="com.petrochina.job.ExampleJob"></property>  
  7.     </bean> -->  
  8.     <!-- 方式二:使用MethodInvokingJobDetailFactoryBean,任务类可以不实现Job接口,通过targetMethod指定调用方法-->  
  9.     <bean id="exampleJob" class="com.petrochina.job.ExampleJob2"></bean>  
  10.     <bean id="myjob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">  
  11.      <property name="targetObject" ref="exampleJob"/>  
  12.      <property name="targetMethod" value="execute"/>  
  13.      <property name="concurrent" value="false"/>  
  14.     </bean>   
  15.     <!-- 定义名为mytrigger的触发器 -->  
  16.     <bean id="mytrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">  
  17.      <property name="jobDetail" ref="myjob"/>  
  18.      <property name="cronExpression">  
  19.       <value>0/15 * * * * ? </value>  
  20.      </property>  
  21.     </bean>  
  22.    <!-- 定义调度器 -->  
  23.     <bean id="myscheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" lazy-init="false" autowire="no">  
  24.      <property name="triggers">  
  25.       <list>  
  26.        <ref bean="mytrigger"/>  
  27.       </list>  
  28.      </property>  
  29.      <property name="quartzProperties">  
  30.       <props>  
  31.        <prop key="org.quartz.threadPool.threadCount">1</prop>  
  32.       </props>  
  33.      </property>  
  34.     </bean>  
说明:在spring中配置JobDetail有两种方式,第一种是使用org.springframework.scheduling.quartz.JobDetailBean,这种方式ExampleJob要实现Job接口;第二种是使用org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean调用指定类的指定方法,这个比较灵活,这种方式下ExampleJob2的代码如下:
[java] view plaincopy
  1. package com.petrochina.job;  
  2.   
  3. public class ExampleJob2 {  
  4.   
  5.     public void execute() {  
  6.         System.out.print("I can count to 10 ->");  
  7.   
  8.         for (int i = 1; i <= 10; i++) {  
  9.             System.out.print(" | " + i + " ");  
  10.             try {  
  11.                 Thread.sleep(1000);  
  12.             } catch (InterruptedException ie) {  
  13.             }  
  14.         }  
  15.   
  16.         System.out.println("<- See I did it.");  
  17.     }  
  18. }  

这样只要启动spring容器即可启动调度程序。

1、使用方法testJob启动spring容器

[java] view plaincopy
  1. public static void testJob() throws InterruptedException, SchedulerException {  
  2.        // 方法一:基于spring配置job、trigger、scheduler之间的关联关系  
  3.        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");  
  4.        Scheduler scheduler = (Scheduler) context.getBean("myscheduler");  
  5.   
  6.       Thread.sleep(20000);// 等待20秒  
  7.        scheduler.shutdown();// 关闭调度程序  
  8.   
  9.        SchedulerMetaData metaData = scheduler.getMetaData();  
  10.       System.out.println("Executed " + metaData.getNumberOfJobsExecuted() + " jobs.");  
  11.    }  

结果如下:

2011-09-02 16:52:27,203 [main] INFO  [org.quartz.impl.StdSchedulerFactory] - Quartz scheduler 'myscheduler' initialized from an externally provided properties instance.
2011-09-02 16:52:27,203 [main] INFO  [org.quartz.impl.StdSchedulerFactory] - Quartz scheduler version:1.8.5
2011-09-02 16:52:27,203 [main] INFO  [org.quartz.core.QuartzScheduler] - JobFactory set to:org.springframework.scheduling.quartz.AdaptableJobFactory@bf7190
2011-09-02 16:52:27,203 [main] INFO  [org.springframework.context.support.DefaultLifecycleProcessor] - Starting beans in phase 2147483647
2011-09-02 16:52:27,203 [main] INFO  [org.springframework.scheduling.quartz.SchedulerFactoryBean] - Starting Quartz Scheduler now
2011-09-02 16:52:27,203 [main] INFO  [org.quartz.core.QuartzScheduler] - Scheduler myscheduler_$_NON_CLUSTERED started.
I can count to 10 -> | 1  | 2  | 3  | 4  | 5  | 6  | 7  | 8  | 9  | 10 <- See I did it.
I can count to 10 -> | 1  | 2  | 3 2011-09-02 16:52:47,203 [main] INFO  [org.quartz.core.QuartzScheduler] - Scheduler myscheduler_$_NON_CLUSTERED shutting down.
2011-09-02 16:52:47,203 [main] INFO  [org.quartz.core.QuartzScheduler] - Scheduler myscheduler_$_NON_CLUSTERED paused.
2011-09-02 16:52:47,203 [main] INFO  [org.quartz.core.QuartzScheduler] - Scheduler myscheduler_$_NON_CLUSTERED shutdown complete.
Executed 2 jobs.
 | 4  | 5  | 6  | 7  | 8  | 9  | 10 <- See I did it.
可见和在控制台编写代码实现的效果一样。

2、在web.xml中添加listener来启动spring容器

[html] view plaincopy
  1. <!-- 配置启动spring容器 -->  
  2.     <listener>  
  3.         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
  4.     </listener>  

注意!!!在做示例的时候发现使用Quartz2.0.2+Spring3.0.5配置的applicationContext运行时会出错:

Caused by: org.springframework.beans.factory.CannotLoadBeanClassException: Error loading class [org.springframework.scheduling.quartz.CronTriggerBean] for bean with name 'mytrigger' defined in class path resource [applicationContext.xml]: problem with class file or dependent class; nested exception is java.lang.IncompatibleClassChangeError: class org.springframework.scheduling.quartz.CronTriggerBean has interface org.quartz.CronTrigger as super class

查看发现spring3.0.5中org.springframework.scheduling.quartz.CronTriggerBean继承了org.quartz.CronTrigger(public class CronTriggerBeanextends CronTrigger),而在quartz2.0.2中org.quartz.CronTrigger是个接口(publicabstract interface CronTrigger extends Trigger),而在quartz1.8.5及1.8.4中org.quartz.CronTrigger是个类(publicclass CronTrigger extends Trigger),从而造成无法在applicationContext中配置触发器。这是spring3.0.5和quartz2.0.2版本不兼容的一个bug。

三、将Quartz任务信息持久化到数据库中

  Quartz默认将运行信息存放在内存中,一旦程序重启那么以前的任务信息就会丢失,最保险的方式就是将任务信息持久化到数据库中。这里还是使用Quartz2.0.2+Oracle10g来做示例

1、将解压包里的quartz-oracle-2.0.2.jar以及commons-dbcp-1.3.jar 、commons-pool-1.5.4.jar、ojdbc6-11.1.0.7.0.jar拷贝到WEB-INF/lib下。

2、创建quartz配置文件quartz.properties

[html] view plaincopy
  1. #============================================================================  
  2. # Configure Main Scheduler Properties    
  3. #============================================================================  
  4. org.quartz.scheduler.instanceName = My_Quartz  
  5. org.quartz.scheduler.instanceId = AUTO  
  6.   
  7. #============================================================================  
  8. # Configure ThreadPool    
  9. #============================================================================  
  10. org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool  
  11. org.quartz.threadPool.threadCount = 5  
  12. org.quartz.threadPool.threadPriority = 5  
  13. org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true  
  14.   
  15. #============================================================================  
  16. # Configure JobStore single  
  17. #============================================================================  
  18. #RAM  
  19. #org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore #这是默认的  
  20.   
  21. #============================================================================  
  22. # Configure JobStore Cluster  
  23. #============================================================================  
  24. org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX  
  25. org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate  
  26. org.quartz.jobStore.tablePrefix = QRTZ_  
  27. #org.quartz.jobStore.misfireThreshold = 60000  
  28. #org.quartz.jobStore.isClustered = true  
  29. #org.quartz.jobStore.clusterCheckinInterval = 15000  
  30.   
  31. org.quartz.jobStore.dataSource = myDS  #指定数据源  
  32. #============================================================================  
  33. # Configure dataSource    
  34. #============================================================================  
  35. #dataSource--myDS  
  36. org.quartz.dataSource.myDS.driver = oracle.jdbc.driver.OracleDriver  
  37. org.quartz.dataSource.myDS.URL = jdbc:oracle:thin:@127.0.0.1:1521:cui  
  38. org.quartz.dataSource.myDS.user = cui  
  39. org.quartz.dataSource.myDS.password = cui  
  40. org.quartz.dataSource.myDS.maxConnections = 10  

3、根据quartz-2.0.2\docs\dbTables\tables_oracle.sql在数据库中创建Quartz保存任务信息需要的12张表(针对各种数据库的创建语句都有),注意quartz1.8.5和quartz2.0.2有些表的字段有些差异。

4、使用ContextLoaderListener中初始化的StdSchedulerFactory获取Scheduler来调度Job,这样Job的运行信息就会持久化到数据库。这里我创建一个Listener在程序部署时调度Job,当然你也可以在写一个页面来添加、启动、暂停一个Job。

QuartzListener.java

[java] view plaincopy
  1. import static org.quartz.JobBuilder.newJob;  
  2. import static org.quartz.SimpleScheduleBuilder.simpleSchedule;  
  3. import static org.quartz.TriggerBuilder.newTrigger;  
  4. import java.util.Date;  
  5. import javax.servlet.ServletContextEvent;  
  6. import javax.servlet.ServletContextListener;  
  7. import org.quartz.JobDetail;  
  8. import org.quartz.JobKey;  
  9. import org.quartz.Scheduler;  
  10. import org.quartz.SchedulerException;  
  11. import org.quartz.SimpleTrigger;  
  12. import org.quartz.ee.servlet.QuartzInitializerListener;  
  13. import org.quartz.impl.StdSchedulerFactory;  
  14. public class QuartzListener implements ServletContextListener {  
  15.     @Override  
  16.     public void contextDestroyed(ServletContextEvent arg0) {  
  17.     }  
  18.     @Override  
  19.     public void contextInitialized(ServletContextEvent arg0) {  
  20.         StdSchedulerFactory factory = (StdSchedulerFactory) arg0.getServletContext().getAttribute(QuartzInitializerListener.QUARTZ_FACTORY_KEY);  
  21.         Scheduler scheduler = null;  
  22.         try {  
  23.             scheduler = factory.getScheduler();  
  24.             // -----------Quartz2.0.2--------------//  
  25.             // 如果不存在名为“myjob”,组名为“group1”的Job,则添加进去  
  26.             if (scheduler.getJobDetail(new JobKey("myjob""group1")) == null) {  
  27.                 JobDetail myJob = newJob(ExampleJob.class).withIdentity("myjob""group1").build();  
  28.                 SimpleTrigger trigger = newTrigger().withIdentity("mytrigger""trigger-group").startAt(new Date())  
  29.                         .withSchedule(simpleSchedule().withIntervalInSeconds(15).repeatForever()).build();  
  30.                 scheduler.scheduleJob(myJob, trigger);  
  31.             }  
  32.         } catch (SchedulerException e) {  
  33.             e.printStackTrace();  
  34.         }  
  35.     }}  

配置web.xml

[html] view plaincopy
  1.         <!-- 配置启动spring容器 -->  
  2. <listener>  
  3.     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
  4. </listener>  
  5. <!-- 配置Quartz -->  
  6. <listener>  
  7.     <listener-class>org.quartz.ee.servlet.QuartzInitializerListener</listener-class>  
  8. </listener>  
  9. <!-- 使用Quartz调度Job的Listener -->  
  10. <listener>  
  11.     <listener-class>com.petrochina.job.QuartzListener</listener-class>  
  12. </listener>  

 

5、将上面applicationContext.xml中使用bean配置的调度程序去掉,因为它是使用org.springframework.scheduling.quartz.SchedulerFactoryBean创建的Scheduler,它配置的调度程序不能持久化入库。启动Tomcat,计数的Job开始工作,查看数据库。


可见,关于Job和Trigger的信息已经入库,但下次程序部署时Quartz会自动还原各个调度程序的状态。

 

另:Quartz的CronTrigger配置相当灵活,下面贴出一些Cron的资料

格式

A cron expression is a string comprised of 6 or 7 fields separated by white space. Fields can contain any of the allowed values, along with various combinations of the allowed special characters for that field. The fields are as follows:

Field NameMandatoryAllowed ValuesAllowed Special CharactersSecondsYES0-59, - * /MinutesYES0-59, - * /HoursYES0-23, - * /Day of monthYES1-31, - * ? / L WMonthYES1-12 or JAN-DEC, - * /Day of weekYES1-7 or SUN-SAT, - * ? / L #YearNOempty, 1970-2099, - * /

So cron expressions can be as simple as this: * * * * ? *
or more complex, like this: 0 0/5 14,18,3-39,52 ? JAN,MAR,SEP MON-FRI 2002-2010

样例

Here are some full examples:

ExpressionMeaning0 0 12 * * ?Fire at 12pm (noon) every day0 15 10 ? * *Fire at 10:15am every day0 15 10 * * ?Fire at 10:15am every day0 15 10 * * ? *Fire at 10:15am every day0 15 10 * * ? 2005Fire at 10:15am every day during the year 20050 * 14 * * ?Fire every minute starting at 2pm and ending at 2:59pm, every day0 0/5 14 * * ?Fire every 5 minutes starting at 2pm and ending at 2:55pm, every day0 0/5 14,18 * * ?Fire every 5 minutes starting at 2pm and ending at 2:55pm, AND fire every 5 minutes starting at 6pm and ending at 6:55pm, every day0 0-5 14 * * ?Fire every minute starting at 2pm and ending at 2:05pm, every day0 10,44 14 ? 3 WEDFire at 2:10pm and at 2:44pm every Wednesday in the month of March.0 15 10 ? * MON-FRIFire at 10:15am every Monday, Tuesday, Wednesday, Thursday and Friday0 15 10 15 * ?Fire at 10:15am on the 15th day of every month0 15 10 L * ?Fire at 10:15am on the last day of every month0 15 10 ? * 6LFire at 10:15am on the last Friday of every month0 15 10 ? * 6LFire at 10:15am on the last Friday of every month0 15 10 ? * 6L 2002-2005Fire at 10:15am on every last friday of every month during the years 2002, 2003, 2004 and 20050 15 10 ? * 6#3Fire at 10:15am on the third Friday of every month0 0 12 1/5 * ?Fire at 12pm (noon) every 5 days every month, starting on the first day of the month.0 11 11 11 11 ?Fire every November 11th at 11:11am.

 Pay attention to the effects of '?' and '*' in the day-of-week and day-of-month fields!
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 两个学生打闹受伤的孩子家长怎么办 小孩学习不好做家长的该怎么办 对学习不入门的小孩家长该怎么办 孩子老做作业发神上课不专心怎么办 儿子成绩考得差不专心未来怎么办 五年级学生写字慢又丑怎么办 宝宝上课坐不住不听老师话怎么办 三岁宝宝特调皮打他还还手怎么办 怀孕40天不知道喝酒了怎么办 怀孕四十天的时候喝酒抽烟了怎么办 宝宝怀孕三十天左右喝酒了怎么办 两个人都喝酒了意外怀孕怎么办 不知道自己怀孕了喝了很多酒怎么办 不知道自己怀孕了喝了一次酒怎么办 我儿子11岁了有多动症怎么办 面对老师的冷暴力家长该怎么办? 面对无德的老师家长该怎么办 如果你家长屏蔽老师老师该怎么办 小孩出完水痘后身上出现疱疹怎么办 脑子里兴奋的头疼怎么办 吃什么药 一个月宝宝异常兴奋不睡觉怎么办 四个月宝宝晚上兴奋不睡觉怎么办 20个月宝宝半夜惊醒哭闹怎么办 小孩吃了氨茶碱兴奋不睡觉怎么办 孩子在学校被同学撞鼻骨折怎么办 孩子在学校无意致使同学受伤怎么办 9个月的宝宝吃坏东西腹泻怎么办 8个月发烧到38度怎么办 1岁半宝宝鼻塞发烧38度6怎么办 八个月的宝宝发热38度怎么办 八个月宝宝发热在38度怎么办 8个月孩子发烧38度怎么办 6个月孩子发烧38度多怎么办 7个月孩子发烧38度怎么办 小明上课总是东张西望你该怎么办 初中二年级贪玩游戏说不听怎么办 孩子上课经常和别的同学说话怎么办 小孩五年级了上课坐不住怎么办 孩子老是纠结小事抓不住重点怎么办 没文化不懂教不了孩孑怎么办 孩孑学习不好老师不让上课怎么办