Java 实现ftp文件上传

Java 实现ftp文件上传

在JAVA程序中,经常需要和FTP打交道,比如向FTP服务器上传文件、下载文件,本文详细介绍如何利用FTPClient(在commons-net包中)图片的上传和HTTP请求图片;

在进行介绍如何通过代码实现FTP上传文件之前,请小伙伴确认自己已经有一台已经搭建成功的FTP服务器和使用Nginx搭建的静态资源服务器,如果没有请小伙伴按照我之前的文章进行安装;
地址为:Nginx和FTP搭载图片服务器

1.在pom.xml中引入依赖

首先添加jakarta commons中的FTPClient,即:commons-net包

1
2
3
4
5
6
<!--commons-net -->
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.5</version>
</dependency>

2.创建FTPUtils

具体代码如下:

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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
package www.hrabbit.cn.util;

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 java.io.*;
import java.net.MalformedURLException;

/**
* @Auther: hrabbit
* @Date: 2018-04-21 下午12:35
* @Description:
*/
public class FTPUtils {

public static FTPClient ftpClient = null;

/**
* 初始化ftp服务器
*/
public static void initFtpClient(String hostname,String username,String password,Integer port) {
ftpClient = new FTPClient();
ftpClient.setControlEncoding("utf-8");
try {
//连接ftp服务器
ftpClient.connect(hostname, port);
//登录ftp服务器
ftpClient.login(username, password);
//是否成功登录服务器
int replyCode = ftpClient.getReplyCode();
if(!FTPReply.isPositiveCompletion(replyCode)){
System.out.println("ftp服务器登录成功");
}
}catch (MalformedURLException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
}

/**
* 上传文件
* @param pathname ftp服务保存地址
* @param fileName 上传到ftp的文件名
* @param inputStream 输入文件流
* @return
*/
public static boolean uploadFile(String hostname,String username,String password,Integer port, String pathname, String fileName,InputStream inputStream){
boolean flag = false;
try{
System.out.println("开始上传文件");
initFtpClient(hostname,username,password,port);
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
ftpClient.enterLocalPassiveMode();
CreateDirecroty(pathname);
ftpClient.makeDirectory(pathname);
ftpClient.setControlEncoding("utf-8");
ftpClient.storeFile(fileName, inputStream);
System.out.println("上传结束");
inputStream.close();
ftpClient.logout();
flag = true;
System.out.println("上传文件成功");

}catch (Exception e) {
System.out.println("上传文件失败");
e.printStackTrace();
}finally{
if(ftpClient.isConnected()){
try{
ftpClient.disconnect();
}catch(IOException e){
e.printStackTrace();
}
}
if(null != inputStream){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return true;
}
//改变目录路径
public static boolean changeWorkingDirectory(String directory) {
boolean flag = true;
try {
flag = ftpClient.changeWorkingDirectory(directory);
if (flag) {
System.out.println("进入文件夹" + directory + " 成功!");
} else {
System.out.println("进入文件夹" + directory + " 失败!开始创建文件夹");
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
return flag;
}

//创建多层目录文件,如果有ftp服务器已存在该文件,则不创建,如果无,则创建
public static boolean CreateDirecroty(String remote) throws IOException {
boolean success = true;
String directory = remote + "/";
// 如果远程目录不存在,则递归创建远程服务器目录
if (!directory.equalsIgnoreCase("/") && !changeWorkingDirectory(new String(directory))) {
int start = 0;
int end = 0;
if (directory.startsWith("/")) {
start = 1;
} else {
start = 0;
}
end = directory.indexOf("/", start);
String path = "";
String paths = "";
while (true) {
String subDirectory = new String(remote.substring(start, end).getBytes("UTF-8"), "iso-8859-1");
path = path + "/" + subDirectory;
if (!existFile(path)) {
if (makeDirectory(subDirectory)) {
changeWorkingDirectory(subDirectory);
} else {
System.out.println("创建目录[" + subDirectory + "]失败");
changeWorkingDirectory(subDirectory);
}
} else {
changeWorkingDirectory(subDirectory);
}

paths = paths + "/" + subDirectory;
start = end + 1;
end = directory.indexOf("/", start);
// 检查所有目录是否创建完毕
if (end <= start) {
break;
}
}
}
return success;
}

//判断ftp服务器文件是否存在
public static boolean existFile(String path) throws IOException {
boolean flag = false;
FTPFile[] ftpFileArr = ftpClient.listFiles(path);
if (ftpFileArr.length > 0) {
flag = true;
}
return flag;
}
//创建目录
public static boolean makeDirectory(String dir) {
boolean flag = true;
try {
flag = ftpClient.makeDirectory(dir);
if (flag) {
System.out.println("创建文件夹" + dir + " 成功!");

} else {
System.out.println("创建文件夹" + dir + " 失败!");
}
} catch (Exception e) {
e.printStackTrace();
}
return flag;
}

/** * 下载文件 *
* @param pathname FTP服务器文件目录 *
* @param filename 文件名称 *
* @param localpath 下载后的文件路径 *
* @return */
public static boolean downloadFile(String hostname,String username,String password,Integer port,String pathname, String filename, String localpath){
boolean flag = false;
OutputStream os=null;
try {
System.out.println("开始下载文件");
initFtpClient(hostname,username,password,port);
//切换FTP目录
ftpClient.changeWorkingDirectory(pathname);
FTPFile[] ftpFiles = ftpClient.listFiles();
for(FTPFile file : ftpFiles){
if(filename.equalsIgnoreCase(file.getName())){
File localFile = new File(localpath + "/" + file.getName());
os = new FileOutputStream(localFile);
ftpClient.retrieveFile(file.getName(), os);
os.close();
}
}
ftpClient.logout();
flag = true;
System.out.println("下载文件成功");
} catch (Exception e) {
System.out.println("下载文件失败");
e.printStackTrace();
} finally{
if(ftpClient.isConnected()){
try{
ftpClient.disconnect();
}catch(IOException e){
e.printStackTrace();
}
}
if(null != os){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return flag;
}

/** * 删除文件 *
* @param pathname FTP服务器保存目录 *
* @param filename 要删除的文件名称 *
* @return */
public static boolean deleteFile(String hostname,String username,String password,Integer port,String pathname, String filename){
boolean flag = false;
try {
System.out.println("开始删除文件");
initFtpClient(hostname,username,password,port);
//切换FTP目录
ftpClient.changeWorkingDirectory(pathname);
ftpClient.dele(filename);
ftpClient.logout();
flag = true;
System.out.println("删除文件成功");
} catch (Exception e) {
System.out.println("删除文件失败");
e.printStackTrace();
} finally {
if(ftpClient.isConnected()){
try{
ftpClient.disconnect();
}catch(IOException e){
e.printStackTrace();
}
}
}
return flag;
}
}

2.1 注意事项
  1. 上传文件的时候,有时候FTPClient提示成功,而且在服务器上也将文件夹创建了,但是里面却没有文件,这是FTP的主动模式和被动模式搞得鬼;

(1) PORT(主动模式)

PORT中文称为主动模式,工作的原理: FTP客户端连接到FTP服务器的21端口,发送用户名和密码登录,登录成功后要list列表或者读取数据时,客户端随机开放一个端口(1024以上),发送 PORT命令到FTP服务器,告诉服务器客户端采用主动模式并开放端口;FTP服务器收到PORT主动模式命令和端口号后,通过服务器的20端口和客户端开放的端口连接,发送数据,原理如下图。

(2) PASV(被动模式)

PASV是Passive的缩写,中文成为被动模式,工作原理:FTP客户端连接到FTP服务器的21端口,发送用户名和密码登录,登录成功后要list列表或者读取数据时,发送PASV命令到FTP服务器, 服务器在本地随机开放一个端口(1024以上),然后把开放的端口告诉客户端, 客户端再连接到服务器开放的端口进行数据传输

从上面的运行原来看到,主动模式和被动模式的不同简单概述为: 主动模式传送数据时是“服务器”连接到“客户端”的端口;被动模式传送数据是“客户端”连接到“服务器”的端口。

主动模式需要客户端必须开放端口给服务器,很多客户端都是在防火墙内,开放端口给FTP服务器访问比较困难。

被动模式只需要服务器端开放端口给客户端连接就行了。

因此只需要将模式改为被动模式即可:

FTPClient.enterLocalPassiveMode();

  1. 在上传文件的时候,我们的文件名称有时候需要被保留,但是有时候如果文件名称为中文的话,会产生保存失败的现象,因此只需要将FTPClient的编码方式更改为UTF-8模式即可解决;
    ftpClient.setControlEncoding(“utf-8”);

3.获取FTP的配置文件

我们在进行ftp连接服务器的时候,需要一些配置文件,如何更加方便和优雅的去获取properties配置文件呢?

3.1 application.xml

首先将配置文件加载到spring容器中

1
2
3
4
5
6
7
8
9
10
<!-- 加载多个properties配置文件-->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true"/>
<property name="locations">
<list>
<value>classpath:jdbc.properties</value>
<value>classpath:Ftp.properties</value>
</list>
</property>
</bean>

3.2 创建FtpProperties.java

通过@Value的方式,将配置信息注入到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
package www.hrabbit.cn.model;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
* ftp配置文件封装
* @Auther: hrabbit
* @Date: 2018-04-17 下午6:13
* @Description:
*/
@Component("ftpProperties")
public class FTPProperties {
//ftp服务器地址
@Value("${ftp.hostName}")
private String hostName;

//ftp服务器端口号默认为21
@Value("${ftp.port}")
private String port;

//ftp的用户名称
@Value("${ftp.userName}")
private String userName;

//ftp的密码
@Value("${ftp.passWord}")
private String passWord;

//存储图片数据的根路径
@Value("${ftp.baseFile}")
private String baseFile;

//文件http服务器地址
@Value("${ftp.serverUrl}")
private String serverUrl;

public String getHostName() {
return hostName;
}

public void setHostName(String hostName) {
this.hostName = hostName;
}

public String getPort() {
return port;
}

public void setPort(String 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 String getBaseFile() {
return baseFile;
}

public void setBaseFile(String baseFile) {
this.baseFile = baseFile;
}

public String getServerUrl() {
return serverUrl;
}

public void setServerUrl(String serverUrl) {
this.serverUrl = serverUrl;
}
}

4.图片保存到图片服务器上

在业务层中通过调用FTPUtils的uploadFile方法,实现将文件上传到服务器上

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
/**
* 业务层
*/
@Service("fileService")
public class FileServiceImpl implements FileService {

/**
* 注入Dao层
*/
@Autowired
private FileMapper fileMapper;

@Autowired
private FTPProperties ftpProperties;

/**
* 获取配置文件
* @return
*/
public String getFTPProperties(String base64){
try{
MultipartFile multipartFile = BaseToMultipart.base64ToMultipart(base64);
//设置生成的目录
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/HH/mm/ss");
//生成目录
String dir = sdf.format(new Date());
//获取文件的名称
String originalFilename = multipartFile.getOriginalFilename();
//调用FTP上传工具
boolean flag = FTPUtils.uploadFile(ftpProperties.getHostName(), ftpProperties.getUserName(), ftpProperties.getPassWord(), Integer.valueOf(ftpProperties.getPort()), dir, originalFilename, multipartFile.getInputStream());
//如果上传成功
String imageUrl="";
if (flag){
imageUrl = ftpProperties.getServerUrl()+"/"+dir+"/"+originalFilename;
}
return imageUrl;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}

5. 测试上传

启动项目之后,进入到上传图片的页面
image.png

等待几秒钟,即可弹出上传到服务器的图片
image.png
我们可以看到这张图片的地址已经变成了图片服务器的地址,OK,到这里,我们通过java实现了FTP的文件上传功能!

如果大家想查看具体的代码可以通过我的码云进行下载:

hrabbit.jpg

个人博客:www.hrabbit.xin
简书:https://www.jianshu.com/u/c0657ceed065
码云:https://gitee.com/hrabbit/spring-ftp

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×