软件编程
位置:首页>> 软件编程>> java编程>> SpringBoot 使用 FTP 操作文件的过程(删除、上传、下载文件)

SpringBoot 使用 FTP 操作文件的过程(删除、上传、下载文件)

作者:tansci  发布时间:2021-07-26 10:40:05 

标签:SpringBoot,FTP

简介

使用 SpringBoot 配置 FTP 服务器,上传、删除、下载文件。

配置 FTP

检查是否安装 vsftpd

rpm -qa | grep vsftpd

检修是否已经安装 vsftpd 及查看版本号.

安装 vsftpd

yum -y install vsftpd

如果报错,则使用管理员权限执行 sudo yum -y install vsftpd

关闭匿名访问

关闭匿名访问后,想访问里面的文件就需要账号和密码;如果不关,就可以直接访问。

vim /etc/vsftpd/vsftpd.conf

如果提示是只读文件,那么你只需要输入命令: sudo vim /etc/vsftpd/vsftpd.conf

如下:

# Example config file /etc/vsftpd/vsftpd.conf
#
# The default compiled in settings are fairly paranoid. This sample file
# loosens things up a bit, to make the ftp daemon more usable.
# Please see vsftpd.conf.5 for all compiled in defaults.
#
# READ THIS: This example file is NOT an exhaustive list of vsftpd options.
# Please read the vsftpd.conf.5 manual page to get a full idea of vsftpd's
# capabilities.
#
# Allow anonymous FTP? (Beware - allowed by default if you comment this out).
anonymous_enable=NO
#
# Uncomment this to allow local users to log in.
local_enable=YES
#
# Uncomment this to enable any form of FTP write command.
write_enable=YES
#
# Default umask for local users is 077. You may wish to change this to 022,
# if your users expect that (022 is used by most other ftpd's)
local_umask=022
#
# Uncomment this to allow the anonymous FTP user to upload files. This only
# has an effect if the above global write enable is activated. Also, you will
# obviously need to create a directory writable by the FTP user.
# When SELinux is enforcing check for SE bool allow_ftpd_anon_write, allow_ftpd_full_access
#anon_upload_enable=YES
#
# Uncomment this if you want the anonymous FTP user to be able to create
# new directories.
#anon_mkdir_write_enable=YES
#
# Activate directory messages - messages given to remote users when they
# go into a certain directory.
dirmessage_enable=YES
#
# Activate logging of uploads/downloads.
xferlog_enable=YES
#
# Make sure PORT transfer connections originate from port 20 (ftp-data).
connect_from_port_20=YES
#
# If you want, you can arrange for uploaded anonymous files to be owned by
# a different user. Note! Using "root" for uploaded files is not
# recommended!
#chown_uploads=YES
#chown_username=whoever
#
# You may override where the log file goes if you like. The default is shown
# below.
#xferlog_file=/var/log/xferlog
#
# If you want, you can have your log file in standard ftpd xferlog format.
# Note that the default log file location is /var/log/xferlog in this case.
xferlog_std_format=YES
#
# You may change the default value for timing out an idle session.
#idle_session_timeout=600

关闭匿名访问就是将:anonymous_enable=NO

启动服务

systemctl start vsftpd.service

查看服务状态

systemctl status vsftpd.service
[root@hadoop-master ~]# systemctl status vsftpd.service
● vsftpd.service - Vsftpd ftp daemon
  Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; disabled; vendor preset: disabled)
  Active: active (running) since 一 2022-12-19 10:15:39 CST; 58min ago
 Process: 21702 ExecStart=/usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf (code=exited, status=0/SUCCESS)
Main PID: 21703 (vsftpd)
  CGroup: /system.slice/vsftpd.service
          └─21703 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf

12月 19 10:15:39 hadoop-master systemd[1]: Starting Vsftpd ftp daemon...
12月 19 10:15:39 hadoop-master systemd[1]: Started Vsftpd ftp daemon.
[root@hadoop-master ~]#

看到绿色的 active(running),代表着启动成功正在运行中。

添加 FTP 用户

因为在 Linux 上,root 用户是不能登陆 FTP 的。如果你输入的是 root 用户,登陆会失败的。

adduser ftpadmin

设置密码:

passwd ftpadmin

输入两次密码就 ok 了。

配置允许root用户登录

/etc/vsftpd/user_list 文件和 /etc/vsftpd/ftpusers 文件中的root这一行注释掉

修改/etc/vsftpd/vsftpd.conf,在最后一行处添加local_root=/

service vsftpd  restart

这样远程就可以root用户身份登录ftp了。

文件存储地址授权

如存储地址为:app/upload/,设置权限为:

chmod 777 /app/upload/

SpringBoot 编码

添加依赖

<dependency>
   <groupId>com.jcraft</groupId>
   <artifactId>jsch</artifactId>
   <version>0.1.55</version>
</dependency>

操作文件工具类

package com.demo.utils;

import com.jcraft.jsch.*;
import com.demo.dto.UploadFileDto;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.FileOutputStream;
import java.util.Properties;

/**
* @ClassName: UploadFileUtils.java
* @Description: 上传文件
* @Author: tanyp
* @Date: 2022/12/19 10:38
**/
@Slf4j
public class UploadFileUtils {

/**
    * @MonthName: upload
    * @Description: 上传文件
    * @Author: tanyp
    * @Date: 2022/12/19 10:38
    * @Param: [dto]
    * @return: boolean
    **/
   public static boolean upload(UploadFileDto dto) throws Exception {
       log.info("============上传文件开始==============");
       Boolean result = false;
       ChannelSftp sftp = null;
       Channel channel = null;
       Session sshSession = null;
       try {
           JSch jSch = new JSch();
           jSch.getSession(dto.getAccount(), dto.getHost(), dto.getPort());
           sshSession = jSch.getSession(dto.getAccount(), dto.getHost(), dto.getPort());
           sshSession.setPassword(dto.getPasswd());
           Properties sshConfig = new Properties();
           sshConfig.put("StrictHostKeyChecking", "no");
           sshSession.setConfig(sshConfig);
           sshSession.connect();
           channel = sshSession.openChannel("sftp");
           channel.connect();
           sftp = (ChannelSftp) channel;

sftp.cd(dto.getWorkingDir());
           sftp.put(dto.getInputStream(), dto.getFileName());
           result = true;
           log.info("============上传文件结束==============");
       } catch (JSchException e) {
           result = false;
           log.error("=====上传文件异常:{}", e.getMessage());
           e.printStackTrace();
       } finally {
           closeChannel(sftp);
           closeChannel(channel);
           closeSession(sshSession);
       }
       return result;
   }

/**
    * @MonthName: delete
    * @Description: 删除文件
    * @Author: tanyp
    * @Date: 2022/12/19 10:38
    * @Param: [dto]
    * @return: boolean
    **/
   public static boolean delete(UploadFileDto dto) throws Exception {
       log.info("============删除文件开始==============");
       Boolean result = false;
       ChannelSftp sftp = null;
       Channel channel = null;
       Session sshSession = null;
       try {
           JSch jSch = new JSch();
           jSch.getSession(dto.getAccount(), dto.getHost(), dto.getPort());
           sshSession = jSch.getSession(dto.getAccount(), dto.getHost(), dto.getPort());
           sshSession.setPassword(dto.getPasswd());
           Properties sshConfig = new Properties();
           sshConfig.put("StrictHostKeyChecking", "no");
           sshSession.setConfig(sshConfig);
           sshSession.connect();
           channel = sshSession.openChannel("sftp");
           channel.connect();
           sftp = (ChannelSftp) channel;

sftp.cd(dto.getWorkingDir());
           sftp.rm(dto.getFileName());
           result = true;
           log.info("============删除文件结束==============");
       } catch (JSchException e) {
           result = false;
           log.error("=====删除文件异常:{}", e.getMessage());
           e.printStackTrace();
       } finally {
           closeChannel(sftp);
           closeChannel(channel);
           closeSession(sshSession);
       }
       return result;
   }

/**
    * @MonthName: download
    * @Description: 下载文件
    * @Author: tanyp
    * @Date: 2022/12/19 10:38
    * @Param: [dto]
    * @return: boolean
    **/
   public static boolean download(UploadFileDto dto) throws Exception {
       log.info("============下载文件开始==============");
       Boolean result = false;
       ChannelSftp sftp = null;
       Channel channel = null;
       Session sshSession = null;
       try {
           JSch jSch = new JSch();
           jSch.getSession(dto.getAccount(), dto.getHost(), dto.getPort());
           sshSession = jSch.getSession(dto.getAccount(), dto.getHost(), dto.getPort());
           sshSession.setPassword(dto.getPasswd());
           Properties sshConfig = new Properties();
           sshConfig.put("StrictHostKeyChecking", "no");
           sshSession.setConfig(sshConfig);
           sshSession.connect();
           channel = sshSession.openChannel("sftp");
           channel.connect();
           sftp = (ChannelSftp) channel;

sftp.cd(dto.getWorkingDir());
           sftp.get(dto.getFileName(), new FileOutputStream(new File(dto.getDownloadPath())));
           sftp.disconnect();
           sftp.getSession().disconnect();
           result = true;
           log.info("============下载文件结束==============");
       } catch (JSchException e) {
           result = false;
           log.error("=====下载文件异常:{}", e.getMessage());
           e.printStackTrace();
       } finally {
           closeChannel(sftp);
           closeChannel(channel);
           closeSession(sshSession);
       }
       return result;
   }

private static void closeChannel(Channel channel) {
       if (channel != null) {
           if (channel.isConnected()) {
               channel.disconnect();
           }
       }
   }

private static void closeSession(Session session) {
       if (session != null) {
           if (session.isConnected()) {
               session.disconnect();
           }
       }
   }

}

UploadFileDto.java

package com.demo.dto;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.InputStream;

/**
* @ClassName: UploadFileDto.java
* @ClassPath: com.demo.dto.UploadFileDto.java
* @Description: 上传文件
* @Author: tanyp
* @Date: 2022/12/19 10:38
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ApiModel(value = "上传文件Dto")
public class UploadFileDto {

@ApiModelProperty(value = " ftp 服务器ip地址")
   private String host;

@ApiModelProperty(value = " ftp 服务器port,默认是21")
   private Integer port;

@ApiModelProperty(value = " ftp 服务器用户名")
   private String account;

@ApiModelProperty(value = " ftp 服务器密码")
   private String passwd;

@ApiModelProperty(value = " ftp 服务器存储图片的绝对路径")
   private String workingDir;

@ApiModelProperty(value = "上传到ftp 服务器文件名")
   private String fileName;

@ApiModelProperty(value = " 文件流")
   private InputStream inputStream;

@ApiModelProperty(value = " 下载文件的路径")
   private String downloadPath;

}

UploadVo.java

package com.demo.vo;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* @ClassName: UploadVo.java
* @ClassPath: com.demo.vo.UploadVo.java
* @Description: 文件VO
* @Author: tanyp
* @Date: 2022/12/19 15:18
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ApiModel(value = "文件VO")
public class UploadVo {

@ApiModelProperty(value = "原始文件名称")
   private String oldName;

@ApiModelProperty(value = "新文件名称")
   private String newName;

@ApiModelProperty(value = "访问路径")
   private String path;

}

UploadController

package com.demo.controller;

import com.demo.vo.UploadVo;
import com.demo.service.UploadService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

/**
* @ClassName: UploadController.java
* @ClassPath: com.demo.controller.UploadController.java
* @Description: 上传文件
* @Author: tanyp
* @Date: 2022/12/19 15:18
**/
@Slf4j
@RestController
@RequestMapping("/upload")
@Api(value = "upload", tags = "上传文件")
public class UploadController {

@Autowired
   private UploadService uploadService;

@ApiOperation(value = "上传图片", notes = "上传图片")
   @PostMapping("/uploadImage")
   public UploadVo uploadImage(@RequestParam("file") MultipartFile file) {
       return uploadService.uploadImage(file);
   }

@ApiOperation(value = "删除文件", notes = "删除文件")
   @GetMapping("/delFile")
   public Boolean delFile(String fileName) {
       return uploadService.delFile(fileName);
   }

@ApiOperation(value = "下载文件", notes = "下载文件")
   @GetMapping("/downloadFile")
   public Boolean downloadFile(String fileName, String downloadPath) {
       return uploadService.downloadFile(fileName, downloadPath);
   }

}

UploadService

package com.demo.service;

import com.demo.vo.UploadVo;
import org.springframework.web.multipart.MultipartFile;

/**
* @ClassName: UploadService.java
* @ClassPath: com.demo.service.UploadService.java
* @Description:上传文件
* @Author: tanyp
* @Date: 2022/12/19 15:18
**/
public interface UploadService {

UploadVo uploadImage(MultipartFile file);

Boolean delFile(String fileName);

Boolean downloadFile(String fileName, String downloadPath);

}

UploadServiceImpl

package com.demo.service.impl;

import com.demo.dto.UploadFileDto;
import com.demo.vo.UploadVo;
import com.demo.config.FtpConfig;
import com.demo.service.UploadService;
import com.demo.utils.UUIDUtils;
import com.demo.utils.UploadFileUtils;
import com.demo.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Objects;

/**
* @ClassName: UploadServiceImpl.java
* @ClassPath: com.demo.service.impl.UploadServiceImpl.java
* @Description: 上传文件
* @Author: tanyp
* @Date: 2022/12/19 15:18
**/
@Slf4j
@Service
public class UploadServiceImpl implements UploadService {

@Autowired
   private FtpConfig ftpConfig;

@Override
   public UploadVo uploadImage(MultipartFile file) {
       log.info("=======上传图片开始,图片名称:{}", file.getOriginalFilename());
       try {
           // 1. 取原始文件名
           String oldName = file.getOriginalFilename();

// 2. ftp 服务器的文件名
           String newName = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + UUIDUtils.getUUID(10) + oldName.substring(oldName.lastIndexOf("."));

// 3.上传图片
           Boolean result = UploadFileUtils.upload(
                   UploadFileDto.builder()
                           .host(ftpConfig.host)
                           .port(ftpConfig.post)
                           .account(ftpConfig.username)
                           .passwd(ftpConfig.password)
                           .workingDir(ftpConfig.basePath)
                           .fileName(newName)
                           .inputStream(file.getInputStream())
                           .build()
           );

// 4.返回结果
           if (!result) {
               throw new BusinessException("上传图片失败!");
           }

log.info("=======上传图片结束,新图片名称:{}", newName);
           return UploadVo.builder()
                   .oldName(oldName)
                   .newName(newName)
                   .path(ftpConfig.imageBaseUrl + "/" + newName)
                   .build();
       } catch (Exception e) {
           log.error("=======上传图片异常,异常信息:{}", e.getMessage());
           e.printStackTrace();
       }
       return null;
   }

@Override
   public Boolean delFile(String fileName) {
       if (Objects.isNull(fileName)) {
           throw new BusinessException("文件名称为空,请核实!");
       }
       try {
           Boolean result = UploadFileUtils.delete(
                   UploadFileDto.builder()
                           .host(ftpConfig.host)
                           .port(ftpConfig.post)
                           .account(ftpConfig.username)
                           .passwd(ftpConfig.password)
                           .workingDir(ftpConfig.basePath)
                           .fileName(fileName)
                           .build()
           );
           return result;
       } catch (Exception e) {
           log.error("=======删除文件异常,异常信息:{}", e.getMessage());
           e.printStackTrace();
       }
       return null;
   }

@Override
   public Boolean downloadFile(String fileName, String downloadPath) {
       if (Objects.isNull(fileName) || Objects.isNull(downloadPath)) {
           throw new BusinessException("文件名称或下载路径为空,请核实!");
       }
       try {
           Boolean result = UploadFileUtils.download(
                   UploadFileDto.builder()
                           .host(ftpConfig.host)
                           .port(ftpConfig.post)
                           .account(ftpConfig.username)
                           .passwd(ftpConfig.password)
                           .workingDir(ftpConfig.basePath)
                           .fileName(fileName)
                           .downloadPath(downloadPath)
                           .build()
           );
           return result;
       } catch (Exception e) {
           log.error("=======下载文件异常,异常信息:{}", e.getMessage());
           e.printStackTrace();
       }
       return null;
   }

}

FtpConfig

package com.demo.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
* @ClassName: FtpConfig.java
* @ClassPath: com.demo.config.FtpConfig.java
* @Description: FTP配置
* @Author: tanyp
* @Date: 2022/12/19 22:28
**/
@Component
public class FtpConfig {

// ftp 服务器ip地址
   @Value("${ftp.host}")
   public String host;

// ftp 服务器port,默认是21
   @Value("${ftp.post}")
   public Integer post;

// ftp 服务器用户名
   @Value("${ftp.username}")
   public String username;

// ftp 服务器密码
   @Value("${ftp.password}")
   public String password;

// ftp 服务器存储图片的绝对路径
   @Value("${ftp.base-path}")
   public String basePath;

// ftp 服务器外网访问图片路径
   @Value("${ftp.image-base-url}")
   public String imageBaseUrl;

}

application.yml

# ftp
ftp:
 host: 127.0.0.1
 post: 22
 username: ftpadmin
 password: ftpadmin
 base-path: /app/upload/images
 image-base-url: http://127.0.0.1:8080/images

配置 Nginx

server {
   listen       8080;
   server_name  localhost;

location /images/ {
       root  /app/upload/;
       autoindex on;
   }
}

SpringBoot 使用 FTP 操作文件整合完成。

来源:https://blog.csdn.net/typ1805/article/details/128370773

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com