springboot结合FTP服务器实现文件上传

关于springboot配合Ftp服务器实现文件上传(单/多文件)的实例

jar包、配置信息、配置类、上传的工具类、生成新文件名的工具类、单文件以及多文件上传的业务层、用到的枚举


需要的jar包:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.aaa.liu.ftp</groupId>
    <artifactId>2019-9-1-ftp</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!--
        fileUpload的包
        ftp:commons的包
        http
        joda-time(做时间日期转换的包)
    -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.22.RELEASE</version>
    </parent>

    <dependencies>
        <!--
            springboot-starter-web
        -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--
            springboot-mybatis整合包
        -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.0</version>
        </dependency>
        <!--
            mysql的驱动包
        -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>
        <!--
            druid连接池
        -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>
        <!--
            html的thymeleaf模板
        -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!--
            fastjson包
        -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.8.1</version>
        </dependency>
        <!--
            添加springboot的进程jar包
                里面包含了properties文件的读取(其实就是包含了@ConfigurationProperties()注解)
        -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- joda time begin -->
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>2.9.4</version>
        </dependency>
        <!-- joda time end -->

        <!--json start -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.8.1</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.8.1</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.8.1</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.17</version>
        </dependency>
        <!--json end -->

        <!-- file upload -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>
        <!-- file upload -->

        <!-- httpclient begin -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.3.5</version>
        </dependency>
        <!-- httpclient end -->

        <!-- ftp begin -->
        <dependency>
            <groupId>commons-net</groupId>
            <artifactId>commons-net</artifactId>
            <version>3.5</version>
        </dependency>
        <!-- ftp end -->

        <dependency>
            <groupId>net.sourceforge.nekohtml</groupId>
            <artifactId>nekohtml</artifactId>
            <version>1.9.21</version>
        </dependency>

    </dependencies>


</project>

配置信息:resources/application.properties:

 1 server.port=8081
 2 server.context-path=/
 3 
 4 spring.datasource.driver-class-name=com.mysql.jdbc.Driver
 5 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
 6 spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?userSSL=false
 7 spring.datasource.username=root
 8 spring.datasource.password=123456
 9 mybatis.type-aliases-package=com.aaa.liu.ftp.model
10 mybatis.mapper-locations=classpath:mapper/*Mapper.xml
11 
12 spring.thymeleaf.cache=false
13 spring.thymeleaf.mode=LEGACYHTML5
14 
15 #ftp服务器的地址
16 spring.ftp.host=192.168.134.139
17 #ftp服务器的端口号(连接端口号)
18 spring.ftp.port=21
19 #ftp的用户名
20 spring.ftp.username=ftpuser
21 #ftp的密码
22 spring.ftp.password=123456
23 #ftp上传的根目录
24 spring.ftp.basePath=/home/ftp/www
25 #回显地址
26 spring.ftp.httpPath=http://192.168.134.139

在Java代码中根据配置信息创建配置类:/config/FtpProperties.class

 1 package com.aaa.liu.ftp.config;
 2 
 3 import org.springframework.boot.context.properties.ConfigurationProperties;
 4 import org.springframework.stereotype.Component;
 5 
 6 /**
 7  * @Author 刘其佳
 8  * @DateTime 2019/9/1 23:03
 9  * @Project_Name 2019-9-1-ftp
10  */
11 @Component
12 @ConfigurationProperties(prefix = "spring.ftp")
13 public class FtpProperties {
14     private String host;
15     private String port;
16     private String username;
17     private String password;
18     private String basePath;
19     private String httpPath;
20 
21     public String getHost() {
22         return host;
23     }
24 
25     public void setHost(String host) {
26         this.host = host;
27     }
28 
29     public String getPort() {
30         return port;
31     }
32 
33     public void setPort(String port) {
34         this.port = port;
35     }
36 
37     public String getUsername() {
38         return username;
39     }
40 
41     public void setUsername(String username) {
42         this.username = username;
43     }
44 
45     public String getPassword() {
46         return password;
47     }
48 
49     public void setPassword(String password) {
50         this.password = password;
51     }
52 
53     public String getBasePath() {
54         return basePath;
55     }
56 
57     public void setBasePath(String basePath) {
58         this.basePath = basePath;
59     }
60 
61     public String getHttpPath() {
62         return httpPath;
63     }
64 
65     public void setHttpPath(String httpPath) {
66         this.httpPath = httpPath;
67     }
68 }

上传的工具类:

 1 package com.aaa.liu.ftp.utils;
 2 
 3 import org.apache.commons.net.ftp.FTP;
 4 import org.apache.commons.net.ftp.FTPClient;
 5 import org.apache.commons.net.ftp.FTPReply;
 6 
 7 import java.io.IOException;
 8 import java.io.InputStream;
 9 
10 /**
11  * @Author 刘其佳
12  * @DateTime 2019/9/2 8:16
13  * @Project_Name 2019-9-1-ftp
14  */
15 public class FtpUtil {
16     public static Boolean uploadFile(String host, int port, String username, String password, String basePath,
17                                      String filePath, String fileName, InputStream inputStream) throws IOException {
18         //1、创建临时路径
19         String tempPath="";
20         //2、创建FTPClient对象(对于连接ftp服务器,以及上传和上传都必须要用到一个对象)
21         FTPClient ftp=new FTPClient();
22     try{
23         //3、定义返回的状态码
24         int reply;
25         //4、连接ftp(当前项目所部署的服务器和ftp服务器之间可以相互通讯,表示连接成功)
26         ftp.connect(host,port);
27         //5、输入账号和密码进行登录
28         ftp.login(username,password);
29         //6、接受状态码(如果成功,返回230,如果失败返回503)
30         reply=ftp.getReplyCode();
31         //7、根据状态码检测ftp的连接,调用isPositiveCompletion(reply)-->如果连接成功返回true,否则返回false
32         if(!FTPReply.isPositiveCompletion(reply)){
33             //说明连接失败,需要断开连接
34             ftp.disconnect();
35             return false;
36         }
37         //8、changWorkingDirectory(linux上的文件夹):检测所传入的目录是否存在,如果存在返回true,否则返回false
38         //basePath+filePath-->home/ftp/www/2019/09/02
39         if(!ftp.changeWorkingDirectory(basePath+filePath)){
40             //9、截取filePath:2019/09/02-->String[]:2019,09,02
41             String[] dirs=filePath.split("/");
42             //10、把basePath(/home/ftp/www)-->tempPath
43             tempPath=basePath;
44             for (String dir:dirs){
45                 //11、循环数组(第一次循环-->2019)
46                 if(null==dir||"".equals(dir))
47                 continue;//跳出本地循环,进入下一次循环
48                 //12、更换临时路径:/home/ftp/www/2019
49                 tempPath += "/" + dir;
50                 //13、再次检测路径是否存在(/home/ftp/www/2019)-->返回false,说明路径不存在
51                 if(!ftp.changeWorkingDirectory(tempPath)){
52                     //14、makeDirectory():创建目录  返回Boolean雷类型,成功返回true
53                     if(!ftp.makeDirectory(tempPath)){
54                         return false;
55                     }else {
56                         //15、严谨判断(重新检测路径是否真的存在(检测是否创建成功))
57                         ftp.changeWorkingDirectory(tempPath);
58                     }
59                 }
60             }
61         }
62         //16.把文件转换为二进制字符流的形式进行上传
63         ftp.setFileType(FTP.BINARY_FILE_TYPE);
64         //17、这才是真正上传方法storeFile(filename,input),返回Boolean雷类型,上传成功返回true
65         if (!ftp.storeFile(fileName, inputStream)) {
66             return false;
67         }
68         // 18.关闭输入流
69         inputStream.close();
70         // 19.退出ftp
71         ftp.logout();
72     } catch (IOException e) {
73         e.printStackTrace();
74         throw new IOException(e);
75     } finally {
76         if (ftp.isConnected()) {
77             try {
78                 // 20.断开ftp的连接
79                 ftp.disconnect();
80             } catch (IOException ioe) {
81                 ioe.printStackTrace();
82             }
83         }
84     }
85         return true;
86     }
87 }

生成新文件名的工具类: 

 1 package com.aaa.liu.ftp.utils;
 2 
 3 import java.util.Random;
 4 
 5 /**
 6  * @Author 刘其佳
 7  * @DateTime 2019/9/2 8:16
 8  * @Project_Name 2019-9-1-ftp
 9  */
10 
11 
12 public class FileNameUtil {
13     public static String getFileName(Integer userId){
14         //1、获取当前时间的毫秒数
15         long currentTimeMillis = System.currentTimeMillis();
16         //2、创建Random对象,获取0-999之间随机数
17         Random random=new Random();
18         int randomNum = random.nextInt(999);
19         //3、最终的文件名
20         //%03d: %是占位符 3:3位数  0:不够3位数补零   d:数字
21         String fileName = currentTimeMillis + userId + String.format("%03d", randomNum);
22             //0补在后面的写法
23 //        String fileName = currentTimeMillis + userId + String.format("%3d0", randomNum);
24         //4、返回文件名
25         return fileName;
26     }
27 
28     public static void main(String[] args) {
29         String fileName = FileNameUtil.getFileName(1);
30         System.out.println(fileName);
31     }
32 
33 }

单文件上传的业务层:

 1 package com.aaa.liu.ftp.service;
 2 
 3 import com.aaa.liu.ftp.config.FtpProperties;
 4 import com.aaa.liu.ftp.mapper.UserMapper;
 5 import com.aaa.liu.ftp.model.User;
 6 import com.aaa.liu.ftp.statuscode.StatusEnum;
 7 import com.aaa.liu.ftp.utils.FileNameUtil;
 8 import com.aaa.liu.ftp.utils.FtpUtil;
 9 import org.joda.time.DateTime;
10 import org.springframework.beans.factory.annotation.Autowired;
11 import org.springframework.stereotype.Service;
12 import org.springframework.web.multipart.MultipartFile;
13 import javax.servlet.http.HttpSession;
14 import java.io.File;
15 import java.util.HashMap;
16 import java.util.Map;
17 
18 /**
19  * @Author 刘其佳
20  * @DateTime 2019/9/2 20:52
21  * @Project_Name 2019-9-1-ftp
22  */
23 @Service
24 public class DoUploadService0 {
25     @Autowired
26     FtpProperties ftpProperties;
27     @Autowired
28     UserMapper userMapper;
29 
30     public Map<String,Object> doUpload(MultipartFile multipartFile, HttpSession session){
31         Map<String,Object> resultMap=new HashMap<String,Object>();
32             try {
33                 //老文件名
34                 String oldFileName = multipartFile.getOriginalFilename();
35                 //  取出session中存的用户user
36                 User user = (User) session.getAttribute("user");
37                 //取出user中的id
38                 Integer id = user.getId();
39                 //根据id调用工具类生成新文件名
40                 String newFileName = FileNameUtil.getFileName(id);
41                 //截取老文件名的后缀
42                 String substring = oldFileName.substring(oldFileName.lastIndexOf("."));
43                 //将后缀放在新文件名的后面
44                 newFileName = newFileName + substring;
45                 //生成路径
46                 String filePath = new DateTime().toString("yyyy/MM/dd");
47                 //上传
48                 Boolean resultBoolean = FtpUtil.uploadFile(ftpProperties.getHost(), Integer.parseInt(ftpProperties.getPort()), ftpProperties.getUsername(), ftpProperties.getPassword(), ftpProperties.getBasePath(), filePath, newFileName, multipartFile.getInputStream());
49                 //判断是否上传成功
50                 if (resultBoolean) {
51                     //上传成功
52                     String head = ftpProperties.getHttpPath() + File.separator + filePath + File.separator + newFileName;
53                     user.setHead(head);
54                     //调用修改方法,更新数据库中的头像名
55                     int i = userMapper.updateHead(user);
56                     //如果更新成功
57                     if (i > 0) {
58                         resultMap.put(StatusEnum.SUCCESS.getCodeName(), StatusEnum.SUCCESS.getCode());
59                         resultMap.put(StatusEnum.SUCCESS.getResultName(), head);
60                     } else {
61                         //如果没有更新成功
62                         resultMap.put(StatusEnum.FAILED.getCodeName(), StatusEnum.FAILED.getCode());
63                         resultMap.put(StatusEnum.SUCCESS.getResultName(), head);
64                     }
65                 } else {
66                     //如果没有上传成功
67                     resultMap.put(StatusEnum.ERROR.getCodeName(), StatusEnum.ERROR.getCode());
68                 }
69             } catch (Exception e) {
70                 e.printStackTrace();
71             }
72         return resultMap;
73     }
74 
75 
76 }

多文件上传的业务层:

 1 package com.aaa.liu.ftp.service;
 2 
 3 import com.aaa.liu.ftp.config.FtpProperties;
 4 import com.aaa.liu.ftp.mapper.UserMapper;
 5 import com.aaa.liu.ftp.model.User;
 6 import com.aaa.liu.ftp.statuscode.StatusEnum;
 7 import com.aaa.liu.ftp.utils.FileNameUtil;
 8 import com.aaa.liu.ftp.utils.FtpUtil;
 9 import org.joda.time.DateTime;
10 import org.springframework.beans.factory.annotation.Autowired;
11 import org.springframework.stereotype.Service;
12 import org.springframework.transaction.annotation.Transactional;
13 import org.springframework.web.multipart.MultipartFile;
14 
15 import javax.servlet.http.HttpSession;
16 import java.io.File;
17 import java.io.IOException;
18 import java.util.HashMap;
19 import java.util.Map;
20 
21 /**
22  * @Author 刘其佳
23  * @DateTime 2019/9/2 20:52
24  * @Project_Name 2019-9-1-ftp
25  */
26 @Service
27 public class DoUploadService {
28     @Autowired
29     FtpProperties ftpProperties;
30     @Autowired
31     UserMapper userMapper;
32 
33     public Map<String, Object> doUpload(MultipartFile[] multipartFiles, HttpSession session) {
34         Map<String, Object> resultMap = new HashMap<String, Object>();
35         String headAll="";
36         //  取出session中存的用户user
37         User user = (User) session.getAttribute("user");
38         //取出user中的id
39         Integer id = user.getId();
40         //根据id调用工具类生成新文件名
41         String newFileName = FileNameUtil.getFileName(id);
42 
43         //对文件数组进行遍历
44         for (MultipartFile multipartFile : multipartFiles) {
45             //老文件名
46             String oldFileName = multipartFile.getOriginalFilename();
47             //截取老文件名的后缀
48             String substring = oldFileName.substring(oldFileName.lastIndexOf("."));
49             //将后缀放在新文件名的后面
50             newFileName = newFileName + substring;
51             //生成路径
52             String filePath = new DateTime().toString("yyyy/MM/dd");
53             //上传
54             try {
55                 Boolean resultBoolean = FtpUtil.uploadFile(ftpProperties.getHost(), Integer.parseInt(ftpProperties.getPort()), ftpProperties.getUsername(), ftpProperties.getPassword(), ftpProperties.getBasePath(), filePath, newFileName, multipartFile.getInputStream());
56                 //判断是否上传成功
57                 if (resultBoolean) {
58                     //上传成功
59                     String head = ftpProperties.getHttpPath() + File.separator + filePath + File.separator + newFileName;
60                     //将当前图片的地址加进headAll,组合成一个新字符串,每个地址中间用隔开
61                     headAll=headAll+";"+head;
62                 } else {
63                     //如果没有上传成功
64                     resultMap.put(StatusEnum.ERROR.getCodeName(), StatusEnum.ERROR.getCode());
65                     resultMap.put(StatusEnum.SUCCESS.getResultName(), headAll);
66                     //只要有一个没有上传成功,直接结束上传,不再继续
67                     break;
68                 }
69             } catch (Exception e) {
70                 e.printStackTrace();
71             }
72         }
73         user.setHead(headAll);
74         //调用修改方法,更新数据库中的头像名
75         int i = userMapper.updateHead(user);
76         //如果更新成功
77         if (i > 0) {
78             resultMap.put(StatusEnum.SUCCESS.getCodeName(), StatusEnum.SUCCESS.getCode());
79             resultMap.put(StatusEnum.SUCCESS.getResultName(), headAll);
80         } else {
81             //如果没有更新成功
82             resultMap.put(StatusEnum.FAILED.getCodeName(), StatusEnum.FAILED.getCode());
83             resultMap.put(StatusEnum.SUCCESS.getResultName(), headAll);
84         }
85         return resultMap;
86     }
87 }

 其中用到的枚举值:

 1 package com.aaa.liu.ftp.statuscode;
 2 
 3 /**
 4  * @Author 刘其佳
 5  * @DateTime 2019/9/2 19:50
 6  * @Project_Name 2019-9-1-ftp
 7  */
 8 public enum  StatusEnum {
 9     SUCCESS(200,"code","操作成功","result"),
10     FAILED(404,"code","操作失败","result"),
11     ERROR(500,"code","操作无效","result");
12     private Integer code;
13     private String codeName;
14     private String result;
15     private String resultName;
16 
17     StatusEnum(Integer code,String codeName,String result,String resultName){
18         this.code=code;
19         this.codeName=codeName;
20         this.result=result;
21         this.resultName=resultName;
22     }
23     public Integer getCode() {
24         return code;
25     }
26 
27     public void setCode(Integer code) {
28         this.code = code;
29     }
30 
31     public String getCodeName() {
32         return codeName;
33     }
34 
35     public void setCodeName(String codeName) {
36         this.codeName = codeName;
37     }
38 
39     public String getResult() {
40         return result;
41     }
42 
43     public void setResult(String result) {
44         this.result = result;
45     }
46 
47     public String getResultName() {
48         return resultName;
49     }
50 
51     public void setResultName(String resultName) {
52         this.resultName = resultName;
53     }
54 }
乾坤未定,你我皆是黑马
原文地址:https://www.cnblogs.com/liuqijia/p/11457497.html