手把手教学 Springboot+ftp+下载图片
简单教学,复制即用的Ftp下载图片
引入配置包
<dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.1</version></dependency><dependency><groupId>commons-net</groupId><artifactId>commons-net</artifactId><version>3.9.0</version></dependency>
首先创建连接客户端,中间如果赋值进去找不到变量,则是自己需要配置的 ,比如host:则表示主机ip
public FTPClient connFtp() {FTPClient ftpClient = null;String errorMsg = null;try {ftpClient = new FTPClient();//设置连接超时时间ftpClient.setConnectTimeout(1000 * 30);// 连接FTP服务器if (port == 0) {ftpClient.connect(host);} else {ftpClient.connect(host, port);}// 登陆FTP服务器ftpClient.login(user, pwd);// 中文支持 ,避免图片或文件中文乱码ftpClient.setControlEncoding("GBK"); FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);conf.setServerLanguageCode("zh");// 设置文件类型为二进制(如果从FTP下载或上传的文件是压缩文件的时候,不进行该设置可能会导致获取的压缩文件解压失败)ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {ftpClient.disconnect();Assert.isTrue(false, ERROR_CONN + "用户名或密码错误");} else {log.info("FTP连接成功!");}} catch (Exception e) {log.info("登陆FTP失败,请检查FTP相关配置信息是否正确!" + e);Assert.isTrue(false, ERROR_CONN + e.getMessage());return null;}return ftpClient;}
// deviceId :其实这个是文件名,拼接的,只是我们这以这个id存的文件名,所以用这个
// batch 主要是判断是否需要批量
@Overridepublic List<MultipartFile> getFtpImage(String deviceId, boolean batch) {FTPClient ftpClient = connFtp();String imgUrl = null;List<MultipartFile> fileList = new ArrayList<>();try {String path = null;String filename = null;//指定文件路径 和 路径下的文件名path = "/5/panorama/";filename = "5_"+deviceId+".jpg";//这一步很重要,主要是类似打开目录,ftpClient.changeWorkingDirectory(path);if(batch){FTPFile[] ftpFiles = ftpClient.listFiles();//获取目录下面文件列表,在下面for (int i =0;i<ftpFiles.length;i++){FTPFile ftpFile = ftpFiles[i];if (ftpFile.getName().equals(filename)) {// 此处表示直接返回到浏览器下载,需要添加参数 HttpServletResponse// response.setHeader("Content-disposition","attachment;filename="+ URLEncoder.encode(filename, "utf-8"));// 将文件保存到输出流outputStream中//ftpClient.retrieveFile(new String(ftpFile.getName().getBytes("GBK"), "ISO-8859-1"), outputStream);// ftpclient自带方法 将图片转换成 inputStream InputStream inputStream = ftpClient.retrieveFileStream(new String(ftpFile.getName().getBytes("GBK"), "ISO-8859-1"));MultipartFile multipartFile = FileUtil.getMultipartFile(inputStream, filename);fileList.add(multipartFile);inputStream.close();System.out.println("ftp获取图片成功。。。。");}}}else {InputStream inputStream = ftpClient.retrieveFileStream(new String(filename.getBytes("GBK"), "ISO-8859-1"));MultipartFile multipartFile = FileUtil.getMultipartFile(inputStream, filename);//如果想直接上传的话 到这里就可以调用上传方法了fileList.add(multipartFile);inputStream.close();System.out.println("ftp获取图片成功。。。。");}ftpClient.logout();} catch (UnsupportedEncodingException ex) {throw new RuntimeException(ex);} catch (IOException ex) {throw new RuntimeException(ex);}finally {if (ftpClient.isConnected()) {try {ftpClient.disconnect();} catch (IOException ioe) {}}}return fileList;}
获取指定目录下的文件列表
public List<String> getFileNameList(String ftpDirPath) {FTPClient ftpClient = connFtp();List<String> list = new ArrayList();try {// 通过提供的文件路径获取FTPFile对象列表FTPFile[] files = ftpClient.listFiles(ftpDirPath);for (int i = 0; i < files.length; i++) {FTPFile ftpFile = files[i];if (ftpFile.isFile()) {list.add(ftpFile.getName());}}ftpClient.logout();} catch (IOException e) {log.error("错误" + e);}finally {if (ftpClient.isConnected()) {try {ftpClient.disconnect();} catch (IOException ioe) {}}}return list;}
以下这个方法主要是判断,目录下是否有这个文件,用于某个文件主要判断是否需要录取文件流
/*** 判断ftp服务器文件是否存在** @param ftpClient* @param path* @return* @throws IOException*/private static boolean existFile(FTPClient ftpClient, String path) throws IOException {boolean flag = false;FTPFile[] ftpFileArr = ftpClient.listFiles(path);if (ftpFileArr.length > 0) {flag = true;}return flag;}
后续即是扩展内容,将文件流转换成MultipartFile ,剩下的就是正常上传业务逻辑了
import org.apache.commons.fileupload.FileItem;import org.apache.commons.fileupload.FileItemFactory;import org.apache.commons.fileupload.disk.DiskFileItem;import org.apache.commons.fileupload.disk.DiskFileItemFactory;/*** 获取封装得MultipartFile** @param inputStream inputStream* @param fileName fileName* @return MultipartFile*/public static MultipartFile getMultipartFile(InputStream inputStream, String fileName) {FileItem fileItem = createFileItem(inputStream, fileName);//CommonsMultipartFile是feign对multipartFile的封装,但是要FileItem类对象return new CommonsMultipartFile(fileItem);}/*** FileItem类对象创建** @param inputStream inputStream* @param fileName fileName* @return FileItem*/public static FileItem createFileItem(InputStream inputStream, String fileName) {FileItemFactory factory = new DiskFileItemFactory(16, null);String textFieldName = "file";FileItem item = factory.createItem(textFieldName, MediaType.MULTIPART_FORM_DATA_VALUE, true, fileName);int bytesRead = 0;byte[] buffer = new byte[8192];OutputStream os = null;//使用输出流输出输入流的字节try {os = item.getOutputStream();while ((bytesRead = inputStream.read(buffer, 0, 8192)) != -1) {os.write(buffer, 0, bytesRead);}inputStream.close();} catch (IOException e) {log.error("Stream copy exception", e);throw new IllegalArgumentException("文件上传失败");} finally {if (os != null) {try {os.close();} catch (IOException e) {log.error("Stream close exception", e);}}if (inputStream != null) {try {inputStream.close();} catch (IOException e) {log.error("Stream close exception", e);}}}return item;}
总结起来,开发中主要遇到的问题:
1,文件命名不规范,导致拉取失败
2,文件中文乱码,导致找不到
有不懂的或理解不到的,可以留言,相互探讨