一. http协议规定:
1. 必须使用POST方式提交请求;
2. 在HTML页面表单中必须配置 enctype="multipart/form-data" (表示数据使用什么样的编码方式);
另外,在HTML页面表单中必须使用 <input type="file">控件
二. 基于SpringMVC的文件上传
简易客户端:
<form method="post" enctype="multipart/form-data" action="/upload"> <h3>选择文件</h3> <input type="file" name="file" placeholder="请选择文件"> <input type="submit" value="提交"> </form>
简易服务端:
@PostMapping("/upload") public String upload(MultipartFile file) throws IOException { file.transferTo(new File("d:1.jpg")); return "OK"; }
1. 文件大小:默认上传大小是有限制的,如果服务端报FileSizeLimitExceededExceprion,说明是文件大小受限,如果需要自定义,就向SpringBoot容器中添加一个MultipartConfigElement对象
在配置类中添加以下代码:
@Bean public MultipartConfigElement multipartConfigElement(){ MultipartConfigFactory multipartConfigFactory = new MultipartConfigFactory(); // 设置文件上传最大限制为 5 M multipartConfigFactory.setMaxFileSize(DataSize.ofMegabytes(5)); // 设置请求最大限制为 6 M multipartConfigFactory.setMaxRequestSize(DataSize.ofMegabytes(6)); return multipartConfigFactory.createMultipartConfig(); }
注意:全局的上传限制和控制器中的文件上传限制应该同时存在
全局的上传限制:自定义上传限制;拦截明显的错误(即明显超出大小限制)请求
控制器上传限制:划分业务上传,根据业务不同自定义上传限制
2. 关于文件可以使用api获取文件相关属性.如:
3. 关于文件名称,在写入磁盘时,需要定义其文件名和扩展名,一些特殊文件只有文件名没有扩展名或者在Linux和MacOS中隐藏文件只有文件名而且是以点开头
4. 上传是为了下载,所以,所有的文件上传的路径必须是可以通过hkttp访问到的位置,解决方法:
1) 使用 HttpServletRequest 对象获取可访问的webapp路径(父级路径定位到request.gettServletContext().getRealPath("")),将其上传到webapp目录下.
2) 使用SpringBoot或者SpringMVC自定义资源目录,http可以直接访问该资源目录
在配置文件中添加以下配置
spring.resources.static-locations[0] = file:e:/upload,
spring.resources.static-locations[1] = file:e:/img
spring.resources.static-locations[2] = classpath:/static
注意:
① 静态目录可以配置多个
② 配置时如果没有配置原静态目录(static目录),则该目录下的资源文件就不可用了,需要显式的配置
进行上传时,只需要写入到该目录下,既可以通过http访问
5. 文件类型
使用contentType进行文件类型判断,只需要获取文件的类型,然后与允许类型进行比较即可,可以将文件类型创建为一个列表,调用contains方法判断即可
6. 关于其他限制,如空判断,大小判断只需要调用相应的api进行判断即可
7. 关于使用ajax异步请求的方式发送请求
$.ajax({ url: ‘/upload‘, type: ‘POST‘, data: new FormData($("#form")[0]), processData: false, contentType: false, success: function (json) { // 处理响应 } });
注意:
1) enctype="multipart/form-data" 的form表单数据必须是FormData类型,传入该表单
2) 上传文件的ajax请求必须配置processData: false和contentType: false这两项
3) contentType在此处填false的原因是告诉ajax函数data数据已经处理过,不需要进行再处理
三. 使用base64编码方式的上传(一般是图片)
1. 客户端
提交请求:
$("#send").click(function () { var files = $(‘#background_pic‘)[0].files var file = files[0]; var reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function (theFile) { var image = new Image(); // 图片可以得到base64编码 image.src = theFile.target.result;
var img = image.src.replaceAll("%", "-") var data = { img: image.src } $.ajax({ url:‘/upload‘, type: ‘POST‘, data: data, dataType: ‘json‘, success: function (json) { if(json.status != 200){ alert("上传图片失败!请稍后重试!"); }else { alert("上传成功!"); } } }) } });
此外,使用种方式可以对图片在前端进行校验(校验内容自定义即可)
function checkImg(files){ var file = files[0]; var fileTypes = [".jpg", ".png",".gif",".jpeg"]; var filePath = file.name; var flag = false; if(filePath){ var fileEnd = filePath.substring(filePath.indexOf(".")); for (var i = 0; i < fileTypes.length; i++) { if (fileTypes[i] == fileEnd) { flag = true; break; } } } if (!flag){ alert("请上传 jpg、png、jpeg 的图片格式文件!"); $(‘#background_pic‘).val(null); return; } var reader = new FileReader(); reader.readAsDataURL(file); var ret = []; reader.onload = function (theFile) { var image = new Image(); image.src = theFile.target.result; //console.log(image.src); image.onload = function () { width = this.width; height = this.height; console.log(width!=1920 + " and " + height!=1080) if (width != 1920 || height != 1080) { alert("为了更好的显示效果,请使用分辨率为1920×1080的图片!"); $(‘#background_pic‘).val(null); return; } }; } }
2. 服务端
@PostMapping("/upload") public String upload(String img){ // 格式: data:image/jpeg;base64,{{具体内容的数据编码}}或者data:text/txt;base64,{{具体内容的数据编码}}等等 // 传输过程中会将 + 替换为空格 // 前端自定义将 % 替换为 - img = img.replaceAll(" ", "+"); img = img.replaceAll("-", "%"); String[] strArr = img.split(","); String dataType = strArr[0]; String imgBase64 = strArr[1]; String suffix = dataType.substring(dataType.indexOf("/"), dataType.indexOf(";")); String parent = "e:/img"; String child = UUID.randomUUID().toString() + "." + suffix; File file = new File(parent, child); BASE64Decoder decoder = new BASE64Decoder(); try { byte[] b = new byte[0]; b = decoder.decodeBuffer(imgBase64); for (int j = 0; j < b.length; ++j) { //调整异常数据 if (b[j] < 0) { b[j] += 256; } } OutputStream out = new FileOutputStream(file); out.write(b); out.flush(); out.close(); } catch (IOException e) { throw new RuntimeException("描述"); } return "OK"; }