1.加入核心依赖
<dependency><groupId>commons-net</groupId><artifactId>commons-net</artifactId><version>3.8.0</version></dependency>
完整依赖
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>commons-net</groupId><artifactId>commons-net</artifactId><version>3.8.0</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency><!-- hutool --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.22</version></dependency></dependencies>
2.配置文件
ftp:host: 127.0.0.1port: 21username: rootpassword: root
3.FTP配置类
package com.example.config;import org.apache.commons.net.ftp.FTPClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @author lenovo*/
@Configuration
public class FTPConfig {@Value("${ftp.host}")private String host;@Value("${ftp.port}")private int port;@Value("${ftp.username}")private String username;@Value("${ftp.password}")private String password;@Beanpublic FTPClient ftpClient() {FTPClient ftpClient = new FTPClient();try {ftpClient.connect(host, port);ftpClient.login(username, password);ftpClient.enterLocalPassiveMode();} catch (Exception e) {e.printStackTrace();}return ftpClient;}
}
4.Service层
package com.example.service;import cn.hutool.crypto.digest.MD5;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;import java.io.*;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Objects;@Service
public interface FTPService {public boolean uploadFile(MultipartFile file) ;public boolean downloadFile(String remoteFilePath, String localFilePath);public boolean deleteFile(String remoteFilePath);}
实现类:
package com.example.service.impl;import com.example.service.FTPService;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Objects;@Service
public class FTPServiceImpl implements FTPService {@Autowiredprivate FTPClient ftpClient;@Overridepublic boolean uploadFile(MultipartFile file) {try {String remoteFilePath = "/w/n";ftpClient.enterLocalPassiveMode(); // 设置Passive ModeftpClient.setBufferSize(1024 * 1024); // 设置缓冲区大小为1MBftpClient.setFileType(FTP.BINARY_FILE_TYPE); // 设置传输模式为二进制createRemoteDirectory(ftpClient, remoteFilePath);// 切换工作目录boolean success = ftpClient.changeWorkingDirectory(remoteFilePath);if (!success) {System.out.println("切换工作目录失败:" + remoteFilePath);return false;}if (file.isEmpty()) {System.out.println("上传的文件为空");return false;}String s = md5(Objects.requireNonNull(file.getOriginalFilename()));success = ftpClient.storeFile(s, file.getInputStream());if (success) {System.out.println("文件上传成功");} else {System.out.println("文件上传失败");}return success;} catch (IOException e) {e.printStackTrace();System.out.println("文件上传失败:" + e.getMessage());return false;}}@Overridepublic boolean downloadFile(String remoteFilePath, String localFilePath) {try {boolean b = ftpClient.retrieveFile(remoteFilePath, Files.newOutputStream(Paths.get(localFilePath)));System.out.println(b);return b;} catch (IOException e) {e.printStackTrace();return false;}}@Overridepublic boolean deleteFile(String remoteFilePath) {try {return ftpClient.deleteFile(remoteFilePath);} catch (IOException e) {e.printStackTrace();return false;}}// 创建文件夹(多层也可创建) public void createRemoteDirectory(FTPClient ftpClient, String remotePath) throws IOException {String[] dirs = remotePath.split("/");String tempDir = "";for (String dir : dirs) {if (dir.isEmpty()) {continue;}tempDir += "/" + dir;if (!ftpClient.changeWorkingDirectory(tempDir)) {if (!ftpClient.makeDirectory(tempDir)) {throw new IOException("Failed to create remote directory: " + tempDir);}ftpClient.changeWorkingDirectory(tempDir);}}}private static String md5(String fileN) {try {MessageDigest md = MessageDigest.getInstance("MD5");byte[] digest = md.digest(fileN.getBytes());// 将字节数组转换为十六进制字符串StringBuilder str = new StringBuilder();for (byte b : digest) {str.append(String.format("%02x", b));}fileN = str.toString();} catch (NoSuchAlgorithmException e) {throw new RuntimeException(e);}return fileN;}
}
5.Controller层
package com.example.controller;import com.example.service.FTPService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;@RestController
@RequestMapping("/ftp")
public class FTPController {@Autowiredprivate FTPService ftpService;@PostMapping("/upload")public String uploadFile(MultipartFile file) {if (ftpService.uploadFile(file)) {return "File uploaded successfully!";} else {return "Failed to upload file!";}}@GetMapping("/download")public String downloadFile(String remoteFilePath, String localFilePath) {if (ftpService.downloadFile(remoteFilePath, localFilePath)) {return "File downloaded successfully!";} else {return "Failed to download file!";}}@DeleteMapping("/delete")public String deleteFile(@RequestParam String remoteFilePath) {if (ftpService.deleteFile(remoteFilePath)) {return "File deleted successfully!";} else {return "Failed to delete file!";}}
}
6.运行效果
以上就创建好了一个小demo,快去试试吧。