Spring+Quartz實現定時從FTP服務器讀取文件並存入Oracel數據庫

package com.nstc.safe.action;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.SocketException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.codec.net.URLCodec;
import org.apache.commons.el.parser.ParseException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

import com.nstc.safe.Config;
import com.nstc.safe.domain.SafeErrorFile;
import com.nstc.safe.domain.SafeReport;
import com.nstc.safe.server.CommonServer;
import com.nstc.safe.server.SafeServer;
import com.nstc.safe.server.ServerLocator;

/**
 * <p>
 * Title:外管局錯誤文件查看
 * </p>
 * 
 * <p>
 * Description:外管局文件下載Action層
 * </p>
 * 
 * <p>
 * Company: 北京九恆星科技股份有限公司
 * </p>
 * 
 * @author zhangyongguang
 * 
 * @since:2015年9月8日 09:48:34
 * 
 * @version 1.0
 */
public class SAFE_U01_17 extends ActionSupport {
	private static final Log log = LogFactory.getLog(SAFE_U01_17.class);
	/**
	 * 由於Spring配置quartz在調用action的時候,對應server還沒有注入到容器中,
	 * 所以需要這個action中注入對應server,並且commonServer在spring配置文件中要找得到對應bean,
	 * 並在commonServer對應的bean中繼承事務控制tx
	 * 
	 * commonServer的注入主要是針對work方法(定時任務方法)所用到的與後臺交互的代碼,
	 * */
	private CommonServer commonServer;
	
	public CommonServer getCommonServer() {
		return commonServer;
	}
	public void setCommonServer(CommonServer commonServer) {
		this.commonServer = commonServer;
	}
	
	/**
	 * 查詢錯誤文件列表
	 */
	public String execute(HttpServletRequest request) {
		
		String errPath = request.getParameter("errorPath");
		String start = request.getParameter("startDate");
		String end = request.getParameter("endDate");
		// 用於下拉選擇框的值
		List list = getLocator().getCommonServer().findAll(SafeErrorFile.class);
		// 列表數據
		List list2 = getLocator().getCommonServer().findAll(errPath, start,
				end, SafeErrorFile.class);
		//把list放入request對象中,在前臺遍歷
		request.setAttribute("list", list);
		request.setAttribute("list2", list2);
		return "page";
	}
   /**
    * 查看XML文件內容,顯示在前臺的頁面上
    * @author zhangyonggguang
    * @param request
    * @param list
    * @param id
    * */
	public String viewXML(HttpServletRequest request) {
		//接收前臺傳來的文件ID
		String id = request.getParameter("errId");
		SafeErrorFile sa = new SafeErrorFile();
		//根據ID查詢對應的文件
		sa = (SafeErrorFile) getLocator().getCommonServer().findById(id,
				SafeErrorFile.class);
		//把查詢的結果放入list集合中,
		List list = new ArrayList();
		list.add(sa);
		//把list放入request對象中,在前臺遍歷
		request.setAttribute("list", list);
		return "view";
	}
	/**
	 * 定時任務,定時讀取FTP服務器的文件,做入庫操作。
	 * @author zhangyongguang
	 * @exception Exception
	 * @date 2015-09-09 14:35:24
	 * @return page
	 * */
	public void work()throws Exception {
		 System.out.println("自動任務執行"+new Date());
		 //執行查詢有多少個路徑需要讀取的方法,並存入set集合中,遍歷set集合,取出有幾個路徑
		 Set set=findPath();
         Iterator it =set.iterator();
         while(it.hasNext()){
        	 //上傳路徑爲配置文件配置的文件路徑,與數據庫的發送文件加路徑組合而成,
        	 String st=it.next().toString();
        	 System.out.println("SET的值爲"+st);
        	 listRemoteAllFiles(st);
         	}
	}
	/**
	 * @author zhangyongguang
	 * @param  查詢FTP服務器有多少路徑需要讀取
	 * */
	public Set findPath(){
		SafeReport sa=new SafeReport();
		//定義set集合,去除重複的路徑
		Set set=new HashSet();
		//查詢safeReport所有數據
		List list=commonServer.findAll(SafeReport.class);
		for(int i=0;i<list.size();i++){
			//把list中的數據強轉成safereport對象
			sa=(SafeReport) list.get(i);
			//判斷sa.getRep_errmsg()裏的值是否爲空
			if(sa.getRep_errmsg()!=null&&!sa.getRep_errmsg().equals("")){
				//如果不爲空,則存儲到set集合中,如果有重複的值,則添加不進去
				set.add(sa.getRep_errmsg().toString());
			}
		}
		return set;
	}
	
	/**
	 * @author zhangyongguang
	 * @param 鏈接FTP服務器的工具類
	 * @param ftpHost FTP主機服務器
	 * @param ftpPassword FTP 登錄密碼
	 * @param ftpUserName FTP登錄用戶名
	 * @param ftpPort FTP端口 默認爲21
	 * @author zhangyongguang
	 * @throws Exception 
	 */
	public static FTPClient getFTPClient() throws Exception {
		 String ip=Config.getProperty("IP");
		 int port=Integer.parseInt(Config.getProperty("PORT"));
		 String username=Config.getProperty("USERNAME");
		 String password=Config.getProperty("PASSWORD");
		 String pa=Config.getProperty("PATH","utf-8");
		 //防止中文路徑亂碼的情況 ,properties默認爲ISO-8859-1,如果存在用外部編輯器保存爲GBK格式的中文,需要轉換成GBK,否則路徑亂碼上傳失敗
		 String path=new String(pa.getBytes("ISO-8859-1"),"gbk");
		 //上傳路徑爲配置文件配置的文件路徑,與數據庫的發送文件加路徑組合而成,
		 FTPClient ftpClient = null;
		try {
			ftpClient = new FTPClient();
			ftpClient.connect(ip,port);// 連接FTP服務器
			ftpClient.login(username,password);// 登陸FTP服務器
			if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
				log.info("未連接到FTP,用戶名或密碼錯誤。");
				ftpClient.disconnect();
			} else {
				log.info("FTP連接成功。");
			}
		} catch (SocketException e) {
			e.printStackTrace();
			log.info("FTP的IP地址可能錯誤,請正確配置。");
		} catch (IOException e) {
			e.printStackTrace();
			log.info("FTP的端口錯誤,請正確配置。");
		}
		return ftpClient;
	}

	/**
	 * @param 去服務器的FTP路徑下上讀取文件
	 * @param remotePath讀取的路徑
	 * @author zhangyongguang
	 */
	  public void listRemoteAllFiles(String errPath) throws Exception{ 
		    String pa=Config.getProperty("PATH","utf-8");
			 //防止中文路徑亂碼的情況 ,properties默認爲ISO-8859-1,如果存在用外部編輯器保存爲GBK格式的中文,需要轉換成GBK,否則路徑亂碼上傳失敗
			String path=new String(pa.getBytes("ISO-8859-1"),"gbk");
			 
		  	String remotePath=path+errPath;
	    	FTPClient ftpClient=new FTPClient();
	    	String fileInfo[]=new String[4];
	    	ftpClient=SAFE_U01_17.getFTPClient();//初始化一個FTP客戶端,調用鏈接程序鏈接測試,IF成功,返回打開的鏈接
	    	boolean s=ftpClient.changeWorkingDirectory(new String(remotePath.getBytes(),"ISO-8859-1"));// 轉移到FTP服務器目錄  
    		if(s=true){
    			System.out.println("成功切換至:"+remotePath);
    		}
	    	try { 
	        	   //讀取remotePath路徑下的所有文件放入數據中,
	               FTPFile[] files = ftpClient.listFiles(); 
	               //如果files.length大於0,說明路徑下存在文件。
	               for (int i = 0; i < files.length; i++) { 
	            	   //判斷數組裏的值是文件還是文件夾,如果是我文件打印輸出,如果是目錄,調用listRemoteAllFiles繼續判斷
	                	if (files[i].isFile()) {   
	                		//獲取文件名存入數據組
	                		fileInfo[0]=files[i].getName();
	                		//獲取文件日期存入數組
	                		Date d=files[i].getTimestamp().getTime();
	                		SimpleDateFormat st= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	                		fileInfo[1]=st.format(d);
	                		//獲取文件內容存入數組
	                		fileInfo[2]=readFile(ftpClient, remotePath,files[i].getName());
	                		//入庫操作
	                		List list=commonServer.findByName(fileInfo[0].toString(),errPath, SafeErrorFile.class);
	                		if(list.size()<1)
	                		{	
	                			SafeErrorFile safeErrorFile=new SafeErrorFile();
	                			safeErrorFile.setError_name(fileInfo[0].toString());
	                			safeErrorFile.setError_path(errPath);
	                			safeErrorFile.setError_info(fileInfo[2].toString());
	                			safeErrorFile.setError_date(fileInfo[1].toString());
	                			commonServer.save(safeErrorFile);
	                		}
	                		
	                	} else if (files[i].isDirectory()) { 
	                		System.out.println("目錄"+files[i].getName());
	                		//如果是文件夾,則與原來的路徑拼接起來,並在尾部加上/,,例如,原路徑爲:/,拼接後:/文件夾名字/.
	                		listRemoteAllFiles(remotePath + files[i].getName() + "/"); 
	                		System.out.println("遍歷結束");
	                    }
	                }
	        } catch (Exception e) { 
	                e.printStackTrace();
	               System.out.println("出異常了 ");
	        } 
	     }
    		
	  /** 
	   * @param fileName 
	   * @return function:解析文件內容
	   * @throws ParseException 
	   * @throws IOException 
	   */ 
	 public String readFile(FTPClient ftpClient,String remotePath,String fileName) throws ParseException { 
	   InputStream ins = null; 
	   String str=null;
	   try { 
	    // 從服務器上讀取指定的文件 
	    ins = ftpClient.retrieveFileStream(fileName); 
	    ByteArrayOutputStream baos = new ByteArrayOutputStream();  
	    int i;  
	    while ((i = ins.read()) != -1) {  
	        baos.write(i);  
	    }  
	    str = baos.toString();  
	    if (ins != null) { 
	     ins.close(); 
	    } 
	    // 主動調用一次getReply()把接下來的226消費掉. 這樣做是可以解決這個返回null問題 
	    ftpClient.getReply(); 
	   } catch (IOException e) { 
	    e.printStackTrace(); 
	   } 
	   return str; 
	 } 	  
	  
}

下面是spring配置,

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
	<import resource="datasource.xml" />
	<bean id="propertyConfigurer" class="com.nstc.safe.spring.PropertyConfigurer">
		<property name="location">
			<value>appContext.properties</value>
		</property>
		<property name="fileEncoding">
			<value>GBK</value>
		</property>
	</bean>
	<!--hibernate事務 -->
	<bean id="transactionManager"
		class="org.springframework.orm.hibernate3.HibernateTransactionManager">
		<property name="sessionFactory">
			<ref local="sessionFactory" />
		</property>
	</bean>
	<!-- 基礎事務代理 -->
	<bean id="baseTxProxy" abstract="true"
		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
		<property name="transactionManager">
			<ref local="transactionManager" />
		</property>
		<property name="transactionAttributes">
			<props>
				<prop key="save*">PROPAGATION_REQUIRED,-Throwable</prop>
				<prop key="remove*">
					PROPAGATION_REQUIRED,-Throwable
				</prop>
				<prop key="merge">PROPAGATION_REQUIRED,-Throwable</prop>
				<prop key="update">
					PROPAGATION_REQUIRED,-Throwable
				</prop>
				<prop key="do*">PROPAGATION_REQUIRED,-Throwable</prop>
			</props>
		</property>
	</bean>
	<!-- sqlMapClient -->
	<bean id="sqlMapClient" class="com.nstc.safe.spring.NstcSqlMapClientFactoryBean">
		<property name="configLocation">
			<value>sql-map-config.xml</value>
		</property>
	</bean>
	<!-- Hibernate的sessionFactory工廠 -->
	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
		<property name="dataSource">
			<ref bean="dataSource" />
		</property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">
					org.hibernate.dialect.OracleDialect
				</prop>
				<prop key="hibernate.show_sql">false</prop>
				<prop key="hibernate.format_sql">false</prop>
				<prop key="hibernate.use_sql_comments">false</prop>
				<!-- 爲單向關聯(一對一, 多對一)的外連接抓取(outer join fetch)樹設置最大深度. 值爲0意味着將關閉默認的外連接抓取 -->
				<prop key="hibernate.max_fetch_depth">3</prop>
				<!-- 爲Hibernate關聯的批量抓取設置默認數量 -->
				<prop key="hibernate.default_batch_fetch_size">8</prop>
				<!-- 強制Hibernate按照被更新數據的主鍵,爲SQL更新排序。這麼做將減少在高併發系統中事務的死鎖。 -->
				<prop key="hibernate.order_updates">true</prop>
				<!-- session在事務完成後將被自動清洗(flush) -->
				<prop key="hibernate.transaction.flush_before_completion">
					true
				</prop>
				<!-- Oracle限制那些通過JDBC驅動傳輸的字節數組的數目. 如果你希望使用二進值 (binary)或 可序列化的 (serializable)類型的大對象, 
					你應該開啓 hibernate.jdbc.use_streams_for_binary屬性. -->
				<prop key="hibernate.bytecode.use_reflection_optimizer">
					true
				</prop>
			</props>
		</property>
		<property name="mappingResources">
			<list>
				<value>com/nstc/safe/domain/SafeAccount.hbm.xml</value>
				<value>com/nstc/safe/domain/SafeAcntType.hbm.xml</value>
				<value>com/nstc/safe/domain/SafeBalanceChange.hbm.xml</value>
				<value>com/nstc/safe/domain/SafeBz.hbm.xml</value>
				<value>com/nstc/safe/domain/SafeCountry.hbm.xml</value>
				<value>com/nstc/safe/domain/SafeIncomeDetail.hbm.xml</value>
				<value>com/nstc/safe/domain/SafePayoutDetail.hbm.xml</value>
				<value>com/nstc/safe/domain/SafeTransact.hbm.xml</value>
				<value>com/nstc/safe/domain/SafeConfig.hbm.xml</value>
				<value>com/nstc/safe/domain/SafeApNumber.hbm.xml</value>
				<value>com/nstc/safe/domain/SafeExchangeRate.hbm.xml</value>
				<value>com/nstc/safe/domain/SafeTx.hbm.xml</value>
				<value>com/nstc/safe/domain/SafeTxLog.hbm.xml</value>
				<value>com/nstc/safe/domain/SafeRepRows.hbm.xml</value>
				<value>com/nstc/safe/domain/SafeGeneralCash.hbm.xml</value>
				<value>com/nstc/safe/domain/SafeListPrice.hbm.xml</value>
				<value>com/nstc/safe/domain/SafeBigAcnt.hbm.xml</value>
				<value>com/nstc/safe/domain/SafeMonthStat.hbm.xml</value>
				<value>com/nstc/safe/domain/SafeTenDayStat.hbm.xml</value>
				<value>com/nstc/safe/domain/SafeReportFile.hbm.xml</value>
				<value>com/nstc/safe/domain/SafeReport.hbm.xml</value>
				<value>com/nstc/safe/domain/CapitalSafeAccount.hbm.xml</value>
				<value>com/nstc/safe/domain/CapitalBalanceChange.hbm.xml</value>
				<value>com/nstc/safe/domain/SafeForReportFile.hbm.xml</value>
				<value>com/nstc/safe/domain/SafeAcntTypeZB.hbm.xml</value>
				<value>com/nstc/safe/domain/SafeErrorFile.hbm.xml</value>
			</list>
		</property>
	</bean>
	<!-- locator -->
	<bean name="safe.locator" class="com.nstc.safe.server.ServerLocator">
		<property name="commonServer">
			<ref local="commonServer" />
		</property>
		<property name="safeServer">
			<ref local="safeServer" />
		</property>
		<property name="capitalServer">
			<ref local="capitalServer" />
		</property>
	</bean>

	<!-- daoFacade -->
	<bean id="daoFacade" class="com.nstc.safe.dao.DaoFacade" autowire="byName">
	</bean>
	<bean id="baseDao" class="com.nstc.safe.dao.BaseDAO">
		<property name="sessionFactory">
			<ref local="sessionFactory" />
		</property>
		<property name="dataSource">
			<ref bean="dataSource" />
		</property>
		<property name="sqlMapClient">
			<ref local="sqlMapClient" />
		</property>
		<property name="dbType">
			<value>${dbType}</value>
		</property>
	</bean>
	<bean id="testDao" class="com.nstc.safe.dao.TestDAO" parent="baseDao">
	</bean>
	<bean id="commonDao" class="com.nstc.safe.dao.CommonDAO" parent="baseDao">
	</bean>
	<bean id="safeDao" class="com.nstc.safe.dao.SafeDAO" parent="baseDao">
	</bean>
	<bean id="catitalDao" class="com.nstc.safe.dao.CapitalSafeDao"
		parent="baseDao">
	</bean>
	<bean id="downloadDao" class="com.nstc.safe.dao.DownloadDAO"
		factory-method="getInstance">
		<constructor-arg>
			<ref bean="dataSource" />
		</constructor-arg>
		<constructor-arg>
			<ref bean="safe.sqlMapClient" />
		</constructor-arg>
	</bean>
	<!-- baseServer -->
	<bean id="baseServer" class="com.nstc.safe.server.impl.BaseServerImpl">
		<property name="daoFacade">
			<ref local="daoFacade" />
		</property>
	</bean>
	<bean id="commonServer" parent="baseTxProxy">
		<property name="target">
			<bean class="com.nstc.safe.server.impl.CommonServerImpl" parent="baseServer" />
		</property>
	</bean>
	<bean id="safeServer" parent="baseTxProxy">
		<property name="target">
			<bean class="com.nstc.safe.server.impl.SafeServerImpl" parent="baseServer"
				autowire="byName" />
		</property>
	</bean>
	<bean id="capitalServer" parent="baseTxProxy">
		<property name="target">
			<bean class="com.nstc.safe.server.impl.CapitalSafeServerImp"
				parent="baseServer" autowire="byName" />
		</property>
	</bean>

	<bean id="safe.sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
		<property name="configLocation">
			<value>/WEB-INF/classes/sql-map-config.xml</value>
		</property>
	</bean>
/bean>
				
	<!-- ==============================================定時讀取FTP服務器的錯誤文件========================================================= -->	
	<!-- 定義一個定時任務  如果有需要定時的類,直接在list列表裏寫-->
	<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">  
       <property name="triggers">  
           <list>  
              <ref bean="testTrigger"/>  
           </list>  
           
       </property>  
	</bean>  
	<!-- 定時器 -->
	<bean id="testTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">  
       <property name="jobDetail" ref="testJobDetail"/>  
       <property name="cronExpression">
        	<value>60/900 * * * * ?</value>
       </property><!-- 20秒後觸發,每隔3秒鐘觸發一次 -->  
     
	</bean>  
	<!-- 定時器對應bean-->
	<bean id="testJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">   
        
        <property name="targetObject" ref="testJob"/>  
        <property name="targetMethod" value="work"/>  <!--類對應執行的方法  -->
        <!-- 是否允許任務併發執行。當值爲false時,表示必須等到前一個線程處理完畢後纔再啓一個新的線程 --> 
         <property name="concurrent" value="false"/> 
	</bean>  
	<!-- bean映射類 -->
	<bean id="testJob" class="com.nstc.safe.action.SAFE_U01_17" autowire="byName">
	</bean><!-- 
	<bean>
		<property name="" ref=""/>
	</bean>
	<bean name="safe.locator" class="com.nstc.safe.server.ServerLocator">
		<property name="commonServer">
			<ref local="commonServer" />
		</property>
		<property name="safeServer">
			<ref local="safeServer" />
		</property>
		<property name="capitalServer">
			<ref local="capitalServer" />
		</property>
	</bean>
	=======================================================================
	<property name="fixedService">
  			<bean class="com.nstc.wst3.server.DefaultFixedService" autowire="byName">
  				<property name="commonService"><ref local="commService"/></property>
  			</bean>
  		</property>
  		<property name="workutil"><ref bean="workDayUtil" /></property>
		<property name="executorMap">
			<map>
				<entry key="1">
					<ref bean="txExecutor_3"/>
				</entry>
			</map>
		</property>
	
--><!-- ======================================================================================================= -->	
	
	
</beans>


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章