SSM框架集成FTP+nginx实现文件的上传和下载

1、背景与设计思路

1、背景:
在很多场景中,经常会遇到文件或者图片上传的需求。如用户反馈、背景图片上传等等。
2、设计思路:
可以先看看人家是怎么设计的,下面是随意找的一个网站,查看图片上传的逻辑:
a、图片上传页面:
SSM框架集成FTP+nginx实现文件的上传和下载
b、使用F12查看实际发起的请求:
SSM框架集成FTP+nginx实现文件的上传和下载
很显然,在系统调用ajaxuploadpic接口后,返回了一response,这个就是后台服务器在保存了上传的这张图片后,该图片在服务器中保存的文件名
SSM框架集成FTP+nginx实现文件的上传和下载

2、设计方案

根据第一步,我们基本就可以确定下开发思路了。
SSM框架集成FTP+nginx实现文件的上传和下载

3、代码开发

1、首先,为了方便后续集成。开发了一个FTP的单独模块,用于集成。其中该模块的结构图如下所示:
SSM框架集成FTP+nginx实现文件的上传和下载
2、具体的工具类代码如下所示:
FtpVo .java

package com.entity;

public class FtpVo {
	private String host;
	private int port;
	private String username;
	private String password;

	private boolean binaryTransfer = true;
	private boolean passiveMode = true;
	private String encoding = "UTF-8";
	private int clientTimeout = 1000 * 30;

	public String getHost() {
		return host;
	}

	public void setHost(String host) {
		this.host = host;
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public boolean isBinaryTransfer() {
		return binaryTransfer;
	}

	public void setBinaryTransfer(boolean binaryTransfer) {
		this.binaryTransfer = binaryTransfer;
	}

	public boolean isPassiveMode() {
		return passiveMode;
	}

	public void setPassiveMode(boolean passiveMode) {
		this.passiveMode = passiveMode;
	}

	public String getEncoding() {
		return encoding;
	}

	public void setEncoding(String encoding) {
		this.encoding = encoding;
	}

	public int getClientTimeout() {
		return clientTimeout;
	}

	public void setClientTimeout(int clientTimeout) {
		this.clientTimeout = clientTimeout;
	}
}

DeleteServer.java

package com.main;

import java.util.List;

import com.util.FTPUload;

public class DeleteServer {
	public static boolean deleteFile(String url, String projectName) {
		boolean falg = true;
		try {
			FTPUload ftpUload = new FTPUload();
			falg = ftpUload.deleteFile(url, projectName);
		} catch (Exception e) {
			falg = false;
			e.printStackTrace();
		}
		return falg;
	}

	public static boolean deleteFile(List<String> list, String projectName) {
		boolean falg = true;
		try {
			if (list.size() > 0) {
				for (int i = 0; i < list.size(); i++) {
					FTPUload ftpUload = new FTPUload();
					falg = ftpUload.deleteFile(list.get(i), projectName);
				}
			}
		} catch (Exception e) {
			falg = false;
			e.printStackTrace();
		}
		return falg;
	}
}

DownloadToLocal.java

package com.main;

import java.io.File;
import java.net.URL;

import org.apache.commons.io.FileUtils;

import com.util.DateUtil;
import com.util.FTPUload;
import com.util.ProperManagerFTP;

public class DownloadToLocal {

	/**
	 * @description 下载图片后,nginx 做映射
	 * @param url
	 * @return
	 */
	public static String downloadFromUrl(String url, String projectName) {
		String result = ProperManagerFTP.getString("webpath");
		try {
			URL httpurl = new URL(url);
			String extName = getFileExtName(url);
			String fileName = System.currentTimeMillis() + "." + extName;
			System.out.println(result + fileName);

			String webpath = DateUtil.getFilePath();
			result = result + projectName + "/" + webpath + fileName;
			File f = new File(
					System.getProperty("user.dir").replace("\\", "/") + "/" + projectName + "/" + webpath + fileName);
			FileUtils.copyURLToFile(httpurl, f);
			FTPUload ftpUload = new FTPUload();
			ftpUload.ftpUpload(f.getPath());
		} catch (Exception e) {
			e.printStackTrace();
			return "error";
		}
		return result;
	}

	/**
	 * @description 保留原有的名称
	 * @param url
	 * @return
	 */
	public static String getFileNameFromUrl(String url) {
		String name = new Long(System.currentTimeMillis()).toString() + ".X";
		int index = url.lastIndexOf("/");
		if (index > 0) {
			name = url.substring(index + 1);
			if (name.trim().length() > 0) {
				return name;
			}
		}
		return name;
	}

	public static String getFileExtName(String fileName) {
		String extName = "";
		if (fileName != null && !"".equals(fileName)) {
			int i = fileName.lastIndexOf(".");
			if (i > 0) {
				extName = fileName.substring(i + 1, fileName.length());
			}
		}
		return extName;
	}
}

UploadServer.java

package com.main;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.imageio.ImageIO;

import org.springframework.web.multipart.MultipartFile;

import com.util.DateUtil;
import com.util.FTPUload;
import com.util.GlobalVars;

public class UploadServer {

	/**
	 * 保存本地再上传
	 * 
	 * @param multipartFile
	 * @param projectName
	 * @return
	 */
	public static Map<String, String> getUploadPathMap(MultipartFile multipartFile, String projectName) {
		boolean falg = true;
		Map<String, String> map = new HashMap<String, String>();
		String path = System.getProperty("user.dir") + "/";
		String webpath = DateUtil.getFilePath();
		try {
			if (projectName == null || projectName.equals("") || projectName.equals("/")) {
				path = path + "/images/" + webpath;
			} else {
				path = path + "/" + projectName + "/" + webpath;
			}
			File file = new File(path);
			if (!file.exists()) {
				file.mkdirs();
			}
			String extName = getFileExtName(multipartFile.getOriginalFilename());
			String fileName = System.currentTimeMillis() + "." + extName;
			webpath = webpath + fileName;
			String uploadPath = path + "/" + fileName;
			File files = new File(uploadPath);
			multipartFile.transferTo(files);
			BufferedImage sourceImg = ImageIO.read(new FileInputStream(files));
			FTPUload ftpUload = new FTPUload();
			ftpUload.ftpUpload(uploadPath);
			map.put("width", sourceImg.getWidth() + "");
			map.put("height", sourceImg.getHeight() + "");
			String r = "";
			if (projectName == null || projectName.equals("") || projectName.equals("/")) {
				r = "images/" + webpath;
			} else {
				r = projectName + "/" + webpath;
			}
			if (falg == false) {
				map.put("url", GlobalVars.WEBPATH + "/error.jpg");
			} else {
				map.put("url", GlobalVars.WEBPATH + r);
			}
			Thread.sleep(2000);
		} catch (Exception e) {
			map.put("url", GlobalVars.WEBPATH + "/error.jpg");
			e.printStackTrace();
		}
		return map;
	}

	/**
	 * 不保存本地通过流上传
	 * 
	 * @param multipartFile
	 * @param projectName
	 * @return
	 */
	public static Map<String, String> getUploadPathMapInputSteam(MultipartFile multipartFile, String projectName) {
		boolean falg = true;
		Map<String, String> map = new HashMap<String, String>();
		String path = System.getProperty("user.dir") + "/";
		String webpath = DateUtil.getFilePath();
		try {
			if (projectName == null || projectName.equals("") || projectName.equals("/")) {
				path = path + "/images/" + webpath;
			} else {
				path = path + "/" + projectName + "/" + webpath;
			}
			String extName = getFileExtName(multipartFile.getOriginalFilename());
			String fileName = System.currentTimeMillis() + "." + extName;
			webpath = webpath + fileName;
			String uploadPath = path + "/" + fileName;
			BufferedImage sourceImg = ImageIO.read(multipartFile.getInputStream());
			FTPUload ftpUload = new FTPUload();
			ftpUload.ftpUpload(multipartFile.getInputStream(), uploadPath);
			map.put("width", sourceImg.getWidth() + "");
			map.put("height", sourceImg.getHeight() + "");
			String r = "";
			if (projectName == null || projectName.equals("") || projectName.equals("/")) {
				r = "images/" + webpath;
			} else {
				r = projectName + "/" + webpath;
			}
			if (falg == false) {
				map.put("url", GlobalVars.WEBPATH + "/error.jpg");
			} else {
				map.put("url", GlobalVars.WEBPATH + r);
			}
			Thread.sleep(2000);
		} catch (Exception e) {
			map.put("url", GlobalVars.WEBPATH + "/error.jpg");
			e.printStackTrace();
		}
		return map;
	}

	/**
	 *
	 * @Title: getUploadPath @Description: 保存本地再上传 @param
	 *         multipartFile @return @return String @throws
	 */
	public static String getUploadPath(MultipartFile multipartFile, String projectName) {
		boolean falg = true;
		String reStr = "";
		String webpath = DateUtil.getFilePath();
		try {
			String path = System.getProperty("user.dir") + "/";
			if (projectName == null || projectName.equals("") || projectName.equals("/")) {
				path = path + "/images/" + webpath;
			} else {
				path = path + "/" + projectName + "/" + webpath;
			}
			File file = new File(path);
			if (!file.exists()) {
				file.mkdirs();
			}
			String extName = getFileExtName(multipartFile.getOriginalFilename());
			String fileName = System.currentTimeMillis() + "." + extName;
			webpath = webpath + fileName;
			String uploadPath = path + "/" + fileName;
			File files = new File(uploadPath);
			multipartFile.transferTo(files);
			FTPUload ftpUload = new FTPUload();
			falg = ftpUload.ftpUpload(uploadPath);
			if (falg == false) {
				reStr = GlobalVars.WEBPATH + "/error.jpg";
			} else {
				if (projectName == null || projectName.equals("") || projectName.equals("/")) {
					reStr = "images/" + webpath;
				} else {
					reStr = projectName + "/" + webpath;
				}
				reStr = GlobalVars.WEBPATH + reStr;
			}
			Thread.sleep(2000);
		} catch (Exception e) {
			reStr = GlobalVars.WEBPATH + "/error.jpg";
			e.printStackTrace();
		}

		return reStr;
	}

	/**
	 *
	 * @Title: getUploadPath @Description: 不保存本地通过流上传 @param
	 *         multipartFile @return @return String @throws
	 */
	public static String getUploadPathInputSteam(MultipartFile multipartFile, String projectName) {
		boolean falg = true;
		String reStr = "";
		String webpath = "marketdatas/";
		try {
			String path = "/marketdatas";
			String fileName = UUID.randomUUID().toString().replace("-", "");
			String originalName = multipartFile.getOriginalFilename();

			String extName = getFileExtName(originalName);

			if ("png".equals(extName) || "jpg".equals(extName)) {
				path = path + "/images";
			} else if ("apk".equals(extName)) {
				path = path + "/apk";
			} else {
				path = path + "/others";
			}

			webpath = webpath + fileName + "." + extName;
			String uploadPath = path + "/" + fileName + "." + extName;

			FTPUload ftpUload = new FTPUload();
			falg = ftpUload.ftpUpload(multipartFile.getInputStream(), uploadPath);
			if (falg == false) {
				reStr = GlobalVars.WEBPATH + "/error.jpg";
			} else {
				if (projectName == null || projectName.equals("") || projectName.equals("/")) {
					reStr = uploadPath;
				} else {
					reStr = uploadPath;
				}
				reStr = GlobalVars.WEBPATH + reStr;
			}
			Thread.sleep(2000);
		} catch (Exception e) {
			reStr = GlobalVars.WEBPATH + "/error.jpg";
		}

		return reStr;
	}

	public static String getUploadPath(String filePaht, String projectName) {
		String path = "";
		try {
			File file = new File(filePaht);
			if (!file.isFile()) {
				return path = "error";
			}
			FTPUload ftpUload = new FTPUload();
			path = ftpUload.ftpUpload(filePaht.replace("\\", "/"), projectName);
			Thread.sleep(2000);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return path;
	}

	public static String getUploadPathInputSteam(File filePaht, String projectName) {
		String path = "";
		try {
			if (filePaht != null && !filePaht.isFile()) {
				return path = "error";
			}
			FTPUload ftpUload = new FTPUload();
			path = ftpUload.ftpUploadFile(filePaht, projectName);
			Thread.sleep(2000);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return path;
	}

	public static String getFileExtName(String fileName) {
		String extName = "";
		if (fileName != null && !"".equals(fileName)) {
			int i = fileName.lastIndexOf(".");
			if (i > 0) {
				extName = fileName.substring(i + 1, fileName.length());
			}
		}
		return extName;
	}

}

DateUtil.java

package com.util;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateUtil {

	private static ThreadLocal<DateFormat> fullDateFormatter = new ThreadLocal<DateFormat>();
	private static ThreadLocal<DateFormat> shortDateFormatter = new ThreadLocal<DateFormat>();
	private static ThreadLocal<DateFormat> dateFormatter = new ThreadLocal<DateFormat>();
	private static ThreadLocal<DateFormat> yearFormatter = new ThreadLocal<DateFormat>();
	private static ThreadLocal<DateFormat> uploadFormatter = new ThreadLocal<DateFormat>();

	/**
	 * 
	 * @Title: dateToMin @Description: 转化到分 @param date @return @return
	 *         String @throws
	 */
	public static String dateToMin(final Date date) {
		DateFormat df = fullDateFormatter.get();
		if (df == null) {
			df = new SimpleDateFormat("yyyyMMddHHmm");
			fullDateFormatter.set(df);
		}
		return df.format(date);
	}

	/**
	 * 
	 * @Title: dateToHou @Description: 转化到时 @param date @return @return
	 *         String @throws
	 */
	public static String dateToHou(final Date date) {
		DateFormat df = shortDateFormatter.get();
		if (df == null) {
			df = new SimpleDateFormat("yyyyMMddHH");
			shortDateFormatter.set(df);
		}
		return df.format(date);
	}

	/**
	 * 
	 * @Title: dateToDay @Description: 转化到天 @param date @return @return
	 *         String @throws
	 */
	public static String dateToDay(final Date date) {
		DateFormat df = dateFormatter.get();
		if (df == null) {
			df = new SimpleDateFormat("yyyyMMdd");
			dateFormatter.set(df);
		}
		return df.format(date);
	}

	/**
	 * 
	 * @Title: dateToYear @Description: 转化到年 @param date @return @return
	 *         String @throws
	 */
	public static String dateToYear(final Date date) {
		DateFormat df = yearFormatter.get();
		if (df == null) {
			df = new SimpleDateFormat("yyyy");
			yearFormatter.set(df);
		}
		return df.format(date);
	}

	/**
	 * 
	 * 
	 * @Title: getYear @Description: 获取年,公元纪年 @return @return Integer @throws
	 */
	public static Integer getYear() {
		return Integer.parseInt(DateUtil.dateToYear(new Date()));
	}

	public static String getFilePath() {
		DateFormat df = uploadFormatter.get();
		if (df == null) {
			df = new SimpleDateFormat("yyyy/MM/dd/HH/mm/ss/");
			uploadFormatter.set(df);
		}
		return df.format(new Date());
	}

	public static Date date2Str(String Str) {
		Date date = null;
		try {
			date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(Str);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return date;
	}

	public static void main(String[] args) {
		System.out.println(DateUtil.date2Str("2018-12-31 23:59:59"));
	}
}

FTPClientException.java

package com.util;

public class FTPClientException extends Exception {
	private static final long serialVersionUID = 1L;

	public FTPClientException(String s, Exception e) {
		System.out.println(s + e);
	}

	public FTPClientException(String s) {
		System.out.println(s);
	}
}

FtpConnect.java

package com.util;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;

import com.entity.FtpVo;

public class FtpConnect {
	private ThreadLocal<FTPClient> ftpClientThreadLocal = new ThreadLocal<FTPClient>();
	private static final String ftppath = ProperManagerFTP.getString("ftppath");

	private FtpVo ftpVo;

	public FtpConnect() {
	}

	public FtpConnect(FtpVo ftpVo) {
		this.ftpVo = ftpVo;
	}

	public FTPClient getFTPClient() throws FTPClientException {
		if (ftpClientThreadLocal.get() != null && ftpClientThreadLocal.get().isConnected()) {
			return ftpClientThreadLocal.get();
		} else {
			FTPClient ftpClient = new FTPClient(); // 构造一个FtpClient实例
			ftpClient.setControlEncoding(ftpVo.getEncoding()); // 设置字符集
			connect(ftpClient); // 连接到ftp服务器
			// 设置为passive模式
			if (ftpVo.isPassiveMode()) {
				ftpClient.enterLocalPassiveMode();
			}
			setFileType(ftpClient); // 设置文件传输类型

			try {
				ftpClient.setSoTimeout(ftpVo.getClientTimeout());
			} catch (SocketException e) {
				throw new FTPClientException("Ftp 连接超时", e);
			}
			ftpClientThreadLocal.set(ftpClient);
			return ftpClient;
		}
	}

	/**
	 * 设置文件传输类型
	 *
	 * @throws FTPClientException
	 * @throws java.io.IOException
	 */
	private void setFileType(FTPClient ftpClient) throws FTPClientException {
		try {
			if (ftpVo.isBinaryTransfer()) {
				ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
			} else {
				ftpClient.setFileType(FTPClient.ASCII_FILE_TYPE);
			}
		} catch (IOException e) {
			throw new FTPClientException("Could not to set file type.", e);
		}
	}

	/**
	 * 连接到ftp服务器
	 *
	 * @param ftpClient
	 * @return 连接成功返回true,否则返回false
	 * @throws FTPClientException
	 */
	private boolean connect(FTPClient ftpClient) throws FTPClientException {
		try {
			ftpClient.connect(ftpVo.getHost(), ftpVo.getPort());

			// 连接后检测返回码来校验连接是否成功
			int reply = ftpClient.getReplyCode();

			if (FTPReply.isPositiveCompletion(reply)) {
				// 登陆到ftp服务器
				if (ftpClient.login(ftpVo.getUsername(), ftpVo.getPassword())) {
					setFileType(ftpClient);
					return true;
				}
			} else {
				ftpClient.disconnect();
				throw new FTPClientException("FTP 连接服务失败");
			}
		} catch (IOException e) {
			if (ftpClient.isConnected()) {
				try {
					ftpClient.disconnect(); // 断开连接
				} catch (IOException e1) {
					throw new FTPClientException("Could not disconnect from server.", e1);
				}

			}
			throw new FTPClientException("FTP 服务连接异常", e);
		}
		return false;
	}

	public void disconnect() throws FTPClientException {
		try {
			FTPClient ftpClient = getFTPClient();
			ftpClient.logout();
			if (ftpClient.isConnected()) {
				ftpClient.disconnect();
				ftpClient = null;
			}
		} catch (IOException e) {
			throw new FTPClientException("FTP 服务关闭异常", e);
		}
	}

	/**
	 * 上传一个本地文件到远程指定文件
	 *
	 * @param remoteAbsoluteFile
	 *            远程文件名(包括完整路径)
	 * @param localAbsoluteFile
	 *            本地文件名(包括完整路径)
	 * @return 成功时,返回true,失败返回false
	 * @throws FTPClientException
	 */
	public boolean put(String remoteAbsoluteFile, String localAbsoluteFile) throws FTPClientException {
		return put(remoteAbsoluteFile, localAbsoluteFile, true);
	}

	/**
	 * 上传一个本地文件到远程指定文件
	 *
	 * @param remoteAbsoluteFile
	 *            远程文件名(包括完整路径)
	 * @param localAbsoluteFile
	 *            本地文件名(包括完整路径)
	 * @return 成功时,返回true,失败返回false
	 * @throws FTPClientException
	 */
	public boolean put(String remoteAbsoluteFile, InputStream localAbsoluteFile) throws FTPClientException {
		return put(remoteAbsoluteFile, localAbsoluteFile, true);
	}

	/**
	 * 上传一个本地文件到远程指定文件
	 *
	 * @param remoteAbsoluteFile
	 *            远程文件名(包括完整路径)
	 * @param localAbsoluteFile
	 *            本地文件名(包括完整路径)
	 * @param autoClose
	 *            是否自动关闭当前连接
	 * @return 成功时,返回true,失败返回false
	 * @throws FTPClientException
	 */
	public boolean put(String remoteAbsoluteFile, String localAbsoluteFile, boolean autoClose)
			throws FTPClientException {
		InputStream input = null;
		try {
			boolean filemk = false;
			// 截取远程路径最后一个/
			int fnum = remoteAbsoluteFile.lastIndexOf("/");
			String folderPath = remoteAbsoluteFile.substring(0, fnum);
			System.out.println(folderPath);
			// 根据截取的字段判断路径是否存在
			boolean falg = getFTPClient().changeWorkingDirectory(folderPath);
			// false为路径不存在调用CeateDirecroty创建文件夹
			if (falg == false) {
				// 创建文件夹
				CreateDirecroty(folderPath, "");
			}
			// 检查文件是否正确
			filemk = getFTPClient().changeWorkingDirectory("/" + folderPath);
			if (filemk == true) {
				// 处理传输
				input = new FileInputStream(localAbsoluteFile);
				// 上传 如果返回false 注意上传模式 二进制还是文本
				boolean b = getFTPClient().storeFile(remoteAbsoluteFile, input);
				// 删除本地文件
				File file = new File(localAbsoluteFile);
				// 如果判断是文件夹不操作
				if (!file.isDirectory()) {
					if (file.isFile()) {
						// 关闭文件流避免删除失败
						DataOutputStream dos = new DataOutputStream(new FileOutputStream(file));
						dos.close();
						boolean f = file.delete();
						if (f = false) {
							throw new FTPClientException("delete error file:" + localAbsoluteFile);
						}
					}
				}
				System.out.println(b);
			} else {
				return false;
			}
			return true;
		} catch (FileNotFoundException e) {
			throw new FTPClientException("local file not found.", e);
		} catch (IOException e) {
			throw new FTPClientException("Could not put file to server.", e);
		} finally {
			try {
				if (input != null) {
					input.close();
				}
			} catch (Exception e) {
				throw new FTPClientException("Couldn't close FileInputStream.", e);
			}
			if (autoClose) {
				disconnect(); // 断开连接
			}
		}
	}

	/**
	 * 上传一个本地文件到远程指定文件
	 *
	 * @param remoteAbsoluteFile
	 *            远程文件名(包括完整路径)
	 * @param localAbsoluteFile
	 *            本地文件名(包括完整路径)
	 * @param autoClose
	 *            是否自动关闭当前连接
	 * @return 成功时,返回true,失败返回false
	 * @throws FTPClientException
	 */
	public boolean put(String remoteAbsoluteFile, InputStream localAbsoluteFile, boolean autoClose)
			throws FTPClientException {
		InputStream input = null;
		try {
			boolean filemk = false;
			// 截取远程路径最后一个/
			int fnum = remoteAbsoluteFile.lastIndexOf("/");
			String folderPath = remoteAbsoluteFile.substring(0, fnum);
			System.out.println(folderPath);
			// 根据截取的字段判断路径是否存在
			boolean falg = getFTPClient().changeWorkingDirectory(folderPath);
			// false为路径不存在调用CeateDirecroty创建文件夹
			if (falg == false) {
				// 创建文件夹
				CreateDirecroty(folderPath, "");
			}
			// 检查文件是否正确
			filemk = getFTPClient().changeWorkingDirectory("/" + folderPath);
			if (filemk == true) {
				// 处理传输
				if (localAbsoluteFile != null) {
					input = localAbsoluteFile;
					// 上传 如果返回false 注意上传模式 二进制还是文本
					boolean b = getFTPClient().storeFile(remoteAbsoluteFile, input);
					if (b = false) {
						throw new FTPClientException("update error file:" + remoteAbsoluteFile);
					}
				} else {
					throw new FTPClientException("上传文件流为空" + localAbsoluteFile);
				}
			} else {
				return false;
			}
			return true;
		} catch (FileNotFoundException e) {
			throw new FTPClientException("local file not found.", e);
		} catch (IOException e) {
			throw new FTPClientException("Could not put file to server.", e);
		} finally {
			try {
				if (input != null) {
					input.close();
				}
			} catch (Exception e) {
				throw new FTPClientException("Couldn't close FileInputStream.", e);
			}
			if (autoClose) {
				disconnect(); // 断开连接
			}
		}
	}

	/**
	 * 创建文件夹
	 * 
	 * @param remotePath
	 *            //需要创建文件夹的路径
	 * @param pwdstr
	 *            //创建后的路径 主要用于进入路径
	 * @return
	 */
	public boolean CreateDirecroty(String remotePath, String pwdstr) throws FTPClientException {

		try {
			// FTP根目录
			String nofile = ftppath;
			if (remotePath == null || "".equals(remotePath)) {
				return true;
			}
			int startnum = remotePath.indexOf("/");
			String crpath = "";
			String endpath = "";
			if (startnum > 0) {
				crpath = remotePath.substring(0, startnum);
				endpath = remotePath.substring(startnum, remotePath.length());
			} else if (startnum == 0) {
				remotePath = remotePath.substring(1, remotePath.length());
				startnum = remotePath.indexOf("/");
				crpath = remotePath.substring(0, startnum);
				endpath = remotePath.substring(startnum, remotePath.length());
			} else {
				crpath = remotePath;
			}
			pwdstr = pwdstr + "/" + crpath;
			// 检查文件夹是否存在
			boolean falg = getFTPClient().changeWorkingDirectory(pwdstr);
			// 不存在创建文件夹进入 存在直接进入
			if (falg == false) {
				getFTPClient().makeDirectory(crpath);
				getFTPClient().changeWorkingDirectory(pwdstr);
			} else {
				getFTPClient().changeWorkingDirectory(pwdstr);
			}
			// endpath的长度=0表示需要创建的文件夹没有了
			if (endpath.length() == 0) {
				return true;
			} else {
				// 减1去掉/线
				endpath = endpath.substring(1, endpath.length());
				// 递归
				CreateDirecroty(endpath, pwdstr);
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new FTPClientException("Ftp 创建文件夹失败", e);
		} finally {
			try {
				if (true) {
					// 创建完后关闭连接
					disconnect(); // 断开连接
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return true;
	}

	/**
	 * 下载一个远程文件到本地的指定文件
	 *
	 * @param remoteAbsoluteFile
	 *            远程文件名(包括完整路径)
	 * @param localAbsoluteFile
	 *            本地文件名(包括完整路径)
	 * @return 成功时,返回true,失败返回false
	 * @throws FTPClientException
	 */
	public boolean get(String remoteAbsoluteFile, String localAbsoluteFile) throws FTPClientException {
		return get(remoteAbsoluteFile, localAbsoluteFile, true);
	}

	/**
	 * 下载一个远程文件到本地的指定文件
	 *
	 * @param remoteAbsoluteFile
	 *            远程文件名(包括完整路径)
	 * @param localAbsoluteFile
	 *            本地文件名(包括完整路径)
	 * @param autoClose
	 *            是否自动关闭当前连接
	 *
	 * @return 成功时,返回true,失败返回false
	 * @throws FTPClientException
	 */
	public boolean get(String remoteAbsoluteFile, String localAbsoluteFile, boolean autoClose)
			throws FTPClientException {
		OutputStream output = null;
		try {
			output = new FileOutputStream(localAbsoluteFile);
			return get(remoteAbsoluteFile, output, autoClose);
		} catch (FileNotFoundException e) {
			throw new FTPClientException("local file not found.", e);
		} finally {
			try {
				if (output != null) {
					output.close();
				}
			} catch (IOException e) {
				throw new FTPClientException("Couldn't close FileOutputStream.", e);
			}
		}
	}

	/**
	 * 下载一个远程文件到指定的流 处理完后记得关闭流
	 *
	 * @param remoteAbsoluteFile
	 * @param output
	 * @return
	 * @throws FTPClientException
	 */
	public boolean get(String remoteAbsoluteFile, OutputStream output) throws FTPClientException {
		return get(remoteAbsoluteFile, output, true);
	}

	/**
	 * 下载一个远程文件到指定的流 处理完后记得关闭流
	 *
	 * @param remoteAbsoluteFile
	 * @param output
	 * @return
	 * @throws FTPClientException
	 */
	public boolean get(String remoteAbsoluteFile, OutputStream output, boolean autoClose) throws FTPClientException {
		try {
			FTPClient ftpClient = getFTPClient();
			// 处理传输
			return ftpClient.retrieveFile(remoteAbsoluteFile, output);
		} catch (IOException e) {
			throw new FTPClientException("Couldn't get file from server.", e);
		} finally {
			if (autoClose) {
				disconnect(); // 关闭链接
			}
		}
	}

	/**
	 * 从ftp服务器上删除一个文件
	 *
	 * @param delFile
	 * @param autoClose
	 *            是否自动关闭当前连接
	 *
	 * @return
	 * @throws FTPClientException
	 */
	public boolean delete(String delFile, boolean autoClose) throws FTPClientException {
		try {
			getFTPClient().deleteFile(delFile);
			return true;
		} catch (IOException e) {
			throw new FTPClientException("Couldn't delete file from server.", e);
		} finally {
			if (autoClose) {
				disconnect(); // 关闭链接
			}
		}
	}

	/**
	 * 批量删除 该方法将自动关闭当前连接
	 *
	 * @param delFiles
	 * @return
	 * @throws FTPClientException
	 */
	public boolean delete(String[] delFiles) throws FTPClientException {
		return delete(delFiles, true);
	}

	/**
	 * 批量删除
	 *
	 * @param delFiles
	 * @param autoClose
	 *            是否自动关闭当前连接
	 *
	 * @return
	 * @throws FTPClientException
	 */
	public boolean delete(String[] delFiles, boolean autoClose) throws FTPClientException {
		try {
			FTPClient ftpClient = getFTPClient();
			for (String s : delFiles) {
				ftpClient.deleteFile(s);
			}
			return true;
		} catch (IOException e) {
			throw new FTPClientException("Couldn't delete file from server.", e);
		} finally {
			if (autoClose) {
				disconnect(); // 关闭链接
			}
		}
	}

	/**
	 * 列出远程默认目录下所有的文件
	 *
	 * @return 远程默认目录下所有文件名的列表,目录不存在或者目录下没有文件时返回0长度的数组
	 * @throws FTPClientException
	 */
	public String[] listNames() throws FTPClientException {
		return listNames(null, true);
	}

	public String[] listNames(boolean autoClose) throws FTPClientException {
		return listNames(null, autoClose);
	}

	/**
	 * 列出远程目录下所有的文件
	 *
	 * @param remotePath
	 *            远程目录名
	 * @param autoClose
	 *            是否自动关闭当前连接
	 *
	 * @return 远程目录下所有文件名的列表,目录不存在或者目录下没有文件时返回0长度的数组
	 * @throws FTPClientException
	 */
	public String[] listNames(String remotePath, boolean autoClose) throws FTPClientException {
		try {
			String[] listNames = getFTPClient().listNames(remotePath);
			return listNames;
		} catch (IOException e) {
			throw new FTPClientException("列出远程目录下所有的文件时出现异常", e);
		} finally {
			if (autoClose) {
				disconnect(); // 关闭链接
			}
		}
	}
}

FTPUload.java

package com.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;

import com.entity.FtpVo;
import com.main.UploadServer;

public class FTPUload {
	protected final Logger log = Logger.getLogger(this.getClass());
	private static final String ftpip = PropertiesUtil.get("ftpip");
	private static final String ftpuser = PropertiesUtil.get("ftpname");
	private static final String ftppass = PropertiesUtil.get("ftppassword");
	private static final String ftpprot = PropertiesUtil.get("ftpprot");
	private static final String ftppath = PropertiesUtil.get("ftppath");

	public static void main(String[] args) throws FTPClientException, InterruptedException, Exception {
		FtpVo ftp = new FtpVo();
		ftp.setHost("192.168.1.11");
		ftp.setPort(21);
		ftp.setUsername("testftp");
		ftp.setPassword("123456");
		ftp.setBinaryTransfer(true);
		ftp.setPassiveMode(true);
		ftp.setEncoding("utf-8");
		FtpConnect ftpConnect = new FtpConnect(ftp);
		// ftpConnect.ftpUpload("D:\\文档\\123456789.xlsx".replace("\\","/"),"execl");
		// ftp.deleteFile("http://192.168.1.11:8060/app_store/2016/12/14/16/47/01/1481705221029.jpg","app_store");
	}

	/**
	 * 从ftp服务器上删除一个文件 该方法将自动关闭当前连接
	 *
	 * @param delFile
	 * @return
	 * @throws FTPClientException
	 */
	public boolean deleteFile(String delFile, String projectName) throws FTPClientException {
		boolean falg = false;
		try {
			String rmpath = ftppath;
			int indexnum = delFile.indexOf(projectName);
			String locapath = "";
			if (indexnum >= 0) {
				locapath = rmpath + delFile.substring(indexnum, delFile.length());
			} else {
				throw new FTPClientException("项目文件夹名称不存在" + projectName);
			}
			locapath = locapath.replace("\\", "/");
			List<FtpVo> list = getFtpUload();
			for (int i = 0; i < list.size(); i++) {
				FtpConnect ftpConnect = new FtpConnect(list.get(i));
				falg = ftpConnect.delete(locapath, true);
				if (falg == false) {
					throw new FTPClientException("FTP删除失败 文件地址" + locapath);
				}
			}

		} catch (Exception e) {
			falg = false;
			throw new FTPClientException("删除异常", e);
		}
		return falg;
	}

	public boolean ftpUpload(String local) throws FTPClientException {
		boolean ret = true;
		try {
			List<FtpVo> list = getFtpUload();
			for (int i = 0; i < list.size(); i++) {
				if (list.get(i) == null) {
					throw new FTPClientException("读取ftp配置文件失败 ip:" + list.get(i).getHost());
				}
				FtpConnect ftpConnect = new FtpConnect(list.get(i));
				ftpConnect.getFTPClient();
				String rmpath = ftppath;
				String locapath = local;
				String substr = System.getProperty("user.dir").replace("\\", "/") + "/";
				locapath = locapath.replace("\\", "/").replaceAll("//", "/");
				int numc = locapath.indexOf(substr);
				if (numc >= 0) {
					rmpath = rmpath + locapath.substring(numc + substr.length(), locapath.length());
				} else {
					System.out.println(numc + ":" + substr + ":" + locapath);
					throw new FTPClientException("error:路径截取为空");
				}
				System.out.println(rmpath);
				ret = ftpConnect.put(rmpath, locapath);
			}
		} catch (FTPClientException e) {
			throw new FTPClientException("FTP上传失败", e);
		}
		return ret;
	}

	public boolean ftpUpload(InputStream local, String filename) throws FTPClientException {
		boolean ret = true;
		try {
			List<FtpVo> list = getFtpUload();
			for (int i = 0; i < list.size(); i++) {
				if (list.get(i) == null) {
					throw new FTPClientException("读取ftp配置文件失败 ip:" + list.get(i).getHost());
				}
				FtpConnect ftpConnect = new FtpConnect(list.get(i));
				ftpConnect.getFTPClient();
				// String rmpath=ftppath;
				// String locapath=filename;
				// String
				// substr=System.getProperty("user.dir").replace("\\","/")+"/";
				// locapath=locapath.replace("\\","/").replaceAll("//","/");
				// int numc=locapath.indexOf(substr);
				// if(numc>=0){
				// rmpath=rmpath+locapath.substring(numc+substr.length(),locapath.length());
				// }else{
				// System.out.println(numc+":"+substr+":"+locapath);
				// throw new FTPClientException("error:路径截取为空");
				//// }
				// System.out.println(rmpath);
				ret = ftpConnect.put(filename, local);
			}
		} catch (FTPClientException e) {
			e.printStackTrace();
			throw new FTPClientException("FTP上传失败", e);
		}
		return ret;
	}

	public String ftpUpload(String local, String projectName) throws FTPClientException {
		String rpath = "";
		try {
			List<FtpVo> list = getFtpUload();
			for (int i = 0; i < list.size(); i++) {
				FtpConnect ftpConnect = new FtpConnect(list.get(i));
				String rmpath = ftppath;
				int num = local.lastIndexOf("/");
				int leg = local.length();
				if (num > 0 && num != leg) {
					rmpath = rmpath + projectName + "/" + local.substring(num, leg);
				} else {
					throw new FTPClientException("地址不正确" + local);
				}
				boolean ret = ftpConnect.put(rmpath, local);
				if (ret == false) {
					rpath = ProperManagerFTP.getString("webpath") + "/error.jpg";
					log.debug("FTP upload fail for FTP ip:" + list.get(i).getHost());
				} else {
					rpath = ProperManagerFTP.getString("webpath") + "/" + projectName + "/" + local.substring(num, leg);
				}
			}
		} catch (FTPClientException e) {
			throw new FTPClientException("FTP上传失败", e);
		}
		return rpath;
	}

	public String ftpUploadFile(File file, String projectName) throws FTPClientException {
		String rpath = "";
		try {
			List<FtpVo> list = getFtpUload();
			for (int i = 0; i < list.size(); i++) {
				FtpConnect ftpConnect = new FtpConnect(list.get(i));
				String rmpath = ftppath;
				String webpath = DateUtil.getFilePath();
				String extName = UploadServer.getFileExtName(file.getName());
				String fileName = System.currentTimeMillis() + "." + extName;
				rmpath = rmpath + "/" + projectName + "/" + webpath + "/" + fileName;
				InputStream inputStream = new FileInputStream(file);
				boolean ret = ftpConnect.put(rmpath, inputStream);
				if (ret == false) {
					rpath = ProperManagerFTP.getString("webpath") + "/error.jpg";
					log.debug("FTP upload fail for FTP ip:" + list.get(i).getHost());
				} else {
					rpath = ProperManagerFTP.getString("webpath") + "/" + projectName + "/" + webpath + "/" + fileName;
				}
			}
		} catch (FTPClientException e) {
			throw new FTPClientException("FTP上传失败", e);
		} catch (FileNotFoundException ex) {
			throw new FTPClientException("文件流不存在", ex);
		}
		return rpath;
	}

	/**
	 * 读取FTP配置文件信息
	 * 
	 * @return
	 * @throws FTPClientException
	 */
	public List<FtpVo> getFtpUload() throws FTPClientException {
		List<FtpVo> list = new ArrayList<FtpVo>();
		try {
			// 判断ip是否有多个
			String[][][] ftplog;
			String[] ip = ftpip.split(",");
			// 多个FTP连接
			if (ip.length > 1) {
				ftplog = new String[ip.length][ip.length][ip.length];
				for (int i = 0; i < ip.length; i++) {
					ftplog[i][0][0] = ip[i];
				}
				String[] username = ftpuser.split(",");
				// 当用户分割的数组长度有多个并且和ip长度一样,则一一对应否则默认为第一个
				if (username.length > 1 && username.length == ip.length) {
					for (int i = 0; i < ip.length; i++) {
						ftplog[i][1][1] = username[i];
					}
				} else {
					for (int i = 0; i < ip.length; i++) {
						ftplog[i][1][1] = username[0];
					}
				}
				String[] password = ftppass.split(",");
				// 当用户分割的数组长度有多个并且和ip长度一样,则一一对应否则默认为第一个
				if (password.length > 1 && password.length == ip.length) {
					for (int i = 0; i < ip.length; i++) {
						ftplog[i][2][2] = password[i];
					}
				} else {
					for (int i = 0; i < ip.length; i++) {
						ftplog[i][2][2] = password[0];
					}
				}
				for (int i = 0; i < ftplog.length; i++) {
					FtpVo ftp = new FtpVo();
					ftp.setHost(ftplog[i][0][0]);
					ftp.setPort(Integer.parseInt(ftpprot));
					ftp.setUsername(ftplog[i][1][1]);
					ftp.setPassword(ftplog[i][2][2]);
					ftp.setBinaryTransfer(true);
					ftp.setPassiveMode(true);
					ftp.setEncoding("utf-8");
					list.add(ftp);
				}
			} else {
				// 一个FTP连接
				FtpVo ftp = new FtpVo();
				ftp.setHost(ftpip);
				ftp.setPort(Integer.parseInt(ftpprot));
				ftp.setUsername(ftpuser);
				ftp.setPassword(ftppass);
				// 文件上传模式
				ftp.setBinaryTransfer(true);
				ftp.setPassiveMode(true);
				ftp.setEncoding("utf-8");
				list.add(ftp);
			}
		} catch (Exception e) {
			throw new FTPClientException("FTP 连接读取配置错误");
		}
		return list;
	}
}

GlobalVars.java

package com.util;

public class GlobalVars {

	// ************************************配置文件读取***********************//
	public static String WEBPATH = PropertiesUtil.get("webpath");

	/**
	 * 应用管理
	 */
	public static String APP_MANAGE_API = "app_manage/api";

	public static String APP_MANAGE_WEB = "app_manage/web";
}

ProperManagerFTP.java

package com.util;

import java.util.MissingResourceException;

public class ProperManagerFTP {
	public static String getString(String key) {
		try {
			return PropertiesUtil.get(key);
		} catch (MissingResourceException e) {
			throw new RuntimeException("! config : " + key + '!');
		}
	}

}

PropertiesUtil.java

package com.util;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;

public class PropertiesUtil extends PropertyPlaceholderConfigurer {

	private static Map<String, Object> ctxPropertiesMap;

	@Override
	protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props)
			throws BeansException {
		super.processProperties(beanFactoryToProcess, props);
		ctxPropertiesMap = new HashMap<String, Object>();
		for (Object key : props.keySet()) {
			String keyStr = key.toString();
			String value = props.getProperty(keyStr);
			ctxPropertiesMap.put(keyStr, value);
		}
	}

	public static Object getContextProperty(String name) {
		return ctxPropertiesMap.get(name);
	}

	/**
	 * 根据key读取对应的value
	 * 
	 * @param key
	 * @return
	 */
	public static String get(String key) {
		return (String) ctxPropertiesMap.get(key);
	}
}

pom.xml

<?xml version="1.0"?>
<project
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
	xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<modelVersion>4.0.0</modelVersion>

	<artifactId>dc-upload</artifactId>
	<packaging>jar</packaging>
	<parent>
		<groupId>com.xxl.dc</groupId>
		<artifactId>dc-parent</artifactId>
		<version>1.0.3</version><!--$NO-MVN-MAN-VER$ -->
		<relativePath>../dc-parent/</relativePath>
	</parent>

	<properties>
		<maven.build.timestamp.format>yyyy-MM-dd HH:mm:ss</maven.build.timestamp.format>
	</properties>

	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>commons-net</groupId>
			<artifactId>commons-net</artifactId>
			<version>3.1</version>
		</dependency>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.17</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>2.4</version>
		</dependency>
	</dependencies>


	<build>
		<finalName>dc-upload</finalName>
		<plugins>
			<!-- define the project compile level -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.3.2</version><!--$NO-MVN-MAN-VER$ -->
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

2、实际接口:


package com.xxl.dc.upload;

import java.io.IOException;
import java.util.Iterator;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import com.main.UploadServer;
import com.xxl.dc.common.util.CommonConsts;

@Controller
@RequestMapping(CommonConsts.API_DC)
public class UploadController {

	private static final Logger logger = Logger.getLogger(UploadController.class.getName());

	@RequestMapping(value = "/fileUpload")
	public void upload(HttpServletRequest request, HttpServletResponse respones) {

		// 解析器解析request的上下文
		CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
				request.getSession().getServletContext());
		// 保存图片文件名
		String path = "";
		// 先判断request中是否包涵multipart类型的数据,
		if (multipartResolver.isMultipart(request)) {
			// 再将request中的数据转化成multipart类型的数据
			MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
			Iterator iter = multiRequest.getFileNames();
			while (iter.hasNext()) {
				// 这里的name为fileItem的alias属性值,相当于form表单中name
				String name = (String) iter.next();
				// 根据name值拿取文件
				MultipartFile file = multiRequest.getFile(name);
				if (null != file) {
					path = UploadServer.getUploadPathInputSteam(file, "app_store");
				}
			}
		}
		try {
			// 指定允许其他域名访问
			respones.setHeader("Access-Control-Allow-Origin", "*");
			// 响应类型
			respones.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
			// 响应头设置
			respones.setHeader("Access-Control-Allow-Headers", "Content-Type, x-requested-with, X-Custom-Header");
			respones.getWriter().write(path);
		} catch (IOException e) {
			logger.error(e);
		}
	}

}

配置文件如下所示:
SSM框架集成FTP+nginx实现文件的上传和下载

同时还需要在你的springmvc.xml配置文件中配置如下:

	<bean id="multipartResolver"
		class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<property name="maxUploadSize" value="314572800" />
		<property name="maxInMemorySize" value="40960000" />
	</bean>

	<bean id="propertyConfigurer" class="com.util.PropertiesUtil">
		<property name="ignoreResourceNotFound" value="true" />
		<property name="locations">
			<list>
				<value>classpath:config.properties</value>
			</list>
		</property>
	</bean>

3、效果演示

在浏览器中上传图片,返回的结果为一个图片的地址。
SSM框架集成FTP+nginx实现文件的上传和下载
SSM框架集成FTP+nginx实现文件的上传和下载
SSM框架集成FTP+nginx实现文件的上传和下载
至于为什么在浏览器访问http://192.168.10.101:8066/marketdatas/images/a81edfddb83047cc8b0d7198c4ae6a22.png时,能看到这张图片,是因为8066是配置的一个nginx服务器。
SSM框架集成FTP+nginx实现文件的上传和下载
而图片上传后保存的地址为:所以就能直接下载到该文件了。
SSM框架集成FTP+nginx实现文件的上传和下载