由于项目中要求做一个数据交互功能,大概就是为外系统将一些数据导入到本系统,数据中涉及到大量图片,以及文档,或其他资料,大小大概50-200M左右,因此决定使用ftp进行交互。
首先,提供外系统ftp账号,上传文件到文件服务器。
然后,本系统监控文件服务器相应文件夹。
本人在项目中使用的是WatchService类。
1、项目初始化后,开启一个线程做文件监控服务(此处建议是重新开启一个线程,避免影响项目其他功能)。
package com.*.*.modules.*.listener;
import javax.annotation.Resource;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import com.*.*.modules.*.service.FileWatcherService;
@Component("ContextEventHandler")
public class ContextEventHandler implements ApplicationListener<ContextRefreshedEvent > {
private static final Logger logger = Logger.getLogger(ContextEventHandler.class);
@Resource
private FileWatcherService fileWatcherService;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if(event.getApplicationContext().getParent() == null){//root application context 没有parent,他就是老大.
//需要执行的逻辑代码,当spring容器初始化完成后就会执行该方法。
logger.info("-------------开启一个线程进行FTP文件监控服务-------------");
new Thread(new Runnable() {
@Override
public void run() {
try {
fileWatcherService.handleEvents();
} catch (Exception e) {
logger.error("-------------文件监控服务开启失败-------------", e);
}
}
}).start();
}
}
}
2、
package com.*.*.modules.*.service;
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static java.nio.file.StandardWatchEventKinds.OVERFLOW;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Resource;
import org.apache.log4j.Logger;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* **数据交互处理service
* @author wuyp
* @date 2017/11/25
*/
@Service("FileWatcherService")
public class FileWatcherService {
@Resource
...
@Resource
private ThreadPoolTaskExecutor executor;
private final String uploadDir = Global.getConfig("uploadDir"); // 上传文件夹
private final String backupDir = Global.getConfig("backupDir"); // 备份文件夹
private final String unzipDir = Global.getConfig("unzipDir"); // 解压文件夹
private WatchService watcher;
private static final Logger logger = Logger.getLogger(FileWatcherService.class);
public FileWatcherService()throws IOException{
Path myDir = Paths.get(uploadDir);
logger.info("监控文件夹为"+uploadDir);
watcher = myDir.getFileSystem().newWatchService();
myDir.register(watcher, ENTRY_CREATE,ENTRY_DELETE); //ENTRY_MODIFY
}
public void handleEvents() throws Exception{
while(true){
WatchKey key = watcher.take();
for(WatchEvent<?> event : key.pollEvents()){
WatchEvent.Kind kind = event.kind();
if(kind == OVERFLOW){//事件可能lost or discarded
continue;
}
WatchEvent<Path> e = (WatchEvent<Path>)event;
/* Path fileName = e.context();
File file = fileName.toFile();*/
String filePath = uploadDir+e.context();
logger.info("文件变动类型:"+kind.name()+",文件及路径:"+filePath);
if (kind == ENTRY_CREATE) {
// 判断文件是否创建成功
boolean fileIsCreateSuccess = fileIsCreateSuccess(filePath);
if (fileIsCreateSuccess) {
File file = new File(filePath);
FileHandlingTask fileHandlingTask = new FileHandlingTask(file);
executor.execute(fileHandlingTask);// 此处对文件进行处理
}
}
}
if(!key.reset()){
break;
}
}
}
}
大致的代码,就如上所示了。下面说下在开发过程中遇到的几个问题
1、在项目初始化时候启动监控服务
由于项目是单体架构,初始化时候需要去完成一些其他功能,开始时候没有另起一个线程,直接在 WebContextListener里里监控,结果项目跑不动了,因为监控里是while(true),导致后续的初始化执行不了,因此需要另外开启一个线程。
2、ftp上传文件后,WatchService能立即监控到,但是此时文件不一定上传成功,立即对文件处理,造成很多错误
开始,一直以为是文件夹权限,文件权限,或者ftp账号权限,最后赋予777权限都不行,最后证明统统都不是。
原因是上传文件并没有完全成功就立即被监控到,立即对文件进行复制、解压处理。后来是在操作前睡眠10s,最终 还是偶尔有问题,因为大文件上传并不是10s就够,因此需要判断文件上传成功(http://blog.csdn.net/w20228396/article/details/78646336)