vsftpd 学习

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); } }