(참고: open API를 이용한 custom GPT는 불가능함, 내부 api로 외부데이터 연동은 가능)

1. OpenAI 플랫폼에서 Custom GPT 생성하기

Custom GPT를 설정하려면 OpenAI 플랫폼에서 새로운 Custom GPT를 생성해야 합니다.

1.1. OpenAI 플랫폼 접속

  1. OpenAI Custom GPT 페이지로 이동
  2. 로그인 후 상단의 My GPTs 메뉴 클릭
  3. "Create a GPT" 버튼을 클릭하여 새로운 Custom GPT 생성 시작

2. Custom GPT 설정 과정

Custom GPT는 OpenAI의 Guided Setup을 통해 설정할 수 있습니다.
이 과정에서는 GPT의 성격, 역할, 학습 데이터, API 기능 설정을 조정할 수 있습니다.

2.1. 기본 정보 입력

  • GPT의 이름 설정 → (예: "채권 전문가 GPT")
  • 설명 입력 → (예: "이 GPT는 채권 회수 및 법률 상담을 위한 맞춤형 AI입니다.")

2.2. 역할 및 동작 방식 정의 (Instructions)

Custom GPT의 동작 방식을 정의하는 가장 중요한 과정입니다.

✅ "Instructions" 탭에서 설정할 내용

  1. Assistant Instructions
    → GPT가 어떻게 행동해야 하는지 설명
  2. text
    복사편집
    당신은 금융 및 법률 전문가로서 채권 회수와 관련된 법률 상담을 제공합니다. 사용자의 질문에 대해 구체적인 법률 조항을 참조하며, 금융 기관의 실무적인 조언을 제공합니다.
  3. User Instructions
    → 사용자가 Custom GPT를 어떻게 사용할지 안내
  4. text
    복사편집
    질문을 작성할 때, 관련된 법률 조항이나 금융 용어를 포함해 주세요. 예시: "대여금 반환 청구 소송을 진행하려면 어떤 절차를 따라야 하나요?"

2.3. 추가적인 데이터 업로드 (Knowledge)

사용자가 Custom GPT에 대한 추가 정보를 제공할 수도 있습니다.

  • FAQ 데이터 업로드 (CSV, JSON 형식)
  • PDF, 텍스트 문서 업로드 (예: 회사 내부 지침, 법률 문서 등)

예시:

  • 금융 기관의 채권 회수 정책을 포함한 PDF 파일 업로드
  • 법률 상담 시 자주 묻는 질문(FAQ) 데이터 업로드

2.4. API 호출 및 도구 사용 설정 (Actions)

Custom GPT는 API 호출 및 외부 도구(Functions)와 연동할 수도 있습니다.

  • 예를 들어, Spring Boot API, Google 검색, 데이터베이스 API 등을 호출 가능

예제:

{
  "name": "채권 회수 API",
  "description": "고객의 채권 정보를 조회하고 법률 절차를 안내합니다.",
  "parameters": {
    "채권자명": {
      "type": "string",
      "description": "채권자의 이름"
    },
    "채무자명": {
      "type": "string",
      "description": "채무자의 이름"
    }
  }
}

이 기능을 활용하면 API를 직접 호출하여 최신 정보를 제공하는 Custom GPT를 만들 수 있습니다.


3. Custom GPT를 API에서 호출하는 방법

Custom GPT를 OpenAI API에서 사용하려면, API에서 model 값을 Custom GPT ID로 변경하면 됩니다.

✅ Custom GPT API 호출 예제 (Java)

import okhttp3.*;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.IOException;

@Service
public class OpenAICustomService {
    private static final String API_URL = "https://api.openai.com/v1/chat/completions";
    private final OkHttpClient client = new OkHttpClient();

    @Value("${openai.api.key}")
    private String apiKey;

    @Value("${openai.custom.gpt.id}") // Custom GPT ID (예: gpt-4-custom-XXXXX)
    private String customGptId;

    public String getCustomGptResponse(String userInput) throws IOException {
        String json = "{"
                + "\"model\":\"" + customGptId + "\","
                + "\"messages\":[{\"role\":\"user\",\"content\":\"" + userInput + "\"}],"
                + "\"temperature\":0.7"
                + "}";

        RequestBody body = RequestBody.create(json, MediaType.get("application/json"));

        Request request = new Request.Builder()
                .url(API_URL)
                .header("Authorization", "Bearer " + apiKey)
                .header("Content-Type", "application/json")
                .post(body)
                .build();

        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("Unexpected code " + response);
            }

            ObjectMapper mapper = new ObjectMapper();
            JsonNode rootNode = mapper.readTree(response.body().string());
            return rootNode.get("choices").get(0).get("message").get("content").asText();
        }
    }
}

설정 완료 후 API에서 Custom GPT를 호출하면, 사전에 설정한 역할, 동작 방식, 지식 등을 반영한 응답을 반환합니다.


4. 결론

OpenAI API에서 Custom GPT를 사용하려면 먼저 OpenAI 플랫폼에서 설정이 필요합니다.
사전 설정을 통해 특정한 업무(법률, 금융, IT 등)에 최적화된 GPT를 만들 수 있습니다.
API에서 model 값을 Custom GPT ID로 변경하면 사전 설정이 반영된 맞춤형 응답을 받을 수 있습니다.

 

 

5. customGptId 조회 방식

curl https://api.openai.com/v1/models \
  -H "Authorization: Bearer YOUR_OPENAI_API_KEY"

 

 

 

6. custom GPT 구성(Config)

- 우측 큰화면의 상단에 GPT제목을 누르고, 편집을 누른 후, "구성"탭에서 설정.

인증형식은 API key로 하고, https://platform.openai.com/ 에서 카드설정+발급받은 키를 이용하게 되며,
인증방식은 기본이 아닌->  "Bearer" 로 설정하는게 편함.

 

심플 get용 스키마:

{
  "openapi": "3.1.0",
  "info": {
    "title": "간단한 GET API",
    "description": "GET 요청을 받아 텍스트를 반환하는 API",
    "version": "v1.0.0"
  },
  "servers": [
    {
      "url": "https://api.example.com"
    }
  ],
  "paths": {
    "/hello": {
      "get": {
        "summary": "텍스트 반환",
        "operationId": "getHello",
        "responses": {
          "200": {
            "description": "성공적인 응답",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string",
                  "example": "Hello, GPT!"
                }
              }
            }
          }
        }
      }
    }
  }
}

 

 

post용 스키마:

{
  "openapi": "3.1.0",
  "info": {
    "title": "채권 조회 API",
    "description": "채권자 및 채무자 정보를 입력하면 채권 상태를 반환합니다.",
    "version": "v1.0.0"
  },
  "servers": [
    {
      "url": "https://api.example.com"
    }
  ],
  "paths": {
    "/getDebtStatus": {
      "post": {
        "summary": "채권 상태 조회",
        "operationId": "getDebtStatus",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DebtRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "채권 상태 응답",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DebtResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "DebtRequest": {
        "type": "object",
        "properties": {
          "채권자명": {
            "type": "string",
            "description": "채권자의 이름"
          },
          "채무자명": {
            "type": "string",
            "description": "채무자의 이름"
          }
        },
        "required": ["채권자명", "채무자명"]
      },
      "DebtResponse": {
        "type": "object",
        "properties": {
          "결과": {
            "type": "string",
            "description": "응답 상태 (성공 또는 실패)"
          },
          "채권 상태": {
            "type": "string",
            "description": "채권의 현재 상태 (예: 연체, 회수 완료 등)"
          },
          "회수 가능 금액": {
            "type": "number",
            "description": "현재 회수 가능한 금액 (원화 기준)"
          }
        }
      }
    }
  }
}
Posted by yongary
,

javascript 혹은 react상에서 간단한 템플릿 랭기지인 mustache 를 살펴보면 다음과 같다.

설치: npm install mustache

 

 

예제코드.

import React from "react";
import Mustache from "mustache";

const TemplateRenderer = () => {
  const template = "Hello, {{name}}! Welcome to {{platform}}.";
  const data = {
    name: "John",
    platform: "React Mustache",
  };

  const renderedText = Mustache.render(template, data);

  return <div>{renderedText}</div>;
};

export default TemplateRenderer;
Posted by yongary
,

golang 개요

golang 2025. 1. 21. 09:12

포인터가 존재: c언어와 유사
패키지명/가비지 컬렉션존재: java와 유사 

 

- 함수의 지연된 실행 허용

 

- 동시 프로그래밍을 지원하여 여러 프로세스를 동시에 실행할 수 있음

이는 채널, 고루틴 등을 사용하여 달성됩니다.

Posted by yongary
,


코드 에디터 (아래에 실행영역)이 있는 것 처럼 아래 위 두개의 영역이 있고,
중간을 마우스로 드래그하면서  둘 사이의 비율을 조절하고 싶을때
다음과 같은 방식으로 가능하다. 

동작 원리

  1. 상단 div의 높이 조절:
    • onMouseDown: 마우스 조절 시작을 감지.
    • onMouseMove: 마우스의 Y축 좌표(e.clientY)를 기준으로 height 상태를 업데이트.
    • onMouseUp: 조절 종료.
  2. 하단 div의 크기 계산:
    • 상단 div의 높이를 기준으로 나머지 공간을 자동으로 차지하도록 flex 사용.
  3. 유저 경험:
    • resizer 영역에서 마우스 커서가 변경(row-resize).
    • 조절 중 user-select: none을 사용해 텍스트 선택을 방지.

 

 

 

react 코드:

import React, { useState } from "react";
import "./ResizableDiv.css"; // 스타일 관리

const ResizableDiv = () => {
  const [height, setHeight] = useState(300); // 상단 div 초기 높이
  const [isResizing, setIsResizing] = useState(false); // 조절 상태 관리

  const handleMouseDown = () => {
    setIsResizing(true); // 마우스 드래그 시작
  };

  const handleMouseMove = (e) => {
    if (!isResizing) return;
    const newHeight = e.clientY; // 마우스 위치를 기준으로 높이 계산
    setHeight(newHeight);
  };

  const handleMouseUp = () => {
    setIsResizing(false); // 마우스 드래그 종료
  };

  return (
    <div
      className="container"
      onMouseMove={handleMouseMove}
      onMouseUp={handleMouseUp}
      onMouseLeave={handleMouseUp}
    >
      <div className="top-div" style={{ height: `${height}px` }}>
        상단 Div
      </div>
      <div className="resizer" onMouseDown={handleMouseDown}></div>
      <div className="bottom-div">하단 Div</div>
    </div>
  );
};

export default ResizableDiv;

 

 

CSS

.container {
  display: flex;
  flex-direction: column;
  height: 100vh;
  width: 100%;
  user-select: none; /* 텍스트 선택 방지 */
}

.top-div {
  background-color: #f0f0f0;
  border-bottom: 2px solid #ccc;
  overflow: auto;
}

.resizer {
  height: 10px;
  background-color: #888;
  cursor: row-resize;
}

.bottom-div {
  background-color: #e0e0e0;
  flex: 1;
  overflow: auto;
}
Posted by yongary
,

Slack API 키를 발급받기 위해서는 Slack 앱 생성과정을 거쳐야 합니다. Slack 앱을 생성한 후, API 키(토큰)를 발급받아 다양한 Slack API 호출에 사용할 수 있습니다. 아래는 단계별 방법입니다.


1. Slack 앱 생성하기 : 스크린샷은 https://zzang9ha.tistory.com/400#google_vignette 참고

  1. Slack API 페이지 방문:
  2. 앱 생성 시작:
    • 상단의 "Create an App" 버튼을 클릭합니다.
  3. 앱 생성 방법 선택:
    • **"From scratch"**를 선택하여 새 앱을 생성합니다.
  4. 앱 이름 및 워크스페이스 선택:
    • 앱 이름을 입력하고, 앱을 설치할 워크스페이스를 선택합니다.
    • "Create App" 버튼을 클릭하여 앱 생성을 완료합니다.

2. OAuth & Permissions 설정

  1. OAuth & Permissions 메뉴로 이동:
    • 생성된 앱의 관리 페이지에서 "OAuth & Permissions" 탭으로 이동합니다.
  2. OAuth 범위(Scope) 설정:
    • "Scopes" 섹션에서 앱이 필요로 하는 권한을 설정합니다.
    • 예를 들어: 특정 User가 로그인해서 마치 bot인것 처럼 메시지를  보낼때
      "User Token Scopes" 에 아래 2개 추가  필수. 
      • chat:write는 반드시 추가
      • chat::read Public 도 꼭 추가
    • 필요한 범위를 선택하고 추가합니다.
  3. 앱 설치:
    • "Install App to Workspace" 버튼을 클릭하여 앱을 워크스페이스에 설치합니다.
    • 설치를 완료하면 **OAuth 토큰(Access Token)**이 생성됩니다.

3. API 키(Access Token) 확인

  1. OAuth 토큰 복사:
    • 설치 완료 후 표시되는 "Bot User OAuth Token" 또는 **"User OAuth Token"**을 복사합니다.
    • 이 토큰이 Slack API 호출 시 사용하는 API 키입니다.
  2. 보안 저장:
    • 토큰은 민감한 정보이므로 안전한 곳에 저장합니다.
    • 코드에 직접 포함시키기보다는 환경변수로 관리하는 것이 권장됩니다.

4. 토큰 사용 예제

복사한 API 키를 사용하여 Slack API를 호출할 수 있습니다. 예를 들어, 메시지 전송 API를 호출하려면 다음과 같이 작성합니다:

bash
코드 복사
curl -X POST -H "Authorization: Bearer xoxb-your-token" -H "Content-Type: application/json" \ --data '{"channel":"#general","text":"Hello, Slack!"}' \ https://slack.com/api/chat.postMessage
Posted by yongary
,

original_window = self.driver.current_window_handle
self.driver.switch_to.window(original_window)  # 메인 창으로 이동

# 새로운 창에서 실행
## child window
for window_handle in self.driver.window_handles:
    print(window_handle, original_window, window_handle != original_window)
    if window_handle != original_window:
        print("자식 창 변경")
        self.driver.switch_to.window(window_handle)
        print("current handle 2:: ", self.driver.current_window_handle)

self.driver.implicitly_wait(5)

 

 

self.driver.switch_to.window(original_window)  # 메인 창으로 이동

Posted by yongary
,

추가: ssh는 기존 pem파일 로그인, sftp는 비번 로그인으로 설정하는 법. /etc/ssh/sshd_config 파일 에 추가. 

# 공개 키 인증을 기본으로 사용
PasswordAuthentication no
PubkeyAuthentication yes

# SFTP만 비밀번호로 허용
Match Group sftpusers  (이건 맞는 그룹으로 변경필요) 
    PasswordAuthentication yes
    PubkeyAuthentication no
    ForceCommand internal-sftp

$sudo systemctl restart sshd

 

 

SFTP(Secure File Transfer Protocol)를 사용하기 위해서는 현재 설정된 vsftpd를 변경할 필요는 없습니다. SFTP는 SSH(Secure Shell) 서비스로 작동하기 때문입니다. CentOS 7에서 SFTP를 사용하도록 설정하는 방법은 다음과 같습니다:

1. SSH 설치 및 실행 확인

SFTP는 SSH를 통해 작동하므로, SSH 서버(sshd)가 설치되고 실행 중인지 확인해야 합니다.

 
sudo yum install openssh-server sudo systemctl start sshd sudo systemctl enable sshd

2. SFTP 사용자 설정

이미 cncity라는 사용자가 있습니다. 이 사용자가 유효한 쉘(예: /bin/bash)을 가지고 있고 올바른 홈 디렉토리를 가지고 있는지 확인합니다:

bash
 
sudo usermod -s /bin/bash cncity

사용자의 홈 디렉토리가 존재하고 올바른 권한을 가지고 있는지 확인하세요:

bash
 
sudo mkdir -p /home/centos/nfs/cncity sudo chown cncity:cncity /home/centos/nfs/cncity

3. SFTP만 허용하도록 사용자 제한 (선택 사항)

만약 SFTP만 허용하고 전체 SSH 접근을 제한하려면, SFTP를 위한 제한된 쉘을 설정할 수 있습니다:

SSH 설정 파일 편집:

bash
코드 복사
sudo vi /etc/ssh/sshd_config
cncity 사용자에 대한 SFTP 제한 설정 추가:

plaintext
코드 복사
Match User cncity
    ForceCommand internal-sftp
    ChrootDirectory /home/centos/nfs
    PermitTunnel no
    AllowAgentForwarding no
    AllowTcpForwarding no
    X11Forwarding no
ForceCommand internal-sftp는 사용자가 SFTP만 사용하도록 강제합니다.
ChrootDirectory /home/centos/nfs는 사용자를 지정된 디렉토리(/home/centos/nfs)로만 제한합니다.
ChrootDirectory는 root가 소유하고 사용자에게 쓰기 권한이 없어야 합니다.
Chroot 디렉토리의 권한 설정:

bash
코드 복사
sudo chown root:root /home/centos/nfs
sudo chmod 755 /home/centos/nfs
SSH 서비스 재시작:

bash
코드 복사
sudo systemctl restart sshd

 

 

4. 기본적으로는 id/비번만으로 동작함. but 키 인증기반으로 변경할 수도 있음.

1. 기본 설정 (암호 인증)
클라이언트에게 제공할 것: 사용자 이름과 비밀번호
설명: SFTP 접속 시 클라이언트는 서버의 IP 주소, 사용자 이름, 비밀번호만으로 접속할 수 있습니다. 추가적인 인증 키나 인증서는 필요하지 않습니다.
보안 수준: 기본적인 암호 인증은 충분히 안전하지만, 키 기반 인증보다 상대적으로 보안이 낮을 수 있습니다.
2. 키 기반 인증 (더 안전한 방법)
클라이언트에게 제공할 것: 개인 SSH 키 (Private Key)

설정 방법:

서버에서 SSH 키 쌍을 생성 (클라이언트가 생성할 수도 있음):

bash
코드 복사
ssh-keygen -t rsa -b 2048
이 명령을 실행하면 id_rsa(개인 키)와 id_rsa.pub(공개 키)라는 두 개의 파일이 생성됩니다.

클라이언트의 공개 키를 서버에 복사:

공개 키 파일(id_rsa.pub)을 서버의 사용자의 홈 디렉토리에 있는 ~/.ssh/authorized_keys 파일에 추가합니다:

bash
코드 복사
cat id_rsa.pub >> /home/cncity/.ssh/authorized_keys
SSH 설정 파일에서 키 인증 사용 (이미 기본적으로 활성화되어 있을 수 있음):

/etc/ssh/sshd_config 파일을 열고 PubkeyAuthentication이 yes로 설정되어 있는지 확인합니다:

plaintext
코드 복사
PubkeyAuthentication yes
SSH 서비스 재시작:

bash
코드 복사
sudo systemctl restart sshd
클라이언트 측: 클라이언트는 개인 키(id_rsa)를 SFTP 접속 시 사용해야 합니다. SFTP 클라이언트에서 개인 키를 설정하거나, 명령줄에서 다음과 같이 사용할 수 있습니다:

bash
코드 복사
sftp -i /path/to/private_key cncity@your_server_ip
보안 수준: 키 기반 인증은 암호 기반 인증보다 안전합니다. 개인 키를 분실하지 않도록 주의해야 하며, 개인 키는 암호로 보호하는 것이 좋습니다.
Posted by yongary
,

vsftpd for CentOS7

IT 2024. 9. 4. 16:44

기본 설치 방법.

sudo yum install vsftpd

sudo systemctl start vsftpd
sudo systemctl enable vsftpd

 

 

 

sudo vi /etc/vsftpd/vsftpd.conf 기본설정 항목. 

# 익명 사용자 접속 금지
anonymous_enable=NO

# 로컬 사용자 접속 허용
local_enable=YES

# 업로드 권한 부여
write_enable=YES

# 사용자 홈 디렉토리를 루트 디렉토리로 설정
chroot_local_user=YES

# FTP에 허용할 사용자 목록을 지정하는 설정
userlist_enable=YES
userlist_file=/etc/vsftpd/user_list
userlist_deny=NO

 

sudo vi /etc/vsftpd/user_list 에는
cncity
라는 유저명 한줄만 있으면 됨. 

 

 

 

FTP 루트 디렉토리를 홈 디렉토리로 설정하는 chroot_local_user=YES가 이미 활성화된지 확인합니다. 이 설정은 사용자가 자신의 홈 디렉토리(지금은 /home/centos/nfs/cncity)로만 접근하도록 제한하는 역할을 합니다.

$sudo vi /etc/vsftpd/vsftpd.conf

# 로컬 사용자 홈 디렉토리를 루트 디렉토리로 설정
chroot_local_user=YES

# 일부 사용자만 chroot 제한을 적용하려면
# chroot_list_enable=YES
# chroot_list_file=/etc/vsftpd/chroot_list
Posted by yongary
,
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 10초 동안 팝업이 나타날 때까지 기다림
try:
    popup_element = WebDriverWait(self.driver, 10).until(
        EC.presence_of_element_located((By.ID, "popup_element_id"))  # 여기서 ID는 팝업의 요소 ID
    )
    # 팝업이 나타났을 때 수행할 동작
except TimeoutException:
    print("팝업이 나타나지 않았습니다.")
Posted by yongary
,

이렇게 하면 file이 업로드 되었을때, 이벤트도 받을 수 있다.

 

<dependency>
    <groupId>org.apache.ftpserver</groupId>
    <artifactId>ftpserver-core</artifactId>
    <version>1.1.1</version>
</dependency>

 

import org.apache.ftpserver.FtpServer;
import org.apache.ftpserver.FtpServerFactory;
import org.apache.ftpserver.ftplet.Ftplet;
import org.apache.ftpserver.ftplet.FtpletContext;
import org.apache.ftpserver.ftplet.FtpletResult;
import org.apache.ftpserver.ftplet.FtpException;
import org.apache.ftpserver.listener.ListenerFactory;
import org.apache.ftpserver.usermanager.PropertiesUserManagerFactory;
import org.apache.ftpserver.usermanager.SaltedPasswordEncryptor;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Component
public class EmbeddedFtpServer {

    @PostConstruct
    public void startFtpServer() {
        FtpServerFactory serverFactory = new FtpServerFactory();
        ListenerFactory factory = new ListenerFactory();
        
        // Set the port of the listener
        factory.setPort(2221);
        serverFactory.addListener("default", factory.createListener());

        // Setup user manager
        PropertiesUserManagerFactory userManagerFactory = new PropertiesUserManagerFactory();
        userManagerFactory.setFile(new File("users.properties"));
        userManagerFactory.setPasswordEncryptor(new SaltedPasswordEncryptor());
        serverFactory.setUserManager(userManagerFactory.createUserManager());

        // Add Ftplet to handle FTP events
        Map<String, Ftplet> ftplets = new HashMap<>();
        ftplets.put("eventListenerFtplet", new EventListenerFtplet());
        serverFactory.setFtplets(ftplets);

        // Start the server
        FtpServer server = serverFactory.createServer();
        try {
            server.start();
            System.out.println("Embedded FTP server started.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

이벤트 수신

import org.apache.ftpserver.ftplet.*;

import java.io.IOException;

public class EventListenerFtplet extends DefaultFtplet {

    @Override
    public FtpletResult onUploadStart(FtpSession session, FtpRequest request) throws FtpException, IOException {
        System.out.println("Start uploading file: " + request.getArgument());
        return FtpletResult.DEFAULT;
    }

    @Override
    public FtpletResult onUploadEnd(FtpSession session, FtpRequest request) throws FtpException, IOException {
        System.out.println("Finished uploading file: " + request.getArgument());
        return FtpletResult.DEFAULT;
    }

    @Override
    public FtpletResult onConnect(FtpSession session) throws FtpException, IOException {
        System.out.println("User connected: " + session.getUser().getName());
        return FtpletResult.DEFAULT;
    }

    @Override
    public FtpletResult onDisconnect(FtpSession session) throws FtpException, IOException {
        System.out.println("User disconnected: " + session.getUser().getName());
        return FtpletResult.DEFAULT;
    }
}

 

사용자까지 설정한 예제는:

import org.apache.ftpserver.FtpServerFactory;
import org.apache.ftpserver.listener.ListenerFactory;
import org.apache.ftpserver.usermanager.PropertiesUserManagerFactory;
import org.apache.ftpserver.usermanager.impl.BaseUser;
import org.apache.ftpserver.usermanager.impl.SaltedPasswordEncryptor;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.File;

@Component
public class EmbeddedFtpServer {

    @PostConstruct
    public void startFtpServer() {
        FtpServerFactory serverFactory = new FtpServerFactory();
        ListenerFactory factory = new ListenerFactory();
        
        // Set the port of the listener
        factory.setPort(2221);
        serverFactory.addListener("default", factory.createListener());

        // Setup user manager
        PropertiesUserManagerFactory userManagerFactory = new PropertiesUserManagerFactory();
        userManagerFactory.setPasswordEncryptor(new SaltedPasswordEncryptor());
        var userManager = userManagerFactory.createUserManager();

        // Create a new user
        BaseUser user = new BaseUser();
        user.setName("user1");
        user.setPassword("pass1");
        user.setHomeDirectory("/path/to/root/folder1");
        user.setEnabled(true);

        // Set permissions if needed (e.g., write permission)
        userManager.save(user);

        serverFactory.setUserManager(userManager);

        // Start the server
        FtpServer server = serverFactory.createServer();
        try {
            server.start();
            System.out.println("Embedded FTP server started.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Posted by yongary
,