码迷,mamicode.com
首页 > 数据库 > 详细

Spring+Quartz实现定时从FTP服务器读取文件并存入Oracel数据库

时间:2015-09-10 19:39:27      阅读:279      评论:0      收藏:0      [点我收藏+]

标签:spring   定时器   自动执行任务   quartz   

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>


本文出自 “听雨盼永恒” 博客,请务必保留此出处http://yongguang.blog.51cto.com/9153118/1693502

Spring+Quartz实现定时从FTP服务器读取文件并存入Oracel数据库

标签:spring   定时器   自动执行任务   quartz   

原文地址:http://yongguang.blog.51cto.com/9153118/1693502

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!