首页 > 其他分享 >SpringBoot 文件上传下载工具样例

SpringBoot 文件上传下载工具样例

时间:2023-11-21 14:26:57浏览次数:38  
标签:文件 SpringBoot 上传下载 样例 Result File fileupdown 上传 dir

最近工作遇到这样的情景:一大堆 linux 内网服务器,上面部署了 mysql,nacos,xxl job 等中间件,当然也给了一个很干净的 windows 内网服务器,什么软件都没有安装。比较欣慰的是:可以通过浏览器访问 nacos、xxl job 的管理页面。不幸的是:没有安装 mysql 客户端和 xshell 等工具。我可以通过中间机连接到 linux 服务器去上传和下载文件,但是无法往连接的 windows 服务器去上传和下载文件。

遇到这种情况,比较好的办法就是:在其中一台 linux 服务器上部署一个 SpringBoot 程序,提供简单的文件上传和下载功能。比如采用 Get 请求提供文件下载接口,这样 windows 服务器就通过浏览器地址栏访问 SpringBoot 的下载接口,从 linux 服务器上下载到所需要的组件进行安装,比如下载 xshell 和 xftp 进行安装,后续就可以使用 xshell 或 xftp 操作各个 linux 服务器上传和下载文件就方便多了。

由此可见,提前准备好一个 SpringBoot 开发的文件上传下载程序,是一件比较重要的事情,没准儿哪天就能够解决燃眉之急。本篇博客就简单的罗列一下上传和下载的核心代码,在博客的最后会提供源代码,关键紧急时刻大家可以随时下载直接使用。


一、搭建工程

搭建一个 SpringBoot 工程 fileupdown 结构如下:

 

从上图可见,结构非常简单,具体如下:

  • Result 是用来组织返回结果的实体对象
  • UpdownController 提供上传文件、下载文件、展示已上传的文件列表、删除文件、清空文件的接口
  • index.html 提供了一个简单的可视化界面,没有使用任何的 js ,主要使用的是 Form 表单实现功能

下面看一下 pom 文件的内容:

<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.5</version>
    </parent>

    <groupId>com.jobs</groupId>
    <artifactId>fileupdown</artifactId>
    <version>1.0</version>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.26</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.4.5</version>
            </plugin>
        </plugins>
    </build>
</project>

使用的 SpringBoot 的版本是 2.4.5 ,引用 lombok 的依赖,目的是为了记录简单的日志。


二、代码细节

Result 的实体类代码如下:

package com.jobs.common;

import lombok.Data;
import java.io.Serializable;

@Data
public class Result<T> implements Serializable {

    private Integer code; //状态码:1 成功,其它数字为失败

    private String msg; //状态信息

    private T data; //要返回的数据

    public static <T> Result<T> success(T object) {
        Result<T> r = new Result<T>();
        r.code = 1;
        r.msg = "成功";
        r.data = object;
        return r;
    }

    public static <T> Result<T> fail(Integer code, String msg) {
        Result r = new Result();
        r.code = code;
        r.msg = msg;
        return r;
    }
}

UpdownController 提供的接口代码如下:(除了上传文件的接口必须得使用 Post 请求外,其它接口都采用 Get 请求,方便在浏览器地址栏上直接输入 url 进行操作,虽然本博客的 Demo 中提供了简单的 index.html 可视化界面)

package com.jobs.controller;

import com.jobs.common.Result;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/updown")
public class UpdownController {

    @Value("${upload.path}")
    private String uploadPath;

    //获取已经上传的文件列表,按照上传的先后顺序排列
    @GetMapping("/list")
    public Result<List<String>> getFileList() {
        File dir = new File(uploadPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        //获取文件夹下的文件列表
        File[] flist = dir.listFiles();
        List<String> sss = Arrays.stream(flist).filter(s -> s.isFile())
                .sorted((s1, s2) -> {
                    //按照文件修改时间倒序排列,后上传的文件,排在前面
                    return (int) (s2.lastModified() - s1.lastModified());
                })
                .map(s -> s.getName()).collect(Collectors.toList());
        return Result.success(sss);
    }

    //上传文件
    @PostMapping("/upload")
    public Result<String> upload(MultipartFile file) {
        /**
         //如果你想要上传的文件,使用一个随机的文件名称时,可以使用这些代码
         //原始文件名
         String originalName = file.getOriginalFilename();
         //获取后缀名
         String extName = "";
         int index = originalName.lastIndexOf(".");
         if (index > -1) {
         extName = originalName.substring(index);
         }

         String newName = UUID.randomUUID().toString() + extName;
         File dir = new File(uploadPath);
         if (!dir.exists()) {
         dir.mkdirs();
         }

         try {
         file.transferTo(new File(uploadPath + newName));
         } catch (IOException e) {
         e.printStackTrace();
         }

         return Result.success(newName);*/

        //这里保留上传后的文件名跟原始文件名一致,服务器上如果文件已存在,则直接覆盖
        //原始文件名
        String originalName = file.getOriginalFilename();
        try {
            File dir = new File(uploadPath);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            file.transferTo(new File(uploadPath + originalName));
        } catch (Exception ex) {
            return Result.fail(0, ex.getMessage());
        }

        return Result.success("上传成功");
    }

    //下载文件
    //之所以使用 get 请求,主要是方便在浏览器地址栏上输入文件名,然后进行下载
    @GetMapping("/download")
    public void download(String name, HttpServletResponse response) throws UnsupportedEncodingException {

        //下载文件的响应类型,这里统一设置成了文件流
        //你可以根据自己所提供下载的文件类型,使用不同的响应 mime 类型
        response.setContentType("application/octet-stream;charset=utf-8");
        //设置下载弹出框中默认显示的文件名称,如果指定中文名称的话,需要转成 iso8859-1 编码,解决乱码问题
        String fileName = new String(name.getBytes(), "iso8859-1");
        response.addHeader("Content-Disposition", "attachment;filename=" + fileName);

        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(uploadPath + fileName))) {
            ServletOutputStream outputStream = response.getOutputStream();
            byte[] bArr = new byte[1024];
            int len;
            while ((len = bis.read(bArr)) != -1) {
                outputStream.write(bArr, 0, len);
            }
        } catch (Exception ex) {
            return;
        }
    }

    //删除具体一个文件
    //之所以使用 get 请求,主要是方便在浏览器地址栏上输入文件名,然后进行删除
    @GetMapping("/delete")
    public Result<String> delete(String name) {
        File file = new File(uploadPath + name);
        if (!file.exists()) {
            return Result.fail(0, name + ",已经不存在,无法删除");
        }

        try {
            file.delete();
            return Result.success(name + ",删除成功");
        } catch (Exception ex) {
            return Result.fail(0, ex.getMessage());
        }
    }

    //清空所有已上传的文件
    //之所以使用 get 请求,主要是方便在浏览器地址栏上输入文件名,然后进行清空
    @GetMapping("/clear")
    public Result<String> clear() {
        File dir = new File(uploadPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        //获取文件夹下的文件列表
        File[] flist = dir.listFiles();
        for (File f : flist) {
            if (f.isFile()) {
                //删除文件
                f.delete();
            } else {
                //删除文件夹
                deleteDirectory(f);
            }
        }

        return Result.success("清空删除成功");
    }

    /**
     * 递归删除一个文件夹,以及文件夹下的所有内容
     */
    private void deleteDirectory(File dir) {
        if (dir.exists()) {
            if (dir.isDirectory()) {
                File[] flist = dir.listFiles();
                for (File f : flist) {
                    if (f.isDirectory()) {
                        deleteDirectory(f);
                    }
                    f.delete();
                }
            }
            dir.delete();
        }
    }
}

index.html 页面的源代码如下所示:(对于 SpringBoot 来说,如果 resources/static 下面有 index.html 页面的话,直接在地址栏上输入域名或者 ip 和端口,就可以访问这个 index.html 页面)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>上传文件测试</title>
</head>
<body>
<fieldset>
    <legend>文件上传</legend>
    <form id="Form1" action="/updown/upload" method="post" enctype="multipart/form-data">
        <table>
            <tr>
                <td>请选择文件:</td>
                <td>
                    <input type="file" name="file">
                    <button type="submit">上传文件</button>
                </td>
            </tr>
        </table>
    </form>
</fieldset>
<br/>
<fieldset>
    <legend>查看服务器上的文件名,当完成文件上传或删除操作后,请手动刷新打开的新页面</legend>
    <a href="/updown/list" target="_blank">点击查看可以【下载】或【删除】的文件名</a>
</fieldset>
<br/>
<fieldset>
    <legend>文件下载,支持中文文件名称</legend>
    <form id="Form2" action="/updown/download" method="get">
        <table>
            <tr>
                <td>请输入要下载的文件名:</td>
                <td>
                    <input type="text" name="name">
                    <button type="submit">下载文件</button>
                </td>
            </tr>
        </table>
    </form>
</fieldset>
<br/>
<fieldset>
    <legend>删除文件,支持中文文件名称</legend>
    <form id="Form3" action="/updown/delete" method="get">
        <table>
            <tr>
                <td>请输入要删除的文件名:</td>
                <td>
                    <input type="text" name="name">
                    <button type="submit">删除文件</button>
                </td>
            </tr>
        </table>
    </form>
</fieldset>
<br/>
<fieldset>
    <legend>清空文件(删除的是服务器上的固定文件夹下的文件,可以放心清空)</legend>
    <form id="Form4" action="/updown/clear" method="get">
        <table>
            <tr>
                <td>清空服务器上的文件:</td>
                <td>
                    <button type="submit">清空文件</button>
                </td>
            </tr>
        </table>
    </form>
</fieldset>
</body>
</html>

最后再列出 application.yml 配置文件的内容:

server:
  port: 9000
spring:
  application:
    name: fileupdown
  servlet:
    multipart:
      # 单个文件的上传大小限制
      max-file-size: 100MB
      # 如果同时上传多个文件时,总大小限制
      max-request-size: 100MB
# 服务器上保存上传文件的文件夹全路径(最后以分隔符结尾)
# windows服务器全路径示例:d:/tmp/
# linux服务器全路径示例:/tmp/
upload:
  path: D:/temp/

在配置文件中,需要重点关注的就是上传文件的大小限制,以及上传的目录。需要注意的是:UpdownController 中所提供的接口,都是基于 upload.path 所配置的目录进行操作的,因此可以放心的使用接口,不会对服务器的其它文件造成影响。

完成以上操作后,启动 SpringBoot 程序,输入 http://localhost:9000 就可以直接访问到 index.html 页面:

 


三、部署使用

我们把工程代码打包之后,会得到一个 fileupdown-1.0.jar 文件,由于 application.yml 也被打包到了 jar 包中,因此内部的 application.yml 肯定是无法修改了,因此我们需要从代码中复制出来一个 application.yml 的文件,启动 SpringBoot 程序时,使用外部的 application.yml 配置文件。

假设我把 jar 包和外部的 application.yml 配置文件都放在了 /root/fileupdown 目录下,我的 jdk 安装在了 /usr/java/jdk1.8.0_151 目录下,此时启动命令如下所示:(反斜杠( \ )表示命令换行,主要是因为命令太长,因此需要换行编写)

# 启动命令最好使用绝对路径编写
nohup /usr/java/jdk1.8.0_151/bin/java \
   -jar /root/fileupdown/fileupdown-1.0.jar \
   --spring.config.location=/root/fileupdown/application.yml \
   > /root/fileupdown/fileupdown.log 2>&1 &

想要停止 SpringBoot 服务,只需要通过如下两个命令即可实现:

# 查询出 fileupdown-1.0.jar 运行的进程信息,最主要是获取到进程号
ps -ef | grep fileupdown

# 通过进程号,杀死进程
kill -9 进程号

当然也可以把 SpringBoot 部署成 linux 服务,这样后续启动和停止服务就方便多了。

进入 linux 的 /etc/systemd/system 目录,新建一个 fileupdown.service 文件,填写内容如下:

[Unit]
Description=fileupdown 
After=syslog.target network.target 
 
[Service]
Type=simple

#注意:ExecStart 后面的命令脚本都是写在一行中,没有手动进行换行,只是横向空间不够,自动换行了
ExecStart=/usr/java/jdk1.8.0_151/bin/java -jar /root/fileupdown/fileupdown-1.0.jar --spring.config.location=/root/fileupdown/application.yml > /root/fileupdown/fileupdown.log 2>&1 &
ExecStop=/bin/kill -15 $MAINPID 
 
User=root
Group=root 
 
[Install]
WantedBy=multi-user.target 

然后执行以下命令即可:(服务名称就是上面创建的文件名称:fileupdown.service ,可以简写为 fileupdown)

# 重新加载 daemon 服务
systemctl daemon-reload

# 启动 fileupdown 服务
systemctl start fileupdown

# 将 fileupdown 服务设置为开机启动
systemctl enable fileupdown

# 查看 fileupdown 是否已经设置为开机启动
# 如果能够查询到内容,则表明 fileupdown 已经添加为开机启动
systemctl list-unit-files | grep fileupdown

### 对于已经安装成的 linux 服务的 fileupdown 服务,还可以使用如下命令进行操作服务
systemctl stop fileupdown
systemctl restart fileupdown
systemctl disable fileupdown

如果没有关闭 linux 防火墙,还需要将 SpringBoot 的启动端口添加到防火墙开放端口列表中

# 本 Demo 配置的 fileupdown 的启动端口配置的是 9000
# 防火墙放开 9000 端口
firewall-cmd --zone=public --add-port=9000/tcp --permanent

# 重新加载防火墙
firewall-cmd --reload

# 查看防火墙对外开放的端口
firewall-cmd --list-ports

 

参考文章:http://blog.ncmem.com/wordpress/2023/11/21/springboot-%e6%96%87%e4%bb%b6%e4%b8%8a%e4%bc%a0%e4%b8%8b%e8%bd%bd%e5%b7%a5%e5%85%b7%e6%a0%b7%e4%be%8b/

欢迎入群一起讨论

 

 

标签:文件,SpringBoot,上传下载,样例,Result,File,fileupdown,上传,dir
From: https://www.cnblogs.com/songsu/p/17846463.html

相关文章

  • springboot jar基本结构
    @[TOC]Jar包的基本概念首先,让我们从JAR包的基本概念开始。JAR,全称JavaArchive,是Java的一种压缩文件格式。它主要用于打包、分发Java类和相关资源,包括Java类文件、资源文件、配置文件以及其他Java应用程序相关文件。与直接编译和运行Java源代码不同,使用JAR包可以更方便地进行应用程......
  • springboot中实现上传文件的功能简单示例
    在SpringBoot中实现文件上传可以通过以下步骤:配置文件上传相关的依赖:在项目的pom.xml文件中,添加以下依赖:<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-web</artifactId></dependency>创建文件上传接口:在......
  • SpringBoot + vue2.0查询所用功能
    导入数据库文件CREATEDATABASE`springboot`/*!40100DEFAULTCHARACTERSETutf8mb4COLLATEutf8mb4_0900_ai_ci*//*!80016DEFAULTENCRYPTION='N'*/CREATETABLE`users`(`id`intunsignedNOTNULLAUTO_INCREMENT,`name`varchar(40)CHARACTERSETu......
  • 基于springboot的七彩云南文化旅游网站-计算机毕业设计源码+LW文档
    摘 要传统办法管理信息首先需要花费的时间比较多,其次数据出错率比较高,而且对错误的数据进行更改也比较困难,最后,检索数据费事费力。因此,在计算机上安装七彩云南文化旅游网站软件来发挥其高效地信息处理的作用,可以规范信息管理流程,让管理工作可以系统化和程序化,同时,七彩云南文化旅......
  • 基于springboot的太原学院商铺管理系统-计算机毕业设计源码+LW文档
    摘 要信息数据从传统到当代,是一直在变革当中,突如其来的互联网让传统的信息管理看到了革命性的曙光,因为传统信息管理从时效性,还是安全性,还是可操作性等各个方面来讲,遇到了互联网时代才发现能补上自古以来的短板,有效的提升管理的效率和业务水平。传统的管理模式,时间越久管理的内容......
  • 基于Springboot的小区疫情购物系统-计算机毕业设计源码+LW文档
    摘 要信息数据从传统到当代,是一直在变革当中,突如其来的互联网让传统的信息管理看到了革命性的曙光,因为传统信息管理从时效性,还是安全性,还是可操作性等各个方面来讲,遇到了互联网时代才发现能补上自古以来的短板,有效的提升管理的效率和业务水平。传统的管理模式,时间越久管理的内容......
  • Springboot自定义starter
    Springboot自定义sarter这里通过自定义mybatis的starter来简单进行分析理解步骤:创建dmybatis-spring-boot-autoconfigure模块,提供自动配置功能,并定义配置文件META-INF/spring/xxx.imports创建dmybatis-spring-boot-starter模块,在starter中引入自动配置模块创建项目:1......
  • day131- springboot 的配置文件yaml的用法
    springboot的配置文件yaml的用法yaml文件同properties文件一样,适合用来做数据为中心的配置文件基本语法key:value;kv之间有空格大小写敏感使用缩进表示层级关系缩进不允许使用tab,只允许空格缩进的空格数不重要,只要相同层级的元素左对齐即可'#'表示注释字......
  • 基于Springboot宠物商城网站系统-计算机毕业设计源码+LW文档
    摘 要如今社会上各行各业,都喜欢用自己行业的专属软件工作,互联网发展到这个时候,人们已经发现离不开了互联网。新技术的产生,往往能解决一些老技术的弊端问题。因为传统宠物商城网站系统信息管理难度大,容错率低,管理人员处理数据费工费时,所以专门为解决这个难题开发了一个宠物商城网......
  • DHorse发布SpringBoot项目
    前言在介绍DHorse的操作之前,先来介绍一下使用k8s发布应用的步骤,以SpringBoot应用为例进行说明。1.首先从代码仓库下载代码,比如GitLab;2.接着进行构建,比如使用Maven;3.如果要使用k8s作为编排,还需要把步骤2产生的包制作成镜像,比如使用Docker;4.上传步骤3的镜像到远程仓库,比如Harho......