链接:样例 源码在本地(文件上传与下载)
文件上传
前端
- form需要设置
enctype
参数为multipart/form-data
,表示编码方式为文件类型兼表单数据类型(即以二进制流传输表单的value值和文件),这关系到后端HttpServletRequest
能否转为MultipartHttpServletRequest
- 默认的一般是
application/x-www=form-urlencoded
,该属性只传输表单的value,不传输文件 - 还有一个类型
text/plain
将空格转换为+号,其它字符不做编码处理,适用于通过表单发送邮件。 - 有时候即使设置了form-data,上传时也不是文件请求,所以最好使用现成的前端组件,如layui
- 默认的一般是
- input如果需要多文件上传功能,就添加
multiple="multiple"
上传时使用ctrl
可以一次选中多个文件上传,但是不能分多次上传,分多次后面会把前面的缓存数据冲掉- 文件表单需要设置
**name**
属性,后端会根据name来取文件表单数据
- 文件表单需要设置
- 使用
new FormData($('#uploadForm')[0]);
获取一个文件类型对象 - 文件上传控件原生html中只有
type="file"
可以实现文件上传- 对文件上传
**input**
设置值是无效的,但是可以在提交时获取文件路径。一般用于对文件进行限制,如获取后缀限制类型 - intput file时设置
accept=".xls,.xlsx"
可以指定上传文件的类型,不过用户选择时还是能下拉选择全部类型
选项
- 对文件上传
- 而
form
表单实现文件上传有如下要求:- 最好采用
**post**
方式提交,因为**post**
携带数据量更大 ```html
<a name="Ez56Z"></a> ## layui文件上传 - **为post类型** ```javascript layui.use('upload', function(){ var upload = layui.upload; var uploadInst = upload.render({ elem: '#file', //绑定的input accept:'file', //表示文件的大致类型,如文件,媒体,默认为图片 data: { //额外携带的参数 "mid":mid2, "cid":cid }, auto: false, //不自动提交 exts:'xls|xlsx', //具体类型 bindAction:'#daorubutton', //手动提交的按钮 headers: {sign: config.headers('daoru').sign} //数字验签 ,url: config.wage()+'/exceltodbModel/daoru' //此处配置你自己的上传接口即可 //此处配置你自己的上传接口即可 ,done: function(res){ layer.msg('上传成功'); console.log(res) } }); });
后端
文件上传配置
- 这里以springboot为准,注意springboot有默认文件最大大小限制(不清楚是1MB还是10MB)。通过如下方式可以修改,前端也可以通过表单控件的属性进行限制
- 单位大小,KB,MB,GB可以设置,其他如字节,TB等单位没试过
- location属性是设置文件本地缓存位置的配置,写配置文件里有个好处是在编译器就会检查该路径是否存在,不存在就编译报错。避免了运行时路径的io异常和空指针
- file-size-threshold: 5MB #指定文件将写入磁盘的大小阈值。 默认值为0。意味文件大小必须大于该值时才允许写入磁盘 ```properties
单个文件最大大小
spring.servlet.multipart.max-file-size = 10MB
总上传的数据最大大小
spring.servlet.multipart.max-request-size = 1GB
spring: servlet: multipart: enabled: true location: C:/Users/yxkj/Documents/code
file-size-threshold: 5MB #指定文件将写入磁盘的大小阈值。 默认值为0 max-file-size: 20MB<a name="AaJJo"></a> ### 文件上传接收 - 这里写了个工具类,可以对上传的文件进行选择,不符合要求的过滤,主要依靠这些方法: - `MultipartHttpServletRequest=(MultipartHttpServletRequest) HttpServletRequest`可以得到一个文件请求体对象, - 注意普通表单数据必须通过控制器映射或者request获得,MultipartHttpServletRequest无法获得表单数据 - 单个文件可以直接`@RequestBody MultipartFile`来接收,文件与参数一起传用`@RequestParam(...) Mul...` - `MultipartHttpServletRequest`对象可以调用`getFiles(name)`得到`MultipartFile`对象或者对象集合 - name是`input`的name属性参数 - `MultipartFile`存储一个文件及其各种信息: - `getSize()`:文件大小 - `getContentType()` 得到文件类型,得到的类型是`contentType`,对应关系见[contentType对应表](https://www.runoob.com/http/http-content-type.html) - `getOriginalFilename`得到原始文件名 - 还有个`getName()`方法,它得到的永远都是`"file"`字符串,表示这是文件类型 - `getInputStream()`得到Multipart的输入流 ```java MultipartHttpServletRequest multipartRequest = null; try { //需要设置enctype为multipare才能进行强转 multipartRequest = (MultipartHttpServletRequest) httpServletRequest; } catch (Exception e) { return new LinkedList<MultipartFile>(); } List<MultipartFile> files = new LinkedList<>(); files = multipartRequest.getFiles("file");
public HttpResult daoru(@RequestParam("file") MultipartFile file,@RequestParam("mid")String mid
springboot API优化接口
transferTo
原本在io中是将输入流传到输出流中,springmvc提供了一个类似的功能,让MultipartFile
对象调用自己的transferTo
并传个路径对象,即可快速输出到磁盘subBefore``subAfter
快速根据分割字符拆分 获取前缀和后缀-
文件下载
后端
必须设置的响应信息如下:
ContentType
:文件类型,也可以全设置为application/force-download
Header
:文件名,还可以设置其他额外信息setCharacterEncoding(charset)
文件名如果有中文,设置utf-8才能正确显示- 其他的就不是必须的设置项
getOutputStream()
从HttpServletResponse
中得到输出流,往输出流中写入信息即可- 使用a标签或者href可以自动跳转请求get下载接口,因为href默认为get请求,而ajax交互是以字符串进行交流,不会自动调用浏览器下载响应内容
- 但是这种方式对于认证与验签的请求不行,这时必须使用ajax或者原生xhr。以添加token等认证信息
header允许存在同名header信息
addheader
:无则添加,有也添加setheader
:无则添加,有则覆盖@GetMapping("/download") public String downloadFile(HttpServletRequest request, HttpServletResponse response) throws IOException { String files = "C:\\Users\\Lw\\Desktop\\xdf.txt"; if (files != null) { File file = new File(files); if (file.exists()) { OutputStream os = response.getOutputStream(); FileInputStream fis = new FileInputStream(files); byte[] buffer = new byte[fis.available()]; try { fis.read(buffer); //不写这一步,buffer只是存储了?长度的0,写进os里也算空白数据。走了这一步才会变成?长度的实际数据, response.setContentType("text/plain");// 设置强制下载不打开 text/plain response.addHeader("Content-Disposition", "attachment;fileName=" + "test.txt");// 设置文件名 response.setHeader("Content-Range", "" + Integer.valueOf(buffer.length - 1)); os.write(buffer); return "下载成功"; } catch (Exception e) { e.printStackTrace(); return "下载失败"; } finally { // 做关闭操作 if (buffer != null) { try { os.flush(); os.close(); fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } else { return "文件不存在"; } } else { return "路径错误"; } }
常用响应头
-
ajax实现文件下载
ajax实现文件下载,一般是为了在请求文件下载的同时进行鉴权,设置请求头等
通过ajax下载文件,响应里面能看到文件数据(一般是乱码)
function download(ajaxType,url) { //ajax请求类型:'post'/'type' const xhr = new XMLHttpRequest(); xhr.open(ajaxType, url, true); //默认async为true xhr.setRequestHeader('token', sessionStorage.getItem('token')); // 设置token xhr.setRequestHeader('Content-Type', 'application/octet-stream'); xhr.responseType = 'blob'; // 返回类型blob xhr.onload = function(e) { if (this.status === 200) { const blob = this.response; const reader = new FileReader(); reader.readAsDataURL(blob); // 转换为base64,可以直接放入a表情href reader.onload = function(e) { const a = document.createElement('a'); a.download = '文件名.xls'; a.href = e.target.result; document.documentElement.appendChild(a); a.click(); a.remove(); // 等价于document.documentElement.removeChild(a); }; } }; xhr.send(); // 发送ajax请求 }
axios实现文件下载
```javascript download2() {
const url = '导出链接';
$get(url , {
startDate: '2021-08-01', endDate: '2021-08-01'
}).then(res => {
res.request.onload = function(e) { const blob = res.data; const reader = new FileReader(); reader.readAsDataURL(blob); reader.onload = function(e) { const a = document.createElement('a'); a.download = '文件名.xls'; a.href = e.target.result; document.documentElement.appendChild(a); a.click(); a.remove(); }; };
}); } // axios代码 const req = axios.create({ responseType: ‘blob’ //关键 }); req.interceptors.request.use( config => {
config.headers = { token: sessionStorage.getItem('token'), 'Content-Type': 'application/octet-stream' }; return config;
}, err => {
return Promise.reject(err);
} ); req.interceptors.response.use( res => {
// 这里做错误判断(这里假设有token直接返回文件流 没有token返回的res包含code) if (res.hasOwnProperty('code') && res.code !== 0) { alert(res.message || '导出错误'); return; } return res;
}, err => {
console.log(err, err.message);
} );
function $get(url, params = {}) { return new Promise((resolve, reject) => { req.get(url, { params }).then( res => { resolve(res); }, err => { reject(err); } ); }); }
```
- 这里以springboot为准,注意springboot有默认文件最大大小限制(不清楚是1MB还是10MB)。通过如下方式可以修改,前端也可以通过表单控件的属性进行限制
- 最好采用