蓝旭暑期培训Day3——文件上传
Posted 嗯我想想
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了蓝旭暑期培训Day3——文件上传相关的知识,希望对你有一定的参考价值。
蓝旭暑期培训Day3——文件上传
我们在之前就讲过,图片等非文本文件不能用字符流,而要使用字节流去操纵,本质上就是将非文本文件转换为二进制数据流,再去进行相对应的操作。
前后端交互中,经常用到的一个功能就是图片等非文本文件的上传(比如QQ头像的上传功能等)今天我们就以图片格式,来前后端交互中的文件上传。
前置知识基础:JavaIO
所用到HTTP Content-Type 的类型
在 JSON字符串 的时候,我们已经对 Content-Type 有了初步的了解,那么在文件上传的时候也有专门对应的Content-Type。
multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式
平常我们使用的类型都是把表单数据使用url编码后传送给后端,二进制文件当然没办法一起编码进去了。所以 multipart/form-data 就诞生了,专门用于有效的传输文件。
multipart/form-data 会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件。当上传的字段是文件时,会有Content-Type来表名文件类型;content-disposition,用来说明字段的一些信息;
由于有boundary隔离,所以multipart/form-data既可以上传文件,也可以上传键值对,它采用了键值对的方式,所以可以上传多个文件。
下图是Postman模拟前端情况,可以看到KEY和VALUE,文件就是VALUE
文件上传前端代码
方法一:普通form表单形式
<form enctype="multipart/form-data" action="url" method="POST">
<!-- name的值与后端接收的参数必须一致 -->
<input type="file" name="file">
<input type="submit" value="提交">
</form>
- enctype 需要使用 multipart/form-data
- method 需要使用post方法
方法二:ajax表单上传
上面的相比于Form表单的提交,使用了浏览器的XMLHttpRequest自定义的提交方式,也就是俗称的AJAX技术。但是使用这种提交方式没有设置编码 enctype=“multipart/form-data” 类型,如果直接将文件内容上传,会导致后端在解析Form表单上传的文件时与Ajax上传的不一致,所以为了后端能够使用相同的代码就能解析前端这两种提交方式,所以前端需要自行格式化文件内容。在格式化的过程中,则需要通过浏览器自身提供的FormData构造函数来实例化的一个文件fd,然后使用实例的append方法将文件内容插入进去,最后利用XMLHttpRequest的实例做出发送动作。
html代码
<input type="file" id="file">
<button id="btn">上传</button>
<img src="" id="img" alt="">
<script src="./index.js"></script>
var file = document.getElementById("file")
var btn = document.getElementById("btn")
btn.onclick = function() {
var img = file.files[0]
// 创建一个空对象
var formdata = new FormData()
// 通过append方法添加数据
formdata.append("imgfile", img)
upload(formdata)
}
function upload(data) {
// 创建xhr对象
var xhr = new XMLHttpRequest()
// 初始化请求
xhr.open("post", "http://localhost:3000/api/upload", true)
// 设置请求头 设置content-type
xhr.setRequestHeader("Content-Type", "multipart/form-data")
// 发送数据
xhr.send(data)
// 处理响应数据
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
var res = JSON.parse(xhr.responseText)
var img = document.getElementById("img")
img.src = 'http://localhost:3000' + res.data
}
}
}
由于后台还没有讲过项目部署在服务器上,后台同学可以先用方式一,自己写一个jsp页面进行测试,这也是文件上传部分的作业,稍后会详细说。
后端文件上传 javax.servlet.http.Part
前端可以发送文件了,后端就需要进行相对应的接收。这里我们采用的是JavaEE中的javax.servlet.http.Part类上传文件。
Part是一个接口继承于javax.servlet.http,代表一部分表单项目接收来自multipart/form-data的POST的请求。
HttpServletRequest 提供了两个方法用于从请求中解析上传的文件:
Part getPart(String name): 用于获取请求中指定name的文件
Coolection< Part > getParts();获取请求中全部的文件
Part part = request.getPart("file"); // file就是你的KEY,和前端沟通好就行
Part API
结合 HttpServletRequest 对象和 @MultipartConfig 注解来处理文件上传.
指定缓存大小和临时目录
@MutipartConfig 可以设置 相应参数限制条件,必须声明,否则会报错,当然也是有默认的参数滴~
FileSize表示上传的单个文件的大小,RequestSize表示一次上传的总的数据量,所以可以在一个表单中一次上传多个文件。
API看完了,下面也就上代码了。
package web;
import com.google.gson.Gson;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@MultipartConfig
@WebServlet(value = "/fileUpload")
public class FileUploadController extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Part part = request.getPart("file");
// 获取上传的文件名扩展名
String disposition = part.getSubmittedFileName();
String suffix = disposition.substring(disposition.lastIndexOf("."));
// 随机的生成uuid,作为文件名的一部分。 加上刚才获取到的后缀作为最终文件名。
String filename = UUID.randomUUID()+suffix;
// 获取文件上传的位置,绝对路径URL
String serverpath = request.getServletContext().getRealPath("upload");
System.out.println(filename);
System.out.println(serverpath);
//不存在文件夹则新建一个
File fileDisk = new File(serverpath);
if (!fileDisk.exists()){
fileDisk.mkdir();
}
// 文件的真正绝对路径 = 文件存储位置 + 文件名
String fileparts = serverpath + "/" + filename;
// 将文件内容写入指定的磁盘位置
part.write(fileparts);
// 准备给前端返回的文件访问的URL
String projectServerPath = request.getScheme()+"://"+request.getServerName()+":"
+request.getServerPort()+request.getContextPath()+"/upload/"+filename;
// request.getSchema()可以返回当前页面使用的协议,http 或是 https;
// request.getServerName()可以返回当前页面所在的服务器的名字;
// request.getServerPort()可以返回当前页面所在的服务器使用的端口,就是8080;
// request.getContextPath()可以返回当前页面所在的应用的名字;
// 拼接起来后就是完整的文件访问路径了!
// 返回给前端文件访问的URL
PrintWriter out = response.getWriter();
Gson gson = new Gson();
Map map = new HashMap();
map.put("address",projectServerPath);
String jsonString = gson.toJson(map);
out.print(jsonString);
out.flush();
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
super.doPost(request, response);
}
}
文件上传作业:
后台同学自己用jsp页面用前端的方法一,form表单上传,测试一下自己的文件上传功能是否成功,并将成功后的URL打印在控制台。
量力而行,有问题随时问。
截止时间:7月23日中午12点前,交给我
以上是关于蓝旭暑期培训Day3——文件上传的主要内容,如果未能解决你的问题,请参考以下文章
JDK的equals方法都写错了,那到底该怎么写呢?(备战2022春招或暑期实习,每天进步一点点,打卡100天,Day3)