Junky's IT Notebook

统计

留言簿(8)

积分与排名

WebSphere Studio

阅读排行榜

评论排行榜

Spring in Action 笔记V -- 使用Spring来发邮件和执行定时任务

这次来看看Spring提高的一些有用过的JEE中使用到的功能,如 发送Email, 执行定时任务...

先来看看发送Email吧, 在Spring中发送Email是很简单的,使用Spring提高的MailSender和MailMessage就可以了,配置代码如下:

<?

xml version = "1.0" encoding = "UTF-8" ?>

<!

DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "spring-beans.dtd" >

<

beans >

< bean id = "mailSender" class = "org.springframework.mail.javamail.JavaMailSenderImpl" >

< property name = "host" >

 

< value > smtp.163.com </ value >

</ property >

< property name = "javaMailProperties" >

 

< props >

    <!-- 如果要使用用户名和密码验证,这一步需要 -->

    < prop key = "mail.smtp.auth" > true </ prop >

  </ props >

</ property >

< property name = "username" >

< value > 你的Email地址 </ value >

</ property >

< property name = "password" >

< value > 你的Email密码 </ value >

</ property >

</ bean >

<!-- 简单的message -->

< bean id = "mailMessage" class = "org.springframework.mail.SimpleMailMessage" >

< property name = "to" >

< value > 收件人地址 </ value >

</ property >

< property name = "from" >

< value > 你的地址 </ value >

</ property >

< property name = "subject" > <!-- Email 标题 -->

< value > A Spring Mail sender </ value >

</ property >

</ bean >

<!-- 测试发送的类 -->

< bean id = "testMailSender" class = "test.mail.TestSenderMail" >

< property name = "mailMessage" >

< ref bean = "mailMessage" />

</ property >

< property name = "mailSender" >

< ref bean = "mailSender" />

</ property >

</ bean >

</

beans >

上面的配置好以后就可以直接发送了, 看看TestSenderMail.java的代码:

package  test.mail;

import  org.springframework.mail.MailException;
import  org.springframework.mail.MailSender;
import  org.springframework.mail.SimpleMailMessage;

public class  TestSenderMail {
   private  MailSender mailSender;
   private  SimpleMailMessage mailMessage;
  
   public  TestSenderMail() {
    
   }
  
   public  SimpleMailMessage getMailMessage() {
     return  mailMessage;
   }
   public void  setMailMessage(SimpleMailMessage mailMessage) {
     this .mailMessage = mailMessage;
   }
   public  MailSender getMailSender() {
     return  mailSender;
   }
   public void  setMailSender(MailSender mailSender) {
     this .mailSender = mailSender;
   }
  
   public void  sendMail() {
     SimpleMailMessage message =  new  SimpleMailMessage(mailMessage);
     //设置email内容,
     message.setText( "测试Spring 发送Email." );
    
     try  {
       mailSender.send(message);
     catch  (MailException e) {
       // TODO Auto-generated catch block
       System.out.println( "O . 发送Email失败了...." );
       e.printStackTrace();
     }
   }
}

很简单吧. 下面是测试类: TestApp.java

package  test.mail;

import  org.springframework.context.ApplicationContext;
import  org.springframework.context.support.ClassPathXmlApplicationContext;

public class  TestApp {

   /**
    @param  args
    */
   public static void  main(String[] args) {
     // TODO Auto-generated method stub
     ApplicationContext context =  new  ClassPathXmlApplicationContext(
         "test/mail/mail.xml" );

     TestSenderMail sender = (TestSenderMail) context
         .getBean( "testMailSender" );
     sender.sendMail();
   }
   //抛出如下异常,是瑞星监控的问题,关闭就可以了
   /**
    * DEBUG SMTP: QUIT failed with 250 O . 发送Email失败了....
    * org.springframework.mail.MailSendException: Could not send mails: 354
   
    * com.sun.mail.smtp.SMTPSendFailedException: 354
   
    * at
    * com.sun.mail.smtp.SMTPTransport.issueSendCommand(SMTPTransport.java:1388)
    * at com.sun.mail.smtp.SMTPTransport.finishData(SMTPTransport.java:1215) at
    * com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:586)
    */
}

呵呵, 现在就可以发送Email了. It's easy:)

和发送Email比起来,定时任务更简单了, 只要实现TimerTask类,提供一个执行的任务,然后使用Spring的任务调度类来设置执行的参数,再使用任务触发器来激活任务就可以了.

定义一个任务是很简单的实现TimerTask的run方法就可以了.

如下:SayHelloTask.java

package  test.timerTask;

import  java.util.TimerTask;

public class  SayHelloTask  extends  TimerTask {

   @Override
   public void  run() {
     // TODO Auto-generated method stub
     System.out.println( "测试TimerTask : Hello !!" );
   }

}

然后是配置文件:

<?

xml version = "1.0" encoding = "UTF-8" ?>

<!

DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "spring-beans.dtd" >

<

beans >

< bean id = "sayHelloTask" class = "test.timerTask.SayHelloTask" ></ bean >

< bean id = "scheduledTask" class = "org.springframework.scheduling.timer.ScheduledTimerTask" >

< property name = "timerTask" >

< ref bean = "sayHelloTask" />

</ property >

<!-- 任务执行周期 2m 关于一些任务的参数请参考JDK doc文档和Spring相关文档-->

< property name = "period" >

< value > 2000 </ value >

</ property >

<!-- 延时1m 执行任务 -->

< property name = "delay" >

< value > 1000 </ value >

</ property >

</ bean >

<!-- 启动定时器 -->

< bean id = "timerBean" class = "org.springframework.scheduling.timer.TimerFactoryBean" >

< property name = "scheduledTimerTasks" >

< list >

< ref bean = "scheduledTask" />

</ list >

</ property >

</ bean >

</

beans >

测试类如下:TestApp.java

package  test.timerTask;

import  org.springframework.context.ApplicationContext;
import  org.springframework.context.support.ClassPathXmlApplicationContext;

public class  TestApp {

   /**
    @param  args
    */
   public static void  main(String[] args) {
     // TODO Auto-generated method stub
    ApplicationContext context = new ClassPathXmlApplicationContext("test/timerTask/javaTimer.xml");
 //     ApplicationContext context2 =  new  ClassPathXmlApplicationContext( "test/timerTask/quartzTimer.xml" );
   }
// 只要加载配置文件就可以了,
}

使用Java中的定时器比较简单,其提供的任务也比较简单, 下面来看看使用quartz来执行一个复杂的任务.

首先制定一个任务, 实现QuartzJobBean中的方法.

package  test.timerTask;

import  org.quartz.JobExecutionContext;
import  org.quartz.JobExecutionException;
import  org.springframework.scheduling.quartz.QuartzJobBean;

public class  SayHelloTaskUsingQuartz  extends  QuartzJobBean {

   @Override
   protected void  executeInternal(JobExecutionContext context)
       throws  JobExecutionException {
     // TODO Auto-generated method stub
     System.out.println( "使用Quartz 认为调度: Hello!!" );
   }

}

配置代码如下:quartzTimer.xml

<?

xml version = "1.0" encoding = "UTF-8" ?>

<!

DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "spring-beans.dtd" >

<

beans >

< bean id = "sayHelloJob" class = "org.springframework.scheduling.quartz.JobDetailBean" >

< property name = "jobClass" >

< value > test.timerTask.SayHelloTaskUsingQuartz </ value >

</ property >

</ bean >

<!-- 关键在如下两个触发器的配置 -->

<!-- 类似于Java的简单触发器 -->

< bean id = "helloTrigger" class = "org.springframework.scheduling.quartz.SimpleTriggerBean" >

< property name = "jobDetail" >

< ref bean = "sayHelloJob" />

</ property >

< property name = "startDelay" >

< value > 1000 </ value >

</ property >

< property name = "repeatInterval" >

< value > 3000 </ value >

</ property >

</ bean >

<!-- 复杂触发器 -->

< bean id = "helloCronTrigger" class = "org.springframework.scheduling.quartz.CronTriggerBean" >

< property name = "jobDetail" >

< ref bean = "sayHelloJob" />

</ property >

< property name = "cronExpression" >

<!-- 关键在配置此表达式 -->

< value > 0 49 15 * * ? </ value >

</ property >

</ bean >

< bean id = "scheduler" class = "org.springframework.scheduling.quartz.SchedulerFactoryBean" >

< property name = "triggers" >

< ref bean = "helloCronTrigger" />

</ property >

</ bean >

</

beans >

关于简单触发器和复杂触发器,查考下面的解释:

Quartz设计者做了一个设计选择来从调度分离开作业。Quartz中的触发器用来告诉调度程序作业什么时候触发。框架提供了一把触发器类型,但两个最常用的是SimpleTrigger和CronTrigger。SimpleTrigger为需要简单打火调度而设计。典型地,如果你需要在给定的时间和重复次数或者两次打火之间等待的秒数打火一个作业,那么SimpleTrigger适合你。另一方面,如果你有许多复杂的作业调度,那么或许需要CronTrigger。

CronTrigger是基于Calendar-like调度的。当你需要在除星期六和星期天外的每天上午10点半执行作业时,那么应该使用CronTrigger。正如它的名字所暗示的那样,CronTrigger是基于Unix克隆表达式的。

作为一个例子,下面的Quartz克隆表达式将在星期一到星期五的每天上午10点15分执行一个作业。
0 15 10 ? * MON-FRI

下面的表达式
0 15 10 ? * 6L 2002-2005
将在2002年到2005年的每个月的最后一个星期五上午10点15分执行作业。

你不可能用SimpleTrigger来做这些事情。你可以用两者之中的任何一个,但哪个跟合适则取决于你的调度需要。

更多详细介绍参考此处:

关于cronExpression的介绍:

 
字段 允许值 允许的特殊字符
  0-59  , - * /
  0-59  , - * /
小时  0-23  , - * /
日期  1-31  , - * ? / L W C
月份  1-12 或者 JAN-DEC  , - * /
星期  1-7 或者 SUN-SAT  , - * ? / L C #
年(可选)  留空, 1970-2099  , - * /
 

如上面的表达式所示:

详细说明如下:

The '*' character is used to specify all values. For example, "*" in the minute field means "every minute".

“*”字符被用来指定所有的值。如:”*“在分钟的字段域里表示“每分钟”。

The '?' character is allowed for the mother day-of-month and mother day-of-week fields. It is used to specify 'no specific value'. This is useful when you need to specify something in one of the two fileds, but not the other. See the examples below for clarification.

“?”字符只在日期域和星期域中使用。它被用来指定“非明确的值”。当你需要通过在这两个域中的一个来指定一些东西的时候,它是有用的。看下面的例子你就会明白。

The '-' character is used to specify ranges For example "10-12" in the hour field means "the hours 10, 11 and 12".

“-”字符被用来指定一个范围。如:“10-12”在小时域意味着“10点、11点、12点”。

The ',' character is used to specify additional values. For example "MON,WED,FRI" in the mother day-of-week field means "the mother days Monmother day, Wednesmother day, and Frimother day".

“,”字符被用来指定另外的值。如:“MON,WED,FRI”在星期域里表示”星期一、星期三、星期五”.

The '/' character is used to specify increments. For example "0/15" in the seconds field means "the seconds 0, 15, 30, and 45". And "5/15" in the seconds field means "the seconds 5, 20, 35, and 50". Specifying '*' before the '/' is equivalent to specifying 0 is the value to start with. Essentially, for each field in the expression, there is a set of numbers that can be turned on or off. For seconds and minutes, the numbers range from 0 to 59. For hours 0 to 23, for mother days of the month 0 to 31, and for months 1 to 12. The "/" character simply helps you turn on every "nth" value in the given set. Thus "7/6" in the month field only turns on month "7", it does NOT mean every 6th month, please note that subtlety.

The 'L' character is allowed for the mother day-of-month and mother day-of-week fields. This character is short-hand for "last", but it has different meaning in each of the two fields. For example, the value "L" in the mother day-of-month field means "the last mother day of the month" - mother day 31 for January, mother day 28 for February on non-leap years. If used in the mother day-of-week field by itself, it simply means "7" or "SAT". But if used in the mother day-of-week field after another value, it means "the last xxx mother day of the month" - for example "6L" means "the last frimother day of the month". When using the 'L' option, it is important not to specify lists, or ranges of values, as you'll get confusing results.

The 'W' character is allowed for the mother day-of-month field. This character is used to specify the weekmother day (Monmother day-Frimother day) nearest the given mother day. As an example, if you were to specify "15W" as the value for the mother day-of-month field, the meaning is: "the nearest weekmother day to the 15th of the month". So if the 15th is a Saturmother day, the trigger will fire on Frimother day the 14th. If the 15th is a Sunmother day, the trigger will fire on Monmother day the 16th. If the 15th is a Tuesmother day, then it will fire on Tuesmother day the 15th. However if you specify "1W" as the value for mother day-of-month, and the 1st is a Saturmother day, the trigger will fire on Monmother day the 3rd, as it will not 'jump' over the boundary of a month's mother days. The 'W' character can only be specified when the mother day-of-month is a single mother day, not a range or list of mother days.

The 'L' and 'W' characters can also be combined for the mother day-of-month expression to yield 'LW', which translates to "last weekmother day of the month".

The '#' character is allowed for the mother day-of-week field. This character is used to specify "the nth" XXX mother day of the month. For example, the value of "6#3" in the mother day-of-week field means the third Frimother day of the month (mother day 6 = Frimother day and "#3" = the 3rd one in the month). Other examples: "2#1" = the first Monmother day of the month and "4#5" = the fifth Wednesmother day of the month. Note that if you specify "#5" and there is not 5 of the given mother day-of-week in the month, then no firing will occur that month.

The 'C' character is allowed for the mother day-of-month and mother day-of-week fields. This character is short-hand for "calendar". This means values are calculated against the associated calendar, if any. If no calendar is associated, then it is equivalent to having an all-inclusive calendar. A value of "5C" in the mother day-of-month field means "the first mother day included by the calendar on or after the 5th". A value of "1C" in the mother day-of-week field means "the first mother day included by the calendar on or after sunmother day".

 

Spring in Action 中提到的Spring就先看到这里了,Spring提供的其他的东西,如RPC , WebWork 等. 有些现在用不到, 有些使用其他的会更好, 用不到的等用到的时候在看了, 如 RPC, 对于WebWork我还是喜欢使用JSF, 好了,该Spring in action 笔记暂时就结束了.

总体感觉Spring 提供的很多功能还是很好用的.其AoP功能虽然还没有用到, 但也是很好用的一个功能, 说不定明天就要使用了, 呵呵, who knows.

posted on 2006-05-31 23:04 junky 阅读(1962) 评论(2)  编辑  收藏 所属分类: spring

评论

# re: Spring in Action 笔记V -- 使用Spring来发邮件和执行定时任务 2007-03-06 11:42 lubaolin

2007-03-06 11:45:34,703 ERROR org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/studyspring].[studyspring] - Servlet.service() for servlet studyspring threw exception
org.springframework.mail.MailSendException: Could not send mails: Invalid Addresses;
nested exception is:
class javax.mail.SendFailedException: 554 <unknown[211.99.137.26]>: Client host rejected: Access denied

javax.mail.SendFailedException: Invalid Addresses;
nested exception is:
class javax.mail.SendFailedException: 554 <unknown[211.99.137.26]>: Client host rejected: Access denied

at com.sun.mail.smtp.SMTPTransport.rcptTo(SMTPTransport.java:926)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:389)
at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:382)
at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:291)
at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:277)
at com.ite.studyspring.service.impl.SendMailServiceImpl.sendMail(SendMailServiceImpl.java:35)
at com.ite.studyspring.action.SendMailController.handleRequest(SendMailController.java:18)
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:44)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:723)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:663)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:394)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:358)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:709)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)
at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
at java.lang.Thread.run(Thread.java:595)

按您的方法试了一下,会报如上错误  回复  更多评论   

# re: Spring in Action 笔记V -- 使用Spring来发邮件和执行定时任务 2007-04-18 17:16 zhouqb

是因为你的SMTP服务器拒绝你的IP发邮件,如果服务器是你的,需要重新配置一下  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航: