SSM使用FTP服务器上传文件[Windows Server 2008 R2虚拟系统下]
1. 搭建FTP服务器[先在本地搭建, 测试成功后, 再在远程服务器上搭建]
* 搭建步骤: http://www.cnblogs.com/josephcnblog/articles/6929345.html
2. 导入jar包(Maven环境下, 如果这里引入补全, 请参看各个类中引入的jar包)
<!-- commons-net --> <dependency> <groupId>commons-net</groupId> <artifactId>commons-net</artifactId> <version>${commons.version}</version> </dependency> <!-- 文件上传所依赖的jar包 commons-fileupload commons-io--> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency>
3. 编写代码
* 配置文件===========================================================================
* resource.properties(静态资源文件, 里面定义了连接FTP服务器需要的参数, 以及一些参数)
# FILI_UPLOAD_PATH FILE_UPLOAD_PATH = FTP服务器的物理路径(在搭建服务器的时候定义的) # FTP_SERVER_IP FTP_SERVER_IP = FTP服务器的IP地址(如果在本地搭建服务器, 就是本机的IP地址) # FTP_SERVER_PORT FTP_SERVER_PORT = FTP服务器的端口号(默认是21端口) # FTP_SERVER_USERNAME FTP_SERVER_USERNAME = FTP服务器的用户名(在搭建服务器时, 看服务器隶属于哪个用户, 就是该用户的用户名) # FTP_SERVER_PASSWORD FTP_SERVER_PASSWORD = FTP服务器的密码(在搭建服务器时, 看服务器隶属于哪个用户, 就是该用户的密码)
* 在spring容器(配置文件)中导入resource.properties(注意路径)
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:config/*.properties</value> </list> </property> </bean>
* 配置文件===========================================================================
* 工具类=============================================================================
* IDUtils.java(文件上传成功之后, 生成的随机的文件名)
package com.wangzhixuan.commons.utils; import java.util.Random; public class IDUtils { /** * 生成文件名称 * @return */ public static String getFileName() { //取当前时间的长整形值包含毫秒 long millis = System.currentTimeMillis(); //long millis = System.nanoTime(); //加上四位随机数 Random random = new Random(); int end3 = random.nextInt(9999); //如果不足四位前面补0 String str = millis + String.format("%04d", end3); return str; } }
* FtpUtil.java(此类是客户端连接FTP服务器的底层代码)
package com.wangzhixuan.commons.utils; 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 org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPFile; import org.apache.commons.net.ftp.FTPReply; /** * FTP工具类 * @author zoumingqiao */ public class FtpUtil { /** * Description: 向FTP服务器上传文件 * @param host FTP服务器hostname * @param port FTP服务器端口 * @param username FTP登录账号 * @param password FTP登录密码 * @param basePath FTP服务器基础目录 * @param filePath FTP服务器文件存放路径。例如分日期存放:/2015/01/01。 文件的路径为basePath+filePath * @param filename 上传到FTP服务器上的文件名 * @param input 输入流 * @return 成功返回true,失败返回false */ public static boolean uploadFile( String host, int port, String username, String password, String basePath, String filePath, String filename, InputStream input) { boolean result = false; FTPClient ftp = new FTPClient(); try { int reply; // 如果采用默认端口,可以使用ftp.connect(host)的方式直接连接FTP服务器 ftp.connect(host, port); // 连接FTP服务器 ftp.login(username, password); // 登录 reply = ftp.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { ftp.disconnect(); return result; } // 进入FTP的物理路径, 如 E:\\FTPLocalDirectory String tempPath = basePath; if (ftp.changeWorkingDirectory("/")) { String[] dirs = filePath.split("/"); // 如[, 2017, 06, 02] if (dirs != null && dirs.length > 0) { for (String dir : dirs) { // 过滤掉空对象和空字符串 if (null == dir || "".equals(dir)) { continue; } /** * 定位到下一级目录, 如: * E:\\FTPLocalDirectory\\2017, * E:\\FTPLocalDirectory\\2017\\06, * E:\\FTPLocalDirectory\\2017\\06\\02 */ if (!ftp.changeWorkingDirectory(dir)) { // 无法定位到该目录, 说明该目录不存在 ftp.mkd(dir); // 创建下一级目录 boolean flag = ftp.changeWorkingDirectory(dir); // 定位到下一级目录 tempPath += "/" + dir; // 全路径 System.out.println("切换到目录:[ " + tempPath + " ]: " + (flag ? "成功!" : "失败!")); } } } } else { // 如果物理路径不存在, 那么直接返回false结果 return result; } /* // 如果完整的目录不存在 String tempPath = ""; System.out.println("FTP开始的物理路径: " + basePath); if (!ftp.makeDirectory(basePath+filePath)) { // 准备创建目录 String[] dirs = filePath.split("/"); tempPath = basePath; for (String dir : dirs) { // 过滤掉空对象和空字符串 if (null == dir || "".equals(dir)) continue; // 拼凑准备创建的第一级目录 tempPath += "/" + dir; File file = new File(tempPath); // 如果要创建的目录不存在 if (!file.exists()) { // 创建这个目录 boolean mkdFlag = file.mkdir(); System.out.println((mkdFlag ? "FTP的物理路径创建成功!" : "FTP的物理路径创建失败!") + " FTP的临时的物理路径是:" + tempPath); //boolean ff = ftp.makeDirectory(tempPath); } } } boolean rt = ftp.changeWorkingDirectory(tempPath); System.out.println("===================切换FTP的开始物理路径到[ "+tempPath+" ]下时: " + (rt ? "成功!" : "失败!")); */ //设置上传文件的类型为二进制类型[避免上传图片类型的文件时读取图片失败] ftp.setFileType(FTP.BINARY_FILE_TYPE); //上传文件 if (!ftp.storeFile(filename, input)) { return result; } input.close(); ftp.logout(); result = true; } catch (IOException e) { e.printStackTrace(); } finally { if (ftp.isConnected()) { try { ftp.disconnect(); } catch (IOException ioe) { ioe.printStackTrace(); } } } return result; } /** * Description: 从FTP服务器下载文件 * @param host FTP服务器hostname * @param port FTP服务器端口 * @param username FTP登录账号 * @param password FTP登录密码 * @param remotePath FTP服务器上的相对路径 * @param fileName 要下载的文件名 * @param localPath 下载后保存到本地的路径 * @return 文件下载成功返回true, 失败返回false */ public static boolean downloadFile( String host, int port, String username, String password, String remotePath, String fileName, String localPath) { boolean result = false; FTPClient ftp = new FTPClient(); try { int reply; ftp.connect(host, port); // 如果采用默认端口,可以使用ftp.connect(host)的方式直接连接FTP服务器 ftp.login(username, password); // 登录 reply = ftp.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { ftp.disconnect(); return result; } ftp.changeWorkingDirectory(remotePath); // 转移到FTP服务器目录 FTPFile[] fs = ftp.listFiles(); for (FTPFile ff : fs) { if (ff.getName().equals(fileName)) { File localFile = new File(localPath + "/" + ff.getName()); OutputStream is = new FileOutputStream(localFile); ftp.retrieveFile(ff.getName(), is); is.close(); } } ftp.logout(); result = true; } catch (IOException e) { e.printStackTrace(); } finally { if (ftp.isConnected()) { try { ftp.disconnect(); } catch (IOException ioe) { } } } return result; } /** * 测试 * @param args */ public static void main(String[] args) { try { FileInputStream in=new FileInputStream(new File("要上传的文件全路径")); boolean flag = uploadFile("FTP服务器IP地址", 端口号, "用户名", "密码", "FTP服务器的物理路径","/2017/06/02(这是当天的日期)", "上传后生成的文件名", 输入流); System.out.println(flag); } catch (FileNotFoundException e) { e.printStackTrace(); } } }
* 工具类=============================================================================
* Service层/Controller层/JSP页面=====================================================
* IFileService.java(Service接口)
package com.wangzhixuan.service; import org.springframework.web.multipart.MultipartFile; /** * 文件操作Service接口 * @author zoumingqiao */ public interface IFileService { public boolean uploadFile(MultipartFile uploadFile) throws Exception; } * FileServiceImpl.java(Service接口实现类) package com.wangzhixuan.service.impl; import java.text.SimpleDateFormat; import java.util.Date; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import com.wangzhixuan.commons.utils.FtpUtil; import com.wangzhixuan.commons.utils.IDUtils; import com.wangzhixuan.service.IFileService; /** * 文件操作Service实现类 * @author zoumingqiao */ @Service public class FileServiceImpl implements IFileService { // 获取连接FTP服务器的参数(这种从配置文件中获取信息的方法很方便, 注意采用) @Value("${FILE_UPLOAD_PATH}") private String FILE_UPLOAD_PATH; // 服务端存放图片的基础目录(即FTP服务器的物理路径) @Value("${FTP_SERVER_IP}") private String FTP_SERVER_IP; // FTP服务器的IP地址 @Value("${FTP_SERVER_PORT}") private Integer FTP_SERVER_PORT; // FTP服务器的端口号 @Value("${FTP_SERVER_USERNAME}") private String FTP_SERVER_USERNAME; // FTP服务器的用户名 @Value("${FTP_SERVER_PASSWORD}") private String FTP_SERVER_PASSWORD; // FTP服务器的密码 /** * 文件上传 * @param uploadFile Controller层传递过来的多部件文件对象 */ @Override public boolean uploadFile(MultipartFile uploadFile) throws Exception { // 上传文件功能实现 String path = saveFile(uploadFile); if (StringUtils.isNotBlank(path)) { return true; } return false; } /** * 保存文件 * @param uploadFile 要保存的文件 * @return 保存成功返回true, 失败返回false */ private String saveFile(MultipartFile uploadFile) { String result = null; try { // 上传文件功能实现 // 判断文件是否为空 if (uploadFile.isEmpty()) return null; // 上传文件以日期为单位分开存放,可以提高图片的查询速度 String filePath = "/" + new SimpleDateFormat("yyyy").format(new Date()) + "/" + new SimpleDateFormat("MM").format(new Date()) + "/" + new SimpleDateFormat("dd").format(new Date()); // 取原始文件名 String originalFilename = uploadFile.getOriginalFilename(); // 新文件名 String newFileName = IDUtils.getFileName() + originalFilename.substring(originalFilename.lastIndexOf(".")); // 转存文件,上传到ftp服务器 boolean connectionFlag = FtpUtil.uploadFile(FTP_SERVER_IP, FTP_SERVER_PORT, FTP_SERVER_USERNAME, FTP_SERVER_PASSWORD, FILE_UPLOAD_PATH, filePath, newFileName, uploadFile.getInputStream()); if (connectionFlag) { result = filePath + "/" + newFileName; } } catch (Exception e) { e.printStackTrace(); } return result; } }
* FileUpController.java(Controller层)
package com.wangzhixuan.controller; import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import com.wangzhixuan.commons.base.BaseController; import com.wangzhixuan.service.IFileService; @Controller @RequestMapping("/fileup") public class FileUpController extends BaseController{ // 注入servcie @Autowired private IFileService fileService; //定位到上传单个文件界面 /fileup/goupload @GetMapping("/goupload1") public String goupload(){ return "admin/goupload"; } @PostMapping("/upload") @ResponseBody public String upload(MultipartFile file, HttpServletRequest request) throws Exception { // 调用Service上传文件 boolean flag = fileService.uploadFile(file); // 文件上传成功 if (flag) { return "{\"msg\":\"success\"}"; } // 文件上传失败 return "{\"msg\":\"error\"}"; } }
* goupload.jsp(页面)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <script type="text/javascript" src="${staticPath }/static/ajaxfileupload.js" charset="utf-8"></script> <script type="application/javascript"> function ajaxFileUpload() { $.ajaxFileUpload ({ url: '${path}/fileup/upload', //用于文件上传的服务器端请求地址 secureuri: false, //是否需要安全协议,一般设置为false fileElementId: 'file', //文件上传域的ID dataType: 'json', //返回值类型 一般设置为json success: function (data, status) { //服务器成功响应处理函数 if (data != null) { if ("success" == data.msg) { alert("程序下达成功!"); } else { alert("程序下达失败!"); } } console.log(data.msg); }, error: function (data, status, e) { //服务器响应失败处理函数 alert("程序下达失败!"); } }); return false; } </script> </head> <body> <h1>程序下达</h1> <div action="${pageContext.request.contextPath}/fileup/upload" method="post" enctype="multipart/form-data"> <input type="file" name="file" id="file"/> <input type="button" value="下达程序" onclick="ajaxFileUpload();"/> </div> </body> </html>