Spring FTP上传下载工具类遇到问题小结

时间:2022-01-24 04:01:36

前言

最近在项目中需要和ftp服务器进行交互,在网上找了一下关于ftp上传下载的工具类,大致有两种。

  第一种是单例模式的类。

  第二种是另外定义一个Service,直接通过Service来实现ftp的上传下载。

  这两种感觉都有利弊。

  第一种实现了代码复用,但是配置信息全需要写在类中,维护比较复杂。

  第二种如果是spring框架,可以通过propertis文件,动态的注入配置信息,但是又不能代码复用。

  所以我打算自己实现一个工具类,来把上面的两种优点进行整合。顺便把一些上传过程中一些常见的问题也给解决了。

  因为我使用的是spring框架,如果把工具类声明为bean给spring管理,他默认就是单例的,所以不需要我再实现单例。并且因为是bean,所以我可以把properties文件的属性注入bean的属性中,实现解耦,下面是具体代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
package com.cky.util;
import java.io.File;
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;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//使用spring自动生成单例对象,
//@Component
public class FtpUtil {
  //通过properties文件自动注入
  @Value("${ftp.host}")
  private String host;  //ftp服务器ip
  @Value("${ftp.port}")
  private int port;    //ftp服务器端口
  @Value("${ftp.username}")
  private String username;//用户名
  @Value("${ftp.password}")
  private String password;//密码
  @Value("${ftp.basePath}")
  private String basePath;//存放文件的基本路径
  //测试的时候把这个构造函数打开,设置你的初始值,然后在代码后面的main方法运行测试
  /*public FtpUtil() {
    //System.out.println(this.toString());
    host="192.168.100.77";
    port=21;
    username="ftpuser";
    password="ftp54321";
    basePath="/home/ftpuser/";
  }*/
  /**
   *
   * @param path    上传文件存放在服务器的路径
   * @param filename  上传文件名
   * @param input    输入流
   * @return
   */
  public boolean fileUpload(String path,String filename,InputStream input) {
    FTPClient ftp=new FTPClient();
    try {
      ftp.connect(host, port);
      ftp.login(username, password);
      //设置文件编码格式
      ftp.setControlEncoding("UTF-8");
      //ftp通信有两种模式
        //PORT(主动模式)客户端开通一个新端口(>1024)并通过这个端口发送命令或传输数据,期间服务端只使用他开通的一个端口,例如21
        //PASV(被动模式)客户端向服务端发送一个PASV命令,服务端开启一个新端口(>1024),并使用这个端口与客户端的21端口传输数据
        //由于客户端不可控,防火墙等原因,所以需要由服务端开启端口,需要设置被动模式
      ftp.enterLocalPassiveMode();
      //设置传输方式为流方式
      ftp.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);
      //获取状态码,判断是否连接成功
      if(!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
        throw new RuntimeException("FTP服务器拒绝连接");
      }
      //转到上传文件的根目录
      if(!ftp.changeWorkingDirectory(basePath)) {
        throw new RuntimeException("根目录不存在,需要创建");
      }
      //判断是否存在目录
      if(!ftp.changeWorkingDirectory(path)) {
        String[] dirs=path.split("/");
        //创建目录
        for (String dir : dirs) {
          if(null==dir||"".equals(dir)) continue;
          //判断是否存在目录
          if(!ftp.changeWorkingDirectory(dir)) {
            //不存在则创建
            if(!ftp.makeDirectory(dir)) {
              throw new RuntimeException("子目录创建失败");
            }
            //进入新创建的目录
            ftp.changeWorkingDirectory(dir);
          }
        }
        //设置上传文件的类型为二进制类型
        ftp.setFileType(FTP.BINARY_FILE_TYPE);
        //上传文件
        if(!ftp.storeFile(filename, input)) {
          return false;
        }
        input.close();
        ftp.logout();
        return true;
      }
    } catch (Exception e) {
      throw new RuntimeException(e);
    }finally {
      if(ftp.isConnected()) {
        try {
          ftp.disconnect();
        } catch (IOException e) {
          throw new RuntimeException(e);
        }
      }
    }
    return false;
  }
  /**
   *
   * @param filename  文件名,注意!此处文件名为加路径文件名,如:/2015/06/04/aa.jpg
   * @param localPath  存放到本地第地址
   * @return   
   */
  public boolean downloadFile(String filename,String localPath) {
    FTPClient ftp=new FTPClient();
    try {
      ftp.connect(host, port);
      ftp.login(username, password);
      //设置文件编码格式
      ftp.setControlEncoding("UTF-8");
      //ftp通信有两种模式
        //PORT(主动模式)客户端开通一个新端口(>1024)并通过这个端口发送命令或传输数据,期间服务端只使用他开通的一个端口,例如21
        //PASV(被动模式)客户端向服务端发送一个PASV命令,服务端开启一个新端口(>1024),并使用这个端口与客户端的21端口传输数据
        //由于客户端不可控,防火墙等原因,所以需要由服务端开启端口,需要设置被动模式
      ftp.enterLocalPassiveMode();
      //设置传输方式为流方式
      ftp.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);
      //获取状态码,判断是否连接成功
      if(!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
        throw new RuntimeException("FTP服务器拒绝连接");
      }
      int index=filename.lastIndexOf("/");
      //获取文件的路径
      String path=filename.substring(0, index);
      //获取文件名
      String name=filename.substring(index+1);
      //判断是否存在目录
      if(!ftp.changeWorkingDirectory(basePath+path)) {
        throw new RuntimeException("文件路径不存在:"+basePath+path);
      }
      //获取该目录所有文件
      FTPFile[] files=ftp.listFiles();
      for (FTPFile file : files) {
        //判断是否有目标文件
        //System.out.println("文件名"+file.getName()+"---"+name);
        if(file.getName().equals(name)) {
          //System.out.println("找到文件");
          //如果找到,将目标文件复制到本地
          File localFile =new File(localPath+"/"+file.getName());
          OutputStream out=new FileOutputStream(localFile);
          ftp.retrieveFile(file.getName(), out);
          out.close();
        }
      }
      ftp.logout();
      return true;
    } catch (Exception e) {
      throw new RuntimeException(e);
    }finally {
      if(ftp.isConnected()) {
        try {
          ftp.disconnect();
        } catch (IOException e) {
          throw new RuntimeException(e);
        }
      }
    }
  }
  //两个功能其中一个使用的话另一个需要注释
  public static void main(String []args) {
    //上传测试-----------------------------------
    /*FileInputStream in;
    try {
      in=new FileInputStream(new File("C:\\Users\\Administrator\\Desktop\\json.png"));
      FtpUtil ftputil=new FtpUtil();
      boolean flag=ftputil.fileUpload("/2015/06/04", "aa.jpg", in);
      System.out.println(flag);
    }catch (Exception e) {
      e.printStackTrace();
    }finally {
    }*/
    //下载测试--------------------------------------
    String filename="/2015/06/04/aa.jpg";
    String localPath="F:\\";
    FtpUtil ftputil=new FtpUtil();
    ftputil.downloadFile(filename, localPath);
  }
  //get set方法自己添加
  //..............
}

具体使用

第一步:配置spring加载properties文件

applicationContext.xml

?
1
2
3
4
5
6
7
<context:property-placeholder location="classpath:*.properties"/>
  ftp.properties
ftp.host=192.168.100.77
ftp.port=21
ftp.username=ftpuser
ftp.password=ftp54321
ftp.basePath=/home/ftpuser/

第二步:将工具类声明为bean

xml方式

?
1
2
3
4
5
6
7
<bean id="ftpUtil" class="com.cky.util.FtpUtil">
    <property name="host" value="${ftp.host}"></property>
    <property name="port" value="${ftp.port}"></property>
    <property name="username" value="${ftp.username}"></property>
    <property name="password" value="${ftp.password}"></property>
    <property name="basePath" value="${ftp.basePath}"></property>
  </bean>

注解方式,组件扫描

?
1
<context:component-scan base-package="com.cky.util"></context:component-scan>

第三部:注入使用

?
1
2
@Autowired
  private FtpUtil ftpUtil;

总结

以上所述是小编给大家介绍的Spring FTP上传下载工具类遇到问题小结,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对服务器之家网站的支持!

原文链接:http://www.cnblogs.com/chenkeyu/p/8001624.html