MultipartFile接口
springboot使用文件上传可以使用springmvc的MultipartFile这个接口,在参数方法中定义这个类的对象,然后使用这个对象完成文件的传送
MultipartFile是SpringMVC提供简化上传操作的工具类。
在不使用框架之前,都是使用原生的HttpServletRequest来接收上传的数据,文件是以二进制流传递到后端的,然后需要我们自己转换为File类。使用了MultipartFile工具类之后,我们对文件上传的操作就简便许多了。
来学习一下MultipartFile工具类全部的接口方法(我已经备注好了哈哈)
import java.io.File;import java.io.IOException;import java.io.InputStream;import java.nio.file.Files;import java.nio.file.Path;import org.springframework.core.io.InputStreamSource;import org.springframework.core.io.Resource;import org.springframework.lang.Nullable;import org.springframework.util.FileCopyUtils;public interface MultipartFile extends InputStreamSource {//getName() 返回参数的名称 String getName();//获取源文件的昵称 @Nullable String getOriginalFilename();//getContentType() 返回文件的内容类型 @Nullable String getContentType();//isEmpty() 判断是否为空,或者上传的文件是否有内容 boolean isEmpty();//getSize() 返回文件大小 以字节为单位 long getSize();//getBytes() 将文件内容转化成一个byte[] 返回 byte[] getBytes() throws IOException;//getInputStream() 返回InputStream读取文件的内容 InputStream getInputStream() throws IOException; default Resource getResource() { return new MultipartFileResource(this); }//transferTo(File dest) 用来把 MultipartFile 转换换成 File void transferTo(File var1) throws IOException, IllegalStateException; default void transferTo(Path dest) throws IOException, IllegalStateException { FileCopyUtils.copy(this.getInputStream(), Files.newOutputStream(dest)); }}
InputStreamSource 这个接口本质上返回的还是一个InputStream 流对象
import java.io.IOException;import java.io.InputStream;public interface InputStreamSource { //定位并打开资源,返回资源对应的输入流。 //每次调用都会返回新的输入流,调用者在使用完毕后必须关闭该资源。 InputStream getInputStream() throws IOException;}正常的文件上传接口你可以写一些帮助类这样就可以帮助你更好的筛选文件了,当然很多条件最好在前端也完成,这里我分享过el-upload组件可以简单参考Element-UI中el-upload上传组件(demo详解)比如:你要现在文件类型,大小等等都可以上传组件完成限制,这样减轻服务器的压力当然Java中也可以写一些校验相关的帮助类,帮助我们筛选,如下:仅供参考//简单的分享一下吧,仅仅给参考 private String validateImg(MultipartFile file) { if (file == null) { throw new RuntimeException("图片不能为空"); } if (file.getSize() >= 20 * 1024 * 1024) { throw new RuntimeException("图片大小超出最大限制"); } boolean isPic = FileUtil.isPic(file.getOriginalFilename()); if (!isPic) { throw new RuntimeException("图片格式错误"); } String fileName = Objects.requireNonNull(file.getOriginalFilename()).length() > 50 ? file.getOriginalFilename().substring(0, 50) : file.getOriginalFilename(); return fileName; }
以上仅是参考MultipartFile的简单用法,接下来我们举一个实际项目中上传头像文件的例子。
页面以简单的Ajax异步请求完成文件的上传
这里不仅包含了前端代码,也包含了后端处理文件的操作步奏
上传头像-前端页面
在upload页面中编写上传头像代码
说明:如果直接使用表单进行简单的文件的上传,需要给表单添加一个属性,
编写了这个属性之后就需要书写Ajax异步请求向后端发送数据,将上传的文件传送到后端去,进行数据库的存放。
上传头像在页面加载前首先会向后端发送Ajax请求,如果用户存放过数据,那么可以直接从数据库拿出相关信息的,
$(document).ready(function () { //这里表示从cookie中获取头像,并给img-avatar的标签赋值图片信息 console.log("cookie中的avatar=" + $.cookie("avatar")); $("#img-avatar").attr("src", $.cookie("avatar")); });
如果没有头像文件,标签就会显示默认图片。
然后你可以点击选择文件的按钮,从你的文件中选择你想要上传的图片,Ajax会保存图片的信息,传送到后端。具体代码如下:
$("#btn-change-avatar").click(function() { $.ajax({ url: "/users/change_avatar", type: "POST", data: new FormData($("#form-change-avatar")[0]), dataType: "JSON", processData: false, // processData处理数据 contentType: false, // contentType发送数据的格式 success: function(json) { if (json.state == 200) { //这里attr表示给某个标签赋什么值 $("#img-avatar").attr("src", json.data); $.cookie("avatar", json.data, {expires: 7}); alert("头像更新成功!!!"); //location.href="index.html"; } else { alert("修改失败!" + json.message); } }, error: function(xhr) { alert("您的登录信息已经过期,请重新登录!HTTP响应码:" + xhr.status); location.href = "login.html"; } }); });
这里有一些值得注意的是,如果是提交文件的形式,Ajax请求必须加上以下两个属性
processData: false, // processData处理数据
contentType: false, // contentType发送数据的格式
传送文件的data的形式必须是,data: new FormData($("#form-change-avatar")[0]),
因为传送普通的json键值对是用 data:$("#form-change-info").serialize(),
前端代码执行完成后,代码执行到后端,在控制层根据业务需求写出对应的代码,这里我依照我自己的项目写出例子仅供参考:
@RequestMapping("/change_avatar") public JsonResultchangeAvatar(HttpSession session, @RequestParam("file") MultipartFile file){ // 判断上传的文件是否为空 if (file.isEmpty()) { // 是:抛出异常 throw new FileEmptyException("上传的头像文件不允许为空"); } // 判断上传的文件大小是否超出限制值 if (file.getSize() > AVATAR_MAX_SIZE) { // getSize():返回文件的大小,以字节为单位 // 是:抛出异常 throw new FileSizeException("不允许上传超过" + (AVATAR_MAX_SIZE / 1024) + "KB的头像文件"); } // 判断上传的文件类型是否超出限制 String contentType = file.getContentType(); // boolean contains(Object o):当前列表若包含某元素,返回结果为true;若不包含该元素,返回结果为false if (!AVATAR_TYPES.contains(contentType)) { // 是:抛出异常 throw new FileTypeException("不支持使用该类型的文件作为头像,允许的文件类型:" + AVATAR_TYPES); } // 获取当前项目的绝对磁盘路径 String parent = session.getServletContext().getRealPath("upload"); // 保存头像文件的文件夹 File dir=new File(parent); if (!dir.exists()){ //若是文件路径不存在,就新建文件路径 dir.mkdirs(); } // 保存的头像文件的文件名 String suffix = ""; String originalFilename = file.getOriginalFilename(); //System.out.println(originalFilename); int index = originalFilename.indexOf("."); if(index>0){ suffix = originalFilename.substring(index); } String filename = UUID.randomUUID().toString().toUpperCase()+suffix; // 创建文件对象,表示保存的头像文件 File dest = new File(dir, filename); try { file.transferTo(dest); } catch (IllegalStateException e) { // 抛出异常 throw new FileStateException("文件状态异常,可能文件已被移动或删除"); }catch (IOException e) { // 抛出异常 throw new FileUploadIOException("上传文件时读写错误,请稍后重新尝试"); } // 头像路径 String avatar = "/upload/" + filename; // 从Session中获取uid和username Integer uid = getUidFromSession(session); String username = getUsernameFromSession(session); // 将头像写入到数据库中 userService.changeAvatar(uid, username, avatar); // 返回成功头像路径 return new JsonResult (OK, avatar); }
有一点需要注意的是我们必须要定义一系列的文件异常类,异常类的书写方法我已经在我的其他博客书写了,书写了文件传送异常类之后就需要配置传送图片的类型和传送图片的大小。我们可以在控制层的controller加上以下代码:
上传图片的controller中加入以下代码限制图片文件的大小
public static final int AVATAR_MAX_SIZE = 10 * 1024 * 1024; public static final ListAVATAR_TYPES = new ArrayList (); static { AVATAR_TYPES.add("image/jpeg"); AVATAR_TYPES.add("image/png"); AVATAR_TYPES.add("image/bmp"); AVATAR_TYPES.add("image/gif"); }
上传文件配置属性
当我们完成控制层代码的书写,但是代码还是会有问题的, 因为spring boot的文件传送大小有限,我们必须手动改变配置文件,改变传送文件的最大限量,如果不改变文件传送大小,上传文件太大的时候就会出bug,但是这个bug我们是可以修改的。
方式一、
在application.properties中加上以下属性就可以改变传送文件的最大传送限制了
#最大文件上传大小
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=15MB
方式二:
在配置类中配置MultipartConfigElement方法,并将配置类注册到容器中,代码示例:
@Configuration@SpringBootApplication@MapperScan("com.ct.store.store.mapper")public class StoreApplication { public static void main(String[] args) { SpringApplication.run(StoreApplication.class, args); } @Bean public MultipartConfigElement getMultipartConfigElement() { MultipartConfigFactory factory = new MultipartConfigFactory(); // DataSize dataSize = DataSize.ofMegabytes(10); // 设置文件最大10M,DataUnit提供5中类型B,KB,MB,GB,TB factory.setMaxFileSize(DataSize.of(10, DataUnit.MEGABYTES)); factory.setMaxRequestSize(DataSize.of(10, DataUnit.MEGABYTES)); // 设置总上传数据总大小10M return factory.createMultipartConfig(); }}
注意:这里的配置可以直接拷贝到项目中使用,这里的格式是固定的,文件的传送大小根据自己需求改写。