SpringBoot 使用 FTP 操作文件的過(guò)程(刪除、上傳、下載文件)
簡(jiǎn)介
使用 SpringBoot 配置 FTP 服務(wù)器,上傳、刪除、下載文件。
配置 FTP
檢查是否安裝 vsftpd
rpm -qa | grep vsftpd
檢修是否已經(jīng)安裝 vsftpd 及查看版本號(hào).
安裝 vsftpd
yum -y install vsftpd
如果報(bào)錯(cuò),則使用管理員權(quán)限執(zhí)行
sudo yum -y install vsftpd
關(guān)閉匿名訪問(wèn)
關(guān)閉匿名訪問(wèn)后,想訪問(wèn)里面的文件就需要賬號(hào)和密碼;如果不關(guān),就可以直接訪問(wèn)。
vim /etc/vsftpd/vsftpd.conf
如果提示是只讀文件,那么你只需要輸入命令:
sudo vim /etc/vsftpd/vsftpd.conf
如下:
# Example config file /etc/vsftpd/vsftpd.conf # # The default compiled in settings are fairly paranoid. This sample file # loosens things up a bit, to make the ftp daemon more usable. # Please see vsftpd.conf.5 for all compiled in defaults. # # READ THIS: This example file is NOT an exhaustive list of vsftpd options. # Please read the vsftpd.conf.5 manual page to get a full idea of vsftpd's # capabilities. # # Allow anonymous FTP? (Beware - allowed by default if you comment this out). anonymous_enable=NO # # Uncomment this to allow local users to log in. local_enable=YES # # Uncomment this to enable any form of FTP write command. write_enable=YES # # Default umask for local users is 077. You may wish to change this to 022, # if your users expect that (022 is used by most other ftpd's) local_umask=022 # # Uncomment this to allow the anonymous FTP user to upload files. This only # has an effect if the above global write enable is activated. Also, you will # obviously need to create a directory writable by the FTP user. # When SELinux is enforcing check for SE bool allow_ftpd_anon_write, allow_ftpd_full_access #anon_upload_enable=YES # # Uncomment this if you want the anonymous FTP user to be able to create # new directories. #anon_mkdir_write_enable=YES # # Activate directory messages - messages given to remote users when they # go into a certain directory. dirmessage_enable=YES # # Activate logging of uploads/downloads. xferlog_enable=YES # # Make sure PORT transfer connections originate from port 20 (ftp-data). connect_from_port_20=YES # # If you want, you can arrange for uploaded anonymous files to be owned by # a different user. Note! Using "root" for uploaded files is not # recommended! #chown_uploads=YES #chown_username=whoever # # You may override where the log file goes if you like. The default is shown # below. #xferlog_file=/var/log/xferlog # # If you want, you can have your log file in standard ftpd xferlog format. # Note that the default log file location is /var/log/xferlog in this case. xferlog_std_format=YES # # You may change the default value for timing out an idle session. #idle_session_timeout=600
關(guān)閉匿名訪問(wèn)就是將:anonymous_enable=NO
啟動(dòng)服務(wù)
systemctl start vsftpd.service
查看服務(wù)狀態(tài)
systemctl status vsftpd.service
[root@hadoop-master ~]# systemctl status vsftpd.service
● vsftpd.service - Vsftpd ftp daemon
Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; disabled; vendor preset: disabled)
Active: active (running) since 一 2022-12-19 10:15:39 CST; 58min ago
Process: 21702 ExecStart=/usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf (code=exited, status=0/SUCCESS)
Main PID: 21703 (vsftpd)
CGroup: /system.slice/vsftpd.service
└─21703 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf
12月 19 10:15:39 hadoop-master systemd[1]: Starting Vsftpd ftp daemon...
12月 19 10:15:39 hadoop-master systemd[1]: Started Vsftpd ftp daemon.
[root@hadoop-master ~]#看到綠色的
active(running),代表著啟動(dòng)成功正在運(yùn)行中。
添加 FTP 用戶
因?yàn)樵?Linux 上,root 用戶是不能登陸 FTP 的。如果你輸入的是 root 用戶,登陸會(huì)失敗的。
adduser ftpadmin
設(shè)置密碼:
passwd ftpadmin
輸入兩次密碼就 ok 了。
配置允許root用戶登錄
將 /etc/vsftpd/user_list 文件和 /etc/vsftpd/ftpusers 文件中的root這一行注釋掉
修改/etc/vsftpd/vsftpd.conf,在最后一行處添加local_root=/
service vsftpd restart
這樣遠(yuǎn)程就可以root用戶身份登錄ftp了。
文件存儲(chǔ)地址授權(quán)
如存儲(chǔ)地址為:app/upload/,設(shè)置權(quán)限為:
chmod 777 /app/upload/
SpringBoot 編碼
添加依賴
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>操作文件工具類
package com.demo.utils;
import com.jcraft.jsch.*;
import com.demo.dto.UploadFileDto;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Properties;
/**
* @ClassName: UploadFileUtils.java
* @Description: 上傳文件
* @Author: tanyp
* @Date: 2022/12/19 10:38
**/
@Slf4j
public class UploadFileUtils {
/**
* @MonthName: upload
* @Description: 上傳文件
* @Author: tanyp
* @Date: 2022/12/19 10:38
* @Param: [dto]
* @return: boolean
**/
public static boolean upload(UploadFileDto dto) throws Exception {
log.info("============上傳文件開始==============");
Boolean result = false;
ChannelSftp sftp = null;
Channel channel = null;
Session sshSession = null;
try {
JSch jSch = new JSch();
jSch.getSession(dto.getAccount(), dto.getHost(), dto.getPort());
sshSession = jSch.getSession(dto.getAccount(), dto.getHost(), dto.getPort());
sshSession.setPassword(dto.getPasswd());
Properties sshConfig = new Properties();
sshConfig.put("StrictHostKeyChecking", "no");
sshSession.setConfig(sshConfig);
sshSession.connect();
channel = sshSession.openChannel("sftp");
channel.connect();
sftp = (ChannelSftp) channel;
sftp.cd(dto.getWorkingDir());
sftp.put(dto.getInputStream(), dto.getFileName());
result = true;
log.info("============上傳文件結(jié)束==============");
} catch (JSchException e) {
result = false;
log.error("=====上傳文件異常:{}", e.getMessage());
e.printStackTrace();
} finally {
closeChannel(sftp);
closeChannel(channel);
closeSession(sshSession);
}
return result;
}
/**
* @MonthName: delete
* @Description: 刪除文件
* @Author: tanyp
* @Date: 2022/12/19 10:38
* @Param: [dto]
* @return: boolean
**/
public static boolean delete(UploadFileDto dto) throws Exception {
log.info("============刪除文件開始==============");
Boolean result = false;
ChannelSftp sftp = null;
Channel channel = null;
Session sshSession = null;
try {
JSch jSch = new JSch();
jSch.getSession(dto.getAccount(), dto.getHost(), dto.getPort());
sshSession = jSch.getSession(dto.getAccount(), dto.getHost(), dto.getPort());
sshSession.setPassword(dto.getPasswd());
Properties sshConfig = new Properties();
sshConfig.put("StrictHostKeyChecking", "no");
sshSession.setConfig(sshConfig);
sshSession.connect();
channel = sshSession.openChannel("sftp");
channel.connect();
sftp = (ChannelSftp) channel;
sftp.cd(dto.getWorkingDir());
sftp.rm(dto.getFileName());
result = true;
log.info("============刪除文件結(jié)束==============");
} catch (JSchException e) {
result = false;
log.error("=====刪除文件異常:{}", e.getMessage());
e.printStackTrace();
} finally {
closeChannel(sftp);
closeChannel(channel);
closeSession(sshSession);
}
return result;
}
/**
* @MonthName: download
* @Description: 下載文件
* @Author: tanyp
* @Date: 2022/12/19 10:38
* @Param: [dto]
* @return: boolean
**/
public static boolean download(UploadFileDto dto) throws Exception {
log.info("============下載文件開始==============");
Boolean result = false;
ChannelSftp sftp = null;
Channel channel = null;
Session sshSession = null;
try {
JSch jSch = new JSch();
jSch.getSession(dto.getAccount(), dto.getHost(), dto.getPort());
sshSession = jSch.getSession(dto.getAccount(), dto.getHost(), dto.getPort());
sshSession.setPassword(dto.getPasswd());
Properties sshConfig = new Properties();
sshConfig.put("StrictHostKeyChecking", "no");
sshSession.setConfig(sshConfig);
sshSession.connect();
channel = sshSession.openChannel("sftp");
channel.connect();
sftp = (ChannelSftp) channel;
sftp.cd(dto.getWorkingDir());
sftp.get(dto.getFileName(), new FileOutputStream(new File(dto.getDownloadPath())));
sftp.disconnect();
sftp.getSession().disconnect();
result = true;
log.info("============下載文件結(jié)束==============");
} catch (JSchException e) {
result = false;
log.error("=====下載文件異常:{}", e.getMessage());
e.printStackTrace();
} finally {
closeChannel(sftp);
closeChannel(channel);
closeSession(sshSession);
}
return result;
}
private static void closeChannel(Channel channel) {
if (channel != null) {
if (channel.isConnected()) {
channel.disconnect();
}
}
}
private static void closeSession(Session session) {
if (session != null) {
if (session.isConnected()) {
session.disconnect();
}
}
}
}
UploadFileDto.java
package com.demo.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.InputStream;
/**
* @ClassName: UploadFileDto.java
* @ClassPath: com.demo.dto.UploadFileDto.java
* @Description: 上傳文件
* @Author: tanyp
* @Date: 2022/12/19 10:38
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ApiModel(value = "上傳文件Dto")
public class UploadFileDto {
@ApiModelProperty(value = " ftp 服務(wù)器ip地址")
private String host;
@ApiModelProperty(value = " ftp 服務(wù)器port,默認(rèn)是21")
private Integer port;
@ApiModelProperty(value = " ftp 服務(wù)器用戶名")
private String account;
@ApiModelProperty(value = " ftp 服務(wù)器密碼")
private String passwd;
@ApiModelProperty(value = " ftp 服務(wù)器存儲(chǔ)圖片的絕對(duì)路徑")
private String workingDir;
@ApiModelProperty(value = "上傳到ftp 服務(wù)器文件名")
private String fileName;
@ApiModelProperty(value = " 文件流")
private InputStream inputStream;
@ApiModelProperty(value = " 下載文件的路徑")
private String downloadPath;
}
UploadVo.java
package com.demo.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @ClassName: UploadVo.java
* @ClassPath: com.demo.vo.UploadVo.java
* @Description: 文件VO
* @Author: tanyp
* @Date: 2022/12/19 15:18
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ApiModel(value = "文件VO")
public class UploadVo {
@ApiModelProperty(value = "原始文件名稱")
private String oldName;
@ApiModelProperty(value = "新文件名稱")
private String newName;
@ApiModelProperty(value = "訪問(wèn)路徑")
private String path;
}
UploadController
package com.demo.controller;
import com.demo.vo.UploadVo;
import com.demo.service.UploadService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
/**
* @ClassName: UploadController.java
* @ClassPath: com.demo.controller.UploadController.java
* @Description: 上傳文件
* @Author: tanyp
* @Date: 2022/12/19 15:18
**/
@Slf4j
@RestController
@RequestMapping("/upload")
@Api(value = "upload", tags = "上傳文件")
public class UploadController {
@Autowired
private UploadService uploadService;
@ApiOperation(value = "上傳圖片", notes = "上傳圖片")
@PostMapping("/uploadImage")
public UploadVo uploadImage(@RequestParam("file") MultipartFile file) {
return uploadService.uploadImage(file);
}
@ApiOperation(value = "刪除文件", notes = "刪除文件")
@GetMapping("/delFile")
public Boolean delFile(String fileName) {
return uploadService.delFile(fileName);
}
@ApiOperation(value = "下載文件", notes = "下載文件")
@GetMapping("/downloadFile")
public Boolean downloadFile(String fileName, String downloadPath) {
return uploadService.downloadFile(fileName, downloadPath);
}
}
UploadService
package com.demo.service;
import com.demo.vo.UploadVo;
import org.springframework.web.multipart.MultipartFile;
/**
* @ClassName: UploadService.java
* @ClassPath: com.demo.service.UploadService.java
* @Description:上傳文件
* @Author: tanyp
* @Date: 2022/12/19 15:18
**/
public interface UploadService {
UploadVo uploadImage(MultipartFile file);
Boolean delFile(String fileName);
Boolean downloadFile(String fileName, String downloadPath);
}UploadServiceImpl
package com.demo.service.impl;
import com.demo.dto.UploadFileDto;
import com.demo.vo.UploadVo;
import com.demo.config.FtpConfig;
import com.demo.service.UploadService;
import com.demo.utils.UUIDUtils;
import com.demo.utils.UploadFileUtils;
import com.demo.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Objects;
/**
* @ClassName: UploadServiceImpl.java
* @ClassPath: com.demo.service.impl.UploadServiceImpl.java
* @Description: 上傳文件
* @Author: tanyp
* @Date: 2022/12/19 15:18
**/
@Slf4j
@Service
public class UploadServiceImpl implements UploadService {
@Autowired
private FtpConfig ftpConfig;
@Override
public UploadVo uploadImage(MultipartFile file) {
log.info("=======上傳圖片開始,圖片名稱:{}", file.getOriginalFilename());
try {
// 1. 取原始文件名
String oldName = file.getOriginalFilename();
// 2. ftp 服務(wù)器的文件名
String newName = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + UUIDUtils.getUUID(10) + oldName.substring(oldName.lastIndexOf("."));
// 3.上傳圖片
Boolean result = UploadFileUtils.upload(
UploadFileDto.builder()
.host(ftpConfig.host)
.port(ftpConfig.post)
.account(ftpConfig.username)
.passwd(ftpConfig.password)
.workingDir(ftpConfig.basePath)
.fileName(newName)
.inputStream(file.getInputStream())
.build()
);
// 4.返回結(jié)果
if (!result) {
throw new BusinessException("上傳圖片失敗!");
}
log.info("=======上傳圖片結(jié)束,新圖片名稱:{}", newName);
return UploadVo.builder()
.oldName(oldName)
.newName(newName)
.path(ftpConfig.imageBaseUrl + "/" + newName)
.build();
} catch (Exception e) {
log.error("=======上傳圖片異常,異常信息:{}", e.getMessage());
e.printStackTrace();
}
return null;
}
@Override
public Boolean delFile(String fileName) {
if (Objects.isNull(fileName)) {
throw new BusinessException("文件名稱為空,請(qǐng)核實(shí)!");
}
try {
Boolean result = UploadFileUtils.delete(
UploadFileDto.builder()
.host(ftpConfig.host)
.port(ftpConfig.post)
.account(ftpConfig.username)
.passwd(ftpConfig.password)
.workingDir(ftpConfig.basePath)
.fileName(fileName)
.build()
);
return result;
} catch (Exception e) {
log.error("=======刪除文件異常,異常信息:{}", e.getMessage());
e.printStackTrace();
}
return null;
}
@Override
public Boolean downloadFile(String fileName, String downloadPath) {
if (Objects.isNull(fileName) || Objects.isNull(downloadPath)) {
throw new BusinessException("文件名稱或下載路徑為空,請(qǐng)核實(shí)!");
}
try {
Boolean result = UploadFileUtils.download(
UploadFileDto.builder()
.host(ftpConfig.host)
.port(ftpConfig.post)
.account(ftpConfig.username)
.passwd(ftpConfig.password)
.workingDir(ftpConfig.basePath)
.fileName(fileName)
.downloadPath(downloadPath)
.build()
);
return result;
} catch (Exception e) {
log.error("=======下載文件異常,異常信息:{}", e.getMessage());
e.printStackTrace();
}
return null;
}
}
FtpConfig
package com.demo.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @ClassName: FtpConfig.java
* @ClassPath: com.demo.config.FtpConfig.java
* @Description: FTP配置
* @Author: tanyp
* @Date: 2022/12/19 22:28
**/
@Component
public class FtpConfig {
// ftp 服務(wù)器ip地址
@Value("${ftp.host}")
public String host;
// ftp 服務(wù)器port,默認(rèn)是21
@Value("${ftp.post}")
public Integer post;
// ftp 服務(wù)器用戶名
@Value("${ftp.username}")
public String username;
// ftp 服務(wù)器密碼
@Value("${ftp.password}")
public String password;
// ftp 服務(wù)器存儲(chǔ)圖片的絕對(duì)路徑
@Value("${ftp.base-path}")
public String basePath;
// ftp 服務(wù)器外網(wǎng)訪問(wèn)圖片路徑
@Value("${ftp.image-base-url}")
public String imageBaseUrl;
}
application.yml
# ftp ftp: host: 127.0.0.1 post: 22 username: ftpadmin password: ftpadmin base-path: /app/upload/images image-base-url: http://127.0.0.1:8080/images
配置 Nginx
server {
listen 8080;
server_name localhost;
location /images/ {
root /app/upload/;
autoindex on;
}
}SpringBoot 使用 FTP 操作文件整合完成。
到此這篇關(guān)于SpringBoot 使用 FTP 操作文件的文章就介紹到這了,更多相關(guān)SpringBoot FTP 操作文件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
IDEA2020.1創(chuàng)建springboot項(xiàng)目(國(guó)內(nèi)腳手架)安裝lombok
這篇文章主要介紹了IDEA2020.1創(chuàng)建springboot項(xiàng)目(國(guó)內(nèi)腳手架)安裝lombok,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06
Spring事件監(jiān)聽器@EventListener與publishEvent的使用
Spring可以通過(guò)事件監(jiān)聽器機(jī)制來(lái)處理應(yīng)用程序中的事件,本文主要介紹了Spring事件監(jiān)聽器@EventListener與publishEvent的使用,具有一定的參考價(jià)值,感興趣的可以了解一下2024-06-06
SpringMvc @RequestParam 使用推薦使用包裝類型代替包裝類型
這篇文章主要介紹了SpringMvc @RequestParam 使用推薦使用包裝類型代替包裝類型,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-02-02
Java數(shù)據(jù)結(jié)構(gòu)與算法之二分查找詳解
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)與算法之二分查找詳解,二分查找算法是一種在有序數(shù)組中查找某一特定元素的搜索算法,其思想就是不斷地將有序查找表“一分為二”,逐漸縮小搜索區(qū)域,進(jìn)而找到目標(biāo)元素,需要的朋友可以參考下2023-12-12

