一、基础原理
文件上传是一个很基础的知识点,尤其是本地上传,在现实开发基本都是云上传,但是作为一个基础要简单了解一下
首先前端我就不多讲解了,网页开发里用<form>表单可以上传文件,只需要加上这三属性: 【action="接口路径"】 【method="post"】 【enctype="multipart/form-data"】就可以上传文件了,这里我不打算讲细,因为这主要是讲后端,有兴趣的自己额外研究一下
代码在这,自己直接复制粘贴就行:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件上传</title>
<style>
.submit{
width: 100px;
height: 30px;
margin-top: 20px;
margin-left: 120px;
}
input{
height: 30px;
margin-bottom: 20px;
}
form{
width: 20%;
border: 1px solid black;
padding: 20px;
margin: auto;
margin-top: 250px;
display: flex;
flex-direction: column;
}
</style>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
姓名:<input type="text" name="userName">
年龄:<input type="text" name="age">
头像:<input type="file" name="image">
<input type="submit" value="提交" class="submit">
</form>
</body>
</html>
提示:
这里为了方便我就直接在【spring boot工程】里写了前端页面,如果要在spring boot工程写前端html页面,必须在【resources】的【static】目录下设置
而且注意,你的html文件的文件名是啥,你到时【接上后端服务之后】访问的前端页面的网址路径就是啥:
在接入后端之前,我们在html文件右上角浏览器临时运行一下就行,后期接上了后端的接口之后再【运行整个后端项目】,然后访问【后端的网址+html文件名】来运行页面
然后打开浏览器的【检查】,右边除了我们常用的Console控制台,还有一个Network网络,谷歌是【Network】,别的可能是中文【网络】
谷歌浏览器Edge浏览器
点到当我们点击【submit提交按钮】时,就会触发一个【请求】,点一下就能展开,就能看到【请求的详情】:
谷歌浏览器
Edge浏览器
然后找到【请求头】(Request Headers),勾选【原始】(Raw)就能看到原请求头代码信息
可以看到【Content-Type】这块有两信息:第一个是表单上传的内容形式,第二个是多个信息上传时,信息之间的分隔符
那么我们具体的信息在哪,可以点到【负载】(Payload)看到我们传过去的信息
上面就是在浏览器查看文件上传的一些基本原理
二、然后讲一下后端怎么获取到上传的资源
注意,前端用<form>的形式发送请求的时候,后端的【请求注解】对应【form的action属性】和【form的method请求方式】、后端的【请求方法的参数名】要对应【form的每个输入框的name属性】
------ 然后后端接收文件参数的数据类型得是**【MultipartFile】**
当然要是参数名跟form的name属性名不也一样也可以,加一个【@RequestParam(" ")】注解就可以
那么现在在controller层加一个【controller类】,就叫:UpLoadController吧
代码如下:
java
//写你们自己的路径
//package com.czm.tliaswebmanagement.controller;
//import com.czm.tliaswebmanagement.pojo.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@Slf4j
@RestController
public class UpLoadController {
@PostMapping("/upload")
public Result uplaod(String userName, Integer age, MultipartFile image){
log.info("上传过来的参数{} {} {}",userName, age, image);
return Result.success();
}
}
接着在运行整个后端项目之前,在你的log.info输出日志的部分打个断点
然后点击【调试】,不要点【运行】,【调试】的话日志才能捕捉到前端发来的请求
然后到前端页面发送一下请求,就会跳到后端看到信息
然后点开"文件"的【location】,这个路径就是我们本地文件的地址
把路径复制到电脑文件夹跳转,就能看到文件了,这里三个文件是对应userName、age、image三个数据
不过这里的原理是:每次上传的时候,后端虽然能接收到文件,但只会生成【临时文件】,再运行完之后就会删除临时文件
只要去掉断点,在重新放行让程序运行完,再回到那个文件夹就会发现那三个文件被清空了
那就需要【文件上传的本地储存】
三、后端获取文件后本地储存
因为黑马讲得太细了,而且现实开发里本来本地储存就很少用,那我这里就简短高效讲了
其实上传文件的原理就是:前端把文件变为二进制编码数据,通过后端传送给服务器,然后服务器保存下来这个文件。
那么现在我们本地储存的话,就可以理解本机电脑就是一个服务器了,我们就可以指定将文件保存到哪个位置
代码很简单,逻辑就是1、【获取文件名】,2、调用【文件.transferTo()】方法来指定文件存储路径,然后存储,3、给transferTo()里传入一个【File对象】,参数就是结尾是【文件名】的【绝对路径】字符串
(简单了解不要记,我后面会放源代码在下面,以后直接复制粘贴即可)
写的时候如果报错,那就鼠标悬停,点一下那个提示的帮助方法,就会在方法头那加一个【throws IOException抛出异常】就OK了
但是如果要传递多个文件,如果存在相同文件名的文件,上一个就会被覆盖,比如原来上传了一个【1.png】的文件,后面又上传一个叫【1.png】的文件,就会把上一张覆盖了,所以我们要保证每个文件名要【不同】【唯一】,那么就调用【UUID.randomUUID.toString()】方法获得随机的唯一的乱码字符串,来作为文件名
完整代码:(这就是完整的本地文件存储的代码,以后用到直接来这【复制】就行)
java
//写你们自己的路径
//package com.czm.tliaswebmanagement.controller;
//import com.czm.tliaswebmanagement.pojo.Result;
import lombok.extern.slf4j.Slf4j;
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;
@Slf4j
@RestController
public class UpLoadController {
@PostMapping("/upload")
public Result uplaod(String userName, Integer age, MultipartFile image) throws IOException {
log.info("上传过来的参数{} {} {}",userName, age, image);
/*---------------------------------【本地存储】----------------------------------*/
//获取本地文件名(比如:1.jpg、 xxx.txt、 qids.png...)
String originalFileName = image.getOriginalFilename();
//获取原文件名的后缀名【.jpg】、【.png】、【.html】...
int index = originalFileName.lastIndexOf(".");
String extname = originalFileName.substring(index);
//然后生成一个新的文件名
String newFileName = UUID.randomUUID().toString() + extname;
//调用【文件的transferTo】方法,往里面传入一个【File对象】,就可以指定文件【存储的具体路径】
//当然【存储的具体路径】包括了【前面的绝对路径】+【后面的文件名】
//下面例子就是把"F:\images\"和"asjhwuhwndm.jpg"拼成"F:\images\asjhwuhwndm.jpg"
image.transferTo(new File("F:\\images\\" + newFileName));
/*----------------------------------------------------------------------------*/
return Result.success();
}
}
最后一步,去【application.properties】文件,把下面两个代码配置上去,因为文件保存默认限制了单个文件1M以内,多个文件上传也有大小限制,这两个配置你就可以根据自己需要上传大文件了
XML
#配置单个文件最大上传大小
spring.servlet.multipart.max-file-size = 10MB
#配置单个请求最大上传大小(一次请求可以上传多个文件)
spring.servlet.multipart.max-request-size = 100MB
四、发请求试一下
注意发请求这里写接口时,参数换成body的【form-data】,然后类型选【file】
发送请求的时候就点那个【Upload】按钮,上传你的本地文件,这里我传来三次不同的图片,我就不一一演示了
点开文件夹,成功
缺点就是文件本地会爆,所以了解即可,可能会用到,但不多,大部分还是【云存储】