vsftpd 学习
- 服务器
- 2023-02-01
VSFTD 介绍
FTP 服务器
有状态
FTP 是 File Transfer Protocol 的英文简称,中文简称“文传协议”
VSFTPD
vsftpd 是 “very secure FTP daemon” 的缩写,
是一个完全免费、开放源代码的 ftp 服务器软件,支持其他 FTP 服务器所不支持的特征。
项目中图片服务器
单体架构
采用在 WEB-ROOT 目录建立 images 目录,存放图片。
分布式架构
采用 vsFTPD 图片服务器存放图片。
安装 VSFTPD
安装 vsftpd 组件
yum -y install vsftpd
#安装完成后, /etc/vsftpd/vsftpd.conf 是vsftpd 服务器的配置目录
添加一个 Linux 用户
useradd ftpuser
passwd ftpuser
防火墙开启 21 端口
#使用 vim /etc/sysconfig/iptabls
-A INPUT -p tcp -m state --state NEW -m tcp --dport 21 -j ACCEPT
#重启 iptables
service iptables restart
修改 selinux
[root@zwz home]# getsebool -a | grep ftp
allow_ftpd_anon_write --> off
allow_ftpd_full_access --> off
allow_ftpd_use_cifs --> off
allow_ftpd_use_nfs --> off
ftp_home_dir --> off
ftpd_connect_db --> off
ftpd_use_fusefs --> off
ftpd_use_passive_mode --> off
httpd_enable_ftp_server --> off
tftp_anon_write --> off
tftp_use_cifs --> off
tftp_use_nfs --> off
#设置允许,注意参数 P 大写
[root@zwz home]# setsebool -P allow_ftpd_full_access on
[root@zwz home]# setsebool -P ftp_home_dir on
关闭匿名访问
修改 /etc/vsftpf/vsftpd.conf 文件
# Allow anonymous FTP? (Beware - allowed by default if you comment this out).
anonymous_enable=no
重启 vsftpd 服务
service vsftpd restart
设置开机启动
chkconfig vsftpd on
图片上传
使用 XFTP 上传图片
使用 FTP 协议访问图片服务器
FTP 协议的 URL 格式
ftp://username:userpassword@IP/path/图片名称
#但是在 vsftpd 中,不能自动登录,需要手动登录
FTPClient 工具
apache 提供的一个开源的基于 Java 语言的 ftp 客户端
<!-- https://mvnrepository.com/artifact/commons-net/commons-net -->
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.3</version>
</dependency>
public void ftpClientDemo() throws Exception{
System.out.println("ftp 服务器...");
//创建 FTPClient
FTPClient ftp = new FTPClient();
//连接 ftp 服务器的 IP和 port
ftp.connect("192.168.170.4", 21);
//指定登录 ftp 服务器的用户名和密码
ftp.login("ftpuser", "123");
//创建输入流
InputStream is = new FileInputStream("d://1.png");
//指定上传目录以绝对路径的形式
ftp.changeWorkingDirectory("/home/ftpuser/img");
//指定上传以字符流上传,默认会采用字符流上传,图片会有损失
ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
//第一个参数表示上传后图片的名称,第二个参数表示要上传图片的资源
ftp.storeFile("java.png", is);
//关闭资源
is.close();
//关闭 ftp 连接
ftp.logout();
System.out.println("ftp 服务器结束....");
}
FTPClientUtil.java
package cn.ego.util;
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上传下载工具类
*/
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, port);// 连接FTP服务器
// 如果采用默认端口,可以使用ftp.connect(host)的方式直接连接FTP服务器
ftp.login(username, password);// 登录
reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
return result;
}
//切换到上传目录
if (!ftp.changeWorkingDirectory(basePath+filePath)) {
//如果目录不存在创建目录
String[] dirs = filePath.split("/");
String tempPath = basePath;
for (String dir : dirs) {
if (null == dir || "".equals(dir)) continue;
tempPath += "/" + dir;
if (!ftp.changeWorkingDirectory(tempPath)) {
if (!ftp.makeDirectory(tempPath)) {
return result;
} else {
ftp.changeWorkingDirectory(tempPath);
}
}
}
}
//设置上传文件的类型为二进制类型
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) {
}
}
}
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
*/
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;
}
public static void main(String[] args) {
try {
FileInputStream in=new FileInputStream(new File("D:\\1.jpg"));
boolean flag = uploadFile("192.168.10.128", 21, "ftpuser", "ftpuser", "/home/ftpuser/www/images","/2015/01/21", "gaigeming.jpg", in);
System.out.println(flag);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
KindEditor 简介
KindEditor 是一套开源的 HTML 可视化编辑器
KindEditor 初始化参数
uploadJson指定上传文件的程序
filePostName指定上传文件的名称
dir上传文件的类型
基于 KindEditor 实现文件上传
文件上传页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>首页</title>
<script charset="utf-8" src="/js/kindeditor/kindeditor-all.js"></script>
<script charset="utf-8" src="/js/kindeditor/lang/zh-CN.js"></script>
<script src="https://code.jquery.com/jquery-2.2.4.js"></script>
<script type="text/javascript">
$(function(){
var obj;
KindEditor.ready(function(K) {
obj= K.create(#text_id, {
uploadJson : /upload,
filePostName:fileName,
dir:"image"
});
});
//给按钮添加点击事件
$("#but").click(function(){
//将KindEditor中的数据同步到textarea中
obj.sync();
//通过ajax方式提交表单 serialize()作用:将表单中的数据序列化为key=value&key=value.....
$.post("/content/save2",$("#myForm").serialize(),function(data){
/* eval("var data="+data1); */
if(data.status == 200){
alert("提交成功");
}else{
alert("提交失败");
}
});
});
});
</script>
</head>
<body>
<h1 align="center">Welcome to SSM</h1>
<hr />
<form id="myForm">
<textarea rows="20" cols="20" id="text_id" name="desc"></textarea>
<input type="button" value="OK" id="but" />
</form>
</body>
</html>
文件上传 Controller
package cn.szxy.web.controller;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
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 cn.szxy.commons.JsonUtils;
import cn.szxy.service.PhotoUploadService;
/**
* 图片 上传
*
*/
@Controller
public class PhotoUploadController {
@Autowired
private PhotoUploadService photoUploadService;
@RequestMapping("/upload")
@ResponseBody
public String uploadPhoto(MultipartFile fileName){
Map<String,Object> map = photoUploadService.uploadPhoto(fileName);
return JsonUtils.objectToJson(map);
}
}
KindEditor 提交数据
step1:使用 ajax 方式提交数据
step2:使用 KindEditor 的 sync 方法将数据同步到 textarea中
step3:后台接受数据
注意: 在 Object 类型方法前加上 @ResponseBody 注解表示当前数据以 json格式返回
package cn.szxy.web.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import cn.szxy.commons.JsonUtils;
/**
* 获取 KindEdior 中的文本内容
*
*/
@Controller
@RequestMapping("/content")
public class KindEditor {
//方式一
@RequestMapping("/save")
@ResponseBody
public Object save(String desc){
System.out.println(desc);
Map<String,Object> map = new HashMap<>();
map.put("status",200);
return map;
}
//方式二
@RequestMapping(value="/save2",produces="application/json;charset=utf-8")
@ResponseBody
public String save2(String desc){
System.out.println(desc);
Map<String,Object> map = new HashMap<>();
map.put("status",200);
return JsonUtils.objectToJson(map);
}
}