开发环境如果没有ftp 服务器的话,可以下载一个serv-U 挺好用的;运行起来就行一个本地的ftp服务器;
1.需求 给各省根据配置表以ftp或sftp协议的方式,多线程 定时任务 给各省同步所需的数据;
设计表:业务基本配置表:配置对外提供哪些业务;
省份 业务关系表:配合 业务和省份的关系,配置 哪些省份需要同步哪些业务数据;
省份 业务 模板关系表:针对模板信息,根据 省份 业务 以及模板 配置对外提供的哪些数据;
省份 文件路径表:配置省份 及 ftp或sftp 的文件夹 路径 及传输协议;
省份 ip 端口号 用户名 密码表:记录ftp sftp的ip端口 用户名 密码等信息;用来初始化 链接;
等等等表....
2 ,设计:ftp sftp 的链接创建 设计6个类:涉及接口,抽象类,工程类,
优点:需要增加 传输协议例如 本来只是ftp后来增加sftp 或者htttp等,只需要 增加 实现类就可以;不需要改动之前的代码逻辑;
1顶级抽象类:
/**
* Created by 12 on 2018/8/11.
*/
@Component
public abstract class AbstractFTPFileTransfer implements FileTransferInterface{}
2接口类:定义通用方法:
public interface FileTransferInterface {
public void init(HashMap connectInfo);
public void upload(String fileName, InputStream fileInputStream);
public void rename(String ftppathName,String newftpPathName);
public void close();}
3工厂类:提供初始化链接以及 提供一些接口;
@Component
public class FTPTransterFactory {
private static final Logger logger = LoggerFactory.getLogger(FTPTransterFactory.class);
@Reference
private IKmSyncFtpPathSV iKmSyncFtpPathSV;
@Reference
private IKmSyncCollectLogSV iKmSyncCollectLogSV; @Reference
private IKmSyncUploadLogSV iKmSyncUploadLogSV; @Reference
private IKmTaskSV kmTaskSV;// public Map<String, FileTransferInterface> getFileTransferInterface(List<HashMap<String, String>> map) {
FileTransferInterface ftpInfotr = AppContext.getBean((String) ftpInfo.getTrsfAgrmt());
ftpInfotr.init();
// return new HashMap<String, FileTransferInterface>();
// }
HashMap connectInfo;
public FileTransferInterface getFileTransferInterface(HashMap pathAndProvince) {
String pathId = String.valueOf(pathAndProvince.get("pathId"));
connectInfo = iKmSyncFtpPathSV.getConnectInfo(pathId);
String connectClassName = String.valueOf(connectInfo.get("connectClassName"));
FileTransferInterface connectObj = AppContext.getBean(connectClassName);
return connectObj;
} public HashMap getConnectInfo(){
return connectInfo;
} public IKmSyncCollectLogSV getIkmSyncCollectLogSv(){
return iKmSyncCollectLogSV;
} public IKmSyncUploadLogSV getiKmSyncUploadLogSV(){
return iKmSyncUploadLogSV;
} public IKmTaskSV getKmTaskSV(){return kmTaskSV;}
}
4,5 ftp 和sftp 的具体类:因为涉及多线程调用,所以需要加@scope
@Component("fTPFileTransfer")
@Scope(value = "prototype")
public class FTPFileTransfer extends AbstractFTPFileTransfer {
private static final com.cmos.core.logger.Logger logger = LoggerFactory.getLogger(FTPFileTransfer.class); private FtpUtil ftpUtil = null;
private FTPClient ftpClient;
@Override
public void init(HashMap connectInfo){
try{
String ipValue = String.valueOf(connectInfo.get("ipValue"));
int portValue = Integer.parseInt(String.valueOf(connectInfo.get("portValue")));
String userName = String.valueOf(connectInfo.get("userName"));
String password = String.valueOf(connectInfo.get("password"));
String catalogPath = String.valueOf(connectInfo.get("catalogPath"));
ftpUtil = new FtpUtil();
ftpClient = ftpUtil.initFtpClient(ipValue,portValue,userName,password);
boolean changeFlag = ftpClient.changeWorkingDirectory(catalogPath);
if (!changeFlag){
logger.error("ftp链接初始化,变更到指定目录失败");
return;
}
}catch (Exception e){
logger.error("ftp链接初始化:"+e);
}
} @Override
public void upload(String tempFileName, InputStream fileInputStream) {
try {
ftpClient.storeFile(tempFileName,fileInputStream);
}catch (Exception e){
logger.error("ftp上传文件异常:"+e);
}
} @Override
public void rename(String tempFileName, String fileName) {
try {
ftpClient.rename(tempFileName, fileName);
}catch (Exception e){
logger.error("ftp修改文件名称异常"+e);
}
} @Override
public void close() {
try {
ftpClient.logout();
ftpClient.disconnect();
}catch (Exception e ){
logger.error("ftp退出异常"+e);
}
}
}@Component("sFTPFileTransfer")
@Scope(value = "prototype")
public class SFTPFileTransfer extends AbstractFTPFileTransfer{ private static final com.cmos.core.logger.Logger logger = LoggerFactory.getLogger(SFTPFileTransfer.class);
private MySFtp mySFtp = null;
private ChannelSftp channelSftp = null; @Override
public void init(HashMap connectInfo) {
try{
String ipValue = String.valueOf(connectInfo.get("ipValue"));
int portValue = Integer.parseInt(String.valueOf(connectInfo.get("portValue")));
String userName = String.valueOf(connectInfo.get("userName"));
String password = String.valueOf(connectInfo.get("password"));
String catalogPath = String.valueOf(connectInfo.get("catalogPath"));
mySFtp = new MySFtp();
channelSftp = mySFtp.connect(ipValue,portValue,userName,password);
channelSftp.cd(catalogPath);
}catch (Exception e){
logger.error("sftp链接初始化:"+e);
}
} @Override
public void upload(String tempFileName, InputStream fileInputStream) {
try {
channelSftp.put(fileInputStream,tempFileName);
}catch (Exception e){
logger.error("sftp上传文件异常:"+e);
}
} @Override
public void rename(String tempFileName, String fileName) {
try {
channelSftp.rename(tempFileName,fileName);
}catch (Exception e){
logger.error("sftp修改文件名称异常"+e);
}
} @Override
public void close() {
try {
channelSftp.exit();
}catch (Exception e ){
logger.error("sftp退出异常"+e);
}
}
}
6 ftp sftp 工具类:
public class FtpUtil {
private static final Logger logger = LoggerFactory.getLogger(FtpUtil.class);
private static FTPClient ftpClient = null;
private String _host = null;
private int _port = 0;
private String _username = null;
private String _password = null;
private String _remotePath = null;
public static final String FILE_SPEARATROR = "/"; // 路径分隔符
private static String LOCAL_CHARSET = "GBK"; // 本地字符编码
private static String SERVER_CHARSET = "ISO-8859-1";// FTP协议里面,规定文件名编码为iso-8859-1 public FTPClient initFtpClient(String ip, int port, String username, String password) {
long start = System.currentTimeMillis();
ftpClient = new FTPClient();
ftpClient.setControlEncoding("utf-8");
try {
ftpClient.connect(ip, port);
//登录ftp服务器
ftpClient.login(username, password);
//是否成功登录服务器
int replyCode = ftpClient.getReplyCode();
logger.info("reply == " + replyCode);
//设置被动模式
ftpClient.enterLocalPassiveMode();
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
if(!FTPReply.isPositiveCompletion(replyCode)){
ftpClient.disconnect();
logger.error("connect failed...ftp服务器:" + ip + ":" + port);
return null;
} else {
logger.info("connect successful...ftp服务器:" + ip + ":" + port);
}
long end = System.currentTimeMillis();
logger.info("ftp connect time:" +(end - start)); } catch (IOException e) {
logger.error("ftp连接失败:" + ip + ":" + port, e);
return null;
}
return ftpClient;
} //判断ftp服务器文件是否存在
public boolean existFile(String path) {
boolean flag = false;
FTPFile[] ftpFileArr;
try {
ftpFileArr = ftpClient.listFiles(path);
} catch (IOException e) {
logger.error("读取文件失败");
return flag;
}
if (ftpFileArr.length > 0) {
flag = true;
}
return flag;
} /**
* 退出ftp
*/
public void logout() {
try {
ftpClient.logout();
ftpClient.disconnect();
} catch (IOException e) {
logger.error("logout ftp fail ....." + e.getMessage(), e);
}
} /**
* 空的构造方法
*/
public FtpUtil(){
} /**
* 创建实例对象
* @param hostIp
* @param port
* @param username
* @param password
* @throws IOException
*/
public FtpUtil(String hostIp, int port, String username, String password) throws IOException {
logger.debug("hostIp --> " + hostIp + " , port -->" + port + " , username -->" + username + " , password -->" + password);
initFtpClient(hostIp,port,username,password);
_host = hostIp;
_port = port;
_username = username;
_password = password;
} /**
* 创建一个带路径的实例对象
* @param hostIp
* @param port
* @param username
* @param password
* @param remotepath
* @throws IOException
*/
public FtpUtil(String hostIp, int port, String username, String password, String remotepath) throws IOException {
logger.debug("hostIp --> " + hostIp + " , port -->" + port + " , username -->" + username + " , password -->" + password + " , remotepath -->" + remotepath);
initFtpClient(hostIp,port,username,password);
ftpClient.changeWorkingDirectory(remotepath);
_host = hostIp;
_port = port;
_username = username;
_password = password;
_remotePath = remotepath;
} /**
* 上传文件
* @param remotePath 路径
* @param filename 文件名
* @param input 文件流
* @return
*/
public boolean uploadFile(String remotePath, String filename,InputStream input) {
boolean result = false;
try {
if(!ftpClient.isConnected()){
this.forceReconnect();
}
// 检验是否连接成功
boolean isConnected = this.isConnected();
//注意:有的FTP是需要先发送CLNT版本号的
if (FTPReply.isPositiveCompletion(ftpClient.sendCommand("OPTS UTF8", "ON"))) {// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码,否则就使用本地编码(GBK).
setLocalCharset("UTF-8");
}
ftpClient.setControlEncoding(LOCAL_CHARSET);
ftpClient.enterLocalPassiveMode();// 设置被动模式
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
// 判断链接是否可用
if(ftpClient.isAvailable()){
// 切换到正确的目录,无则创建
changeToRightDir(remotePath); // 上传
result = ftpClient.storeFile(new String(filename.getBytes(LOCAL_CHARSET), SERVER_CHARSET), input);
if (result) { }
}
input.close();
ftpClient.logout();
} catch (IOException e) {
logger.error(e.getMessage(), e);
} finally {
if (ftpClient.isConnected()) {
try {
ftpClient.disconnect();
} catch (IOException ioe) {
logger.error(ioe.getMessage(), ioe);
}
}
}
return result;
} public void reconnect(){
if (!ftpClient.isConnected()) {
try {
FtpUtil.setConnected();
ftpClient.connect(_host, _port);
ftpClient.login(_username, _password);
ftpClient.changeWorkingDirectory(_remotePath);
} catch (IOException e) {
logger.error("",e);
}
}
} public void forceReconnect() throws IOException {
if (!ftpClient.isConnected()) {
ftpClient.disconnect();
}
FtpUtil.setConnected();
ftpClient.connect(_host, _port);
ftpClient.login(_username, _password);
ftpClient.changeWorkingDirectory(_remotePath);
} /**
* 强制更换目录到目标目录
* @param pathName
* @throws IOException
*/
public void changeWorkingDirectory(String pathName) throws IOException {
if (FtpUtil.ftpClient != null) {
try {
FtpUtil.ftpClient.changeWorkingDirectory(pathName);
} catch (IOException e) {
logger.error(e.getMessage(), e);
throw new IOException(e.getMessage());
}
}
} /**
* 获取当前的工作目录
* @return
* @throws IOException
*/
public String getWorkingDirectory() throws IOException {
if (FtpUtil.ftpClient != null) {
return FtpUtil.ftpClient.printWorkingDirectory();
}
return null;
} /**
* 切换到指定目录(不存在就创建目录同时切换到新建的目录)
* @param directoryId
* @throws Exception
*/
public void changeToRightDir(String directoryId) throws IOException {
if (ftpClient != null) {
String ftpDir;
try {
ftpDir = ftpClient.printWorkingDirectory();
} catch (IOException e) {
logger.error(e.getMessage(), e);
throw new IOException(e.getMessage());
}
if (ftpDir == null) {
ftpDir = "/";
}
String curDir;
if (directoryId.startsWith("/")) {
curDir = directoryId;
} else {
if (!ftpDir.endsWith("/")) {
curDir = ftpDir + FILE_SPEARATROR + directoryId;
} else {
curDir = ftpDir + directoryId;
}
} boolean flag;
try {
flag = ftpClient.changeWorkingDirectory(curDir);
} catch (IOException e) {
logger.error(e.getMessage(), e);
throw new IOException(e.getMessage());
}
if (flag == false) {
try {
ftpClient.makeDirectory(directoryId);
ftpClient.changeWorkingDirectory(curDir);
} catch (IOException e) {
logger.error(e.getMessage(), e);
throw new IOException(e.getMessage());
}
}
}
} /**
* 校验连接是否正常
* @return
* @throws IOException
*/
public boolean isConnected() throws IOException {
// 检验是否连接成功
int reply = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) { ftpClient.disconnect();
return false;
}
return true;
} private static void setLocalCharset(String localCharset) {
LOCAL_CHARSET = localCharset;
} private static void setConnected() throws IOException {
FTPClient tempClient = new FTPClient();
ftpClient = tempClient;
}
}
ok,准备就绪之后,剩下 的就只有 业务层面的代码逻辑了;时间有限,不忙了补充下一篇;