文件的上传

news2024/10/2 16:14:39

文件上传方便用户将本地文件传输到互联网上的应用程序或网站中,实现信息的共享和传递。它不仅提供了便捷的数据传输方式,还增强了用户的体验,使用户能够轻松分享个人创作、照片、视频、文档等内容。同时,文件上传也促进了远程协作和合作,使得团队成员可以方便地分享和访问文件,提高工作效率,本次将通过使用spring-boot实现文件上传与下载的功能。 

1.文件上传

单个文件上传需要引入Java相关包,这里为了简单先写一个简单前端页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>fileload</title>
</head>
<body>
  <div class="m-auto row blue-div">
    <form action="http://localhost:8080/testc002/upload" method="POST" enctype="multipart/form-data">
        <div class="form-group">
            <label for="upload_single_file">Upload your file</label>
            <input type="file" name="single_file" id="upload_single_file" class="form-control-file"/><br>

        </div>
        <div class="form-group">
            <input type="submit" value="submit" class="btn btn-primary"/>
            <input type="reset" value="reset" class="btn btn-outline-secondary">
        </div>
    </form>
  </div>
</body>
</html>

特别注意:在 form 标签上要加上 enctype="multipart/form-data" 属性设置,不然 spring Boot 不容易解析

enctype="multipart/form-data"在HTML表单中用来指定当表单提交到服务器时,表单数据应该如何编码。当表单包括类型为fileinput元素时,即允许用户上传文件,使用这种编码类型是必要的。这样可以确保文件在上传过程中不会被编码,而是以二进制形式发送。如果表单仅包含文本字段,通常使用默认的编码类型application/x-www-form-urlencoded。在使用multipart/form-data编码类型时,每个表单值或文件都作为一个“部分”(part)发送,每个部分都有可能有自己的HTTP头信息,比如Content-Type,这使得浏览器可以将文件作为原始二进制数据流来发送。

这里为了样式美观,同时引入了 bootstrap 框架

      <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>bootstrap</artifactId>
            <version>4.4.1-1</version>
        </dependency>

正式编写接受 POST请求的接口。

文件实体类

public class UploadFileResponse {
    private String fileName;
    private String fileDownLoadUri;
    private String fileType;
    private long size;

    public UploadFileResponse(String fileName, String fileDownLoadUri, String fileType, long size) {
        this.fileName = fileName;
        this.fileDownLoadUri = fileDownLoadUri;
        this.fileType = fileType;
        this.size = size;
    }

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public String getFileDownLoadUri() {
        return fileDownLoadUri;
    }

    public void setFileDownLoadUri(String fileDownLoadUri) {
        this.fileDownLoadUri = fileDownLoadUri;
    }

    public String getFileType() {
        return fileType;
    }

    public void setFileType(String fileType) {
        this.fileType = fileType;
    }

    public long getSize() {
        return size;
    }

    public void setSize(long size) {
        this.size = size;
    }
}

针对上传的文件进行封装 编写属性类

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "file")
public class FileStorageProperties {
    //上传到服务器的文件路径
    private String uploadDir;

    //获取上传路径
    public String getUploadDir() {
        return uploadDir;
    }

    //设置上传路径
    public void setUploadDir(String uploadDir) {
        this.uploadDir = uploadDir;
    }
}

在 properties 配置文件中写入文件路径信息 

file.upload-dir=package

封装文件存储异常类,当文件遇到意外时需要抛出的异常信息

public class FileStorageException extends RuntimeException{
    //只传入错误原因
    public FileStorageException(String message) {
        super(message);
    }
    //传入错误原因和错误信息
    public FileStorageException(String message, Throwable cause) {
        super(message, cause);
    }
}

找不到文件的异常信息

public class FileNotFoundException extends RuntimeException{
    public FileNotFoundException(String message) {
        super(message);
    }

    public FileNotFoundException(String message, Throwable cause) {
        super(message, cause);
    }
}

由于采用MVC的方式,将业务处理都封装到Service层

package org.example.service;

import org.example.Exception.FileStorageException;
import org.example.config.FileStorageProperties;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Objects;

@Service
public class FileStorageService {

    private final Path fileStorageLocation;
    @Autowired(required = false)//找不到实例不会变异常而是设置为 null
    public FileStorageService(FileStorageProperties fileStorageProperties) {
        //normalize() 方法消除多余的斜杠.等。
        this.fileStorageLocation = Paths.get(fileStorageProperties.getUploadDir()).toAbsolutePath().normalize();
        try{
            //创建路经
            Files.createDirectories(this.fileStorageLocation);
        } catch (IOException ex) {
            throw new FileStorageException("Could not create the directory" +
                    " while the uploaded files will be stored.",ex);
        }
    }

    /**
     * 储存文件
     *
     * @param file 文件流对象
     * @return  String 文件名 | Exception
     */
    public String storeFile(MultipartFile file){
        //规划文件名
        // 1.此方法用于获取上传文件的原始文件名。当处理HTTP文件上传时,你可以通过这个方法来访问上传文件的原始文件名(即用户上传的文件在用户设备上的名称。
        String fileName = StringUtils.cleanPath(Objects.requireNonNull(file.getOriginalFilename()));//
        try {
            //2.检查文件中是否含有无效字符
            if (fileName.contains("..")){
                throw new FileStorageException("抱歉,文件名里面有无效字符 "+fileName);
            }
            //3.resolve将当前路径追加在源路径之后
            Path targetLocation = this.fileStorageLocation.resolve(fileName);
            //复制文件到目标路径
            Files.copy(file.getInputStream(),targetLocation, StandardCopyOption.REPLACE_EXISTING);
            return fileName;
        } catch (IOException e) {
            throw new FileStorageException("不能保存文件"+fileName+". 请重新尝试!",e);
        }
    }

    /**
     *
     * 加载文件资源
     * @param fileName 文件名
     * @return  Resource | Exception
     */
    public Resource loadFileResource(String fileName){
        try {
            Path filePath = this.fileStorageLocation.resolve(fileName).normalize();
            //将filePath转成uri后将其 构建 Resource对象
            Resource resource = new UrlResource(filePath.toUri());
            if (resource.exists()){
                return resource;
            }else {
                throw new FileStorageException("文件没找到 "+fileName);
            }
        } catch (MalformedURLException e) {
            throw new FileStorageException("文件没找到 "+fileName,e);
        }
    }

}

编写 controller 层

import org.example.pojo.UploadFileResponse;
import org.example.service.FileStorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@RestController
@RequestMapping()
public class UploadController {
    @Autowired
    private FileStorageService fileStorageService;
    @PostMapping("/upload")
    public UploadFileResponse uploadFileResponse(@RequestParam("single_file")MultipartFile file){
        //存储文件并获得保存后的文件名称
        String fileName = fileStorageService.storeFile(file);
        //获取文件下载地址
        String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()
                .path("/downloadFile/")
                .path(fileName)
                .toUriString();
        //返回一个上传好的文件对象,这里返回下载地址,文件大小以及类型。
        return new UploadFileResponse(fileName,fileDownloadUri,file.getContentType(),file.getSize());
    }
    //根据文件名获取上传好的文件信息
    @GetMapping("/downloadFile/{fileName:.+}")
    public ResponseEntity<Resource> downloadFile(@PathVariable String fileName, HttpServletRequest request){
        //根据文件名获取文件存储资源
        Resource resource = fileStorageService.loadFileResource(fileName);
        //尝试确定文件的内容类型
        //Try  to determine file `s content type
        String contentType = null;
        try{
            //根据资源调用getMimeType()方法来获取文件的MIME类型(即文件的互联网媒体类型,例如"text/plain", "image/jpg"等
            contentType = request.getServletContext().getMimeType(resource.getFile()
                    .getAbsolutePath());
        } catch (IOException e) {
            System.out.println("Could not determine file type.");
        }
        //如果无法确定类型,则退回到默认内容类型
        //Fallback to the default content type if type could not be determined
        //如果无法确定文件的MIME类型,将其默认设置为"application/octet-stream"。
        // 这是一种二进制文件流的MIME类型,常用于表示不能识别文件类型的情况。
        if (contentType == null){
            contentType = "application/octect-stream";
        }
        //返回文件流
        return ResponseEntity.ok().contentType(MediaType.parseMediaType(contentType)).header(HttpHeaders.CONTENT_DISPOSITION
        ,"attachment;filename=\""+resource.getFilename()+"\"").body(resource);
    }

}

最后成功上传文件并可以成功下载:

补充: 

ServletUriComponentsBuilder 是 Spring Framework 提供的一个用于构建和操作 Servlet 相关的 URI【统一资源标识符(Uniform Resource Identifier)】的辅助类。

这个类主要用于在 Servlet 环境中创建和操作 URI,特别是在构建返回的响应中包含链接或定位资源时非常有用。它提供了一组静态方法,用于创建 URI,并且可以与 Spring Web MVC 框架的其他组件(如控制器、处理器等)无缝集成。

使用 ServletUriComponentsBuilder,您可以方便地构建包含应用程序上下文路径、请求路径、请求参数等信息的 URI。它还支持对 URI 进行更改、扩展和相对路径解析等操作。

以下是 ServletUriComponentsBuilder 常用的方法:

  • fromCurrentRequest():从当前的 Servlet 请求创建 ServletUriComponentsBuilder
  • fromCurrentContextPath():从当前的 Servlet 上下文路径创建 ServletUriComponentsBuilder
  • path(String path):将指定的路径添加到已创建的 URI 中。
  • queryParam(String name, Object... values):将查询参数添加到已创建的 URI 中。
  • build():根据已定义的信息构建 URI。

多个文件上传就是单个文件的循环,这里不进行更多了解。

2.文件上传限制和服务器限制 

对于文件的类型和大小常常有限制,这一方面与业务有关也和服务器的安全有关,为了不被 shell 木马注入和提权,必须限制上传的文件类型,例如只能是 jpg 或者 png 格式的图片等。 

public class ValidFileType {
    private List<String> validType = new ArrayList<>();

    public ValidFileType(List<String> validType) {
        if (validType.isEmpty()){
            validType.add("png");
            validType.add("jpg");
            validType.add("jepg");
        }
        this.validType=validType;
    }

    public List<String> getValidType() {
        return validType;
    }
}

使用也非常简单,遍历后进行判断即可。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1241266.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux常用命令——blockdev命令

在线Linux命令查询工具 blockdev 从命令行调用区块设备控制程序 补充说明 blockdev命令在命令调用“ioxtls”函数&#xff0c;以实现对设备的控制。 语法 blockdev(选项)(参数)选项 -V&#xff1a;打印版本号并退出&#xff1b; -q&#xff1a;安静模式&#xff1b; -v&…

免费多域名SSL证书

顾名思义&#xff0c;免费多域名SSL证书就是一种能够为多个域名或子域提供HTTPS安全保护的证书。这意味着&#xff0c;如果您有三个域名——例如example.com、example.cn和company.com&#xff0c;您可以使用一个免费的多域名SSL证书为所有这些域名提供安全保障&#xff0c;而无…

【LeetCode】每日一题 2023_11_23 HTML 实体解析器(调库/打工)

文章目录 刷题前唠嗑题目&#xff1a;HTML 实体解析器题目描述代码与解题思路 结语 刷题前唠嗑 题目&#xff1a;HTML 实体解析器 题目链接&#xff1a;1410. HTML 实体解析器 题目描述 代码与解题思路 func entityParser(s string) (ans string) {return strings.NewRepla…

【Java工具篇】Java反编译工具Bytecode Viewer

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

ps软件下载PS2024正式版下载安装教程 ps新功能25.0 AI创成式填充中文版本ps2024神经滤镜平面设计摄影后期修图软件Adobe Photoshop2024下载

Photoshop简称“PS”&#xff0c;是一款常用和功能强大的图像处理软件。主要处理以像素所构成的数字图像。使用其众多的编修与绘图工具&#xff0c;可以有效地进行图片编辑工作。PS有很多功能&#xff0c;在图像、图形、文字、视频、出版等各方面都有涉及。 一、PS软件下载 1、…

【双指针】有效三角形的个数

有效三角形的个数 611. 有效三角形的个数 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给定一个包含非负整数的数组 nums &#xff0c;返回其中可以组成三角形三条边的三元组个数。 示例 1: 输入: nums [2,2,3,4] 输出: 3 解释:有效的组合是: 2,3,4 (使用第一个 2…

Mybatis-Plus3.0默认主键策略导致自动生成19位长度主键id的坑

码字不易&#xff0c;如果对您有用&#xff0c;求各位看官点赞关注~ 原创/朱季谦 目前的Mybatis-Plus版本是3.0&#xff0c;至于最新版本是否已经没有这个问题&#xff0c;后续再考虑研究。 某天检查一位离职同事写的代码&#xff0c;发现其对应表虽然设置了AUTO_INCREMENT自…

第95步 深度学习图像目标检测:Faster R-CNN建模

基于WIN10的64位系统演示 一、写在前面 本期开始&#xff0c;我们学习深度学习图像目标检测系列。 深度学习图像目标检测是计算机视觉领域的一个重要子领域&#xff0c;它的核心目标是利用深度学习模型来识别并定位图像中的特定目标。这些目标可以是物体、人、动物或其他可识…

事关Django的静态资源目录设置与静态资源文件引用(Django的setting.py中的三句静态资源(static)目录设置语句分别是什么作用?)

在Django的setting.py中常见的三句静态资源(static)目录设置语句如下&#xff1a; STATICFILES_DIRS [os.path.join(BASE_DIR, static_list)] # 注意这是一个列表,即可以有多个目录的路径 STATIC_ROOT os.path.join(BASE_DIR, static_root) STATIC_URL /static-url/本文介…

气候变化和人类活动对中国植被固碳的贡献量化数据月度合成产品

简介&#xff1a; 气候变化和人类活动对中国植被固碳的贡献量化数据月度合成产品包括中国2001~2018年地表短波波段反照率、植被光合有效辐射吸收比、叶面积指数、森林覆盖度和非森林植被覆盖度、地表温度、地表净辐射、地表蒸散发、地上部分自养呼吸、地下部分自养呼吸、总初级…

PTA-6-45 工厂设计模式-运输工具

题目如下&#xff1a; 工厂类用于根据客户提交的需求生产产品&#xff08;火车、汽车或拖拉机&#xff09;。火车类有两个子类属性&#xff1a;车次和节数。拖拉机类有1个子类方法耕地&#xff0c;方法只需简单输出“拖拉机在耕地”。为了简化程序设计&#xff0c;所有…

Python之pyc文件的生成与反编译

目录 1、什么是pyc文件 2、手动生成pyc文件 3、pyc文件的执行 4、pyc文件的反编译 1、什么是pyc文件 pyc文件&#xff08;PyCodeObject&#xff09;是Python编译后的结果。当python程序运行时&#xff0c;编译的结果是保存于PyCodeObject&#xff0c;程序运行结束后&#x…

009 OpenCV threshold

一、环境 本文使用环境为&#xff1a; Windows10Python 3.9.17opencv-python 4.8.0.74 二、二值化算法 2.1、概述 在机器视觉应用中&#xff0c;OpenCV的二值化函数threshold具有不可忽视的作用。主要的功能是将一幅灰度图进行二值化处理&#xff0c;以此大幅降低图像的数…

webAPI serial——串口连称

重点 关闭正在读的串口 借鉴文章:webapi串口 async closeport() {this.$emit("changeSerialStatus", false);//这里要注意&#xff0c;一定要关闭读取this.status false;//取消后&#xff0c;done会变成true&#xff0c;会执行reader.releaseLock();this.reader.c…

ESP32 MicroPython 颜色及二维码识别⑫

ESP32 MicroPython 颜色及二维码识别⑫ 1、颜色识别2、二维码识别 1、颜色识别 使用AI颜色识别功能&#xff0c;可以实现颜色辨别、颜色追踪等应用。颜色识别模型内置有9种常见的颜色识别和一种颜色学习识别模式。他们分别是&#xff1a; ai.COLOR_RED 表示识别红色 ai.COLOR…

【C语言】深入解开指针(四)

&#x1f308;write in front :&#x1f50d;个人主页 &#xff1a; 啊森要自信的主页 ✏️真正相信奇迹的家伙&#xff0c;本身和奇迹一样了不起啊&#xff01; 欢迎大家关注&#x1f50d;点赞&#x1f44d;收藏⭐️留言&#x1f4dd;>希望看完我的文章对你有小小的帮助&am…

使用 PowerShell 创建共享目录

在 Windows 中&#xff0c;可以使用共享目录来将文件和文件夹共享给其他用户或计算机。共享目录可以通过网络访问&#xff0c;这使得它们非常适合用于文件共享、协作和远程访问。 要使用 PowerShell 创建共享目录&#xff0c;可以使用 New-SmbShare cmdlet。New-SmbShare cmdl…

【C++高阶(四)】红黑树深度剖析--手撕红黑树!

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习C   &#x1f51d;&#x1f51d; 红黑树 1. 前言2. 红黑树的概念以及性质3. 红黑…

图像分类原理

一、什么是图像分类(Image Classification) 图像分类任务是计算机视觉中的核心任务&#xff0c;其目标是根据图像信息中所反映的不同特征&#xff0c;把不同类别的图像区分开来。 二、图像分类任务的特点 对于人来说&#xff0c;完成上述的图像分类任务简直轻而易举&#xf…

Elasticsearch:FMA 风格的向量相似度计算

作者&#xff1a;Chris Hegarty 在 Lucene 9.7.0 中&#xff0c;我们添加了利用 SIMD 指令执行向量相似性计算的数据并行化的支持。 现在&#xff0c;我们通过使用融合乘加 (Fused Mulitply-Add - FMA) 进一步推动这一点。 什么是 FMA 乘法和加法是一种常见的运算&#xff0c;…