GET的参数会以明文的形式附带在url后面,因此只能用于传递少量且不考虑安全的数据。
如果表单中含有二进制数据,那么一定只能用POST提交,而且表单的 enctype 属性必须设置为 multipart/form-data。action 声明了表单提交的地址。
多文件上传和单文件,在前端的区别只是在input标签中是否加上 multiple 标记而已。
文件下载用到了 prompt 请求输入框,返回值是输入的内容。如果单击取消,会返回 null。
function downloadPromptUrl() {
const value = prompt("请输入文件名", "test.jpg");
if(value !== null) downloadUrl(value);
}
function downloadPromptBlob() {
const value = prompt("请输入文件名", "test.jpg");
if(value !== null) downloadBlob(value);
}
onreadystatechange 存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数。
readyState 存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。
status
function getBrowser() {
var ua = window.navigator.userAgent;
var isIE = !!window.ActiveXObject || "ActiveXObject" in window;
var isFirefox = ua.indexOf("Firefox") != -1;
var isOpera = window.opr != undefined;
var isChrome = ua.indexOf("Chrome") && window.chrome;
var isSafari = ua.indexOf("Safari") != -1 && ua.indexOf("Version") != -1;
if (isIE) {
return "IE";
} else if (isFirefox) {
return "Firefox";
} else if (isOpera) {
return "Opera";
} else if (isChrome) {
return "Chrome";
} else if (isSafari) {
return "Safari";
} else {
return "Unkown";
}
}
function downloadUrl(downloadName) {
const url = "http://127.0.0.1:8080/download/" + downloadName;
// window.location.href = url;
window.open(url)
}
function downloadBlob(downloadName) {
const url = "http://127.0.0.1:8080/download/" + downloadName;
const xhr = new XMLHttpRequest();
xhr.responseType = "blob";
xhr.open('GET', url);
xhr.onreadystatechange = function(e) {
console.log(this.readyState + ", " + this.status);
if (this.readyState == 4 && this.status == 200) {
const type = xhr.getResponseHeader("Content-Type");
console.log(type)
const name = xhr.getResponseHeader("Content-Disposition");
console.log(name);
const filename = name.split(";")[1].substring(9).replace(/^[\'\"]+|[\'\"]+$/g,"");
console.log(filename);
/*
const blob = new Blob([xhr.response], {type: 'image/jpeg'});
const objectURL = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = objectURL;
link.download = filename;
link.innerText = "test.jpg";
//link.style.display="none";
//只有添加到html中,点击事件才有效
document.body.appendChild(link);
link.click();
*/
var browser = getBrowser();
console.log(browser)
if (browser == "Chrome") {
var link = document.createElement('a');
var file = new Blob([xhr.response], { type: type });
link.href = window.URL.createObjectURL(file);
link.download = filename;
link.click();
window.URL.revokeObjectURL(link.href);
} else if (browser == "Firefox") {
var file = new File([xhr.response], filename, { type: type });
var url = URL.createObjectURL(file);
parent.location.href = url;
window.URL.revokeObjectURL(url);
}
}
}
xhr.send(null);
}
对于 java.io.tmpdir 的路径
private static final String TMP_DIR = System.getProperty("java.io.tmpdir") + "Diffpatch" + File.separator;
private static final String FILE_DIR = TMP_DIR + "file" + File.separator;
private static final String CACHE_DIR = TMP_DIR + "cache" + File.separator;
private static final int BUFF_SIZE = 1024;
private ResultModel newResult(boolean success, String msg) {
return new ResultModel(success, msg, TMP_DIR);
}
当前端不选择任何文件直接点 “提交” 的时候,会返回 “文件为空”
@PostMapping(value="/upload")
public ResultModel upload(@RequestParam("file") MultipartFile file) {
if(file.isEmpty()) {
return newResult(false, "文件为空");
}
//确保存储目录存在
File dir = new File(FILE_DIR);
if(!dir.exists()) dir.mkdirs();
//文件名
String fileName = file.getOriginalFilename();
String path = FILE_DIR + fileName;
try {
File dstFile = new File(path);
file.transferTo(dstFile);
return newResult(true, "上传成功");
} catch (IllegalStateException e) {
e.printStackTrace();
return newResult(false, e.toString());
} catch (IOException e) {
e.printStackTrace();
return newResult(false, e.toString());
}
}
即使前端不选择任何文件,也是可以取得一个长度为1的 MultipartFile 列表,只是它的 isEmpty 属性为真。
当然,在我的前一篇文章中,试过了,用 MultipartFile[] 也是可以的。
@PostMapping(value="/uploadbatch")
public ResultModel uploadBatch(HttpServletRequest request) {
List files = ((MultipartHttpServletRequest) request).getFiles("file");
MultipartFile file = null;
BufferedOutputStream stream = null;
byte[] buffer = new byte[BUFF_SIZE];
int len;
for(int i=0; i
Content-disposition 是 MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件。Content-disposition其实可以控制用户请求所得的内容存为一个文件的时候提供一个默认的文件名,文件直接在浏览器上显示或者在访问时弹出文件下载对话框。
Content-Type 一般是附带文件编码的,常用的如下
HttpServletRequest 和 HttpServletResponse 分别是原始的请求和下载,可以放在函数中,也可以自动绑定到类的属性里。
@GetMapping(value="/download/{name}")
public void download(@PathVariable String name, HttpServletResponse response) throws IOException {
String path = FILE_DIR + name;
File file = new File(path);
if(file.exists()) {
//设置强制下载不打卡
response.setContentType("application/force-download");
response.addHeader("Content-Disposition", "attachment;fileName=\"" + name + "\"");
response.setContentLength((int) file.length());
byte[] buffer = new byte[1024];
FileInputStream fis = null;
BufferedInputStream bis = null;
try {
fis = new FileInputStream(file);
bis = new BufferedInputStream(fis);
OutputStream os = response.getOutputStream();
int len;
while((len = bis.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
response.flushBuffer();
} catch (IOException e) {
e.printStackTrace();
response.sendError(HttpServletResponse.SC_NOT_FOUND, e.toString());
} finally {
try {
if(bis != null) bis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(fis != null) fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND, "文件不存在");
}
}