文件的上传

文件上传方便用户将本地文件传输到互联网上的应用程序或网站中,实现信息的共享和传递。它不仅提供了便捷的数据传输方式,还增强了用户的体验,使用户能够轻松分享个人创作、照片、视频、文档等内容。同时,文件上传也促进了远程协作和合作,使得团队成员可以方便地分享和访问文件,提高工作效率,本次将通过使用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)//找不到实例不会变异常而是设置为 nullpublic 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 {@Autowiredprivate 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 typeString 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.hqwc.cn/news/210918.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于SSM安全生产培训管理平台设计与实现 毕业设计源码26918

赠送源码-毕业设计&#xff1a;SSM 安全生产培训平台https://www.bilibili.com/video/BV1gH4y1z7c6/?vd_source72970c26ba7734ebd1a34aa537ef5301 目录 摘 要 Abstract 第1章 前 言 1.1 研究背景 1.2 研究现状 1.3 系统开发目标 第2章 系统开发环境 2.1 JAVA简介…

windows根据已有的安卓签名文件获取MD5签名

windows根据已有的安卓签名文件获取MD5签名 0 现状 uniapp 本机号码一键登录需要MD5的&#xff0c;现有的签名文件但是只有SHA1和SHA256 查看SHA1和SHA256 keytool -list -v -keystore [你的.keystore文件]1 前提 已有生成签名文件的环境 搭建Openssl环境&#xff0c;设置…

conda环境module ‘clip‘ has no attribute ‘load‘解决

1 问题描述 运行基于clip的zero-shot预测代码&#xff0c;报错如下&#xff1a; Traceback (most recent call last):File "D:\code\ptcontainer\clip\clipembeding.py", line 38, in <module>clip_embeding ClipEmbeding()File "D:\code\ptcontainer\c…

企业邮箱即时提醒服务推荐

现在用企业邮箱比较多&#xff0c;但是不能即时提醒&#xff0c;总是误事&#xff0c;什么邮箱可以即时提醒呢&#xff1f;随着工作和生活节奏的加快&#xff0c;传统的电子邮件系统由于不能即时提醒&#xff0c;往往会导致重要邮件的漏接&#xff0c;从而引发一系列的麻烦和误…

Windows小工具_剪切板

Windows11自带剪切板功能,可以保存剪切的全部历史,避免了多次重复打开文件剪切复制的烦恼. 打开步骤如下: 1.点击桌面下方任务栏的开始按钮 2.选择"设置" 如果"开始"里面的"已固定栏"找不到设置,在此处点击"所有应用" 3.找到"系…

基于qemu_v8+optee 3.17平台的ca/ta Demo

1、整体集成构建 基于官方构建&#xff0c;加入自定义ca/ta后一体构建到rootfs&#xff0c;在qemu上运行 $ mkdir -p <optee-project> $ cd <optee-project> $ repo init -u https://github.com/OP-TEE/manifest.git -m ${TARGET}.xml [-b ${BRANCH}] $ repo syn…

劲松中西医医院HPV诊疗中心科普:扁平疣4个知识点要了解

扁平疣是一种常见的皮肤病&#xff0c;其表现为皮肤上的扁平丘疹&#xff0c;通常无痛无痒&#xff0c;但会影响患者的外貌和心理。许多人在患上扁平疣后会考虑是否可以自己消退&#xff0c;下面我们将从几个方面进行探讨。 扁平疣的病因 扁平疣是由人乳头瘤病毒(HPV)引起的。…

V2X全方位通信部署解决方案如何支持智能交通建设?

背景介绍 后疫情时代人们更注重于享受当下&#xff0c;掀起了一股“旅游热”。大批量游客的到来给旅游胜地带来更多的人气和收益的同时&#xff0c;也带来了一系列的交通问题&#xff1a;游客和当地人民不仅会面临停车困难、交通拥堵的烦恼&#xff0c;还会因为游客对交通环境…

【考研数据结构代码题7】求一元多项式之和

题目&#xff1a;编写一个算法&#xff0c;求一元多项式之和 考纲&#xff1a;一元多项式的表示与相加 题型&#xff1a;代码填空或算法设计 难度&#xff1a;★★★ 参考代码 typedef struct node{float coef;//系数int exp;//次数struct node *next; }polynode; polynode *…

Python 自动化测试全攻略:五种自动化测试模型实战详解!

随着移动互联网的发展&#xff0c;软件研发模型逐步完善&#xff0c;软件交付质量越来越受到软件公司的重视&#xff0c;软件测试技术特别是自动化测试技术开始在软件系统研发过程中发挥着越来越重要的作用。 与传统的手工测试技术相比&#xff0c;自动化测试具备了良好的可操…

mysql允许远程连接

1. 检查服务器防火墙 防火墙若开启则需要开放mysql使用的3306端口才可远程访问&#xff1b; 若无安全性要求也可以直接关闭防火墙。 防火墙相关命令&#xff1a; # 检查防火墙状态 systemctl status firewalld # 开启防火墙 systemctl start firewalld # 停止防火墙 systemctl …

从入门到精通:掌握Python测试框架pytest的必备技能!

这篇文章主要介绍了Python测试框架&#xff1a;pytest的相关资料&#xff0c;帮助大家更好的利用python进行单元测试&#xff0c;感兴趣的朋友可以了解下 python通用测试框架大多数人用的是unittestHTMLTestRunner&#xff0c;这段时间看到了pytest文档&#xff0c;发现这个框…