目錄
一、引入依賴
二、配置文件
三、Controller層
四、Service層
五、相關(guān)工具類
由于服務(wù)在內(nèi)網(wǎng)部署,需要使用ftp服務(wù)器管理文件,總結(jié)如下
一、引入依賴
<!-- https://mvnrepository.com/artifact/commons-net/commons-net -->
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.9.0</version>
</dependency>
<!-- hutool -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.22</version>
</dependency>
Tip:使用commons-net 3.9.0版本,之前的版本有漏洞
二、配置文件
ftp:
basePath: /
host: 192.168.1.100
httpPath: ftp://192.168.1.100
password: demo
port: 21
username: demo
配置文件類:
package com.example.demo.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
/**
* @Author: meng
* @Description: ftp配置
* @Date: 2023/6/30 13:44
* @Version: 1.0
*/
@Data
@Component
@ConfigurationProperties(prefix = "ftp")
public class FtpProperties {
/**
* ftp服務(wù)器的地址
*/
private String host;
/**
* ftp服務(wù)器的端口號(連接端口號)
*/
private String port;
/**
* ftp的用戶名
*/
private String username;
/**
* ftp的密碼
*/
private String password;
/**
* ftp上傳的根目錄
*/
private String basePath;
/**
* 回顯地址
*/
private String httpPath;
}
三、Controller層
Tip:Response為通用返回類,不熟悉的可以看這篇文章:Springboot - 通用返回類BaseResults_W_Meng_H的博客-CSDN博客BaseResults類public class BaseResults { private Integer code; private String message; private T data; public BaseResults() { super(); } public BaseResu...https://blog.csdn.net/W_Meng_H/article/details/104995823文章來源:http://www.zghlxwxcb.cn/news/detail-518759.html
package com.example.demo.controller;
import com.example.demo.service.FtpService;
import com.template.common.core.data.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Author: meng
* @Description: 文件服務(wù)
* @Date: 2023/6/30 14:33
* @Version: 1.0
*/
@RestController
@RequestMapping("/file")
public class FileController {
@Autowired
private FtpService ftpService;
// 單上傳文件
@PostMapping(value = "upload", consumes = "multipart/*", headers = "content-type=multipart/form-data")
public Response uploadFile(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
return ftpService.uploadMultipartFile(file, request);
}
// 導(dǎo)出文件
@GetMapping(value = "download")
public void downloadFile(@RequestParam String fileName, @RequestParam String ftpFilePath, HttpServletResponse response) {
ftpService.downloadFileToFtp(fileName, ftpFilePath, response);
}
// 刪除文件
@GetMapping(value = "delete")
public Response deleteFile(@RequestParam String ftpFilePath) {
return ftpService.deleteFileToFtp(ftpFilePath);
}
}
四、Service層
package com.example.demo.service;
import com.template.common.core.data.Response;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Author: meng
* @Description: ftp服務(wù)類
* @Date: 2023/6/30 13:46
* @Version: 1.0
*/
public interface FtpService {
/**
* 上傳文件到ftp
* @param multipartFile
* @param request
* @return
*/
public Response uploadMultipartFile(MultipartFile multipartFile, HttpServletRequest request);
/**
* 下載ftp文件,直接轉(zhuǎn)到輸出流
* @param fileName
* @param ftpFilePath
* @param response
*/
public void downloadFileToFtp(String fileName, String ftpFilePath, HttpServletResponse response);
/**
* 刪除ftp文件
* @param ftpFilePath ftp下文件路徑,根目錄開始
* @return
*/
Response deleteFileToFtp(String ftpFilePath);
}
實(shí)現(xiàn)類:文章來源地址http://www.zghlxwxcb.cn/news/detail-518759.html
package com.example.demo.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.example.demo.config.FtpProperties;
import com.example.demo.service.FtpService;
import com.example.demo.tools.FileUtils;
import com.template.common.core.data.Response;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.Date;
/**
* @Author: meng
* @Description: ftp服務(wù)類
* @Date: 2023/6/30 13:47
* @Version: 1.0
*/
@Service
public class FtpServiceImpl implements FtpService {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private FtpProperties ftpProperties;
// 方式一
@Override
public Response uploadMultipartFile(MultipartFile multipartFile, HttpServletRequest request) {
if (multipartFile == null || multipartFile.isEmpty()) {
return Response.error("沒有上傳文件");
}
//1、獲取原文件后綴名
String originalFileName = multipartFile.getOriginalFilename();
String suffix = originalFileName.substring(originalFileName.lastIndexOf('.'));
//2、使用UUID生成新文件名
String newFileName = IdUtil.fastSimpleUUID();
//3、將MultipartFile轉(zhuǎn)化為File
File file = null;
try {
// file = FileUtils.multipartFileToFile(multipartFile);
flag = uploadFileToFtp(multipartFile.getInputStream(), newFileName + suffix, today, ftpClient);
} catch (Exception e) {
logger.error("文件上傳失敗:", e);
return Response.error("文件上傳失敗");
}
if (ObjectUtil.isNull(file)) {
return Response.error("文件上傳失敗");
}
//當(dāng)前日期字符串
String today = File.separator + DateUtil.format(new Date(), "yyyyMMdd");
Boolean flag = uploadFileToFtp(file, newFileName + suffix, today);
if (!flag) {
return Response.error("文件上傳失敗");
}
System.out.println(file.toURI());
File f = new File(file.toURI());
f.delete();
String filePath = ftpProperties.getHttpPath() + today + File.separator + newFileName + suffix;
return Response.success(filePath);
}
// 方式二
public Response uploadMultipartFile2(MultipartFile multipartFile, HttpServletRequest request) {
FTPClient ftpClient = connectFtpServer();
if (multipartFile == null || multipartFile.isEmpty()) {
return R.error(Constants.FILE_EMPTY);
}
//獲取原文件后綴名
String originalFileName = multipartFile.getOriginalFilename();
String suffix = originalFileName.substring(originalFileName.lastIndexOf('.'));
//使用UUID生成新文件名
String newFileName = IdUtil.fastSimpleUUID();
//當(dāng)前日期字符串
String today = separator + DateUtil.date().toString(DATE_FORMAT);
Boolean flag = false;
try {
flag = uploadFileToFtp(multipartFile.getInputStream(), newFileName + suffix, today, ftpClient);
} catch (Exception e) {
logger.error("文件上傳失敗:", e);
}
if (!flag) {
logger.info("文件上傳失敗");
return R.error("文件上傳失敗");
}
String filePath = ftpProperties.getHttpPath() + today + File.separator + newFileName + suffix;
return Response.success(filePath);
}
public Boolean uploadFileToFtp(File file, String fileName, String filePath) {
logger.info("調(diào)用文件上傳接口");
// 定義保存結(jié)果
boolean iaOk = false;
// 初始化連接
FTPClient ftp = connectFtpServer();
if (ftp != null) {
try {
// 設(shè)置文件傳輸模式為二進(jìn)制,可以保證傳輸?shù)膬?nèi)容不會被改變
ftp.setFileType(FTP.BINARY_FILE_TYPE);
ftp.enterLocalPassiveMode(); //注:上傳文件都為0字節(jié),設(shè)置為被動(dòng)模式即可
// 跳轉(zhuǎn)到指定路徑,逐級跳轉(zhuǎn),不存在的話就創(chuàng)建再進(jìn)入
toPathOrCreateDir(ftp, filePath);
InputStream inputStream = new FileInputStream(file);
// 上傳文件 參數(shù):上傳后的文件名,輸入流,,返回Boolean類型,上傳成功返回true
iaOk = ftp.storeFile(fileName, inputStream);
// 關(guān)閉輸入流
inputStream.close();
// 退出ftp
ftp.logout();
} catch (IOException e) {
logger.error(e.toString());
} finally {
if (ftp.isConnected()) {
try {
// 斷開ftp的連接
ftp.disconnect();
} catch (IOException ioe) {
logger.error(ioe.toString());
}
}
}
}
return iaOk;
}
@Override
public void downloadFileToFtp(String fileName, String ftpFilePath, HttpServletResponse response) {
FTPClient ftpClient = connectFtpServer();
try {
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
ftpClient.enterLocalPassiveMode();
// 設(shè)置文件ContentType類型,這樣設(shè)置,會自動(dòng)判斷下載文件類型
response.setContentType("application/x-msdownload");
// 設(shè)置文件頭:最后一個(gè)參數(shù)是設(shè)置下載的文件名并編碼為UTF-8
response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(fileName, "UTF-8"));
InputStream is = ftpClient.retrieveFileStream(ftpFilePath);
BufferedInputStream bis = new BufferedInputStream(is);
OutputStream out = response.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while ((len = bis.read(buf)) > 0) {
out.write(buf, 0, len);
}
out.flush();
out.close();
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
ftpClient.logout();
} catch (Exception e) {
logger.error("FTP文件下載失敗:", e);
} finally {
if (ftpClient.isConnected()) {
try {
ftpClient.disconnect();
} catch (IOException ioe) {
logger.error(ioe.toString());
}
}
}
}
@Override
public Response deleteFileToFtp(String ftpFilePath) {
FTPClient ftp = connectFtpServer();
boolean resu = false;
try {
resu = ftp.deleteFile(ftpFilePath);
ftp.logout();
} catch (Exception e) {
logger.error("FTP文件刪除失敗:{}", e);
return Response.error("文件刪除失敗");
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioe) {
logger.error(ioe.toString());
}
}
}
return Response.SUCCESS;
}
private FTPClient connectFtpServer() {
// 創(chuàng)建FTPClient對象(對于連接ftp服務(wù)器,以及上傳和上傳都必須要用到一個(gè)對象)
logger.info("創(chuàng)建FTP連接");
FTPClient ftpClient = new FTPClient();
// 設(shè)置連接超時(shí)時(shí)間
ftpClient.setConnectTimeout(1000 * 60);
// 設(shè)置ftp字符集
ftpClient.setControlEncoding("utf-8");
// 設(shè)置被動(dòng)模式,文件傳輸端口設(shè)置,否則文件上傳不成功,也不報(bào)錯(cuò)
ftpClient.enterLocalPassiveMode();
try {
// 定義返回的狀態(tài)碼
int replyCode;
// 連接ftp(當(dāng)前項(xiàng)目所部署的服務(wù)器和ftp服務(wù)器之間可以相互通訊,表示連接成功)
ftpClient.connect(ftpProperties.getHost());
// 輸入賬號和密碼進(jìn)行登錄
ftpClient.login(ftpProperties.getUsername(), ftpProperties.getPassword());
// 接受狀態(tài)碼(如果成功,返回230,如果失敗返回503)
replyCode = ftpClient.getReplyCode();
// 根據(jù)狀態(tài)碼檢測ftp的連接,調(diào)用isPositiveCompletion(reply)-->如果連接成功返回true,否則返回false
if (!FTPReply.isPositiveCompletion(replyCode)) {
logger.info("connect ftp {} failed", ftpProperties.getHost());
// 連接失敗,斷開連接
ftpClient.disconnect();
return null;
}
logger.info("replyCode:" + replyCode);
} catch (IOException e) {
logger.error("connect fail:" + e.toString());
return null;
}
return ftpClient;
}
private void toPathOrCreateDir(FTPClient ftp, String filePath) throws IOException {
String[] dirs = filePath.split("/");
for (String dir : dirs) {
if (StrUtil.isBlank(dir)) {
continue;
}
if (!ftp.changeWorkingDirectory(dir)) {
ftp.makeDirectory(dir);
ftp.changeWorkingDirectory(dir);
}
}
}
}
五、相關(guān)工具類
package com.example.demo.tools;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
/**
* @Author: meng
* @Description: 文件轉(zhuǎn)換工具類
* @Date: 2023/6/30 14:13
* @Version: 1.0
*/
public class FileUtils {
/**
* MultipartFile 轉(zhuǎn) File
* @param file
* @throws Exception
*/
public static File multipartFileToFile(MultipartFile file) throws Exception {
File toFile = null;
if(file.equals("")||file.getSize()<=0){
file = null;
}else {
InputStream ins = null;
ins = file.getInputStream();
toFile = new File(file.getOriginalFilename());
toFile = inputStreamToFile(ins, toFile);
ins.close();
}
return toFile;
}
private static File inputStreamToFile(InputStream ins, File file) {
try {
OutputStream os = new FileOutputStream(file);
int bytesRead = 0;
byte[] buffer = new byte[8192];
while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
ins.close();
return file;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
到了這里,關(guān)于SpringBoot-集成FTP(上傳、下載、刪除)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!