文件上传的简介:文件上传是指将本地计算机中的文件传输到网络上的服务器或另一台计算机上的过程。在 Web 开发中,文件上传通常指的是将用户通过 Web 页面提交的文件(如图像、文档、音频、视频等)传输到服务器端的操作。
文件上传通常涉及以下几个主要组件:
文件上传在 Web 开发中非常常见,常见的应用场景包括但不限于用户头像上传、文件分享、数据备份等。
文件上传的步骤:
项目结构
文件上传前端的三要素:
元素应该包含一个
元素,用于让用户选择要上传的文件。编写的html文件:
文件上传 上传文件
编写的controller
package com.knife.controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; @RestController public class UploadController { @PostMapping("/upload") public void upload(MultipartFile file){ System.out.println("file == " + file); } }
运行截图:(通过xml配置的路径去访问html文件,然后点击上传文件)
file内容不等于null,说明文件上传成功。
总结:服务端要想接收到从前端页面上传的文件,需要使用到一个api:MultipartFile,通过该api来接收上传的文件。而上传上来的文件是一个临时文件,当文件上传这次请求完成之后,这些临时文件会自动删除。因此,在上传文件的同时,应该把文件保存起来。
在服务端,接收到上传上来的文件之后,将文件存储在本地服务器磁盘中。
基础实现:在上面的文件上传——入门的基础上,修改一下controller就行。
package com.knife.controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; @RestController public class UploadController { @PostMapping("/upload") public void upload(MultipartFile file) throws IOException { System.out.println("file == " + file); // 获取源文件的文件名 String originalFilename = file.getOriginalFilename(); // 把上传上来的文件存储到磁盘上:transferTo的参数是一个文件 file.transferTo(new File("E:\\images\\"+ originalFilename)); } }
只需把上面的controller改成上面一样,然后运行,然后如果你的路径不对,或者你盘符的目录不存在,就会报错了(因为这里没有对异常处理,只是简单地把异常抛出去了)
最快的解决办法就是,修改本地存储的路径,输入一个存在的目录的路径。
最佳解决办法:如下更改controller
package com.knife.controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.util.UUID; @RestController public class UploadController { @PostMapping("/upload") public void upload(MultipartFile file) throws IOException { System.out.println("file == " + file); // 1. 获取源文件的文件名 String originalFilename = file.getOriginalFilename(); // 定义要上传的路径 String fileUploadPath = "E:\\images\\"+ originalFilename; // 创建要上传的文件 File uploadFile = new File(fileUploadPath); // 判断配置的文件目录是否存在,若不存在则创建一个新的文件目录 File parentFile = uploadFile.getParentFile(); if(!parentFile.exists()) { parentFile.mkdirs(); } System.out.println(uploadFile); file.transferTo(uploadFile); } }
运行:
本地存储第一版存在的问题:
不管文件路径的报错的写法(和上面文件上传——本地存储—第一版就只有controller的差别):
package com.knife.controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.util.UUID; @RestController public class UploadController { @PostMapping("/upload") public void upload(MultipartFile file) throws IOException { System.out.println("file == " + file); // 1. 获取源文件的文件名 String originalFilename = file.getOriginalFilename(); // 2. 构造唯一的文件名 -- 使用uuid(通用唯一识别码,长度固定的字符串,而且是唯一的)+ 原始文件文件后缀名 // 2.1. 通过字符串的截取,获取文件的后缀名 int index = originalFilename.lastIndexOf("."); String extname = originalFilename.substring(index); // 2.2 把uuid和文件后缀名合并 String newFileName = UUID.randomUUID().toString() + extname; System.out.println("newFileName = " + newFileName); // 把上传上来的文件存储到磁盘上:(指定一个路径) file.transferTo(new File("E:\\"+ newFileName)); } }
package com.knife.controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.util.UUID; @RestController public class UploadController { @PostMapping("/upload") public void upload(MultipartFile file) throws IOException { System.out.println("file == " + file); // 1. 获取源文件的文件名 String originalFilename = file.getOriginalFilename(); // 2. 构造唯一的文件名 -- 使用uuid(通用唯一识别码,长度固定的字符串,而且是唯一的)+ 原始文件文件后缀名 // 2.1. 通过字符串的截取,获取文件的后缀名 int index = originalFilename.lastIndexOf("."); String extname = originalFilename.substring(index); // 2.2 把uuid和文件后缀名合并 String newFileName = UUID.randomUUID().toString() + extname; // 定义要上传的路径 String fileUploadPath = "E:\\images\\"+ newFileName; // 创建要上传的文件 File uploadFile = new File(fileUploadPath); // 判断配置的文件目录是否存在,若不存在则创建一个新的文件目录 File parentFile = uploadFile.getParentFile(); if(!parentFile.exists()) { parentFile.mkdirs(); } System.out.println(uploadFile); // 把上传上来的文件存储到磁盘上:(指定一个路径) file.transferTo(uploadFile); } }
运行:
文件上传大小限制的问题:在配置文件里面进行配置
如果是application.properties则如上图一样配置就行,如果是application.yml,则如下配置即可
application.yml:
server: port: 8088 # 配置访问服务器的端口 spring: servlet: multipart: max-file-size: 10MB # 配置单个文件最大上传大小 max-request-size: 100MB # 配置单个请求最大上传文件的大小(一次可以上传多个文件,即多个文件的总和也算)
中加入如下内容(参考官方文档的说明): com.aliyun.oss aliyun-sdk-oss 3.15.1
javax.xml.bind jaxb-api 2.3.1 javax.activation activation 1.1.1 org.glassfish.jaxb jaxb-runtime 2.3.3
import com.aliyun.oss.ClientException; import com.aliyun.oss.OSS; import com.aliyun.oss.common.auth.*; import com.aliyun.oss.OSSClientBuilder; import com.aliyun.oss.OSSException; import com.aliyun.oss.model.PutObjectRequest; import com.aliyun.oss.model.PutObjectResult; import java.io.FileInputStream; import java.io.InputStream; public class Demo { public static void main(String[] args) throws Exception { // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。 String endpoint = "https://oss-cn-hangzhou.aliyuncs.com"; // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider(); // 填写Bucket名称,例如examplebucket。 String bucketName = "examplebucket"; // 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。 String objectName = "exampledir/exampleobject.txt"; // 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。 // 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。 String filePath= "D:\\localpath\\examplefile.txt"; // 创建OSSClient实例。 OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider); try { InputStream inputStream = new FileInputStream(filePath); // 创建PutObjectRequest对象。 PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream); // 创建PutObject请求。 PutObjectResult result = ossClient.putObject(putObjectRequest); } catch (OSSException oe) { System.out.println("Caught an OSSException, which means your request made it to OSS, " + "but was rejected with an error response for some reason."); System.out.println("Error Message:" + oe.getErrorMessage()); System.out.println("Error Code:" + oe.getErrorCode()); System.out.println("Request ID:" + oe.getRequestId()); System.out.println("Host ID:" + oe.getHostId()); } catch (ClientException ce) { System.out.println("Caught an ClientException, which means the client encountered " + "a serious internal problem while trying to communicate with OSS, " + "such as not being able to access the network."); System.out.println("Error Message:" + ce.getMessage()); } finally { if (ossClient != null) { ossClient.shutdown(); } } } }
改写后的入门程序:主要修改自己的endpoint、accessKeyId、bucketName、objectName、filePath
package com.knife; import com.aliyun.oss.ClientException; import com.aliyun.oss.OSS; import com.aliyun.oss.common.auth.*; import com.aliyun.oss.OSSClientBuilder; import com.aliyun.oss.OSSException; import com.aliyun.oss.model.PutObjectRequest; import com.aliyun.oss.model.PutObjectResult; import java.io.FileInputStream; import java.io.InputStream; public class uploadOss{ public static void main(String[] args) throws Exception { // Endpoint:(华北2(北京))请按实际情况填写。 String endpoint = "oss-cn-beijing.aliyuncs.com"; // 根据自己的实际情况填写 // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 // EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider(); // 使用accessKeyId、accessKeyIdSecret替代。 String accessKeyId = "你自己的密钥id"; // 根据自己的实际情况填写 String accessKeyIdSecret ="你自己的密钥";// 根据自己的实际情况填写 // 填写Bucket名称,例如examplebucket。 String bucketName = "你自己的bucketName";// 根据自己的实际情况填写 // 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。 String objectName = "1.jpg"; //设置我们上传的文件,最终在阿里云上面是什么名字 // 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。 // 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。 String filePath= "C:\\Users\\qq351\\Pictures\\Saved Pictures\\1.jpg"; // 创建OSSClient实例。 // OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider); OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId,accessKeyIdSecret); try { InputStream inputStream = new FileInputStream(filePath); // 创建PutObjectRequest对象。 PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream); // 创建PutObject请求。 PutObjectResult result = ossClient.putObject(putObjectRequest); } catch (OSSException oe) { System.out.println("Caught an OSSException, which means your request made it to OSS, " + "but was rejected with an error response for some reason."); System.out.println("Error Message:" + oe.getErrorMessage()); System.out.println("Error Code:" + oe.getErrorCode()); System.out.println("Request ID:" + oe.getRequestId()); System.out.println("Host ID:" + oe.getHostId()); } catch (ClientException ce) { System.out.println("Caught an ClientException, which means the client encountered " + "a serious internal problem while trying to communicate with OSS, " + "such as not being able to access the network."); System.out.println("Error Message:" + ce.getMessage()); } finally { if (ossClient != null) { ossClient.shutdown(); } } } }
路径获取:
运行就可以传进去了
通过浏览器访问该图片的路径时,会直接下载该图片,但是在页面显示出来挺简单的,就是使用一个imag标签,然后把路径放在src下即可
在配置文件里面对oss的参数进行配置
#阿里云OSS aliyun: oss: endpoint: https://oss-cn-hangzhou.aliyuncs.com accessKeyId: LTAI4GCH1vX6DKqJWxd6nEuW accessKeySecret: yBshYweHOpqDuhCArrVHwIiBKpyqSL bucketName: web-tlias
属性配置类:(读取配置文件里面的属性)
import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @Data @Component @ConfigurationProperties(prefix = "aliyun.oss") public class AliOSSProperties { private String endpoint; private String accessKeyId; private String accessKeySecret; private String bucketName; }
封装工具类:
import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; import java.io.*; import java.util.UUID; /** * 阿里云 OSS 工具类 */ @Component public class AliOSSUtils { @Autowired private AliOSSProperties aliOSSProperties; /** * 实现上传图片到OSS */ public String upload(MultipartFile file) throws IOException { //获取阿里云OSS参数 String endpoint = aliOSSProperties.getEndpoint(); String accessKeyId = aliOSSProperties.getAccessKeyId(); String accessKeySecret = aliOSSProperties.getAccessKeySecret(); String bucketName = aliOSSProperties.getBucketName(); // 获取上传的文件的输入流 InputStream inputStream = file.getInputStream(); // 避免文件覆盖 String originalFilename = file.getOriginalFilename(); String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf(".")); //上传文件到 OSS OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); ossClient.putObject(bucketName, fileName, inputStream); //文件访问路径 String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName; // 关闭ossClient ossClient.shutdown(); return url;// 把上传到oss的路径返回 } }
controller类上使用
import com.itheima.pojo.Result; import com.itheima.utils.AliOSSUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.util.UUID; @RestController public class UploadController { @Autowired private AliOSSUtils aliOSSUtils; @PostMapping("/upload") public Result upload(MultipartFile image) throws IOException { log.info("文件上传, 文件名: {}", image.getOriginalFilename()); //调用阿里云OSS工具类进行文件上传 String url = aliOSSUtils.upload(image); log.info("文件上传完成,文件访问的url: {}", url); return Result.success(url); } }