VSFTPD

FTP 服务器

FTP File Transfer Protocol(文件传输协议)的英文简称,而中文简称为“文传协议”。用于 Internet 上的控制文件的双向传输。同时,它也是一个应用程序(Application)。 基于不同的操作系统有不同的 FTP 应用程序,而所有这些应用程序都遵守同一种协议以传输文件。

FTP 的使用当中,用户经常遇到两个概念:"下载"Download)和"上传"Upload)。"下载"文件就是从远程主机拷贝文件至自己的计算机上;"上传"文件就是将文件从自己的计算机中拷贝至远程主机上。用 Internet 语言来说,用户可通过客户机程序向(从)远程主机上传(下载)文件。

 

VSFTPD 简介

vsftpd 是“very secure FTP daemon”的缩写,安全性是它的一个最大的特点。vsftpd是一个 UNIX 类操作系统上运行的服务器的名字,它可以运行在诸如 LinuxBSDSolarisHP-UNIX 等系统上面,是一个完全免费的、开放源代码的 ftp 服务器软件,支持很多其他的FTP 服务器所不支持的特征。

 

项目中图片服务器:

在传统的单体架构项目中,可以在 web 项目中添加一个文件夹,来存放上传的图片。

例如在工程的根目录 WebRoot 下创建一个 images 文件夹用于保存已上传的图片。

优点:使用方便,便于管理

缺点:

1、如果是分布式环境中图片引用会出现问题。

2、图片的下载会给服务器增加额外的压力

 

 

 

 

 

 

 安装 VSFTP

1 安装 vsftpd 组件

yum -y install vsftpd

安装完后,有/etc/vsftpd/vsftpd.conf 文件,是 vsftp 的配置文件。

2 添加一个 Linux 用户

此用户就是用来登录 ftp 服务器用的。

useradd ftpuser

这样一个用户建完,可以用这个登录。登录后默认的路径为 /home/ftpuser.

3 给用户添加密码。

passwd ftpuser

输入两次密码后修改密码。

4 防火墙开启 21 端口

因为 ftp 默认的端口为 21,而 centos 默认是没有开启的,所以要修改 iptables 文件

vim /etc/sysconfig/iptables

在行上面有 22 -j ACCEPT 下面另起一行输入跟那行差不多的,只是把 22 换成 21,然后:

wq 保存。

还要运行下,重启 iptables

service iptables restart

5 修改 selinux

外网是可以访问上去了,可是发现没法返回目录(使用 ftp 的主动模式,被动模式还是无法访问),也上传不了,因为 selinux 作怪了。

修改 selinux

执行以下命令查看状态:

[root@bogon ~]# getsebool -a | grep ftp

执行上面命令,再返回的结果看到两行都是 off,代表,没有开启外网的访问

[root@bogon ~]# setsebool -P allow_ftpd_full_access on

[root@bogon ~]# setsebool -P ftp_home_dir on

 修改/etc/vsftpd/vsftpd.conf 文件:

 

重启 ftp 服务:

service vsftpd restart

 

设置开机启动 vsftpd ftp 服务

chkconfig vsftpd on

 

图片上传:

1 使用 FileZilla 上传图片

 

使用 FTP 协议访问图片服务器

2.1FTP 协议的 URL 格式

ftp://username:userpassword@IP/路径/图片名称

VSFTPD 的插件中。不允许这样访问。必须要有登录环节。

 

FTPClient 工具

3.1FTPClient 介绍

FTPClient Apache 提供的一个开源的基于 JAVA 语言的 FTP 客户端工具。

FTPClient 位于 Apache commons-net 项目中。

 

 

三个工具类 :

com.bjsxt.commons.FtpUtil

package com.bjsxt.commons;

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服务器文件存放路径。例如分日期存放:/2018/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);// 登录
			ftp.enterLocalPassiveMode();
			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;
	}
}

 

com.bjsxt.commons.IDUtils

package com.bjsxt.commons;

import java.util.Random;
import java.util.UUID;

/**
 * 各种id生成策略
 * @version 1.0
 */
public class IDUtils {

	/**
	 * 图片名生成
	 */
	public static String genImageName() {
		//取当前时间的长整形值包含毫秒
		long millis = System.currentTimeMillis();
		//long millis = System.nanoTime();
		//加上三位随机数
		Random random = new Random();
		int end3 = random.nextInt(999);
		//如果不足三位前面补0
		String str = millis + String.format("%03d", end3);
		return str;
	}
	
	/**
	 * 商品id生成
	 */
	public static long genItemId() {
		//取当前时间的长整形值包含毫秒
		long millis = System.currentTimeMillis();
		//long millis = System.nanoTime();
		//加上两位随机数
		Random random = new Random();
		int end2 = random.nextInt(99);
		//如果不足两位前面补0
		String str = millis + String.format("%02d", end2);
		long id = new Long(str);
		return id;
	}
	
}

 

com.bjsxt.commons.JsonUtils

package com.bjsxt.commons;

import java.util.List;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * JSON转换工具类
 */
public class JsonUtils {

    // 定义jackson对象
    private static final ObjectMapper MAPPER = new ObjectMapper();

    /**
     * 将对象转换成json字符串。
     * <p>Title: pojoToJson</p>
     * <p>Description: </p>
     * @param data
     * @return
     */
    public static String objectToJson(Object data) {
    	try {
			String string = MAPPER.writeValueAsString(data);
			return string;
		} catch (JsonProcessingException e) {
			e.printStackTrace();
		}
    	return null;
    }
    
    /**
     * 将json结果集转化为对象
     * 
     * @param jsonData json数据
     * @param clazz 对象中的object类型
     * @return
     */
    public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
        try {
            T t = MAPPER.readValue(jsonData, beanType);
            return t;
        } catch (Exception e) {
        	e.printStackTrace();
        }
        return null;
    }
    
    /**
     * 将json数据转换成pojo对象list
     * <p>Title: jsonToList</p>
     * <p>Description: </p>
     * @param jsonData
     * @param beanType
     * @return
     */
    public static <T>List<T> jsonToList(String jsonData, Class<T> beanType) {
    	JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
    	try {
    		List<T> list = MAPPER.readValue(jsonData, javaType);
    		return list;
		} catch (Exception e) {
			e.printStackTrace();
		}
    	
    	return null;
    }
    
}

 

一个实现类一个接口 :

实现类:PicUploadServiceImpl.java:

package com.bjsxt.service.impl;

import com.bjsxt.commons.FtpUtil;
import com.bjsxt.commons.IDUtils;
import com.bjsxt.service.PicUploadService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.SimpleFormatter;

@Service
public class PicUploadServiceImpl implements PicUploadService {
    @Value("${FTP_HOST}")
    private String FTP_HOST;

    @Value("${FTP_PORT}")
    private int FTP_PORT;

    @Value("${FTP_USERNAME}")
    private String FTP_USERNAME;

    @Value("${FTP_PASSWORD}")
    private String FTP_PASSWORD;

    @Value("${FTP_BASEPATH}")
    private String FTP_BASEPATH;

    @Value("${HTTP_BASE_PATH}")
    private String HTTP_BASE_PATH;

    @Override
    public Map<String, Object> fileUpload(MultipartFile filename) {
        Map<String,Object> map=new HashMap<>();
        Date date=new Date();
        try {
            SimpleDateFormat sdf=new SimpleDateFormat("/yyyy/MM/dd");
            String path=sdf.format(date);
            String newFileName= IDUtils.genImageName()+filename.getOriginalFilename().substring(filename.getOriginalFilename().lastIndexOf("."));
            boolean flag = FtpUtil.uploadFile(this.FTP_HOST, this.FTP_PORT, this.FTP_USERNAME, this.FTP_PASSWORD, this.FTP_BASEPATH, path, newFileName, filename.getInputStream());
            if (flag){
                map.put("error",0);
                map.put("url",this.HTTP_BASE_PATH+path+newFileName);
            }else {
                map.put("error",1);
                map.put("message","上传失败~");
            }

        }catch (Exception e){
            map.put("error",1);
            map.put("message","上传失败~");
            e.printStackTrace();
        }

        return map;
    }
}

 

接口:

package com.bjsxt.service;

import org.springframework.web.multipart.MultipartFile;

import java.util.Map;

public interface PicUploadService {
    Map<String,Object> fileUpload(MultipartFile filename);
}

 

控制层

com.bjsxt.web.controller.PicUploadController

package com.bjsxt.web.controller;

import com.bjsxt.commons.JsonUtils;
import com.bjsxt.service.PicUploadService;
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 java.util.Map;

@Controller
@RequestMapping("/pic")
public class PicUploadController {

    @Autowired
    PicUploadService picUploadService;
    /**
     * 图片上传
     */
    @RequestMapping("/upload")
    @ResponseBody
    public String fileUpload(MultipartFile fileName){
        Map<String, Object> map = picUploadService.fileUpload(fileName);
        return JsonUtils.objectToJson(map);
    }
}

 

com.bjsxt.web.controller.ContentController 

package com.bjsxt.web.controller;

import com.bjsxt.commons.JsonUtils;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.print.attribute.standard.Media;
import java.util.HashMap;
import java.util.Map;

@Controller
@RequestMapping("/content")
public class ContentController {

    /**
     * 内容保存
     *
     */
    @RequestMapping(value = "/save",produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public String saveContent(String desc){
        System.out.println(desc);
        Map<String,Object> map=new HashMap<>();
        map.put("status",200);
        return JsonUtils.objectToJson(map);
    }
}

 

index.xml

<%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2019/9/26
  Time: 15:15
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>首页</title>
    <script type="text/javascript" src="/js/kindeditor/kindeditor.js"></script>
    <script type="text/javascript" src="/js/kindeditor/lang/zh_CN.js"></script>
    <script type="text/javascript" src="/js/jquery-1.7.2.js"></script>
    <script type="text/javascript">
        $(function(){
            var obj;
            KindEditor.ready(function(K) {
                obj= K.create('#text_id', {
                    uploadJson : '/pic/upload',
                    filePostName:'fileName',
                    dir:"image"
                });
            });

            //给按钮添加点击事件
            $("#but").click(function(){
                //将KindEditor中的数据同步到textarea中
                obj.sync();

                //通过ajax方式提交表单      serialize()作用:将表单中的数据序列化为key=value&key=value.....
                $.post("/content/save",$("#myForm").serialize(),function(data){
                    if(data.status == 200){
                        alert("提交成功");
                    }else{
                        alert("提交失败~~");
                    }
                });
            });

        });
    </script>
</head>
<body>
<form id="myForm">
    <textarea rows="20" cols="20" id="text_id" name="desc"></textarea>
    <input type="button" value="OK" id="but"/>
</form>
</body>
</html>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值