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数据库
原文:http://yongguang.blog.51cto.com/9153118/1693502