상세 컨텐츠

본문 제목

ftp사용 파일 업로드/다운로드 괘니 구현

스프링

by e7e 2023. 9. 1. 08:23

본문

ftp(File Transfer Protocol)를 이용해서 파일 업로드/다운로드를 괘니 그냥 구현해보장

먼저  Ftp 서버를 설치하기 위해서 공짜/유료 사용이 가능한 유명한  FileZilla 서버를

아래 링크에서 자신의 OS에 맞는 거슬 다운 받도록 하장 용량작당.(실타면 할 수 없당!)

 

미리 알아두깅 - 예전엔 크롬에서  주소표시줄에 ftp://아이디:암호@IP또는 도메인을
입력하면 접속이 되었지만, 현재 크롬은 지원하지 않는당!
대신 윈도우 탐색기 경로 줄에 위 처럼 치면 접속이 가능하닝 참고용!!
아이디:암호 안 치면 쪼메난 창이 떠서 물어용 콱!~~

 

파일질라 FTP 서버 다운로드 링크

다운받은 설치파일을 실행시켜  FTP 서버를 인스톨하는뎅, 대부분 Next를 누르공

아래 화면에서 잠깐 멈추장.

항상 사용할거면 window 부팅시에 자동 실행되는 default값을 선택하공, 그냥 공부용으로

사용할 거면 위 그림처럼 매뉴얼(수동) 실행을 선택하장.!

관리자 암호도 공부용이라면 쉬운 걸로..., 만약 잊어버렸다면  C:\ProgramData\filezilla-server 에

있는 settings.xml 파일을 관리자 권한으로 실행된 메모장으로 열어서 admin 태그 부분을 

아래처럼 비워주면, 암호가 없어진당.(까막눈이라면, Ftp 서버를 지우공, 다시 까는 것도 방법이겠당!)

       <admin>
               <local_port>14148</local_port>
               <password index="0" />
       </admin>

 

설치가 완료되었다면 아래와 같은 관리자 인터페이스가 실행될 거시당

Connecting to Server를 클릭한 거당

(만약 안 보인다면, 바탕화면에서 "Administer FileZilla Server" 아이콘 클릭!)

  OK를 누르면 아래와 같은 화면이 나올 거시당.!!!!

Error가 없다면 서버가 실행 중인 거시고, 위 처럼 Error가 나온다면 서버가 안 실행 중이당.

바탕화면에서 "Start FileZilla Server" 아이콘을 클릭하면 Error가 없어질 거시당.(Good! 잘했당)

 

Server => Configure => Users 탭을 이용하여  연습용  사용자를 등록하도록 하장

위 그림을 설명하면 사용자 e7e를 추가하였고, 암호를 부여했으며,

d:/myFtp란 폴더가 실제 있어야 하공, 로그인 하면 그냥 "/"  로 보인다는 이야기당.

현실에 비유하자면 집에 있는 시베리안 허스키 <-> 허숙희(별명) 식으로 맵핑시킨거시당. 

 

서버 준비는 끝났고, 이제 ftp의 느낌을 느껴봐야 할 시간이당. 쪼메 준비를 더 하장

d: 드라이브(없다면 c:)에 myLocal 폴더와 myFtp 폴더를 맹글장.

myLocal 폴더에는 cAAA.txt, cBBB.txt, cCCC.txt를 맹글고 ,

myFtp 폴더에는  sXXX.txt, sYYY.txt, sZZZ.txt를 일단 맹글어 두장!  그럼 연습 준비 완룡!! 

이제 cmd(명령 프롬프트)창을 실행시키장.

wsl(Window Sub Linux)를 설치했다면, 그걸 실행 시켜도 더 좋당.(cmd는 가끔 잘 안된당!)

  위 화면대로 한번 따라해 보면 ftp 서버에 로그인이 되고, myFtp 폴더 내용을

  볼 수 있음을 알 수 있당. ftp 프롬프트에서 ?나 help를 치면 ftp 모드에서 사용할 수 있는

  명령어 리스트를 볼 수 있으며, help mput 요따구로 치면 mput 명령어를 설명해 준당.(좋당)

위 화면대로 따라 해 보면, get은 가져오는 거, put은 보내는 거, mget은 마니 가져오기

mput은 마니 보내기란 사실을 느끼게 된당. bin/ascii 명령은 전송모드를 binary/text로 설정하는 건뎅

웬만하면 bin으로 세팅한당.(왱? ascii로 했을 때는 파일이 깨지는 경우가 종종 있당)

prompt 명령은 토글방식으로 묻고 답하기 식(interactive)모드를  사용/안사용(on/off) 으로 

입력할 때 마다 바뀐당.(의심되면 실험한당!)

ftp 모드를 빠져 나가려면 위처럼 하면 되는뎅, 그냥 quit만 쳐도 된당.

접속 할 때도  ftp 모드에서 open으로 열었는뎅, 그냥 아래 식으로 바로 ip 적고 접속해도 되당

ftp는 기본 port값이 21번당. (그냥 그렇당, 서버관리자라면 바꿀 수 있당!)

ftp 192.168.142.3

 

주의: 만약 ip를 적었을 때 접속이 안된다면, window의 방화벽 설정 때문이닝

잠시 방화벽을 풀도록 하장. 제어판에서 방화벽 치면 설정이 나온당.(그냥 보인당!)

 

 

어케 어케 대략 ftp가 뭔지 느낌이 왔을 거당. (느낌이란 노믄 그런식이당)

이제 ftp를 Spring에 적용시켜 보장. (이거이 원래 목표였딩! 그러팅!)

 

Spring FTP Client를 적용시키기 위해서는 아래 라이브러리가 필요하당. 추가하장.

		<!-- https://mvnrepository.com/artifact/commons-net/commons-net -->
		<dependency>
			<groupId>commons-net</groupId>
			<artifactId>commons-net</artifactId>
			<version>3.9.0</version>
		</dependency>

 

업로드와 다운로드를 편하게 쓰도록 하기 위해 Utility식으로 맹글장.

접속열기(open),닫기(close),업로드(upload),다운로드(download)의 4개  핵심 메소드

초 간단히 현실적으로 구현해 보았당.

package com.e7e.sec.ftp;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.SocketException;
import java.net.URLEncoder;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.net.PrintCommandListener;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class FtpUtils {

   @Value("localhost")
    private String server;
    
    @Value("21")
    private int port;
    
    @Value("e7e")
    private String username;
    
    @Value("roze")
    private String password;
    
    private FTPClient ftp;
 
    //FTPClient 객체를 통한 ftp 서버 연결
    public void open() throws SocketException, IOException { 
    	log.debug("server:" + server);
    	log.debug("port:" + port);
    	log.debug("username:" + username);
    	log.debug("password:" + password);
    	
    	ftp = new FTPClient();
    	ftp.setControlEncoding("UTF-8");
        
        //log에 주고받은 명령 출력해주는 설정
    	ftp.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out), true));

            ftp.connect(server, port);
            int reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();
                log.error("연결 실패예용 엉터링!!!.");
            }

            ftp.setSoTimeout(1000);
            ftp.login(username, password);
            ftp.setFileType(FTP.BINARY_FILE_TYPE);
    }
    
    public void close() throws IOException { 
            ftp.logout();
            ftp.disconnect();
    }
    
    public void upload(MultipartFile file) throws IOException {
    	open();
        InputStream inputStream = null;
        inputStream = file.getInputStream();
        
        //뽀인토 put 명령에 해당
        ftp.storeFile(file.getOriginalFilename(), inputStream);
        inputStream.close();
        close();
    }
    
    public void downlod(String fName,HttpServletResponse resp) throws IOException {
        
    	String fileName = URLEncoder.encode(fName, "UTF-8");
    	
        //간단히 하기위해 크롬 브라우져 기준 설정!
    	resp.setContentType("application/octet-stream");
        resp.setHeader("Content-Disposition", "attachment; filename=\""+ fileName + "\"");
        
        
    	open();
        OutputStream outputStream = new BufferedOutputStream(resp.getOutputStream());
    	InputStream inputStream = null;
        
        //뽀인토  get 명령에 해당
    	inputStream =ftp.retrieveFileStream("/"+fName);
        
    	byte[] bytesArray = new byte[4096];
        int bytesRead = -1;
        while ((bytesRead = inputStream.read(bytesArray)) != -1) {
            outputStream.write(bytesArray, 0, bytesRead);
        }

        boolean isOK  = ftp.completePendingCommand();
        log.debug("check: " + isOK);
        outputStream.close();
        inputStream.close();        
        close();         
    }

}

 

이제 테스트를 해보장

FtpTestController.java  (FtpUtils를 autowired   시킨게 뽀인또)

package com.e7e.sec.controller;

import java.io.IOException;

import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import com.e7e.sec.ftp.FtpUtils;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
@RequestMapping("/ftp")
public class FtpTestController {

	@Autowired
	private FtpUtils ftpUtils;
	
	@GetMapping("/main")
	public String main() {
		return "ftpmain";
	}
	
	@PostMapping("/upload")
	@ResponseBody
	public String upload(MultipartFile mFile) throws IOException {
		ftpUtils.upload(mFile);
		return "OK";
	}
	
	@GetMapping("/download/{fname}")
	public void download(@PathVariable String fname, HttpServletResponse resp) throws IOException {
		ftpUtils.downlod(fname, resp);
	}
	
}

 

ftpmain.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
	<!DOCTYPE html>
	<html>

	<head>
		<meta charset="UTF-8">
		<title>Insert title here</title>
	</head>

	<body>
		<h1>ftp테스통</h1>
		<form action="/sec/ftp/upload" method="post" enctype="multipart/form-data">
			<input type="file" name="mFile" value="">
			<button>떤송</button>
		</form>
	</body>

	</html>

 

이제 브라우져에서 http://호스트:포트/웹컨텍스트/ftp/main 으로 접속

파일선택 후 떤송을 누르고 d:/myFtp에 가보면 파일이 있음을 확인할 수 있당.

 

http://호스트:포트/웹컨텍스트/ftp/download/파일명  (파일명은 myFtp폴더에 있는 것만)

하면 download  폴더에 파일이 다운되는 거슬 확인할 수  있당.

쓰다 보닝, 기럭지만 기러진 느낌이 없지 않아 있지만,  그래동.....

ㅠㅠㅠ  어찌 어찌 기본 완성이당.  확장은 당신 몫으로 남겨 놓겠당!( ^-^)

 

서버!  클라이언트! 

서비스 제공자, 서비스를 받는 고객

울 현실속에서 매일 매일 접하는 일상인데, 이런 걸 공부해야 하다닝....

컴터로 연결된 네트워크 공간이란 사실은 다르당.

 

아이러니하당. 결국 사이버세상을 통해 현실을 배우는 건강?

현실을 사이버세상에 투영하려던 거시 아니었던강?

 

거울밖의 내가 거울 속의 나를 따라하려니, 어렵당!

마구 깨닫는당...  그......녀는 멈출 수 없는 원더우먼임을......

 

 

https://www.youtube.com/watch?v=W_9CcHC3VRs 

관련글 더보기