蓝旭暑期培训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>
  1. enctype 需要使用 multipart/form-data
  2. 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>

JavaScript代码

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点前,交给我

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值