Spring Integration FTP/FTPS Adapters
简介
Spring 官方为 FTP 和 FTPS 文件传输提供了插件。
使用方式
引入依赖:
1 2 3 4 5
| <dependency> <groupId>org.springframework.integration</groupId> <artifactId>spring-integration-ftp</artifactId> <version>6.0.0</version> </dependency>
|
编写链接配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPFile; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.integration.file.remote.session.CachingSessionFactory; import org.springframework.integration.file.remote.session.SessionFactory; import org.springframework.integration.ftp.session.DefaultFtpSessionFactory; import org.springframework.integration.ftp.session.FtpRemoteFileTemplate; import org.springframework.integration.ftp.session.FtpSession;
@Configuration public class FTPConfiguration {
@Bean public SessionFactory<FTPFile> ftpSessionFactory() { DefaultFtpSessionFactory sf = new DefaultFtpSessionFactory() { @Override public synchronized FtpSession getSession() { return super.getSession(); } }; sf.setHost("xxx.xxx.xxx.xxx"); sf.setPort(21); sf.setUsername("xxx"); sf.setPassword("xxx"); sf.setControlEncoding("UTF-8"); sf.setFileType(FTP.BINARY_FILE_TYPE); sf.setClientMode(FTPClient.PASSIVE_LOCAL_DATA_CONNECTION_MODE); CachingSessionFactory<FTPFile> csf = new CachingSessionFactory<>(sf); csf.setPoolSize(1); return csf; }
@Bean public FtpRemoteFileTemplate ftpRemoteFileTemplate(@Qualifier("ftpSessionFactory") SessionFactory<FTPFile> sessionFactory) { FtpRemoteFileTemplate ftpRemoteFileTemplate = new FtpRemoteFileTemplate(sessionFactory); ExpressionParser parser = new SpelExpressionParser(); ftpRemoteFileTemplate.setRemoteDirectoryExpression(parser.parseExpression("''")); ftpRemoteFileTemplate.setExistsMode(FtpRemoteFileTemplate.ExistsMode.STAT); return ftpRemoteFileTemplate; }
}
|
注:在使用匿名模式时将用户设为 “anonymous” 密码设为 “” 即可。
编写业务类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
| import lombok.extern.slf4j.Slf4j; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPFile; import org.springframework.http.ResponseEntity; import org.springframework.integration.file.support.FileExistsMode; import org.springframework.integration.ftp.session.FtpRemoteFileTemplate; import org.springframework.messaging.support.GenericMessage; import org.springframework.util.FileCopyUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile;
import jakarta.annotation.Resource; import javax.servlet.http.HttpServletResponse; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.file.FileSystems; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors;
@Slf4j @RestController @RequestMapping("/test") public class TestController {
@Resource FtpRemoteFileTemplate ftpRemoteFileTemplate;
@GetMapping public ResponseEntity<List<FTPFile>> ls(@RequestParam String path) { FTPFile[] result = ftpRemoteFileTemplate.list(path); return ResponseEntity.ok(Arrays.stream(result).collect(Collectors.toList())); }
@GetMapping public ResponseEntity<Boolean> check(@RequestParam String path) { return ResponseEntity.ok(ftpRemoteFileTemplate.exists(path)); }
@GetMapping("/read") public ResponseEntity<String> read(@RequestParam String path) { if (!ftpRemoteFileTemplate.exists(path)) { throw new RuntimeException("file not exist"); } final ByteArrayOutputStream cache = new ByteArrayOutputStream(); boolean success = ftpRemoteFileTemplate.get(path, stream -> FileCopyUtils.copy(stream, cache)); if (success) { return ResponseEntity.ok(cache.toString()); } else { throw new RuntimeException("file not exist"); } }
@GetMapping("/download") public void download(@RequestParam String path, HttpServletResponse httpServletResponse) { if (!ftpRemoteFileTemplate.exists(path)) { throw new RuntimeException("file not exist"); } FTPFile file = ftpRemoteFileTemplate.list(path)[0]; if (file.isDirectory()) { throw new RuntimeException("path is directory"); } httpServletResponse.reset(); httpServletResponse.setContentType("application/octet-stream;charset=utf-8"); httpServletResponse.setHeader( "Content-disposition", "attachment; filename=" + file.getName()); OutputStream out; try { out = httpServletResponse.getOutputStream(); } catch (IOException e) { throw new RuntimeException("outputStream error"); } boolean success = ftpRemoteFileTemplate.get(path, stream -> FileCopyUtils.copy(stream, out)); if (!success) { throw new RuntimeException("copy error"); } }
@PostMapping public Boolean write(@RequestParam MultipartFile file, @RequestParam String path) { String dest = FileSystems.getDefault().getPath(path, file.getOriginalFilename()).toString(); Session<FTPFile> session = ftpRemoteFileTemplate.getSession(); session.write(file.getInputStream(), dest); session.close(); return true; }
@PutMapping public Boolean mkdir(@RequestParam String path) { try { return ftpRemoteFileTemplate.getSession().mkdir(path); } catch (IOException e) { throw new RuntimeException(e); } }
@DeleteMapping public Boolean delete(@RequestParam String path) throws IOException { if (!ftpRemoteFileTemplate.exists(path)) { throw new RuntimeException("file or directory not exist"); } FTPFile[] files = ftpRemoteFileTemplate.list(path); if (files.length == 0) { return ftpRemoteFileTemplate.getSession().rmdir(path); } else if (files.length == 1) { FTPClient ftpClient = (FTPClient) ftpRemoteFileTemplate.getSession().getClientInstance(); if (ftpClient.deleteFile(path)) { return true; } else { throw new RuntimeException("directory not empty"); } } else { throw new RuntimeException("directory not empty"); } } }
|
注:此处代码并没有详细进行完善,使用时请注意。
编写测试类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| ### mkdir PUT http://localhost:8080/test?path=demo
### upload file POST http://localhost:8080/test Content-Type: multipart/form-data; boundary=WebAppBoundary
--WebAppBoundary Content-Disposition: form-data; name="file"; filename="demo.txt"
< ./demo.txt --WebAppBoundary-- Content-Disposition: form-data; name="path"
demo --WebAppBoundary--
### ls GET http://localhost:8080/test?path=/
### cat GET http://localhost:8080/test/read?path=demo/demo.txt
### download GET http://localhost:8080/test/download?path=demo/demo.txt
### rm DELETE http://localhost:8080/test?path=demo
|
参考文档
官方手册