基于SFTP的文件上传下载服务

来源:互联网 发布:论文查重率软件 编辑:程序博客网 时间:2024/05/17 08:49

       文件上传/下载服务是每个系统都离不开的,最近写了一个简单、通用、好用的文件上传/下载的服务。这里我们使用JSch来实现文件的上传和下载,开发框架采用的是SpringBoot+Swagger。

       首先我们建立一个SFTP的工具类用来对服务器上的文件进行操作。

package org.jack.util;import com.jcraft.jsch.ChannelSftp;import com.jcraft.jsch.JSch;import com.jcraft.jsch.JSchException;import com.jcraft.jsch.Session;import com.jcraft.jsch.SftpATTRS;import com.jcraft.jsch.SftpException;import org.apache.log4j.Logger;import java.io.InputStream;import java.io.OutputStream;import java.util.Properties;/** * @author jack */public class SFTPUtil {    private static final Logger logger = Logger.getLogger(SFTPUtil.class);    /**     * 上传文件     *     * @param dataSource  连接信息     * @param directory   文件目录     * @param fileName    文件名     * @param inputStream 输入流     */    public static void upload(DataSource dataSource, String directory, String fileName, InputStream inputStream) throws SftpException, JSchException {        Session session = null;        ChannelSftp sftp = null;        try {            session = connect(dataSource);            sftp = (ChannelSftp) session.openChannel("sftp");            sftp.connect();            logger.info("Channel opened.");            put(sftp, directory, fileName, inputStream);        } catch (SftpException sftpException) {            logger.error("上传文件失败", sftpException);            throw sftpException;        } catch (JSchException jSchException) {            logger.error("上传文件失败", jSchException);            throw jSchException;        } finally {            disconnect(sftp);            disconnect(session);        }    }    /**     * 下载文件     *     * @param dataSource   连接信息     * @param directory    文件目录     * @param fileName     文件名     * @param outputStream 输出流     */    public static void download(DataSource dataSource, String directory, String fileName, OutputStream outputStream) throws SftpException, JSchException {        Session session = null;        ChannelSftp sftp = null;        try {            session = connect(dataSource);            sftp = (ChannelSftp) session.openChannel("sftp");            sftp.connect();            logger.info("Channel opened.");            get(sftp, directory, fileName, outputStream);        } catch (SftpException sftpException) {            logger.error("下载文件失败", sftpException);            throw sftpException;        } catch (JSchException jSchException) {            logger.error("下载文件失败", jSchException);            throw jSchException;        } finally {            disconnect(sftp);            disconnect(session);        }    }    /**     * 删除文件     *     * @param dataSource 连接信息     * @param directory  文件目录     * @param fileName   文件名     */    public static void delete(DataSource dataSource, String directory, String fileName) throws SftpException, JSchException {        Session session = null;        ChannelSftp sftp = null;        try {            session = connect(dataSource);            sftp = (ChannelSftp) session.openChannel("sftp");            sftp.connect();            logger.info("Channel opened.");            rm(sftp, directory, fileName);        } catch (SftpException sftpException) {            logger.error("删除文件失败", sftpException);            throw sftpException;        } catch (JSchException jSchException) {            logger.error("删除文件失败", jSchException);            throw jSchException;        } finally {            disconnect(sftp);            disconnect(session);        }    }    /* 连接Session */    private static Session connect(DataSource dataSource) throws JSchException {        JSch jSch = new JSch();        Session session = jSch.getSession(dataSource.getUsername(), dataSource.getHost(), dataSource.getPort());        logger.info("Session created.");        session.setPassword(dataSource.getPassword());        Properties config = new Properties();        config.put("StrictHostKeyChecking", "no");        session.setConfig(config);        session.setTimeout(300_000);        session.connect();        logger.info("Session connected.");        return session;    }    /* 关闭Session */    private static void disconnect(Session session) {        if (session != null && session.isConnected()) {            session.disconnect();            logger.info("session closed.");        }    }    /* 关闭sftp通道 */    private static void disconnect(ChannelSftp sftp) {        if (sftp != null && sftp.isConnected()) {            sftp.disconnect();            logger.info("sftp closed.");        }    }    /* 上传文件 */    private static void put(ChannelSftp sftp, String directory, String fileName, InputStream inputStream) throws SftpException {        try {// 切换目录            sftp.cd(directory);            logger.info("run cd directory.");        } catch (SftpException e) {            try {                mkdir(sftp, directory);                sftp.cd(directory);                logger.info("run mkdir directory.");                logger.info("run cd directory.");            } catch (SftpException sftpException) {                logger.error("上传文件失败", sftpException);                throw sftpException;            }        }        try {            sftp.put(inputStream, fileName);            logger.info("run put file.");        } catch (SftpException sftpException) {            logger.error("上传文件失败", sftpException);            throw sftpException;        }    }    /* 下载文件 */    private static void get(ChannelSftp sftp, String directory, String fileName, OutputStream outputStream) throws SftpException {        try {            sftp.cd(directory);            logger.info("run cd directory.");            sftp.get(fileName, outputStream);            logger.info("run get file.");        } catch (SftpException sftpException) {            logger.error("下载文件失败", sftpException);            throw sftpException;        }    }    /* 删除文件 */    private static void rm(ChannelSftp sftp, String directory, String fileName) throws SftpException {        try {            sftp.cd(directory);            logger.info("run cd directory.");            sftp.rm(fileName);            logger.info("run rm file.");        } catch (SftpException sftpException) {            logger.error("删除文件失败", sftpException);            throw sftpException;        }    }    private static void mkdir(ChannelSftp sftp, String directory) throws SftpException {        try {            if (isDirExist(sftp, directory)) {                return;            }            String pathArray[] = directory.split("/");            StringBuffer filePath = new StringBuffer("/");            for (String path : pathArray) {                if (path.equals("")) {                    continue;                }                filePath.append(path + "/");                if (!isDirExist(sftp, filePath.toString())) {                    sftp.mkdir(filePath.toString());                }            }        } catch (SftpException sftpException) {            throw sftpException;        }    }    private static boolean isDirExist(ChannelSftp sftp, String directory) {        boolean isDirExistFlag = false;        try {            SftpATTRS sftpATTRS = sftp.lstat(directory);            isDirExistFlag = true;            return sftpATTRS.isDir();        } catch (Exception e) {            if (e.getMessage().toLowerCase().equals("no such file")) {                isDirExistFlag = false;            }        }        return isDirExistFlag;    }    public static class DataSource {        private String host;        private int port;        private String username;        private String password;        public DataSource(String host, int port, String username, String password) {            this.host = host;            this.port = port;            this.username = username;            this.password = password;        }        public String getHost() {            return host;        }        public void setHost(String host) {            this.host = host;        }        public int getPort() {            return port;        }        public void setPort(int port) {            this.port = port;        }        public String getUsername() {            return username;        }        public void setUsername(String username) {            this.username = username;        }        public String getPassword() {            return password;        }        public void setPassword(String password) {            this.password = password;        }    }}

       然后,我们定义一个业务类,对文件管理的服务进行信息更深层次的封装,以便系统的其他地方能够更简便的使用它。

package org.jack.service;import org.jack.common.CustomerException;import org.jack.common.HttpStatus;import com.eastone.lease.util.SFTPUtil;import com.jcraft.jsch.JSchException;import com.jcraft.jsch.SftpException;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Service;import java.io.InputStream;import java.io.OutputStream;import java.util.UUID;/** * @author jack */@Servicepublic class FileService {    @Value("${sftp.host}")    public String host;    @Value("${sftp.port}")    public int port;    @Value("${sftp.username}")    public String username;    @Value("${sftp.password}")    public String password;    /**     * 上传文件     */    public String upload(String directory, String fileName, InputStream inputStream) {        SFTPUtil.DataSource dataSource = new SFTPUtil.DataSource(host, port, username, password);        String[] fileNameArray = fileName.split("\\.");        String suffixName = fileNameArray[fileNameArray.length - 1];        fileName = UUID.randomUUID().toString().replaceAll("-", "") + "." + suffixName;        try {            SFTPUtil.upload(dataSource, directory, fileName, inputStream);        } catch (SftpException e) {            throw new CustomerException(HttpStatus.BAD);        } catch (JSchException e) {            throw new CustomerException(HttpStatus.BAD);        }        return fileName;    }    /**     * 下载文件     */    public void download(String directory, String fileName, OutputStream outputStream) {        SFTPUtil.DataSource dataSource = new SFTPUtil.DataSource(host, port, username, password);        try {            SFTPUtil.download(dataSource, directory, fileName, outputStream);        } catch (SftpException e) {            throw new CustomerException(HttpStatus.BAD);        } catch (JSchException e) {            throw new CustomerException(HttpStatus.BAD);        }    }}
       最后,我们对外提供一个REST风格的API。

package org.jack.controller.sys;import org.jack.common.JsonMessage;import org.jack.service.FileService;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import io.swagger.annotations.ApiParam;import io.swagger.annotations.ApiResponse;import io.swagger.annotations.ApiResponses;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.http.HttpStatus;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.InputStream;import java.util.HashMap;import java.util.Map;/** * @author jack */@RestController@RequestMapping("/api/file")@Api(tags = "file", description = "文件API")public class FileController {    @Value("${sftp.path}")    public String directoryPrefix;    private final static Map<String, String> directoryMap = new HashMap<>();    static {        directoryMap.put("license", "license");        directoryMap.put("parking", "parking");    }    @Autowired    private HttpServletResponse response;    @Autowired    private FileService fileService;    @RequestMapping(value = "/{directory}", method = RequestMethod.POST)    @ApiOperation("上传文件")    @ApiResponses({        @ApiResponse(code = 200, response = String.class, message = "文件路径"),    })    public JsonMessage upload(@ApiParam(value = "目录", required = true) @PathVariable(value = "directory") String directory,                              @ApiParam(value = "文件", allowMultiple = true, required = true) @RequestParam MultipartFile file) throws IOException {        if (!directoryMap.containsKey(directory)) {            return JsonMessage.failed("文件上传失败");        }        String fileName = file.getOriginalFilename();        System.out.println("文件名:" + fileName);        InputStream inputStream = file.getInputStream();        fileName = directoryMap.get(directory) + "/" + fileService.upload(directoryPrefix + directoryMap.get(directory), fileName, inputStream);        return JsonMessage.successed(fileName, "文件上传成功");    }    @RequestMapping(value = "/{directory}/{fileName}.{suffix}", method = RequestMethod.GET)    @ApiOperation("获取文件")    @ApiResponses({        @ApiResponse(code = 200, response = String.class, message = "下载成功"),    })    public void download(@ApiParam(value = "目录", required = true) @PathVariable(value = "directory") String directory,                         @ApiParam(value = "文件名", required = true) @PathVariable(value = "fileName") String fileName,                         @ApiParam(value = "后缀", required = true) @PathVariable(value = "suffix") String suffix) {        try {            fileService.download(directoryPrefix + directory, fileName + "." + suffix, response.getOutputStream());        } catch (Exception e) {            response.setStatus(HttpStatus.NOT_FOUND.value());        }    }}

总结:

       代码比较简洁,结构比较清晰,没有多余的功能,但是也没有提供比较高级的特性。


原创粉丝点击