开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 11 天,点击查看活动详情
SpringMVC实现文件上传主要用到MultipartFile接口,这个接口有几个常用API:
- String getOriginalFilename():获取用户上传文件的文件名。
- boolean isEmpty():判断文件是否为空。
- long getSize():获取文件大小(字节)。
- String getContentType():获取文件类型(例如jpg格式文件返回image/jpeg).
- InputStream getInputStream():获取上传文件的输入字节流。
- void transferTo(File dest):保存上传的文件,该方法不可与getInputStream()方法同时使用。
在编写上传文件的前端页面时有几点要注意:
要注意enctype属性值,这个属性规定了上传的数据要经过什么样的编码后再传递给后端,如果设置为application/x-www-form-urlencoded,则对表单中所有数据进行编码,空格会被转化成“+”号,特殊符号会根据ASCII进行转化;如果设置为text/plain,则只会对表单中的空格数据进行转换;如果设置为multipart/form-data,则不对任何数据进行转化,因此在上传文件时注意这个属性的修改。
总之,form表单的请求方式要设置为POST,属性enctype要进行修改,并且上传文件所使用到的input控件的属性值要设置为file。
如果不想更改表单属性enctype呢?可以在ajax代码中声明一个FormData对象,选中表单,并设置processData为false(表示是否将上传的数据转化为字符串),contentType设置为false(表示ajax的数据以字符串方式传递)
@PostMapping("change_avatar")
public JsonResult<String> changeAvatar(@RequestParam("file") MultipartFile file, HttpSession session) {
// 判断上传的文件是否为空
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();
// public boolean list.contains(Object o):当前列表若包含某元素,返回结果为true;若不包含该元素,返回结果为false。
if (!AVATAR_TYPES.contains(contentType)) {
// 是:抛出异常
throw new FileTypeException("不支持使用该类型的文件作为头像,允许的文件类型:\n" + AVATAR_TYPES);
}
// 获取当前项目的绝对磁盘路径
String parent = session.getServletContext().getRealPath("upload");
// 保存头像文件的文件夹
File dir = new File(parent);
if (!dir.exists()) {
dir.mkdirs();
}
// 保存的头像文件的文件名
String suffix = "";
String originalFilename = file.getOriginalFilename();
int beginIndex = originalFilename.lastIndexOf(".");
if (beginIndex > 0) {
suffix = originalFilename.substring(beginIndex);
}
String filename = UUID.randomUUID().toString() + 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<String>(OK, avatar);
}
保存到数据库中的其实是一条路径,如果是类似头像这种需要在多个页面显示的文件还可以将这条路径保存到cookie里,就不必每次都发送请求了。