Java 上传文件到ftp服务器

前两篇文章我们搭建了一个ftp服务器,并对服务器进行了相应的配置,这篇文章我们来说一下我们如何上传文件。

         先介绍一下项目,本项目采用的是spring mvc +spring +mybatis ,用maven 进行项目管理。看一下项目结构 。

        

        如果单独做测试的话不用这么费劲,写一个简单的测试类就ok了!而在这个项目中,parent是所有项目的父包,其他的项目都把该项目做为父项目。common中放入的是一些公用的工具类,pojo对象等,pojo和mapper项目是mybatis逆向生成的项目。而service 是处理业务逻辑的项目,web 是展示层的项目。介绍完了,直接看我们要求的代码。

        上传文件需要的工具类。代码如下所示,这个东西一般不用自己再写了,网上有很多,直接找一个用就可以了,但是要弄懂它的意思。

[java]  view plain  copy
  1. public class FtpUtil {  
  2.   
  3.     /**  
  4.      * Description: 向FTP服务器上传文件  
  5.      * @param host FTP服务器hostname  
  6.      * @param port FTP服务器端口  
  7.      * @param username FTP登录账号  
  8.      * @param password FTP登录密码  
  9.      * @param basePath FTP服务器基础目录 
  10.      * @param filePath FTP服务器文件存放路径。例如分日期存放:/2015/01/01。文件的路径为basePath+filePath 
  11.      * @param filename 上传到FTP服务器上的文件名  
  12.      * @param input 输入流  
  13.      * @return 成功返回true,否则返回false  
  14.      */    
  15.     public static boolean uploadFile(String host, int port, String username, String password, String basePath,  
  16.             String filePath, String filename, InputStream input) {  
  17.         boolean result = false;  
  18.         FTPClient ftp = new FTPClient();  
  19.         try {  
  20.             int reply;  
  21.             ftp.connect(host, port);// 连接FTP服务器  
  22.             // 如果采用默认端口,可以使用ftp.connect(host)的方式直接连接FTP服务器  
  23.             ftp.login(username, password);// 登录  
  24.             reply = ftp.getReplyCode();  
  25.             if (!FTPReply.isPositiveCompletion(reply)) {  
  26.                 ftp.disconnect();  
  27.                 return result;  
  28.             }  
  29.             //切换到上传目录  
  30.             if (!ftp.changeWorkingDirectory(basePath+filePath)) {  
  31.                 //如果目录不存在创建目录  
  32.                 String[] dirs = filePath.split("/");  
  33.                 String tempPath = basePath;  
  34.                 for (String dir : dirs) {  
  35.                     if (null == dir || "".equals(dir)) continue;  
  36.                     tempPath += "/" + dir;  
  37.                     if (!ftp.changeWorkingDirectory(tempPath)) {  
  38.                         if (!ftp.makeDirectory(tempPath)) {  
  39.                             return result;  
  40.                         } else {  
  41.                             ftp.changeWorkingDirectory(tempPath);  
  42.                         }  
  43.                     }  
  44.                 }  
  45.             }  
  46.             //设置上传文件的类型为二进制类型  
  47.             ftp.setFileType(FTP.BINARY_FILE_TYPE);  
  48.             //上传文件  
  49.             if (!ftp.storeFile(filename, input)) {  
  50.                 return result;  
  51.             }  
  52.             input.close();  
  53.             ftp.logout();  
  54.             result = true;  
  55.         } catch (IOException e) {  
  56.             e.printStackTrace();  
  57.         } finally {  
  58.             if (ftp.isConnected()) {  
  59.                 try {  
  60.                     ftp.disconnect();  
  61.                 } catch (IOException ioe) {  
  62.                 }  
  63.             }  
  64.         }  
  65.         return result;  
  66.     }  
  67.       
  68.     /**  
  69.      * Description: 从FTP服务器下载文件  
  70.      * @param host FTP服务器hostname  
  71.      * @param port FTP服务器端口  
  72.      * @param username FTP登录账号  
  73.      * @param password FTP登录密码  
  74.      * @param remotePath FTP服务器上的相对路径  
  75.      * @param fileName 要下载的文件名  
  76.      * @param localPath 下载后保存到本地的路径  
  77.      * @return  
  78.      */    
  79.     public static boolean downloadFile(String host, int port, String username, String password, String remotePath,  
  80.             String fileName, String localPath) {  
  81.         boolean result = false;  
  82.         FTPClient ftp = new FTPClient();  
  83.         try {  
  84.             int reply;  
  85.             ftp.connect(host, port);  
  86.             // 如果采用默认端口,可以使用ftp.connect(host)的方式直接连接FTP服务器  
  87.             ftp.login(username, password);// 登录  
  88.             reply = ftp.getReplyCode();  
  89.             if (!FTPReply.isPositiveCompletion(reply)) {  
  90.                 ftp.disconnect();  
  91.                 return result;  
  92.             }  
  93.             ftp.changeWorkingDirectory(remotePath);// 转移到FTP服务器目录  
  94.             FTPFile[] fs = ftp.listFiles();  
  95.             for (FTPFile ff : fs) {  
  96.                 if (ff.getName().equals(fileName)) {  
  97.                     File localFile = new File(localPath + "/" + ff.getName());  
  98.   
  99.                     OutputStream is = new FileOutputStream(localFile);  
  100.                     ftp.retrieveFile(ff.getName(), is);  
  101.                     is.close();  
  102.                 }  
  103.             }  
  104.   
  105.             ftp.logout();  
  106.             result = true;  
  107.         } catch (IOException e) {  
  108.             e.printStackTrace();  
  109.         } finally {  
  110.             if (ftp.isConnected()) {  
  111.                 try {  
  112.                     ftp.disconnect();  
  113.                 } catch (IOException ioe) {  
  114.                 }  
  115.             }  
  116.         }  
  117.         return result;  
  118.     }  
  119. }  

         我们的pojo项目和mapper项目,不需要写代码,在service层要做一些处理,判断是否上传成功。会看到如何代码有很多的获取值的,因为我们不能见ftp服务器的一些信息都写死到代理吗,我们要把它放入配置文件中,可以是xml文件,或者properties等,这里采用的是properties文件形式。Service 项目是jar 类型的,最后要打成jar包,放入到web项目中,所以所有的配置文件信息应该都放入web项目中。

          

         我们ftp配置信息在resource.properties文件中,如下所示,在写这个配置文件的时候千万要注意所有的值前后不要空格,所有的值前后不要空格,所有的值前后不要空格,重要的事情讲三遍,我就是因为一个空格弄了整整半天。

          

[java]  view plain  copy
  1. #ftp相关配置  
  2. FTP_ADDRESS=192.168.xx.xxx  
  3. FTP_PORT=21  
  4. FTP_USERNAME=ftpuser  
  5. FTP_PASSWORD=123456  
  6. FTP_BASEPATH=/home/ftpuser/www/images  
  7. #图片服务器相关配置i  
  8. IMAGE_BASE_URL=http://192.168.xx.xxx/www/images  

         配置完resource.properties以后,要确保在项目启动的时候一定要加载这个文件,在配置文件中加上这句话。<!-- 加载配置文件 -->

         <context:property-placeholderlocation="classpath:resource/*.properties" /> 这样就可以保证配置文件会被加载了。

         然后我们在service中写自己的业务逻辑,

        

[java]  view plain  copy
  1. @Service  
  2. public class PictureServiceImpl implements PictureService {  
  3.   
  4.     //获取ip地址  
  5.     @Value("${FTP_ADDRESS}")  
  6.     private String FTP_ADDRESS;  
  7.     //端口号  
  8.     @Value("${FTP_PORT}")  
  9.     private String FTP_PORT;  
  10.     //用户名  
  11.     @Value("${FTP_USERNAME}")  
  12.     private String FTP_USERNAME;  
  13.     //密码  
  14.     @Value("${FTP_PASSWORD}")  
  15.     private String FTP_PASSWORD;  
  16.     //基本路径  
  17.     @Value("${FTP_BASEPATH}")  
  18.     private String FTP_BASEPATH;  
  19.     //下载地址地基础url  
  20.     @Value("${IMAGE_BASE_URL}")  
  21.     private String IMAGE_BASE_URL;  
  22.   
  23.     @Override  
  24.     public Map uploadPicture(MultipartFile uploadFile) {  
  25.         Map resultmMap = new HashMap<>();  
  26.   
  27.         try {  
  28.             // 生成一个文件名  
  29.             // 获取旧的名字  
  30.             String oldName = uploadFile.getOriginalFilename();  
  31.             String newName = IDUtils.genImageName();  
  32.             //新名字  
  33.             newName = newName + oldName.substring(oldName.lastIndexOf("."));  
  34.             //上传的路径  
  35.             String imagePath = new DateTime().toString("/yyyy/mm/dd");  
  36.             //端口号  
  37.             int port = Integer.parseInt(FTP_PORT);  
  38.             System.out.println(FTP_BASEPATH);  
  39.             //调用方法,上传文件  
  40.             boolean result = FtpUtil.uploadFile(FTP_ADDRESS, port,  
  41.                     FTP_USERNAME, FTP_PASSWORD, FTP_BASEPATH, imagePath,  
  42.                     newName, uploadFile.getInputStream());  
  43.             //判断是否上传成功  
  44.             if (!result) {  
  45.                 resultmMap.put("error"1);  
  46.                 resultmMap.put("message""上传失败");  
  47.                 return resultmMap;  
  48.             }  
  49.             resultmMap.put("error"0);  
  50.             resultmMap.put("url", IMAGE_BASE_URL + imagePath + newName);  
  51.             return resultmMap;  
  52.   
  53.         } catch (IOException e) {  
  54.             resultmMap.put("error"1);  
  55.             resultmMap.put("message""上传发生异常");  
  56.             return resultmMap;  
  57.         }  
  58.     }  
  59. }  

         Controler中服务请求的转发工作。代码如下。

[java]  view plain  copy
  1. @Controller  
  2. public class PictureController {  
  3.       
  4.     @Autowired  
  5.     private PictureService pictureService;  
  6.       
  7.     @RequestMapping("/pic/upload")  
  8.     @ResponseBody  
  9.     public Map pictureUpload(MultipartFile uploadFile){  
  10.         Map result = pictureService.uploadPicture(uploadFile);  
  11.         return result;  
  12.     }  
  13. }  

         在jsp 页面中我们用

[html]  view plain  copy
  1. <span style="font-size:18px;">    <a href="javascript:void(0)" class="easyui-linkbuttonpicFileUpload">上传图片</a>  
  2.    <inputtypeinputtype="hidden" name="image"/></span>  

         而调用到js代码如下所示

        

[java]  view plain  copy
  1. // 初始化图片上传组件  
  2.    initPicUpload : function(data){  
  3.     $(".picFileUpload").each(function(i,e){  
  4.         var _ele = $(e);  
  5.         _ele.siblings("div.pics").remove();  
  6.         _ele.after('\  
  7.             <div class="pics">\  
  8.                 <ul></ul>\  
  9.             </div>');  
  10.         // 回显图片  
  11.         if(data && data.pics){  
  12.             var imgs = data.pics.split(",");  
  13.             for(var i in imgs){  
  14.                 if($.trim(imgs[i]).length > 0){  
  15.                     _ele.siblings(".pics").find("ul").append("<li><a href='"+imgs[i]+"' target='_blank'><img src='"+imgs[i]+"' width='80' height='50' /></a></li>");  
  16.                 }  
  17.             }  
  18.         }  
  19.         //给“上传图片按钮”绑定click事件  
  20.         $(e).click(function(){  
  21.             var form = $(this).parentsUntil("form").parent("form");  
  22.             //打开图片上传窗口  
  23.             KindEditor.editor(TT.kingEditorParams).loadPlugin('multiimage',function(){  
  24.                 var editor = this;  
  25.                 editor.plugin.multiImageDialog({  
  26.                     clickFn : function(urlList) {  
  27.                         var imgArray = [];  
  28.                         KindEditor.each(urlList, function(i, data) {  
  29.                             imgArray.push(data.url);  
  30.                             form.find(".pics ul").append("<li><a href='"+data.url+"' target='_blank'><img src='"+data.url+"' width='80' height='50' /></a></li>");  
  31.                         });  
  32.                         form.find("[name=image]").val(imgArray.join(","));  
  33.                         editor.hideDialog();  
  34.                     }  
  35.                 });  
  36.             });  
  37.         });  
  38.     });  
  39.    },  

         这些代码都写完以后,我们测试会发现依然有问题,Expected MultipartHttpServletRequest: is a MultipartResolverconfigured 这个错误是因为我们没有配置解析文件的jar。所以我们还要在springmvc的配置文件中加上如下配置。这样我们应该就没问题了!

[html]  view plain  copy
  1. <span style="font-size:18px;"><!-- 上传文件拦截,设置最大上传文件大小10M=10*1024*1024(B)=10485760 bytes -->  
  2.    <bean id="multipartResolver"  
  3.    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">  
  4.      <property name="maxUploadSize"value="10485760" />  
  5.    </bean></span>