如何实现ftp的文件上传于下载
第一步准备一个ftp服务器;
最基本的ftp文件夹下应该有public的文件和private的文件,一般公开的文件是直接从浏览器中访问的,而私有的文件是必须通过ftp的方式和下载,基于此逻辑,就需要给到http网址;
第二步准备导入maven:
<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.4</version></dependency>
第三步导入当前代码
package com.yuxin.yijia.utils.ftp;import org.apache.commons.io.FileUtils;import org.apache.commons.net.ftp.FTP;import org.apache.commons.net.ftp.FTPClient;import org.apache.commons.net.ftp.FTPReply;import org.springframework.core.io.ClassPathResource;import org.springframework.core.io.Resource;import org.springframework.core.io.support.PropertiesLoaderUtils;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.util.Properties;public class FileFtpUtil {private String ftpIp;private int port;private String username;private String password;private String baseUrl;private Resource resource = new ClassPathResource("yijia.properties");private FileFtpUtil() {//读取try {Properties props = PropertiesLoaderUtils.loadProperties(resource);ftpIp = props.getProperty("ftpIp");port = Integer.parseInt(props.getProperty("port", "21"));username = props.getProperty("username");password = props.getProperty("password");baseUrl = props.getProperty("baseUrl", "/image");} catch (Exception e) {System.err.println("ftp配置初始化失败,原因:" + e);e.printStackTrace();}}public static FileFtpUtil getInstance() {return Inner.instance;}private static class Inner {private static final FileFtpUtil instance = new FileFtpUtil();}/*** @param file 需要上传的文件* @param filename 上传的----文件名.后缀 例:c.png 不带路径* @param path 文件路径,如果没有此路径则会创建文件夹* @throws IOException*/public boolean picreate(File file, String filename, String path) throws IOException {//创建一个FtpClient对象FTPClient ftpClient = new FTPClient();//创建ftp连接,默认是:21端口ftpClient.connect(ftpIp, port);//登录ftp服务器,使用用户名 和密码ftpClient.login(username, password);ftpClient.setFileType(FTP.BINARY_FILE_TYPE);int reply;// 获取ftp登录应答代码reply = ftpClient.getReplyCode();// 验证是否登陆成功if (!FTPReply.isPositiveCompletion(reply)) {ftpClient.disconnect();System.err.println("FTP server refused connection.");}//上传文件//读取本地文件FileInputStream inputStream = new FileInputStream(file);//设置上传的路径if (!path.startsWith("/"))path = "/" + path;if (!baseUrl.startsWith("/"))baseUrl = "/" + baseUrl;path = baseUrl + path;// String fullpath = "ftp://" + ftpIp + ":" + port + path;String d;try {//目录编码,解决中文路径问题d = new String(path.toString().getBytes("GBK"), "iso-8859-1");//尝试切入目录if (!ftpClient.changeWorkingDirectory(d)) {String[] arr = path.split("/");StringBuffer sbfDir = new StringBuffer();//循环生成子目录for (String s : arr) {if (s == null || s.trim().equals(""))continue;sbfDir.append("/");sbfDir.append(s);//目录编码,解决中文路径问题d = new String(sbfDir.toString().getBytes("GBK"), "iso-8859-1");//尝试切入目录if (ftpClient.changeWorkingDirectory(d))continue;if (!ftpClient.makeDirectory(d)) {System.out.println("[失败]ftp创建目录:" + sbfDir.toString());ftpClient.logout();return false;}System.out.println("[成功]创建ftp目录:" + sbfDir.toString());}//将目录切换至指定路径if (!ftpClient.changeWorkingDirectory(d)) {//切换到指定目录ftpClient.logout();return false;}}} catch (Exception e) {e.printStackTrace();ftpClient.logout();return false;}//修改上传文件的格式//第一个参数:服务器端文档名//第二个参数:上传文档的inputStreamboolean res = ftpClient.storeFile(filename, inputStream);System.out.println("上传文件" + filename + ":" + res);//关闭连接ftpClient.logout();return true;}/*** @param httpUrl 文件的网络地址,请确定是上传到ftp上的文件* @return*/public boolean del4Http(String httpUrl) throws IOException {//创建一个FtpClient对象FTPClient ftpClient = new FTPClient();//创建ftp连接,默认是:21端口ftpClient.connect(ftpIp, port);//登录ftp服务器,使用用户名 和密码ftpClient.login(username, password);ftpClient.setFileType(FTP.BINARY_FILE_TYPE);int reply;// 获取ftp登录应答代码reply = ftpClient.getReplyCode();// 验证是否登陆成功if (!FTPReply.isPositiveCompletion(reply)) {ftpClient.disconnect();System.err.println("FTP server refused connection.");}//设置上传的路径if (!httpUrl.startsWith("http"))return false;String filePath = httpUrl.substring(httpUrl.indexOf(baseUrl));if (!baseUrl.startsWith("/"))baseUrl = "/" + baseUrl;int index = filePath.lastIndexOf("/");if (index == -1) {System.err.println("文件路径异常:" + filePath);ftpClient.logout();return false;}String path = filePath.substring(0, index);System.out.println(path);if (!ftpClient.changeWorkingDirectory(path)) {//切换到指定目录System.err.println("文件路径不存在:" + filePath);ftpClient.logout();return false;}System.out.println(filePath.substring(index + 1));if (!ftpClient.deleteFile(filePath.substring(index + 1))) {System.err.println("文件删除失败:" + filePath);ftpClient.logout();return false;}ftpClient.logout();System.err.println("文件已删除:" + filePath);return true;}public File download4Http(String httpUrl) throws IOException {//创建一个FtpClient对象FTPClient ftpClient = new FTPClient();//创建ftp连接,默认是:21端口ftpClient.connect(ftpIp, port);//登录ftp服务器,使用用户名 和密码ftpClient.login(username, password);ftpClient.setFileType(FTP.BINARY_FILE_TYPE);int reply;// 获取ftp登录应答代码reply = ftpClient.getReplyCode();// 验证是否登陆成功if (!FTPReply.isPositiveCompletion(reply)) {ftpClient.disconnect();System.err.println("FTP server refused connection.");}if (!baseUrl.startsWith("/"))baseUrl = "/" + baseUrl;//设置上传的路径// if (!httpUrl.startsWith("http"))// return null;int i = httpUrl.indexOf(baseUrl);//如果上传路径中没有baseUrl,则应该是相对路径,则追加baseUrlString filePath = null;if (i == -1) {filePath = baseUrl + httpUrl;} else {filePath = httpUrl.substring(i);}int index = filePath.lastIndexOf("/");if (index == -1) {System.err.println("文件路径异常:" + filePath);ftpClient.logout();ftpClient.disconnect();return null;}String path = filePath.substring(0, index);System.out.println(path);if (!ftpClient.changeWorkingDirectory(path)) {//切换到指定目录System.err.println("文件路径不存在:" + filePath);ftpClient.logout();ftpClient.disconnect();return null;}String name = filePath.substring(index + 1);System.out.println(name);File file = new File(filePath.substring(index + 1));if (ftpClient.retrieveFile(name, FileUtils.openOutputStream(file))) {System.out.println("文件下载成功:" + path + ",length:" + file.length());ftpClient.logout();ftpClient.disconnect();return file;} else {System.out.println("文件下载失败:" + path);ftpClient.logout();ftpClient.disconnect();return file;}// ftpClient.enterLocalPassiveMode(); // 设置被动模式,开通一个端口来传输数据}/*** 删除那种** @param filePath* @return* @throws IOException*/public boolean del(String filePath) throws IOException {//创建一个FtpClient对象FTPClient ftpClient = new FTPClient();//创建ftp连接,默认是:21端口ftpClient.connect(ftpIp, port);//登录ftp服务器,使用用户名 和密码ftpClient.login(username, password);ftpClient.setFileType(FTP.BINARY_FILE_TYPE);int reply;// 获取ftp登录应答代码reply = ftpClient.getReplyCode();// 验证是否登陆成功if (!FTPReply.isPositiveCompletion(reply)) {ftpClient.disconnect();System.err.println("FTP server refused connection.");}//设置上传的路径if (!filePath.startsWith("/"))filePath = "/" + filePath;if (!baseUrl.startsWith("/"))baseUrl = "/" + baseUrl;filePath = baseUrl + filePath;int index = filePath.lastIndexOf("/");if (index == -1) {System.err.println("文件路径异常:" + filePath);ftpClient.logout();return false;}String path = filePath.substring(0, index);System.out.println(path);if (!ftpClient.changeWorkingDirectory(path)) {//切换到指定目录System.err.println("文件路径不存在:" + filePath);ftpClient.logout();return false;}System.out.println(filePath.substring(index + 1));if (!ftpClient.deleteFile(filePath.substring(index + 1))) {System.err.println("文件删除失败:" + filePath);ftpClient.logout();return false;}ftpClient.logout();System.err.println("文件已删除:" + filePath);return true;}/*** 判断某个文件(不是文件夹)存在吗** @param filePath 文件或者文件夹路径* @return*/public boolean isExit(String filePath) throws IOException {//创建一个FtpClient对象FTPClient ftpClient = new FTPClient();//创建ftp连接,默认是:21端口ftpClient.connect(ftpIp, port);//登录ftp服务器,使用用户名 和密码ftpClient.login(username, password);ftpClient.setFileType(FTP.BINARY_FILE_TYPE);int reply;// 获取ftp登录应答代码reply = ftpClient.getReplyCode();// 验证是否登陆成功if (!FTPReply.isPositiveCompletion(reply)) {ftpClient.disconnect();System.err.println("连接FTP SERVER失败,SERVER IP[" + ftpIp + port + "], Ftp response:" + ftpClient.getReplyString());return false;}//设置上传的路径if (!filePath.startsWith("/"))filePath = "/" + filePath;if (!baseUrl.startsWith("/"))baseUrl = "/" + baseUrl;filePath = baseUrl + filePath;InputStream inputStream = ftpClient.retrieveFileStream(filePath);if (inputStream == null || ftpClient.getReplyCode() == 550) {System.out.println("FTP SERVER上未找到以下文件[" + filePath + "]");return false;}ftpClient.logout();return true;}public static void main(String[] args) {// try {// FileFtpUtil.picreate(new File("D:\\360MoveData\\Users\\sz\\Pictures\\Saved Pictures\\改革办平台整理2.png"), "/qinglu/888/fff.png");// } catch (IOException e) {// e.printStackTrace();// }FileFtpUtil ftp = new FileFtpUtil();// try {// ftp.del("/course/48996/20191111/0b16f709-1c5e-4b1d-a096-ad13b20c1f1b.jpg");// } catch (IOException e) {// e.printStackTrace();// }try {File file = ftp.download4Http("http://192.168.0.115/image/temp/48996/20191114/e3792e70-44e6-484b-a0f7-0690527f5185.jpg");System.out.println(file.length());} catch (IOException e) {e.printStackTrace();}// try {// System.out.println(ftp.del4Http(path));// } catch (IOException e) {// e.printStackTrace();// }//// String sub = path.substring(path.indexOf("/image"));// System.out.println(sub);}}
第四步:在Controller中调用此静态方法
package com.yuxin.yijia.controller;import com.alibaba.fastjson.JSONArray;import com.alibaba.fastjson.JSONObject;import com.yuxin.wx.util.ToolStr;import com.yuxin.wx.utils.FileUtil;import com.yuxin.wx.utils.PropertiesUtil;import com.yuxin.wx.utils.WebUtils;import com.yuxin.yijia.utils.ftp.FileFtpUtil;import com.yuxin.yijia.utils.rest.ResultJson;import org.apache.commons.lang.ArrayUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.multipart.MultipartFile;import org.springframework.web.multipart.MultipartRequest;import java.io.File;import java.io.IOException;import java.util.Iterator;@Controllerpublic class FileController {public static final String base = "/fileupload";public static final String save = base + "/save";public static final String up = base + "/up";public static final String del = base + "/del";public static final String get = base + "/get";@Autowiredprivate PropertiesUtil propertiesUtil;/*** 实现删除旧的图片上传新的图片,而且还要保证其原子性,不考虑网络连接不稳定的情况(因为解决不了)** @param multiPartRquest 上传的文件内容* @param module 该文件对应的模块(根据其找到文件的前缀)* @param oldPath 需要删除的文件,如果有路径的话携带路径* @return*/@ResponseBody@RequestMapping(value = up, method = RequestMethod.POST)public JSONObject upPic(MultipartRequest multiPartRquest, String module, String oldPath) throws IOException {boolean flag = false;//先看看是不是真的有原来的文件try {if (ToolStr.isEmpty(oldPath)) {return ResultJson.of(4000, "请传入原图片地址");}String basepath = propertiesUtil.getImageServicePath();int basepathIndex = oldPath.indexOf(basepath);oldPath = oldPath.substring(basepathIndex + basepath.length());if (FileFtpUtil.getInstance().isExit(oldPath)) {flag = true;}} catch (IOException e) {e.printStackTrace();}//监控一下是不是只有一个文件if (multiPartRquest.getFileMap().size() > 1) {return ResultJson.of(4000, "只能上传1个文件");}// System.out.println(multiPartRquest.getMultiFileMap().size());// System.out.println(multiPartRquest.getFileMap().size());if (flag) {flag = false;//如果是有则开始进行文件上传JSONObject res = null;try {res = uploadFile(multiPartRquest, getPrefix(module));if (res.getInteger("code") == 200) {flag = true;}} catch (IOException e) {e.printStackTrace();}//文件上传成功后则执行删除 oldPathif (flag) {flag = false;try {if (FileFtpUtil.getInstance().del(oldPath)) {flag = true;return res;} else {System.err.println("FTP:删除文件" + oldPath + "异常");return res;}} catch (IOException e) {e.printStackTrace();}if (!flag) {//如果删除失败则需要再删除新上传的图片JSONObject data = res.getJSONObject("data");if (data != null) {String url = data.getString("url");if (url != null) {boolean ok = FileFtpUtil.getInstance().del(url);//删除新上传的文件if (ok) {return ResultJson.of(4002, "文件上传成功后删除失败,已成功回滚");} else {return ResultJson.of(4002, "文件上传成功后删除失败,回滚失败,新文件已上传");}}}return ResultJson.of(4002, "文件上传成功后删除失败,回滚失败,新文件已上传");} else {return res;}} else {return ResultJson.of(4001, "文件上传异常");}// return ResultJson.of(4001, "文件上传异常");} else {return ResultJson.of(4000, "oldPath不存在");}}/*** 获取前缀** @param module*/private String getPrefix(String module) {if (ToolStr.isEmpty(module)) {module = FileUtil.Module.TEMP;}return FileUtil.getPath(module, WebUtils.getCurrentCompanyId().toString());}/*** FTP上传图片,保存图片** @param multiPartRquest 上传的文件* @param module (分类)模块名称参考下面的类,如果传空默认是temp类型* @return* @see FileUtil.Module*/@ResponseBody@RequestMapping(value = save, method = RequestMethod.POST)public JSONObject queryPic(MultipartRequest multiPartRquest, String module) {if (ToolStr.isEmpty(module)) {module = FileUtil.Module.TEMP;}String path = FileUtil.getPath(module, WebUtils.getCurrentCompanyId().toString());// String contentType = mfile.getContentType();// String checkExcelFileType = checkExcelFileType(contentType);try {return uploadFile(multiPartRquest, path);} catch (IOException e) {e.printStackTrace();return ResultJson.of(4000, "文件上传异常");}}public static final String[] File_Type = {"default", "xlsx", "xls", "doc", "docx", "ppt", "pptx", "pdf", "txt", "zip", "rar", "png", "jpg", "jpeg","3gp", "avi", "flv", "mp4", "mkv", "mov", "ogg", "wmv", "gif", "del", "", "", "", "", ""};/*** 文件类型是不是对应的文件** @param contentType* @return*/// 判断文件类型public static boolean checkFileType(String contentType) {int a = contentType.indexOf(".");if (a != -1) {return ArrayUtils.contains(File_Type, contentType);} else {String str = contentType.substring(a, contentType.length());return ArrayUtils.contains(File_Type, str);}}// 判断文件类型public static String checkExcelFileType(String contentType) {switch (contentType) {case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":return ".xlsx";case "application/vnd.ms-excel":return ".xls";case "application/msword":return ".doc";case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":return ".docx";case "application/pdf":return ".pdf";case "text/plain":return ".txt";case "application/zip":return ".zip";case "application/octet-stream":return ".rar";case "application/x-png":return ".png";case "image/png":return ".png";case "application/x-jpg":return ".jpg";case "image/jpeg":return ".jpeg";case "video/3gpp":return ".3gp";case "video/x-msvideo":return ".avi";case "video/x-flv":return ".flv";case "video/mp4":return ".mp4";case "video/x-matroska":return ".mkv";case "video/quicktime":return ".mov";case "video/x-theora+ogg":return ".ogg";case "video/x-ms-wmv":return ".wmv";case "image/gif":return ".gif";}return "";}/*** 实现文件上传到ftp** @param multiPartRquest 携带文件的对象* @param prefix 文件的路径(前缀)* @return* @throws IOException*/private JSONObject uploadFile(MultipartRequest multiPartRquest, String prefix) throws IOException {JSONObject data = new JSONObject();JSONArray arr = new JSONArray();Iterator iter = multiPartRquest.getFileNames();while (iter.hasNext()) {MultipartFile multipartFile = multiPartRquest.getFile(iter.next().toString());// MultipartFile multipartFile = multiPartRquest.getFile("imgData");//被注释掉的是老的使用方式// String realPath = null;// realPath = FileUtil.upload(multipartFile, "temp", WebUtils.getCurrentCompanyId()+"");//通过ftp方式上传图片或者文件String fileName = FileUtil.generateFileName(multipartFile.getOriginalFilename());if (checkFileType(fileName)) {return ResultJson.of(4001, "文件类型异常");}File file = new File(fileName);// file = File.createTempFile("/qinglu/a/", ".jpg");multipartFile.transferTo(file);FileFtpUtil.getInstance().picreate(file, fileName, prefix);// FileFtpUtil.picreate(multipartFile.getInputStream(), path + fileName);file.deleteOnExit();//程序退出时删除临时文件//上传文件// req.getSession().setAttribute("imgData", multipartFile);String url = "/" + prefix + fileName;arr.add(url);}if (arr.size() == 0) {return ResultJson.of(4000, "没有任何文件上传");}//判断是不是一个文件if (arr.size() == 1) {data.put("url", arr.get(0));} else {//如果是多个文件放到list中data.put("list", arr);}return ResultJson.of(200, data);}}
如此即可实现上传和下载
