Spring 下構建 Quartz 任務調度

昨天 老大 交下一件任務,在Spring框架下構建一個郵件自動發送模塊,接到此任務的第一個想法是利用Timer, 它小巧功能夠用.

以下是寫的一個測試類.写道

package umt.michael.tsk.test;

importjava.util.Date;

importjava.util.Timer;

importjava.util.TimerTask;

/**

*@Title:Test.java

*@Packageumt.michael.tsk.test

*@Description:TODO

*@authorMichaelYang

*@[email protected]

*@date2011/10/13下午9:19:01

*@versionV1.0

*/

classDateTaskextendsTimerTask{

@Override

publicvoidrun(){

System.out.println("現在時間:"+newDate());

}

}

publicclassTest{

/**

*@Title:main

*@Description:TODO

*@paramargs

*@returnvoid

*/

publicstaticvoidmain(String[]args){

Timertimer=newTimer();

timer.schedule(newDateTask(),1000,5000);

try{

Thread.sleep(20000);

}catch(Exceptione){

System.err.println(e.getMessage());

e.printStackTrace();

}

System.out.println("結束時間是:"+newDate());

timer.cancel();

}

}

結果為:

現在時間:Thu Oct 13 21:30:12 CST 2011
現在時間:Thu Oct 13 21:30:17 CST 2011
現在時間:Thu Oct 13 21:30:22 CST 2011
現在時間:Thu Oct 13 21:30:27 CST 2011
結束時間是:Thu Oct 13 21:30:31 CST 2011

  頭兒卻明確要用Quartz 這個任務調度框架.沒辦法,只好拼了,从Quartz官网 http://www.quartz-scheduler.org/上下载jar包 现在该版本已经到了2.10,但是在国外一个网站发现貌似 2.1 和Spring3.x 无法兼容,没有验证,为了安全起见,我下载的是穩定版本quartz1.8.5. 相關配置如下.

Web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/spring-quartz.xml</param-value>
	</context-param>

	<!-- 配置日誌文件打印 -->
	<context-param>
		<param-name>log4jConfigLocation</param-name>
		<param-value>/WEB-INF/properties/log4j.properties</param-value>
	</context-param>
	<context-param>
		<param-name>log4jRefreshInterval</param-name>
		<param-value>6000</param-value>
	</context-param>
	<listener>
		<listener-class>
			org.springframework.web.util.Log4jConfigListener
		</listener-class>
	</listener>
	<!-- 此監聽器 用於加載組件 -->
	<listener>
		<listener-class>
			org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>
	<!-- 字符流過濾器 -->
	<filter>
		<filter-name>characterEncoding</filter-name>
		<filter-class>
			org.springframework.web.filter.CharacterEncodingFilter
		</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
		<init-param>
			<param-name>forceEncoding</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>characterEncoding</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<!-- 配置代理轉發請求 -->
	<servlet>
	<servlet-name>login</servlet-name>
	<servlet-class>com.saq.michael.servlet.HttpServletProxy</servlet-class>
		<init-param>
			<param-name>targetServlet</param-name>
			<param-value>loginServlet</param-value>
		</init-param>
	</servlet>
	<servlet-mapping>
		<servlet-name>login</servlet-name>
		<url-pattern>/login</url-pattern>
	</servlet-mapping>

</web-app>

spring-quartz.xml

<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:tx="http://www.springframework.org/schema/tx"
      xmlns:aop="http://www.springframework.org/schema/aop"
      xsi:schemaLocation="
      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
      http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
      http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <import resource="db-config.xml" />
 <!-- 定時執行的任務 -->
    <bean id="jobDetailBean" class="org.springframework.scheduling.quartz.JobDetailBean">
        <property name="jobClass" value="com.saq.michael.job.SendEmailJob"/>  
        <property name="jobDataAsMap">
            <map>
                <entry key="sendEmailService" value-ref="sendEmailService"/>
            </map>
        </property>          
    </bean>
    
    
	<!--觸發器  -->
    <bean id="simpleTriggerBean"  class="org.springframework.scheduling.quartz.SimpleTriggerBean">
        <property name="jobDetail">
            <ref bean="jobDetailBean"/>
        </property>
        <property name="repeatInterval">
            <value>45000</value>
        </property>
        <property name="startDelay">
            <value>1000</value>
        </property> 
    </bean>
    
    <!-- 任務調度器, 可配置 dataSoure -->
    <bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="simpleTriggerBean"/>
            </list>
        </property>
    </bean>
    
 </beans>

db-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="
	http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context-3.0.xsd">
	<!--加載屬性文件
	<bean id="propertyConfigurer"
			class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
			<property name="locations">
				<list>
					<value>/WEB-INF/properties/common.properties</value>
				</list>
			</property>
	</bean>
      -->

	
	<bean id="loginServlet" class="com.saq.michael.servlet.CommonServlet">
		<property name="operation" ref="operation" />
	</bean>
	
	<bean id="sendEmailService" class="com.saq.michael.service.impl.SendEmailService">
		<property name="dataSource" ref="dataSource" />
	</bean>

	<bean id="dataSource" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
		<property name="url" value="jdbc:sqlserver://XXXXXXX:1433;DatabaseName=testPaper" />
		<property name="username" value="XXX" />
		<property name="password" value="XXXXX" />
	</bean>
	  <!-- set TransactionManager message-->
      <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource" />
      </bean>
   
      <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"/>
      </bean>  

       <!--利用了拦截器的原理-->      
	   <bean id="transactionInterceptor" lazy-init="true" scope="singleton" 
            class="org.springframework.transaction.interceptor.TransactionInterceptor">      
	        <property name="transactionManager" ref="transactionManager">       
	        </property>      
	    <!-- 配置事务属性 
       -Exception                  表示有Exception抛出时,事务回滚. readonly 就是read only, 一般用于查询的方法,优化作用.
        prop key="delete*"         表示方法名 可以用戶通配符*
        PROPAGATION_REQUIRED       支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 
		PROPAGATION_SUPPORTS       支持当前事务,如果当前没有事务,就以非事务方式执行。 
		PROPAGATION_MANDATORY      支持当前事务,如果当前没有事务,就抛出异常。 
		PROPAGATION_REQUIRES_NEW   新建事务,如果当前存在事务,把当前事务挂起。 
		PROPAGATION_NOT_SUPPORTED  以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 
		PROPAGATION_NEVER          以非事务方式执行,如果当前存在事务,则抛出异常。 
		PROPAGATION_NESTED         如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
          -->   
		   <property name="transactionAttributes">      
		        <props>      
		            <prop key="delete*">PROPAGATION_REQUIRED,-Exception</prop>   
		            <prop key="operate*">PROPAGATION_REQUIRED,-Exception</prop>      
		            <prop key="insert*">PROPAGATION_REQUIRED,-Exception</prop>      
		            <prop key="update*">PROPAGATION_REQUIRED,-Exception</prop>      
		            <prop key="save*">PROPAGATION_REQUIRED,-Exception</prop>
		            <prop key="sendMail">PROPAGATION_REQUIRED,-Exception</prop>            
		            <prop key="find*">PROPAGATION_NEVER,readOnly</prop> 
	                <prop key="get*">PROPAGATION_NEVER,readOnly</prop>        
		       </props>      
		   </property>      
	   </bean>
	   
	    <!--Spring 自動代理所有的 ServiceName 為 *ServiceImpl 的Service-->      
	   <bean id="txProxy"   class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">      
	        <property name="beanNames">      
	          <list>      
	             <value>*Service</value> 
	          </list>      
	        </property>      
	        <property name="interceptorNames">      
	          <list>      
	             <value>transactionInterceptor</value>      
	          </list>      
	        </property>      
	   </bean>
</beans>

SendEmailService.java

package com.saq.michael.service.impl;

import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.servlet.ServletException;
import javax.sql.DataSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Logger;
import org.springframework.jdbc.CannotGetJdbcConnectionException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;

import com.saq.michael.bean.EmailAddress;
import com.saq.michael.method.reportViaUrl;

/**
 * @Title: SendEmailService.java
 * @Package com.saq.michael.service.impl
 * @Description: 郵件發送,數據更新.
 * @author MichaelYang
 * @Email [email protected]
 * @date Oct 20, 2011 2:48:34 PM
 * @version V1.0
 */
public class SendEmailService {
	
    private JdbcTemplate jdbcTemplate;
    
    private Connection con ;
    
    private static final Log logger = LogFactory.getLog(SendEmailService.class);
	
	public void setDataSource(DataSource dataSource) {
		if (this.jdbcTemplate == null)
			this.jdbcTemplate = new JdbcTemplate(dataSource);
	}
	
	/**
	 * 發送郵件的相關信息
	 * @param mailSender
	 * @return
	 * @throws SQLException 
	 * @throws Exception 
	 * @throws IOException
	 * @throws ServletException
	 */
	public boolean sendMail(EmailAddress emailAddress,File file) throws MessagingException, SQLException{
		logger.info(" ... 開始發送郵件.... ");
		if(con == null || con.isClosed()) {
			con = this.getConnection();
			logger.info(con.hashCode());
		}
		String msg = reportViaUrl.reportHTMLStringViaURL(emailAddress.getUrl(),con); //獲取郵件內容
		JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
		mailSender.setHost("XXXXX");
		MimeMessage message = mailSender.createMimeMessage();
		MimeMessageHelper helper = new MimeMessageHelper(message, true);
		message.setContent(msg, "text/html;charset=UTF-8");//文本類型
		message.setSubject(msg, "UTF-8");
		helper.setTo(emailAddress.getRecipients());
		helper.setText(msg);
		if(file!=null && file.length()>0){
			helper.addAttachment(file.getName(), file);//添加附件
	    }
		mailSender.send(message);
		logger.info(" ....... ");
		return true;
	}
	
	
	
	/**
	 *  獲取異常信息. 
	 * @param throwable
	 * @return String exceptionMsg
	 */
	public String getException(Throwable throwable){
		StringBuffer  resultMess =new StringBuffer();
		if(resultMess.length()>500){
			return resultMess.substring(0, 500);
		}else{
			resultMess.append(throwable.toString()+"\n");
			if(throwable.getCause()!=null){
				resultMess.append("Cause By: ");
				resultMess.append(getException(throwable.getCause()));
			}
		}
		return resultMess.length()>500?resultMess.substring(0, 500):resultMess.toString();
	}

	/**
	 * 從數據庫中讀取相應的數據,并執行相應操作
	 * @param <EmaillAddress>
	 * @param con
	 * @return
	 * @throws SQLException
	 * @throws IOException
	 */
	@SuppressWarnings({"unused","unchecked"})
	public  List<EmailAddress> getEmailAddress(String  sql){
		System.out.println(" ... 查詢出郵件地址以及對應的URL ... ");
		System.out.println(" ... SQL:"+sql+"... ");
		List<EmailAddress> list = this.jdbcTemplate.query(sql, new EmailAddressRowMapper());
		return list;
	}
	
	/**
	 * 更新發送成功的數據
	 * @param list
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public boolean updateEmailSuccess(final List<Integer> list){
			this.jdbcTemplate.update(new PreparedStatementCreator(){
				public PreparedStatement createPreparedStatement(Connection con)
						throws SQLException {
                        PreparedStatement ps =  con.prepareStatement("UPDATE EMAIL_ADDRESS_URL SET ENABLE=0 WHERE PK_EAU_ID = ?");
                        for(int pk_id:list){
                        	System.out.println(" PK_ID: "+pk_id);
                        	ps.setInt(1, pk_id);
                        	ps.addBatch();
                        }
					return ps;
				}
			});
		return true;
	}
	/**
	 * 
	 * @param list
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public boolean updateEmailSuccess(final int pk_id){
			this.jdbcTemplate.update(new PreparedStatementCreator(){
				public PreparedStatement createPreparedStatement(Connection con)
						throws SQLException {
                        PreparedStatement ps =  con.prepareStatement("UPDATE EMAIL_ADDRESS_URL SET ENABLE=0 WHERE PK_EAU_ID = ?");
                        	System.out.println(" PK_ID: "+pk_id);
                        	ps.setInt(1, pk_id);
					return ps;
				}
			});
		return true;
	}
	
	public  boolean updateEmailFailed(final EmailAddress address){
		final String SQL = "UPDATE  EMAIL_ADDRESS_URL SET modifiedDate = ?),SET tryAgain =1 WHERE PK_EAU_ID = ?";
		logger.info(SQL);
		this.jdbcTemplate.update(new PreparedStatementCreator(){
			public PreparedStatement createPreparedStatement(Connection con) throws SQLException{
				PreparedStatement ps = con.prepareStatement(SQL);
					//System.out.println(" PK_ID: "+address.getId());
					ps.setDate(1, (java.sql.Date) new Date());
					ps.setInt(2, address.getId());
				return ps;
			}
		});
		return true;
	}
	
	public  boolean updateEmailFailed(final List<EmailAddress> list){
		final String SQL = "UPDATE  EMAIL_ADDRESS_URL SET modifiedDate = getDate(),SET tryAgain =1,SET exceptionMsg =? WHERE PK_EAU_ID = ?";
		logger.info(SQL);
		this.jdbcTemplate.update(new PreparedStatementCreator(){
			public PreparedStatement createPreparedStatement(Connection con) throws SQLException{
				PreparedStatement ps = con.prepareStatement(SQL);
				for(EmailAddress address:list){
					System.out.println(" PK_ID: "+address.getId());
					ps.setString(1, address.getExceptionMsg());
					ps.setInt(2, address.getId());
					ps.addBatch();
				}
				return ps;
			}
		});
		return true;
	}
	
	public  Connection getConnection() throws CannotGetJdbcConnectionException, SQLException{
		if(con == null || con.isClosed()){
			con = DataSourceUtils.getConnection(this.jdbcTemplate.getDataSource());
			logger.info(" [創建Connection  hashCode:"+con.hashCode()+" ]");
		}
		return con;
	}
}
 

SendEmailJob.java

package com.saq.michael.job;

import java.sql.SQLException;
import java.util.List;

import javax.mail.MessagingException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

import com.saq.michael.bean.EmailAddress;
import com.saq.michael.service.impl.SendEmailService;

/**
 * @Title: TestJob.java
 * @Package com.saq.michael.job
 * @Description: 郵件發送.
 * @author MichaelYang
 * @Email [email protected]
 * @date Oct 13, 2011 8:41:30 PM
 * @version V1.0
 * @param <EmaillAddress>
 */
public class SendEmailJob extends QuartzJobBean {
	
	private SendEmailService sendEmailService;
	
    private static final Log logger = LogFactory.getLog(SendEmailJob.class);
	
	public void setSendEmailService(SendEmailService sendEmailService) {
		if(this.sendEmailService == null)this.sendEmailService = sendEmailService;
	}

	@Override
	protected void executeInternal(JobExecutionContext context)
			throws JobExecutionException {
		logger.info("...開始執行任務...");
		List<EmailAddress> addressList =this.sendEmailService.getEmailAddress("select * from EMAIL_ADDRESS_URL WHERE ENABLE=1");
		for(EmailAddress emailAddress:addressList){
			try {
				boolean flag =this.sendEmailService.sendMail(emailAddress, null);
				if(flag){
					this.sendEmailService.updateEmailSuccess(emailAddress.getId());
				}else{
					this.sendEmailService.updateEmailFailed(emailAddress);
				}
			} catch (MessagingException e) {
				logger.error(e.getLocalizedMessage());
				e.printStackTrace();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		logger.info("...任務執行完畢...");	
	}
}

其中用到了iReport,關於java中iReport開發,留給下次總計

相关推荐