본문으로 바로가기

SFTP 파일전송

category IT/Java & Jsp & Spring 2017. 11. 10. 21:45



1. SFTP란?


SFTP는 Secure File Transfer Protocol의 약자로 기존 FTP에 보안이 강화된 전송 방식을 말합니다.

FTP는 일반적으로 인터넷상에서 파일을 전송할 때 많이 사용되고 있는 프로토콜이나 로그인 정보 및 파일 정보를 암호화하지 않기 때문에 정보 노출의 위험성이 있습니다.

이런 위험을 방지하기 위해서 SFTP는 파일 전송 시 로그인 정보 및 파일 정보를 암호화해서 통신을 합니다.


2. 기본 환경구성


 - 라이브러리  jsch-0.1.54.jar

 - 22번 port 오픈



3. SFTP 예시소스

 
// Server에 접속 
 private void initChannelSftp()
	{
		channelSftp = null;
		session = null;
		
		try
		{
			// JSch 객체 생성
			JSch jsch = new JSch();
			
			// 세션 객체 생성(사용자이름, 호스트명, 접속포트)
			session = jsch.getSession(userName, hostName, Integer.valueOf(hostPort));
			session.setPassword(passWord);
			
			// 세션과 관련된 정보를 설정
			Properties config = new Properties();
			config.put(STRICT_HOST_KEY_CHECKING, STRICT_HOST_KEY_CHECKING_FLAG); // 호스트 정보를 검사하지 않음.
			
			session.setConfig(config);
		}
		catch(Exception e1)
		{
			logMessage("원격지(파일서버)연결에 필요한 환경정보 셋팅 중 예외가 발생했습니다.(" + e1.getMessage() + ") >> [Method=initChannelSftp()]"
					   , "others"
					   , "EXCEPTION"
					   , "EXCEPTION");
		}
	}

// Server에 업로드 될 파일객체 생성 
public synchronized File[] setUploadFiles(String filePath, List listFileName)
	{
		Collection c = new ArrayList();
        File[] uploadFiles = null;
        
        File dir = null;
        File[] dirList = null;
        
        try
        {
        	dir = new File(filePath);
            dirList = dir.listFiles();
    		
    		if(dirList != null && dirList.length > 0)
    		{
    			for(int i=0; i < dirList.length; i++)
    			{
    				if(listFileName != null && listFileName.size() > 0)
    				{
    					for(int j=0; j < listFileName.size(); j++)
    					{
    						if(listFileName.get(j) != null && !listFileName.get(j).equals(""))
    						{
    							if(dirList[i].getName().equals(listFileName.get(j)))
    							{
    								c.add(dirList[i]);
    								break;
    							}
    						}
    					}
    				}					
    			}
    		}
    		
    		if(!c.isEmpty())
    		{
    			uploadFiles = (File[])c.toArray(new File[0]);
    		}
    		

        }
        catch(Exception e)
        {
        	logMessage("원격지(파일서버)에 업로드 될 파일객체 셋팅 중 예외가 발생했습니다.(" + e.getMessage() + ") >> [Method=setUploadFiles()]"
					   , "others"
					   , "EXCEPTION"
					   , "EXCEPTION");
        }

        return uploadFiles;
	}

 // Server에 파일을 업로드 
 public synchronized String uploadFileToSFTP(HashMap argsParam, String logDir, String logFileType)
	{
		String result = "";
		int cnt = 0;
		
		initChannelSftp();
		
		File[] file = null;
		FileInputStream fis = null;
		
		try
		{
			SqlSession sess = (SqlSession)argsParam.get("sess");
			DatabasesImpl dMod = (DatabasesMod)argsParam.get("dMod");
			file = (File[])argsParam.get("uploadFiles");
			session = (Session)argsParam.get("session");
			channel = (Channel)argsParam.get("channel");
			channelSftp = (ChannelSftp)argsParam.get("channelSftp");
			
			HashMap prvMap = new HashMap();

			//channelSftp.chmod(0777, destinationDir);
			
			try
			{				
				// 실질적으로 파일이 업로드되는 경로로 바꿔준다.	
				channelSftp.cd(destinationDir);
			}
			catch(SftpException e2)
			{
				logMessage("원격지(파일서버)에 파일이 업로드 될 디렉토리를 찾을 수 없습니다.(" + destinationDir + ") >> [Method=uploadFileToSFTP()]"
						   , logDir
						   , "EXCEPTION"
						   , logFileType);
			}
			
			if(file != null && file.length > 0)
			{
				for(int i=0; i < file.length; i++)
				{
					try
					{
						fis = new FileInputStream(file[i].getAbsoluteFile());
						
						channelSftp.put(fis, file[i].getName());
						
						// 원격지 서버에 업로드가 성공된 결과파일 로그 남기기.
						logMessage(String.format("sftp://%s%s%s", hostName, destinationDir+"/", file[i].getName())
								   , logDir
								   , "SUCCESS"
								   , logFileType);
						
						cnt++;
						
						// 업로드대상 파일마다 하나의 InputStream을 Open하기 때문에 업로드가 완료되면 해당 InputStream객체는 닫아줘야 컨트롤이 가능하다.
						fis.close();
						fis = null;
					}
					catch(FileNotFoundException fnfe)
					{
						logMessage("파일을 찾을 수 없습니다.(" + fnfe.getMessage() + ") >> [Method=uploadFileToSFTP()]"
									, logDir
									, "EXCEPTION"
									, logFileType);
						
						if(logFileType.equals("InvoiceBatch"))
						{
							prvMap.put("invoice", file[i].getName().substring(0, file[i].getName().indexOf(".")));
							prvMap.put("ftpFlag", "N");
							prvMap.put("errCd", "PROC002");
							prvMap.put("errMsg", fnfe.getMessage());
							
							dMod.dataCUD(sess, prvMap, "updateFtpFailInvBatchProcData");
							
							prvMap.clear();
						}
						
						result = fnfe.getMessage();
						
						break;
					}
					catch(SftpException sftpe)
					{
						logMessage("원격지서버에 파일 업로드 실패했습니다.(" + file[i].getAbsolutePath() + ") >> [Method=uploadFileToSFTP()]"
								   , logDir
								   , "FAIL"
								   , logFileType);
						
						if(logFileType.equals("InvoiceBatch"))
						{
							prvMap.put("invoice", file[i].getName().substring(0, file[i].getName().indexOf(".")));
							prvMap.put("ftpFlag", "N");
							prvMap.put("errCd", "PROC002");
							prvMap.put("errMsg", sftpe.getMessage());
							
							dMod.dataCUD(sess, prvMap, "updateFtpFailInvBatchProcData");
							
							prvMap.clear();
						}
						
						result = sftpe.getMessage();
						
						break;
					}
				}
			}
			else
			{
				logMessage("업로드 대상 파일이 없거나 File객체가 NULL입니다. >> [Method=uploadFileToSFTP()]"
						   , logDir
						   , "EXCEPTION"
						   , logFileType);
				
				result = "fail";
			}
					
			if(cnt == file.length)
			{
				result = "success";
			}
			else
			{
				result = "fail";
			}
			
			// 연결된 채널, 세션객체를 모두 닫는다.
			disconnection(argsParam);
		}
		catch(Exception e3)
		{
			logMessage("Session, Channel, ChannelSftp등 연결하지 못했습니다.(" + e3.getMessage() + ") >> [Method=uploadFileToSFTP()]"
					   , logDir
					   , "EXCEPTION"
					   , logFileType);
			
			result = "fail";
		}
				
		return result;
	}

 // Client 단에서 java로 Server에 디렉토리 생성하는 로직 
        public synchronized HashMap remoteMakeDir(String destinationDir, String logDir, String logFileType)
	{
		initChannelSftp();
		
		HashMap argsParam = new HashMap();
		
		try
		{
			// 세션 연결이 되어있지 않다면 세션을 재 연결한다.
			if(!session.isConnected()) session.connect();
			
			// sftp 채널을 연다.
			channel = session.openChannel(OPEN_CHANNEL_MODE);
			channel.connect();	// 채널에 연결한다.
			
			// 채널을 FTP용 채널 객체로 캐스팅한다.
			channelSftp = (ChannelSftp) channel;
			
			String[] dirs = destinationDir.split("/");
			
			if(dirs != null && dirs.length > 0)
			{
				SftpATTRS attrs = null;
				int idx = 0;
				
				String pathInfo = "";
				
				for(String folder : dirs)
				{
					if(idx != 0)
					{						
						if(idx == 1)
						{
							pathInfo = "/" + folder;
						}
						else
						{
							pathInfo = pathInfo + "/" + folder;
						}
						
						try
						{
							attrs = channelSftp.stat(pathInfo);
						}
						catch(Exception e)
						{
							//System.out.println("'" + folder + "' not found");
						}
						
						if(attrs != null)
						{
							//System.out.println("Directory exists IsDir=" + attrs.isDir());
						}
						else
						{
							channelSftp.mkdir(pathInfo);
							channelSftp.cd(pathInfo);
						}
					}
					
					idx++;
					attrs = null;
				}
			}
			
			// uploadFileToSFTP 메서드에서 사용될 ftp및 session객체 return.
			argsParam.put("channelSftp", channelSftp);
			argsParam.put("channel", channel);
			argsParam.put("session", session);
		}
		catch(Exception e3)
		{
			logMessage("Session, Channel, ChannelSftp등 연결하지 못했습니다.(" + e3.getMessage() + ") >> [Method=remoteMakeDir()]"
					   , logDir
					   , "EXCEPTION"
					   , logFileType);
		}
		
		return argsParam;
	}

// 다이렉트 업로드 로직 
public boolean directUpload(
             String sftpHost, String sftpUser, String sftpPass, 
             int sftpPort, String sftpWorkingDir, String fileFullPath) {
        
        boolean result = true;
        
        Session session = null;
        Channel channel = null;
        ChannelSftp channelSftp = null;
        System.out.println("preparing the host information for sftp.");
        try {
            JSch jsch = new JSch();
            session = jsch.getSession(sftpUser, sftpHost, sftpPort);
            session.setPassword(sftpPass);
            
            // Host 연결.
            java.util.Properties config = new java.util.Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            session.connect();
            
            // sftp 채널 연결.
            channel = session.openChannel("sftp");
            channel.connect();
            
            // 파일 업로드 처리.
            channelSftp = (ChannelSftp) channel;
            channelSftp.cd(sftpWorkingDir);
            File f = new File(fileFullPath);
            String fileName = f.getName();
            //fileName = URLEncoder.encode(f.getName(),"UTF-8");
            channelSftp.put(new FileInputStream(f), fileName);
            f.delete(); // 파일전송 후 Client단 파일 삭제
        } catch (Exception ex) {
             System.out.println(ex.toString());
             System.out.println("Exception found while tranfer the response.");
             result = false;
        } finally {
            // sftp 채널을 닫음.
            channelSftp.exit();
            
            // 채널 연결 해제.
            channel.disconnect();
            
            // 호스트 세션 종료.
            session.disconnect();
        }
        
        return result;
    }