1. 준비물
*이클립스 = 이클립스라 검색하여 다운받자
*commons-net-X.X.jar = http://commons.apache.org/net/download_net.cgi 다운받자
2. 준비하기
*이클립스 Window -> Preferences -> Ant -> Runtime -> Classpath항목에서
Ant Home Entries 클릭 후 Add External JARs... 클릭하여 commons-net-X.X.jar 를 추가
*프로젝트를 생성후 Bulid.xml 과 bulid.properties 파일 생성
3. 만들기
*bulid.properties
################################### ## FTP INFO ## ################################### FTP.SERVER = xxx.xxx.xxx.xxx FTP.PORT = 21 FTP.USERID = test FTP.PASSWD = 1234567890 FTP.PATH = / FTP.PATH.CLASS = /WEB-INF/classes/ ## /*.class , /test/*.class EXCLUDE.PATTERN = FTP_NOT_PATTERN BACKUP.PATH = D:/ant/backup/ ACCEPT.CLASS = .class, .xml ACCEPT.WEB = .jsp
위와 같이 설정하자.
*Bulid.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68 |
<? xml version = "1.0" encoding = "utf-8" ?> < project name = "ftpUpload" default = "all" basedir = "." >
< property file = "build.properties" />
< property name = "build.dir" value = "." />
< property name = "output.class.dir" value = "${build.dir}/build/classes" />
< property name = "work.web.dir" value = "${build.dir}/web" />
< target name = "all" >
<!--
<antcall target="download" />
<antcall target="delete" />
<antcall target="upload" />
-->
< antcall target = "execute" />
</ target >
<!--FTP Upload-->
< target name = "upload" >
< ftp server = "${FTP.SERVER}" port = "${FTP.PORT}" remotedir = "${FTP.PATH}" userid = "${FTP.USERID}" password = "${FTP.PASSWD}" newer = "true" timediffauto = "true" passive = "yes" binary = "yes" depends = "yes" verbose = "yes" separator = "/" serverLanguageCodeConfig = "en" serverTimeZoneConfig = "KORST-9" >
< fileset dir = "${output.class.dir}" >
< include name = "**/*.class" />
</ fileset >
</ ftp >
</ target >
<!--FTP Download-->
< target name = "download" >
< ftp server = "${FTP.SERVER}" port = "${FTP.PORT}" remotedir = "${FTP.PATH}" userid = "${FTP.USERID}" password = "${FTP.PASSWD}" newer = "true" timediffauto = "true" passive = "yes" binary = "yes" depends = "yes" verbose = "yes" separator = "/" serverLanguageCodeConfig = "en" serverTimeZoneConfig = "KORST-9" >
< fileset dir = "${BACKUP.PATH}" >
< include name = "**/*.class" />
</ fileset >
</ ftp >
</ target >
<!--FTP List-->
< target name = "list" >
< ftp server = "${FTP.SERVER}" port = "${FTP.PORT}" remotedir = "${FTP.PATH}" userid = "${FTP.USERID}" password = "${FTP.PASSWD}" timediffauto = "true" action = "list" listing = "D:/ant/ftp.list" passive = "yes" binary = "yes" depends = "yes" verbose = "yes" separator = "/" serverLanguageCodeConfig = "en" serverTimeZoneConfig = "KORST-9" >
< fileset dir = "${BACKUP.PATH}" >
< include name = "**/*.class" />
</ fileset >
</ ftp >
</ target >
<!--FTP Delete-->
< target name = "delete" >
< echo message = "서버의 파일을 삭제 합니다." />
< ftp server = "${FTP.SERVER}" port = "${FTP.PORT}" remotedir = "${FTP.PATH}" userid = "${FTP.USERID}" password = "${FTP.PASSWD}" action = "del" passive = "yes" binary = "yes" depends = "yes" verbose = "yes" separator = "/" serverTimeZoneConfig = "KORST-9" >
< fileset >
< include name = "**/*.class" />
</ fileset >
</ ftp >
</ target >
<!-- JAVA FTP -->
< target name = "execute" >
< java classname = "com.jang.test.FTPController" classpath = "WebContent/WEB-INF/lib/commons-net-3.2.jar;build/classes;" >
< arg file = "." />
< arg value = "build.properties" />
</ java >
</ target >
</ project > |
라고 입력하고 download, upload, deleted 를 실행해보자
모든 파일을 할때는 잘된다.
하지만 실행할때마다 모든파일을 업로드, 다운로드를 하기엔 쫌 그렇다.
변경파일만 해보자.
인터넷 찾아보니 newer="true" timediffauto="true" passive="yes" binary="yes" depends="yes" verbose="yes"
옵션주면 된다고 한다.
하지만 나는 윈도우서버 FTP를 이용하고 있었는데 잘동작하지 않았다.
그래서 execute를 만들었다.
execute는 이클립스 전용임으로 /bulid/classes와 WebContent가 있는 전제하에 만들었다.
4. FTP 업로드 JAVA로 만들기
package com.jang.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import com.jang.utils.DateUtils;
import com.jang.utils.FileUtils;
import com.jang.utils.StringUtils;
/************************************************************************
* @ClassName : FTPController
* @ClassDescription : FTP 관련 클레스
*
* @MakeDate : 2013-01-23
* @author : Jang.S.H
*
* @Copyright : Media4th & Company
************************************************************************/
public class FTPController {
private FileUtils FU;
private FTPClient ftpClient;
private String server;
private String port;
private String userPw;
private String userId;
private String backupPath;
private String classRoot;
private String uploadRoot;
private String exPattern;
private String acceptClass;
private String acceptWeb;
public static void main(String[] args) {
if(args != null && args.length == 2){
//String path = "D:/web/workspace/JangUtils/build.properties";
String path = args[0]+"\\"+args[1];
FTPController main = new FTPController(path);
try {
main.init();
main.run();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//즉시 테스트 입니다.
// String path = "D:/web/workspace/JangUtils/build.properties";
// FTPController main = new FTPController(path);
//
// try {
// main.init();
// main.run();
// } catch (Exception e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
//
}
public FTPController(String path){
FU = FileUtils.getInstance();
setting(path);
}
/**
* @author Jang.S.H
* @throws Exception
* @description
* FTP 접속 셋팅
* Encoding : EUC-KR
* Connection Check
* Login Check
*/
private void init() throws Exception {
sys("init start");
ftpClient = new FTPClient();
ftpClient.setControlEncoding("EUC-KR");
sys("Connect server:"+server +"\t Port:"+port);
ftpClient.connect(server, Integer.parseInt(port));
int reply = ftpClient.getReplyCode();
//접속 체크
if (!FTPReply.isPositiveCompletion(reply)) {
sys("Connect Error Check server:"+server +"\tport:"+port);
ftpClient.disconnect();
throw new Exception();
}
//로그인 체크
if(!ftpClient.login(userId, userPw)){
sys("LOGIN Error Check userId:"+userId +"\t userPw:"+userPw);
ftpClient.disconnect();
throw new Exception();
}
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
ftpClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);
sys("init end");
}
/**
* @author Jang.S.H
* @description
* FTP 기능 수행
* LOCAL - FTP 간 파일비교
* BACKUP
* UPLOAD
*/
private void run(){
try {
sys("run start");
if(ftpClient.isConnected()){
//로컬 추출
HashMap<String, File> localClass = getLocalFiles(getClassPath(),acceptClass);
//FTP 추출
HashMap<String, FTPFile> ftpClass = getFtpFiles(classRoot, acceptClass);
//리스트 추출 및 백업
ArrayList<String> updateList = compareFileList(localClass, ftpClass, classRoot);
//변경목록 업로드
upload(localClass, updateList, classRoot);
localClass.clear();
ftpClass.clear();
updateList.clear();
//로컬 추출
localClass = getLocalFiles(getWebRootPath(),acceptWeb);
//FTP 추출
ftpClass = getFtpFiles(uploadRoot, acceptWeb);
//리스트 추출 및 백업
updateList = compareFileList(localClass, ftpClass, uploadRoot);
//변경목록 업로드
upload(localClass, updateList, uploadRoot);
localClass.clear();
ftpClass.clear();
updateList.clear();
ftpClient.disconnect();
}
sys("run end");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* @author Jang.S.H
* @param path
* properties 파일 경로
* @description
* 프로퍼티 파일을 읽어와 셋팅하기
*/
private void setting(String path){
if(FU.isFile(path)){
Properties conf = FU.readProperties(path);
server = StringUtils.getProperty(conf, "FTP.SERVER");
port = StringUtils.getProperty(conf, "FTP.PORT");
userId = StringUtils.getProperty(conf, "FTP.USERID");
userPw = StringUtils.getProperty(conf, "FTP.PASSWD");
backupPath = StringUtils.getProperty(conf, "BACKUP.PATH");
classRoot = StringUtils.getProperty(conf, "FTP.PATH.CLASS");
uploadRoot = StringUtils.getProperty(conf, "FTP.PATH");
exPattern = StringUtils.getProperty(conf, "EXCLUDE.PATTERN");
acceptClass = StringUtils.getProperty(conf, "ACCEPT.CLASS");
acceptWeb = StringUtils.getProperty(conf, "ACCEPT.WEB");
sys("SETTING \t server:\t"+server);
sys("SETTING \t port:\t"+port);
sys("SETTING \t userId:\t"+userId);
sys("SETTING \t userPw:\t"+userPw);
sys("SETTING \t backupPath:\t"+backupPath);
sys("SETTING \t classRoot:\t"+classRoot);
sys("SETTING \t uploadRoot:\t"+uploadRoot);
}else{
sys("setting Error NOT FILE");
}
}
/**
* @author Jang.S.H
* @param localMap
* LOCAL 파일정보
* @param ftpMap
* FTP 파일정보
* @param root
* FTP 파일 루트
* @return
* 변경파일 목록
* @description
* LOCAL - FTP 간 파일 비교후 변경파일 리스트 추출
*/
private ArrayList<String> compareFileList(HashMap<String, File> localMap, HashMap<String, FTPFile> ftpMap, String root){
ArrayList<String> returnArray = new ArrayList<String>();
Set<String> set = localMap.keySet();
File f1 = null;
FTPFile f2 = null;
String backupLog = getBackupPath()+"loglog.txt";
FU.setTextFile(backupLog, DateUtils.getNormalDate("yyyy-MM-dd hh:mm:ss"), false);
for (String key : set) {
f1 = localMap.get(key);
if(ftpMap.containsKey(key)){
f2 = ftpMap.get(key);
if(f1.lastModified() > f2.getTimestamp().getTimeInMillis() && f1.length() != f2.getSize()){
sys("Modify :\t"+f1.getAbsolutePath());
backup(key, root);
returnArray.add(key);
FU.setTextFile(backupLog, f1.getAbsolutePath(), true);
}
}else{
sys("INSERT :\t"+f1.getAbsolutePath());
returnArray.add(key);
FU.setTextFile(backupLog, f1.getAbsolutePath(), true);
}
}
return returnArray;
}
/**
* @author Jang.S.H
* @param path
* root로 부터 상대경로
* @param root
* root 경로
* @description
* 백업폴더에 FTP 전체경로 백업한다.
* 전체경로 = root + path
*/
private void backup(String path, String root) {
try{
File put_file = new File(getBackupPath()+root+path); // 저장시켰던 파일을 서버로 전송
put_file.mkdirs();
if(put_file.isDirectory()){
put_file.delete();
FileWriter fi = new FileWriter(put_file);
fi.close();
}
FileOutputStream fos = new FileOutputStream(put_file);
boolean ret = ftpClient.retrieveFile(root+path, fos);
fos.close();
if(ret){
sys("BACKUP SUCCESS :\t"+root+path + "\t=>\t" +put_file.getAbsolutePath() );
}else{
sys("BACKUP FAIL :\t"+root+path + "\t=>\t" +put_file.getAbsolutePath());
}
}catch (Exception e) {
sys("BACKUP Error :\t"+path);
sys(e.toString());
}
}
/**
* @author Jang.S.H
* @param localMap
* LOCAL 파일
* @param list
* 변경 리스트
* @param root
* FTP ROOT
* @description
* 파일을 업로드 한다.
*/
private void upload(HashMap<String, File> localMap, ArrayList<String> list, String root){
try{
File f = null;
InputStream inputStream = null;
boolean result = false;
for(String s : list){
String tmpString = (root+s).replace("//", "/");
f = localMap.get(s);
inputStream = new FileInputStream(f);
int t = tmpString.lastIndexOf("/");
ftpClient.makeDirectory(tmpString.substring(0,t));
result = ftpClient.storeFile(tmpString, inputStream);
if(result){
sys("UPLOAD : \t"+tmpString);
}else{
sys("UPLOAD FAIL : \t"+tmpString);
}
}
inputStream.close();
}catch (Exception e) {
// TODO: handle exception
}
}
/**
* @author Jang.S.H
* @return
* @description
* 이클립스 기준 Class파일의 위치를 리턴.
* {HOME}/bulid/classes/
*/
private String getClassPath(){
return this.getClass().getResource("/").getPath().substring(1);
}
/**
* @author Jang.S.H
* @return
* @description
* 이클립스 기준 WebContent위치를 리턴
* {HOME}/WebContent/
*/
private String getWebRootPath(){
String path = getClassPath();
int lastIndex = path.lastIndexOf("/");
path = path.substring(0,lastIndex);
lastIndex = path.lastIndexOf("/");
path = path.substring(0,lastIndex);
lastIndex = path.lastIndexOf("/");
path = path.substring(0,lastIndex);
path += "/WebContent/";
return path;
}
private String getBackupPath(){
return backupPath;
}
/**
* @author Jang.S.H
* @param path
* 검색 경로
* @param type
* 검색 확장자
* @return
* @throws Exception
* @description
* key : 검색경로로 부터의 경로
* value: 파일정보
*/
private HashMap<String, FTPFile> getFtpFiles( String path, String type) throws Exception{
HashMap<String, FTPFile> returnMap = new HashMap<String, FTPFile>();
getFtpFileList(returnMap, path, path, type);
return returnMap;
}
private void getFtpFileList(HashMap<String, FTPFile> map, String rootPath, String path, String type) throws IOException {
FTPFile[] files = ftpClient.listFiles(path);
for(FTPFile f: files){
String filepath = path+f.getName();
if(f.isDirectory()){
getFtpFileList(map, rootPath, filepath+"/", type);
}else if(f.isFile() && (type.indexOf( FU.lastCut(f.getName(), ".") ) >= 0)){
map.put(filepath.replace(rootPath, "/"), f);
//sys(filepath.replace(rootPath, "/"));
}
}
}
/**
* @author Jang.S.H
* @param path
* 검색 경로
* @param type
* 검색 확장자
* @return
* @description
* key : 검색경로로 부터의 경로
* value: 파일정보
*
*/
private HashMap<String, File> getLocalFiles(String path, String type){
HashMap<String, File> returnMap = new HashMap<String, File>();
ArrayList<String> array = FU.getDirectoryFileList(path, type);
String[] arrAccept = exPattern.split(",");
for (int i = 0; i < array.size(); i++) {
File f = new File(array.get(i));
String filepath = "/"+array.get(i).replaceAll("\\\\", "/").replaceAll(path, "").replaceAll("//", "/");
//sys(filepath + "___"+ f.length()+"______"+f.lastModified());
boolean chk = isUrlPatternProc( arrAccept, filepath);
//sys("TEST_" + chk+"_"+filepath+"_"+arrAccept[0]);
if(!chk){
returnMap.put(filepath, f);
}else{
}
}
return returnMap;
}
/**
* @author Jang.S.H
* @param arrPattern
* @param value
* @return
* @description
* URL 패턴을 체크해서 패턴에 있는지 없는지 체크
*/
private boolean isUrlPatternProc(String[] arrPattern, String value){
if(arrPattern == null || value == null) return false;
Pattern p = null;
Matcher m = null;
for(String s: arrPattern){
s = s.trim().replace("*", "[-a-zA-Z0-9+&@#%?=~_|!:,.;]*");
p = Pattern.compile(s.trim());
m = p.matcher(value);
if(m.find()){
return true;
}
}
return false;
}
/**
* @author Jang.S.H
* @param s
* @description
* 로그 출력
*/
private void sys(String s){
System.out.println("FTP LOG:\t"+s);
}
}
위와 같이 만들자.
동작원리는 다음과 같다.
*LOCAL에 있는 파일들을 체크한다.
*FTP에 있는 파일들을 체크한다.
*LOCAL && FTP 를 비교후 날짜, 크기 변경된 파일들의 목록을 생성한다.
*변경파일을 BACKUP 경로에 다운받는다.
*변경파일을 업로드 한다.
*끝.
참 FileUtils는 파일 목록 긁어오기와 프로퍼티 파일 읽기 로그파일 만들기 정도 사용했는데.
이런건 인터넷쳐보면 금방메소드 만들수 있으니 알아서 하길 바란다.
동작 중 에러나 버그가 날 수도 있다.
안된다고 만든사람 욕하지말고 참고하고 자신이 직접 커스텀하거나 참고해서 새로 만들도록 하자.
노력이 있어야 발전이 있다.
출처 :http://m4nc.tistory.com/16
'기타' 카테고리의 다른 글
대체 URL 코드 - %26, %2F, %3A, %3F, %3D ( 16진수 ) (0) | 2013.05.23 |
---|---|
Commons Net의 FTPClient 사용하기 (0) | 2013.03.27 |
이클립스(eclipse) 속도 향상 (0) | 2013.02.27 |
전자여권 신청방법과 하와이 비자, 미국 비자면제 프로그램 ESTA 신청방법 (0) | 2013.01.30 |
web.xml (0) | 2013.01.30 |