來一個復古的技術FTP

背景

?????? 10年前的老代碼,需要升級springboot框架,在升級過程中,測試業務流程里,有FTP的下載業務,不管測試環境如何測試,都沒有成功,最后只能自己搭建一個FTP服務器,寫一個ftp-demo來測試。記錄一下過程,防止后續使用的時候在來一次。

CentOS7安裝FTP

步驟1:安裝 vsftpd

# 更新系統軟件包
sudo yum update -y# 安裝 vsftpd
sudo yum install vsftpd -y

步驟2:啟動服務并設置開機自啟

# 啟動 vsftpd 服務
sudo systemctl start vsftpd# 設置開機自啟
sudo systemctl enable vsftpd# 檢查服務狀態
sudo systemctl status vsftpd# 停止服務
sudo systemctl stop vsftpd# 重啟服務
sudo systemctl restart vsftpd

步驟3:配置防火墻

# 開放FTP端口(21和被動模式端口范圍)
sudo firewall-cmd --zone=public --add-port=21/tcp --permanent
sudo firewall-cmd --zone=public --add-port=30000-31000/tcp --permanent
sudo firewall-cmd --zone=public --add-service=ftp --permanent# 重新加載防火墻規則
sudo firewall-cmd --reload

步驟4:配置 vsftpd

cd /etc/vsftpd/cp vsftpd.conf vsftpd.conf_default
修改下列參數的值
anonymous_enable=NO          #禁止匿名登錄FTP服務器
local_enable=YES             #允許本地用戶登錄FTP服務器
listen=YES                   #監聽IPv4 sockets
#listen_ipv6=YES             #關閉監聽IPv6 sockets或者改為NO
chroot_local_user=YES        #全部用戶被限制在主目錄
chroot_list_enable=YES       #啟用例外用戶名單
chroot_list_file=/etc/vsftpd/chroot_list  #指定例外用戶列表文件,列表中用戶不被鎖定在主目錄
allow_writeable_chroot=YES
pasv_enable=YES
pasv_min_port=30000
pasv_max_port=31000
以上配置可以直接用下面命令進行替換修改(一句一句執行)
sed -i 's/anonymous_enable=YES/anonymous_enable=NO/' /etc/vsftpd/vsftpd.conf
sed -i 's/listen=NO/listen=YES/' /etc/vsftpd/vsftpd.conf
sed -i 's/listen_ipv6=YES/listen_ipv6=NO/' /etc/vsftpd/vsftpd.conf
sed -i 's/#chroot_local_user=YES/chroot_local_user=YES/' /etc/vsftpd/vsftpd.conf
sed -i 's/#chroot_list_enable=YES/chroot_list_enable=YES/' /etc/vsftpd/vsftpd.conf
sed -i 's/#chroot_list_file=/chroot_list_file=/' /etc/vsftpd/vsftpd.conf
echo "allow_writeable_chroot=YES" >> /etc/vsftpd/vsftpd.conf
# 被動模式
echo "pasv_enable=YES">> /etc/vsftpd/vsftpd.conf
echo "pasv_min_port=30001">> /etc/vsftpd/vsftpd.conf
echo "pasv_max_port=30010">> /etc/vsftpd/vsftpd.conf

?步驟5:創建FTP用戶

# 創建用戶(例如用戶名為 ftpuser,目錄為 /home/ftpuser)
sudo useradd -m -d /home/ftpuser -s /sbin/nologin ftpuser# 設置用戶密碼
sudo passwd ftpuser# 確保用戶目錄權限正確
sudo chmod -R 750 /home/ftpuser
sudo chown -R ftpuser: /home/ftpuser例如:
sudo useradd -m -d /home/douzi -s /sbin/nologin douzi
sudo passwd 123456
sudo chmod -R 750 /home/douzi
sudo chown -R douzi: /home/douzi

步驟6:重啟vsftpd服務

# 啟動 vsftpd 服務
sudo systemctl restart vsftpd

步驟7:客戶端登錄測試

ftp localhost
問題1:ftp客戶端未安裝

解決辦法:
sudo yum install ftp
問題2:登錄失敗

找的截圖,不要糾結里邊的命令,只看紅框部分即可

?解決辦法:
vi /etc/pam.d/vsftpd# 注釋以下一行
#auth       required    pam_shells.so

重啟vsftpd服務,再進行登錄提示:

再手動在/etc/vsftpd/目錄下創建一下chroot_list文件即可

cd /etc/vsftpd/touch /etc/vsftpd/chroot_list

?然后重啟vsftpd服務,登錄即可正常:

登陸后默認為二進制傳輸模式

擴展FTP客戶端命令:

dir ls cd pwd?lcd(切換工作目錄)? mkdir rmdir?get?mget(下載多個文件) put?mput(上傳多個文件) rename?delete?mdelete(刪除多個ftp文件) rmdir?ascii,bin(切換傳輸模式) close(關閉鏈接) open(重連ftp) quit

擴展防火墻命令:

一、防火墻的開啟、關閉、禁用命令
設置開機啟用防火墻:systemctl enable firewalld
設置開機禁用防火墻:systemctl disable firewalld
啟動防火墻:       systemctl start firewalld
關閉防火墻:       systemctl stop firewalld 或 systemctl stop firewalld.service
檢查防火墻狀態     systemctl status firewalld二、使用firewall-cmd配置端口
查看防火墻狀態: firewall-cmd --state
重新加載配置:   firewall-cmd --reload
查看開放的端口: firewall-cmd --list-ports
開啟防火墻端口: firewall-cmd --zone=public --add-port=9200/tcp --permanent

擴展FTP配置項說明:

1. 基礎訪問控制
配置項默認值說明
anonymous_enableNO是否允許匿名登錄(YES/NO
local_enableYES是否允許本地用戶登錄(YES/NO
write_enableYES是否允許寫入操作(上傳/刪除/重命名)
2. 權限與安全
配置項默認值說明
local_umask022本地用戶創建文件的權限掩碼(022表示文件權限為644,目錄為755
chroot_local_userNO是否將本地用戶限制在其主目錄(需配合allow_writeable_chroot=YES使用)
allow_writeable_chrootNO允許被chroot的用戶目錄可寫(需chroot_local_user=YES
3. 連接與日志
配置項默認值說明
dirmessage_enableYES顯示目錄歡迎消息(消息文件默認為.message
xferlog_enableYES啟用傳輸日志(記錄上傳/下載)
xferlog_file/var/log/vsftpd.log指定日志文件路徑
xferlog_std_formatYES使用標準FTP日志格式(兼容wu-ftp格式)
connect_from_port_20YES主動模式時,強制數據連接從端口20發起
4. 超時設置
配置項默認值說明
idle_session_timeout600空閑會話超時時間(秒)
data_connection_timeout120數據連接超時時間(秒)
5. 被動模式(PASV)配置
配置項默認值說明
pasv_enableYES啟用被動模式
pasv_min_port-被動模式端口范圍下限(如30000
pasv_max_port-被動模式端口范圍上限(如31000
pasv_address-服務器公網IP(NAT環境下需指定)
6. 高級選項
配置項默認值說明
listenNO以獨立模式運行(YES=IPv4,NO=通過xinetd啟動)
listen_ipv6NO啟用IPv6監聽
tcp_wrappersYES使用TCP Wrappers進行主機訪問控制
userlist_enableNO啟用用戶列表控制(userlist_file指定文件)
userlist_denyYES用戶列表中的用戶是否被拒絕(YES=黑名單,NO=白名單)

FTP-DEMO Springboot3代碼

maven需要引用的包:

    ......<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.4.5</version><relativePath /> <!-- lookup parent from repository --></parent>    ......<properties><java.version>17</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.35</version></dependency><dependency><groupId>commons-net</groupId><artifactId>commons-net</artifactId><version>3.11.1</version></dependency><dependency><groupId>com.jcraft</groupId><artifactId>jsch</artifactId><version>0.1.55</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-core</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>......

配置文件:

ftp:# 服務器地址host: 192.168.1.56# 端口號port: 21# 用戶名userName: douzi# 密碼password: 123456

代碼部分:

package com.wd.ftp.config;import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;/*** ftp配置*/
@Configuration
public class FtpConfig {/*** 服務器地址*/private static String host;/*** 端口*/private static Integer port;/*** 用戶名*/private static String userName;/*** 密碼*/private static String password;@Value("${ftp.host}")public void setHost(String host) {FtpConfig.host = host;}public static String getHost() {return host;}@Value("${ftp.port}")public void setPort(Integer port) {FtpConfig.port = port;}public static Integer getPort() {return port;}@Value("${ftp.userName}")public void setUserName(String userName) {FtpConfig.userName = userName;}public static String getUserName() {return userName;}@Value("${ftp.password}")public void setPassword(String password) {FtpConfig.password = password;}public static String getPassword() {return password;}
}
package com.wd.ftp.util;import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;import org.apache.commons.net.ftp.FTPFile;import com.wd.ftp.config.FtpConfig;import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.ftp.Ftp;
import cn.hutool.extra.ftp.FtpMode;
import lombok.extern.slf4j.Slf4j;/*** FTP服務工具類*/
@Slf4j
public class FtpUtil {/*** 獲取 FTPClient對象*/private static Ftp getFTPClient() {try {if(StrUtil.isBlank(FtpConfig.getHost()) || FtpConfig.getPort() == null|| StrUtil.isBlank(FtpConfig.getUserName()) || StrUtil.isBlank(FtpConfig.getPassword())) {throw new RuntimeException("ftp配置信息不能為空");}Ftp ftp = new Ftp(FtpConfig.getHost(),FtpConfig.getPort(),FtpConfig.getUserName(),FtpConfig.getPassword());//設置為被動模式,防止防火墻攔截ftp.setMode(FtpMode.Passive);return ftp;} catch (Exception e) {e.printStackTrace();log.error("獲取ftp客戶端異常",e);throw new RuntimeException("獲取ftp客戶端異常:"+e.getMessage());}}/*** 下載ftp服務器上的文件到本地* @param remoteFile    ftp上的文件路徑* @param localFile     輸出的目錄,使用服務端的文件名*/public static void download(String remoteFile, String localPath) {if(StrUtil.isBlank(remoteFile) || StrUtil.isBlank(localPath)) {return;}Ftp ftp = getFTPClient();try {if(!FileUtil.exist(localPath)){FileUtil.mkdir(localPath);}    File lFile = FileUtil.file(localPath);ftp.download(remoteFile, lFile);} catch (Exception e) {e.printStackTrace();log.error("FTP文件下載異常",e);} finally {//關閉連接try {if(ftp != null)  ftp.close();} catch (IOException e) {throw new RuntimeException(e);}}}/*** 本地文件上傳到ftp服務器上* @param remoteDir 上傳的ftp目錄* @param remoteFileName  保存到ftp服務器上的名稱* @param localFile 本地文件全名稱*/public static boolean upload(String remoteDir, String remoteFileName, String localFile) {if(StrUtil.isBlank(remoteDir) || StrUtil.isBlank(remoteFileName) || StrUtil.isBlank(localFile)) {return false;}Ftp ftp = getFTPClient();try {File lFile = FileUtil.file(localFile);if(!lFile.exists()) {log.error("本地文件不存在");return false;}if(StrUtil.isBlank(remoteFileName)) {return ftp.upload(remoteDir, lFile);} else {return ftp.upload(remoteDir, remoteFileName, lFile);}} catch (Exception e) {e.printStackTrace();log.error("文件上傳FTP異常",e);return false;} finally {//關閉連接try {if(ftp != null)  ftp.close();} catch (IOException e) {throw new RuntimeException(e);}}}/*** 刪除FTP服務器中的文件* @param remoteFile    ftp上的文件路徑*/public static boolean delFile(String remoteFile) {if(StrUtil.isBlank(remoteFile)) {return false;}Ftp ftp = getFTPClient();try {return ftp.delFile(remoteFile);} catch (Exception e) {e.printStackTrace();log.error("刪除FTP服務器中的文件異常",e);return false;} finally {//關閉連接try {if(ftp != null)  ftp.close();} catch (IOException e) {throw new RuntimeException(e);}}}/*** 遍歷某個目錄下所有文件,不會遞歸遍歷* @param path    目錄*/public static List<String> listFile(String path) {List<String> listFile = new ArrayList<>();Ftp ftp = getFTPClient();try {FTPFile[] ftpFiles = ftp.lsFiles(path);for (int i = 0; i < ftpFiles.length; i++) {FTPFile ftpFile = ftpFiles[i];if(ftpFile.isFile()){listFile.add(ftpFile.getName());}}return listFile;} catch (Exception e) {e.printStackTrace();log.error("遍歷某個目錄下所有文件異常",e);return null;} finally {//關閉連接try {if(ftp != null)  ftp.close();} catch (IOException e) {throw new RuntimeException(e);}}}
}
package com.wd.ftp.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import com.wd.ftp.util.FtpUtil;
import com.wd.ftp.util.SftpUtil;import jakarta.servlet.http.HttpServletRequest;@RestController
public class FtpController {/*** 下載ftp服務器上的文件到本地* @param rf    ftp上的文件路徑* @param lp     輸出的目錄,使用服務端的文件名*/@GetMapping("/download")public String download(@RequestParam(required = false, defaultValue = "1.xml") String rf, @RequestParam(required = false, defaultValue = "/ftp/download/") String lp) {FtpUtil.download(rf, lp);return "success";}}

可以根據FtpUtil擴展SftpUtil的代碼,從而支持Sftp模式。

執行效果:

隨便造一個1.xml上傳ftp

cd /home/douzi 然后查看內容

?

瀏覽器執行

http://localhost:8080/download

windows下,代碼在哪個盤執行,就會生成在哪個盤。

下載成功!其他上傳,刪除等功能自行試驗。

打完收工。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/81094.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/81094.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/81094.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MyBatis-Flex配置Druid(德魯伊數據庫連接池):Spring Boot 3 集成 MyBatis-Flex 配置 Druid 連接池指南

Spring Boot 3 集成 MyBatis-Flex 配置 Druid 連接池指南 前言 本文詳細講解在 Spring Boot 3 項目中集成 MyBatis-Flex 框架后&#xff0c;如何正確配置 Druid 數據庫連接池。針對開發者常見的配置缺失導致啟動失敗的場景&#xff0c;提供完整的解決方案和原理分析。 前置知識…

安全生產調度管理系統的核心功能模塊

安全生產調度管理系統是運用現代信息技術構建的智能化管理平臺&#xff0c;旨在實現生產安全風險的全面管控和應急資源的優化調度。該系統通過整合物聯網、大數據、人工智能等前沿技術&#xff0c;建立起覆蓋風險監測、預警預測、指揮調度、決策支持的全鏈條安全管理體系。 一…

桃芯ingchips——windows HID鍵盤例程無法同時連接兩個,但是安卓手機可以的問題

目錄 環境 現象 原理及解決辦法 環境 PC&#xff1a;windows11 安卓&#xff1a;Android14 例程使用的是HID Keyboard&#xff0c;板子使用的是91870CQ的開發板&#xff0c;DB870CC1A 現象 連接安卓手機時并不會出現該現象&#xff0c;兩個開發板都可以當做鍵盤給手機發按…

JavaScript - JavaScript 運算符之圓括號運算符與方括號運算符(圓括號運算符概述、圓括號運算符用法、方括號運算符概述、方括號運算符用法)

一、圓括號運算符概述 圓括號運算符&#xff08;()&#xff09;主要用于函數調用、表達式分組、多種語法結構登 二、圓括號運算符用法 調用函數 function greet() {console.log("Hello!"); }greet();# 輸出結果Hello!當箭頭函數有多個參數或零個參數時需要括號 c…

AG-UI 協議:重構多模態交互,開啟智能應用新紀元

一、協議誕生的時代背景&#xff1a;填補 AI 生態最后一塊拼圖 在人工智能技術飛速發展的今天&#xff0c;AI 代理&#xff08;Agent&#xff09;作為能夠主動執行復雜任務的智能實體&#xff0c;正從實驗室走向生產環境&#xff0c;重塑各個行業的工作流程。然而&#xff0c;…

嵌入式學習的第二十天-數據結構-調試+鏈表的一般操作

一、調試 1.一般調試 2.找段錯誤 二、鏈表的一般操作 1.單鏈表的修改 int ModifyLinkList(LinkList*ll,char*name,DATATYPE*data) {DATATYPE * tmp FindLinkList(ll, name);if(NULL tmp){return 1;}memcpy(tmp,data,sizeof(DATATYPE));return 0; } 2.單鏈表的銷毀 int D…

如何同時管理不同平臺的多個賬號?

在當今數字營銷、電商運營、跨境貿易盛行的時代&#xff0c;同時管理多個平臺的賬號幾乎成了從業者的標配。無論是做社媒營銷的廣告主&#xff0c;還是操作亞馬遜、eBay、Shopee 等平臺的跨境賣家&#xff0c;多賬號運營都是提升曝光、分散風險、擴大收益的重要方式。 然而&am…

STM32外設AD/DA-基礎及CubeMX配置

STM32外設AD/DA-基礎及CubeMX配置 一&#xff0c;什么是AD/DA二&#xff0c;基礎概念1&#xff0c;模擬 vs 數字2&#xff0c;AD轉換1&#xff0c;分辨率 (Resolution)2&#xff0c;參考電壓 (Reference Voltage, Vref)3&#xff0c;采樣率 (Sampling Rate) 3&#xff0c;DA轉換…

【軟考 霍夫曼編碼的文檔壓縮比】

霍夫曼編碼的文檔壓縮比計算基于字符頻率的最優編碼分配&#xff0c;以下是詳細步驟及相關案例&#xff1a; 一、壓縮比計算公式 [ \text{壓縮比} \frac{\text{壓縮前總比特數}}{\text{壓縮后總比特數 編碼表存儲開銷}} ] 通常以 比率&#xff08;如 3:1&#xff09; 或 百分…

關閉VSCode 自動更新

參考&#xff1a;關閉VSCode 自動更新_vscode關閉自動更新-CSDN博客 vscode的設置 Update: Mode Update: Enable Windows Background Updates Extensions: Auto Check Updates Extensions: Auto Update

Flask框架搭建

1、安裝Flask 打開終端運行以下命令&#xff1a; pip install Flask 2、創建項目目錄 在Windows上&#xff1a; venv\Scripts\activate 執行 3、創建 app.py 文件 可以在windows終端上創建app.py文件 &#xff08;1&#xff09;終端中創建 使用echo命令 echo "fr…

5G-A和未來6G技術下的操作系統與移動設備變革:云端化與輕量化的發展趨勢

目錄 5G技術帶來的革命性變革 云端化操作系統的實現路徑 完全云端化模式 過渡性解決方案 未來操作系統的發展方向 功能架構演進 安全機制強化 移動設備的形態變革 終端設備輕量化 物聯網設備簡化 實施挑戰與應對策略 技術挑戰 商業模式創新 總結與展望 5G技術作為…

【漫話機器學習系列】261.工具變量(Instrumental Variables)

工具變量&#xff08;Instrumental Variables&#xff09;通俗圖解&#xff1a;破解內生性困境的利器 在數據建模與因果推斷過程中&#xff0c;我們經常遇到一個棘手問題&#xff1a;內生性&#xff08;Endogeneity&#xff09;。它會導致模型估計產生偏差&#xff0c;進而誤導…

CSS:顏色的三種表示方式

文章目錄 一、rgb和rgba方式二、HEX和HEXA方式&#xff08;推薦&#xff09;三、hsl和hsla方式四、顏色名方式 一、rgb和rgba方式 10進制表示方法 二、HEX和HEXA方式&#xff08;推薦&#xff09; 就是16進制表示法 三、hsl和hsla方式 語法&#xff1a;hsl(hue, satura…

支付寶授權登錄

支付寶授權登錄 一、場景 支付寶小程序登錄&#xff0c;獲取用戶userId 二、注冊支付寶開發者賬號 1、支付寶開放平臺 2、點擊右上角–控制臺&#xff0c;創建小程序 3、按照步驟完善信息&#xff0c;生成密鑰時會用到的工具 4、生成的密鑰&#xff0c;要保管好&#xff…

涂色不踩雷:如何優雅解決 LeetCode 柵欄涂色問題

文章目錄 摘要描述例子&#xff1a; 題解答案&#xff08;Swift&#xff09;題解代碼分析動態規劃核心思路初始條件 示例測試及結果示例 1&#xff1a;示例 2&#xff1a;示例 3&#xff1a; 時間復雜度空間復雜度總結實際場景聯系 摘要 在用戶體驗和界面設計中&#xff0c;顏…

GEE計算 RSEI(遙感生態指數)

&#x1f6f0;? 什么是 RSEI&#xff1f;為什么要用它評估生態環境&#xff1f; RSEI&#xff08;遙感生態指數&#xff0c;Remote Sensing Ecological Index&#xff09; 是一種通過遙感數據計算得到的、綜合反映區域生態環境質量的指標體系。 它的設計初衷是用最少的變量&…

圖像處理:預覽并繪制圖像細節

前言 因為最近在搞畢業論文的事情&#xff0c;要做出一下圖像細節對比圖&#xff0c;所以我這里寫了兩個腳本&#xff0c;一個用于框選并同時預覽圖像放大細節&#xff0c;可顯示并返回框選圖像的坐標&#xff0c;另外一個是輸入框選圖像的坐標并將放大的細節放置在圖像中&…

基于javaweb的SSM駕校管理系統設計與實現(源碼+文檔+部署講解)

技術范圍&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬蟲、數據可視化、小程序、安卓app、大數據、物聯網、機器學習等設計與開發。 主要內容&#xff1a;免費功能設計、開題報告、任務書、中期檢查PPT、系統功能實現、代碼編寫、論文編寫和輔導、論文…

限制 MySQL 服務只能被內網 `192.168.1.*` 網段的設備訪問

1. 修改 MySQL 配置文件 MySQL 默認監聽所有網絡接口(0.0.0.0),需要將其綁定到內網 IP 地址或限制訪問范圍。 (1)編輯 MySQL 配置文件 找到 MySQL 的主配置文件,通常是 /etc/my.cnf 或 /etc/mysql/my.cnf。使用文本編輯器打開: sudo vi /etc/my.cnf(2)設置 bind-a…