天天看点

阿里云ECS,CentOs7.3搭建FTP服务器,附带java使用demo

目录

我的需求:

1.安装过程​​​​​​:

附带图:​2.开启远程访问

3.修改配置文件,禁止匿名访问

4.创建一个用户

5.开启被动模式

6.配置用户ftp权限及访问路径限制

碰见的问题:

整合nginx

我的需求:

1.搭建完ftp后,添加一个ftp用户,只允许对指定的目录进行读写操作,其余目录禁止读写.

2.在java代码中使用ftp用户账户,进行上传文件/图片.

3.使用nginx整合ftp,提供对外访问文件/图片的url路径.

在java中使用ftp上传时,有关于目录的问题,参考这篇文章:https://blog.csdn.net/qq_23167527/article/details/66975727

1.安装过程​​​​​​:

第一步:检查是否安装了vsftpd

rpm -qa | grep vsftpd
           

第二步:如果没有安装则安装vsftpd

yum -y install vsftpd
           

第三步: 补充知识点,不需要全部执行

systemctl status vsftpd 查看服务状态

systemctl start vsftpd  启动服务

systemctl stop vsftpd   暂停服务

systemctl restart vsftpd   重启启动服务

systemctl enable vsftpd  开机自启动

systemctl disable vsftpd   取消开机自启动
           

附带图:
阿里云ECS,CentOs7.3搭建FTP服务器,附带java使用demo
2.开启远程访问

在阿里云安全组中,添加安全组规则

阿里云ECS,CentOs7.3搭建FTP服务器,附带java使用demo

3.修改配置文件,禁止匿名访问

编辑配置文件

vim /etc/vsftpd/vsftpd.conf
           

默认是yes将其改为no

anonymous_enable=NO  
           

4.创建一个用户

创建一个用户使用ftp

useradd ftpuser -d /home/ftpimage
           

设置用户密码,输入两次就行

passwd ftpuser
           

5.开启被动模式

被动模式默认是开启的,但是需要指定一个端口范围.

vim /etc/vsftpd/vsftpd.conf
           

在最后面加上,注意这里是开启范围端口,意思是说,8800~8899这个范围内的端口必须全部开启,当然你也可以自己随便设置

pasv_min_port=8800

pasv_max_port=8899
           

表示端口范围为8800~8899,这个可以随便修改,改完记得重启一下vsftpd服务。

友情提示:最大和最小,最好设置为一样,这样就成了固定端口了

对应的我们也应该在安全组策略中添加这个范围的端口。

阿里云ECS,CentOs7.3搭建FTP服务器,附带java使用demo

6.配置用户ftp权限及访问路径限制

编辑配置文件,在末尾添加,这三行

vim /etc/vsftpd/vsftpd.conf
           
userlist_enable=YES
userlist_deny=NO
userlist_file=/etc/vsftpd/user_list
           

编辑user_list文件.将用户名添加进去

ftpuser
           

这时候发现,创建的用户是可以访问其他路径的,如果想要不允许,则编辑配置文件,将这两行前的#号去掉

chroot_list_enable=YES
# (default follows)
chroot_list_file=/etc/vsftpd/chroot_list
           

如果没有chroot_list文件,则手动创建

touch chroot_list
           

编辑chroot_list文件,将用户账号添加进去

阿里云ECS,CentOs7.3搭建FTP服务器,附带java使用demo

如果发现vsftpd: refusing to run with writable root inside chroot错误

原因:从2.3.5之后,vsftpd增强了安全检查,如果用户被限定在了其主目录下,则该用户的主目录不能再具有写权限了!如果检查发现还有写权限,就会报该错误

解决:编辑配置文件,在末尾加上

allow_writeable_chroot=YES
           

如果发现上传不了文件,则需要设置文件夹读写权限

阿里云ECS,CentOs7.3搭建FTP服务器,附带java使用demo

碰见的问题:

1.dos命令能连接,点击查看这篇文章: FileZilla MLSD错误:连接超时、读取目录列表失败

2.dos命令能连接,但是windows连接不上,直接修改被动模式的端口,将最大端口和最小端口修改为一样

整合nginx

1.安装nginx参考这篇文章:https://www.cnblogs.com/wyd168/p/6636529.html

2.修改nginx配置文件

阿里云ECS,CentOs7.3搭建FTP服务器,附带java使用demo

访问效果:

阿里云ECS,CentOs7.3搭建FTP服务器,附带java使用demo

如果这里访问报404,则需要考虑指定的目录是否有可访问权限

导入依赖:

<dependency>
            <groupId>commons-net</groupId>
            <artifactId>commons-net</artifactId>
            <version>3.3</version>
        </dependency>
           

实体类:

public class PicUploadResult {

    private int error;

    /**
     * 图片保存路径
     */
    private String url;
    // set/get......
}
           

java上传工具类:

import com.bbpk.common.base.ConstantInterface;
import com.bbpk.common.base.entity.vo.PicUploadResult;
import com.xiaoleilu.hutool.date.DateTime;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 文件上传帮助类
 */
public class FileUploadUtil {


    public static boolean isImage(String contentType) {
        for (String type : ConstantInterface.IMAGE_CONTENT_TYPE) {
            if (contentType.toLowerCase().equals(type)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 照片上传
     *
     * @param uploadFile    需上传的文件
     * @return
     * @throws Exception
     */
    public static PicUploadResult imgUpload(MultipartFile uploadFile) throws Exception {
        if (null == uploadFile) return null;

        // 封装Result对象,并且将文件的byte数组放置到result对象中
        PicUploadResult fileUploadResult = new PicUploadResult();

        // 校验图片格式
//        boolean isLegal = isImageFile(uploadFile.getOriginalFilename());
        boolean isLegal = isImage(uploadFile.getContentType());

        // 状态
        fileUploadResult.setError(isLegal ? 0 : 1);

        // 文件新路径
        String fileName = getFileName(uploadFile.getContentType());

        File newFile = new File(fileName);


        InputStream is = uploadFile.getInputStream();

        if (null == is) {
            throw new Exception("图片输入流为获取失败");
        }
        // 图片上传到FTP服务器
        boolean rtn = FTPClientUtil.uploadImage("", newFile.getName(), is);
        fileUploadResult.setUrl("http://IP+端口/"+newFile.getName());
        fileUploadResult.setError(isLegal && rtn ? 0 : 1);
        return fileUploadResult;
    }

    public static String getFileName(String contentType) {
        String suffix = "";
        List<String> type = Arrays.stream(ConstantInterface.IMAGE_CONTENT_TYPE)
                .filter(n -> n.equals(contentType))
                .collect(Collectors.toList());
        if (type.size() > 0) {
            suffix = StringUtils.substringAfterLast(type.get(0), "/");
        }

        Date nowDate = new Date();
        return new DateTime(nowDate).toString("yyyyMMddhhmmssSSSS")
                + RandomUtils.nextInt(100, 9999) + "." + suffix;
    }

}
           
import com.bbpk.common.base.ConstantInterface;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;

import java.io.*;

/**
 * FTP客户端 上传文件
 */
public class FTPClientUtil {


    /**
     * 校验图片格式
     *
     * @param filename
     * @return
     */
    public static boolean isImageFile(String filename) {
        // 校验图片格式
        boolean isLegal = false;
        for (String type : ConstantInterface.IMAGE_TYPE) {
            if (org.apache.commons.lang3.StringUtils.endsWithIgnoreCase(filename, type)) {
                isLegal = true;
                break;
            }
        }

        return isLegal;
    }

    /**
     * 获取FTP连接
     *
     * @return
     */
    private static FTPClient getInstance() {
        FTPClient ftp = new FTPClient();
        try {
            int reply;
            ftp.connect("ip地址", 21);//连接FTP服务器
            //如果采用默认端口,可以使用ftp.connect(url)的方式直接连接FTP服务器
            boolean rtn = ftp.login("账户", "密码");//登录
            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

        return ftp;
    }

    /**
     * 上传图片到服务器
     *
     * @param relativePath 相对路径
     * @param filename     文件名
     * @param input        文件流
     * @return 成功返回true,否则返回false
     */
    public static boolean uploadImage(String relativePath, String filename, InputStream input) {

        return FTPClientUtil.uploadFile("/home/monkeyimg/img" + relativePath, filename, input);
    }

    /**
     * 向FTP服务器上传文件
     *
     * @param path     FTP服务器保存目录
     * @param filename 上传到FTP服务器上的文件名
     * @param input    输入流
     * @return 成功返回true,否则返回false
     */
    public static boolean uploadFile(String path, String filename, InputStream input) {
        boolean success = false;
        FTPClient ftpClient = getInstance();
        ftpClient.enterLocalPassiveMode();
        try {
            ftpClient.setControlEncoding("UTF-8");
            ftpClient.changeWorkingDirectory(path);


            //如果是图片 需要修改上传文件的格式,否则图片以文本的形式传输,会失真
            //ftpClient默认上传的格式是文本
            //修改成二进制上传
            if (isImageFile(filename)) {
                ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            }

            //注意注意注意:需要设置目录权限为777 坑死我了
            success = ftpClient.storeFile(new String(filename.getBytes("UTF-8"), "iso-8859-1"), input);

            input.close();
            ftpClient.logout();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftpClient.isConnected()) {
                try {
                    ftpClient.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return success;
    }

}