参考:Linux:CentOS 7 安装JDK8_秦毅翔的专栏-CSDN博客_linux yum下载jdk
1、将apache-ftpserver-1.1.1.tar解压到/usr/local/目录下
2、修改配置文件
vi res/conf/users.properties
# 密码(管理员:用户名:admin,密码:admin)
ftpserver.user.admin.userpassword=admin
# 该用户的根目录
ftpserver.user.admin.homedirectory=./res/home/secret
# 设置当前用户可用
ftpserver.user.admin.enableflag=true
# 设置当前用户具有上传权限
ftpserver.user.admin.writepermission=true
# 最大登录用户数为20
ftpserver.user.admin.maxloginnumber=20
# 同IP登录的用户数为2
ftpserver.user.admin.maxloginperip=2
# 空闲时间为300秒
ftpserver.user.admin.idletime=300
# 上传速率限制为48000000字节每秒
ftpserver.user.admin.uploadrate=48000000
# 下载速率限制为48000000字节每秒
ftpserver.user.admin.downloadrate=48000000
ftpserver.user.anonymous.userpassword=
ftpserver.user.anonymous.homedirectory=./res/home/any
ftpserver.user.anonymous.enableflag=true
ftpserver.user.anonymous.writepermission=false
ftpserver.user.anonymous.maxloginnumber=20
ftpserver.user.anonymous.maxloginperip=2
ftpserver.user.anonymous.idletime=300
ftpserver.user.anonymous.uploadrate=4800
ftpserver.user.anonymous.downloadrate=4800
ftpserver.user.qin.userpassword=qin
ftpserver.user.qin.homedirectory=./res/home/any
ftpserver.user.qin.enableflag=true
ftpserver.user.qin.writepermission=true
ftpserver.user.qin.maxloginnumber=20
ftpserver.user.qin.maxloginperip=2
ftpserver.user.qin.idletime=300
ftpserver.user.qin.uploadrate=4800
ftpserver.user.qin.downloadrate=4800
vi res/conf/ftpd-typical.xml
3、开启防火墙21端口
参考:Linux:centos7防火墙开放端口_秦毅翔的专栏-CSDN博客
4、启动服务器
cd /usr/src/java/ftp/apache-ftpserver-1.1.1
方式1:临时启动(窗口关闭服务停止)
sh bin/ftpd.sh /res/conf/ftpd-typical.xml
方式2:后台启动(窗口关闭服务仍然运行)
nohup ./bin/ftpd.sh res/conf/ftpd-typical.xml &
参考:SpringBoot第 1 讲:HelloWorld_秦毅翔的专栏-CSDN博客
4.0.0
org.springframework.boot
spring-boot-starter-parent
1.5.2.RELEASE
org.personal.qin.demos
apache_ftp_server_demo
1.0.0-SNAPSHOT
jar
UTF-8
UTF-8
1.8
org.springframework.boot
spring-boot-starter-web
org.springframework
spring-webmvc
org.apache.httpcomponents
httpclient
commons-net
commons-net
3.5
${project.artifactId}
org.apache.maven.plugins
maven-resources-plugin
UTF-8
org.apache.maven.plugins
maven-compiler-plugin
1.8
UTF-8
org.springframework.boot
spring-boot-maven-plugin
#ftp服务器的地址
ftp.host=10.211.55.7
#ftp服务器的端口号(连接端口号)
ftp.port=21
#ftp的用户名
ftp.username=admin
#ftp的密码
ftp.password=admin
#被动模式:回显地址
#ftp.httpPath=http://192.168.134.139
package demo.ftp.utils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.servlet.http.HttpServletResponse;
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.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import demo.ftp.entity.FileInfo;
@Configuration
@PropertySource(value = { "classpath:ftp.properties" }, ignoreResourceNotFound = false)
public class FtpClientHelper {
@Value("${ftp.host}")
private String host;
@Value("${ftp.port}")
private int port;
@Value("${ftp.username}")
private String username;
@Value("${ftp.password}")
private String password;
/**
* 上传文件(加密空间)
*
* @param relativeFilePath:路径
* @param remoteFileName:文件名
* @param input:输入流
* @return
*/
public FileInfo uploadSecretFile(String relativeFilePath, String remoteFileName, InputStream input) {
boolean isOk = uploadFile(username, password, relativeFilePath, remoteFileName, input);
if(isOk) {
return new FileInfo(remoteFileName, true, "ftp://"+host+":"+port+relativeFilePath+File.separator+remoteFileName, relativeFilePath+File.separator+remoteFileName);
}
return null;
}
/**
* 上传文件(普通空间)
*
* @param relativeFilePath:路径
* @param remoteFileName:文件名
* @param input:输入流
* @return
*/
public FileInfo uploadSimpleFile(String relativeFilePath, String remoteFileName, InputStream input) {
boolean isOk = uploadFile("qin", "qin", relativeFilePath, remoteFileName, input);
if(isOk) {
return new FileInfo(remoteFileName, false, "ftp://"+host+":"+port+relativeFilePath+File.separator+remoteFileName, relativeFilePath+File.separator+remoteFileName);
}
return null;
}
/**
* 下载文件(加密空间)
* http://127.0.0.1:8080/ftp/download?filePath=20211009&fileName=1633763634571336
* ftp://10.211.55.7/20211009/1633763634571336
*
* @param response
* @param relativeFilePath
* @param filename
*/
public void downloadSecretFile(HttpServletResponse response, String relativeFilePath, String filename) {
// jdk7以后的语法,执行之后,jdk会自动关流,无需提供finally手动关流
try (OutputStream os = response.getOutputStream();) {
response.setContentType("application/x-download");
response.addHeader("Content-Disposition", "attachment;filename=" + filename);
boolean isOk = downloadFile(username, password, os, relativeFilePath, filename);
if (isOk) {
Log.i(getClass(), relativeFilePath + "/" + filename + "下载成功");
}
os.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 下载文件(普通空间)
* http://127.0.0.1:8080/ftp/download?filePath=20211009&fileName=1633763634571336
* ftp://10.211.55.7/20211009/1633763634571336
*
* @param response
* @param relativeFilePath
* @param filename
*/
public void downloadSimpleFile(HttpServletResponse response, String relativeFilePath, String filename) {
// jdk7以后的语法,执行之后,jdk会自动关流,无需提供finally手动关流
try (OutputStream os = response.getOutputStream();) {
response.setContentType("application/x-download");
response.addHeader("Content-Disposition", "attachment;filename=" + filename);
boolean isOk = downloadFile("qin", "qin", os, relativeFilePath, filename);
if (isOk) {
Log.i(getClass(), relativeFilePath + "/" + filename + "下载成功");
}
os.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 删除文件(加密空间)
* http://127.0.0.1:8080/ftp/delete?filePath=20211009&fileName=1633764242506557
*
* @param relativeFilePath
* @param filename
* @return
*/
public boolean deleteSecretFile(String relativeFilePath, String filename) {
return deleteFile(username, password, relativeFilePath, filename);
}
/**
* 删除文件(普通空间)
* http://127.0.0.1:8080/ftp/delete?filePath=20211009&fileName=1633764242506557
*
* @param relativeFilePath
* @param filename
* @return
*/
public boolean deleteSimpleFile(String relativeFilePath, String filename) {
return deleteFile("qin", "qin", relativeFilePath, filename);
}
private boolean uploadFile(String username, String password, String relativeFilePath, String remoteFileName,
InputStream input) {
boolean flag = false;
FTPClient ftp = new FTPClient();
ftp.setControlEncoding("UTF-8");
try {
ftp.enterLocalPassiveMode(); //开启被动模式
int reply;
ftp.connect(host, port);// 连接FTP服务器
ftp.login(username, password);// 登录
reply = ftp.getReplyCode();
Log.i(getClass(), "登录ftp服务返回状态码为:" + reply);
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
return flag;
}
// 8、changWorkingDirectory(linux上的文件夹):检测所传入的目录是否存在,如果存在返回true,否则返回false
// basePath+filePath-->home/ftp/www/2019/09/02
try {
setWorkingDirectory(ftp, relativeFilePath);
} catch (Exception e) {
e.printStackTrace();
}
ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
// 设置为被动模式
// originFilePath就是上传文件的文件名,建议使用生成的唯一命名,中文命名最好做转码
flag = ftp.storeFile(remoteFileName, input);
// flag = ftp.storeFile(new
// String(remoteFileName.getBytes(),"iso-8859-1"),input);
Log.i(getClass(), "要上传的原始文件名为:" + remoteFileName + ", 上传结果:" + flag);
input.close();
ftp.logout();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioe) {
}
}
}
return flag;
}
private boolean downloadFile(String username, String password, OutputStream os, String relativeFilePath,
String filename) {
boolean flag = false;
// FTPSClient ftpClient = new FTPSClient("TLS", true);
FTPClient ftpClient = new FTPClient();
try {
// 连接FTP服务器
ftpClient.connect(host, port);
// 登录FTP服务器
ftpClient.login(username, password);
// 验证FTP服务器是否登录成功
int replyCode = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(replyCode)) {
return flag;
}
// 切换FTP目录
setWorkingDirectory(ftpClient, relativeFilePath);
// 此处为demo方法,正常应该到数据库中查询fileName
FTPFile[] ftpFiles = ftpClient.listFiles();
for (FTPFile file : ftpFiles) {
String name = file.getName();
if (filename.equalsIgnoreCase(name)) {
flag = ftpClient.retrieveFile(name, os);
Log.i(getClass(), "下载文件:" + relativeFilePath + "/" + name);
os.close();
}
}
ftpClient.logout();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (ftpClient.isConnected()) {
try {
ftpClient.logout();
} catch (IOException e) {
}
}
}
return flag;
}
private boolean deleteFile(String username, String password, String relativeFilePath, String filename) {
boolean flag = false;
FTPClient ftpClient = new FTPClient();
try {
// 连接FTP服务器
ftpClient.connect(host, port);
// 登录FTP服务器
ftpClient.login(username, password);
// 验证FTP服务器是否登录成功
int replyCode = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(replyCode)) {
return flag;
}
// 切换FTP目录
// ftpClient.changeWorkingDirectory(basePath);
setWorkingDirectory(ftpClient, relativeFilePath);
int i = ftpClient.dele(filename);
if (i == 250) {// 删除成功状态码
flag = true;
}
ftpClient.logout();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (ftpClient.isConnected()) {
try {
ftpClient.logout();
} catch (IOException e) {
}
}
}
return flag;
}
/**
* 设置ftp服务器文件上传的路径
*
* @param ftp
* @param relativeFilePath
* @throws Exception
*/
private void setWorkingDirectory(FTPClient ftp, String relativeFilePath) throws Exception {
// 判断工作路径是否存在
boolean exisit = ftp.changeWorkingDirectory(relativeFilePath);
if (!exisit) {
ftp.makeDirectory(relativeFilePath); // 不存在就创建
ftp.changeWorkingDirectory(relativeFilePath); // 设置工作路径
}
Log.i(getClass(), "切换ftp文件路径:" + relativeFilePath);
}
}
Ps:
FTP协议有两种工作方式,Port和Pasv方式,主动和被动式。
(1) PORT(主动模式)
工作的原理: FTP客户端连接到FTP服务器的21端口,发送用户名和密码登录,登录成功后要list列表或者读取数据时,客户端随机开放一个端口(1024以上),发送 PORT命令到FTP服务器,告诉服务器客户端采用主动模式并开放端口;FTP服务器收到PORT主动模式命令和端口号后,通过服务器的20端口和客户端开放的端口连接,发送数据
(2) PASV(被动模式) 这就是上面方法的作用。
工作的原理:FTP客户端连接到FTP服务器的21端口,发送用户名和密码登录,登录成功后要list列表或者读取数据时,发送PASV命令到FTP服务器, 服务器在本地随机开放一个端口(1024以上),然后把开放的端口告诉客户端, 客户端再连接到服务器开放的端口进行数据传输
package demo.ftp;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import demo.ftp.entity.FileInfo;
import demo.ftp.utils.FileNameUtil;
import demo.ftp.utils.FtpClientHelper;
@SpringBootApplication
@Controller
@RequestMapping("ftp")
public class FtpBootApplication {
@Autowired
private FtpClientHelper util;
@RequestMapping(value = "upload")
@ResponseBody
public FileInfo upload(MultipartFile file) {
// 根据id调用工具类生成新文件名
String newFileName = FileNameUtil.getFileName(3);
// 生成路径
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String filePath = sdf.format(new Date());
try(InputStream ins = file.getInputStream();){
return util.uploadSecretFile(filePath, newFileName, ins); // 上传到加密空间
// return util.uploadSimpleFile(filePath, newFileName, fis); //上传到普通空间
}catch (Exception e) {
e.printStackTrace();
}
return new FileInfo("", false, "", "");
}
@RequestMapping("delete")
@ResponseBody
public String delete(String filePath, String fileName) {
boolean isok = util.deleteSecretFile(filePath, fileName); // 删除加密空间
// boolean isok = util.deleteSimpleFile(filePath, fileName); //删除普通空间
if (isok) {
return "删除成功";
} else {
return "删除失败";
}
}
@RequestMapping("download")
@ResponseBody
public String download(HttpServletResponse response, String filePath, String fileName) {
// util.downloadSimpleFile(response, filePath, fileName); //下载普通空间
util.downloadSecretFile(response, filePath, fileName); // 下载加密空间
return "";
}
public static void main(String[] args) {
SpringApplication.run(FtpBootApplication.class, args);
}
}
https://download.csdn.net/download/qzc70919700/30557881