文件上传需要使用流,Spring为此准备了一个接口MultipartFile
,其内维护了缓存流,并且具备自动开关流功能。
简单文件上传实现案例基础步骤:
1.获取文件名称
2.准备上传文件的目录
3.封装文件全路径 目录/文件名称
4.实现文件上传
简单示例代码:
//1.获取文件名称
String fileName = file.getOriginalFilename();
//2.准备文件目录
String fileDir = "E:/images/";
//2.1判断文件目录是否存在
File dir = new File(fileDir);
if (!dir.exists()) {
dir.mkdirs();//创建多级目录
}
//3.封装文件全路径
String localPath = fileDir + fileName;
//4.实现文件上传
file.transferTo(new File(localPath));
实现文件校验:
步骤如下:
- 校验文件是否为图片
若要校验一个文件是否为常用图片需要使用正则表达式 首先获取文件名称,需要使用
MultipartFile
接口提供的getOriginalFilename()
方法。String fileName = file.getOriginalFilename();
另外由于windows大小写不敏感需要将文件名转换为全小写,方便使用正则表达式校验fileName = fileName.toLowerCase();
使用正则表达式动态的匹配文件后缀名
if (!fileName.matches("^.+\\.(jpg|png|gif)$")) {
return null;
}
- 判断文件是否满足图片固有属性,而不是1.exe.jpg等文件
使用图片的IO流来获取图片的宽度与高度,根据文件是否有宽度和高度来判断是否为图片
使用图片的字节输入流来获取文件宽度高度,其参数为字符输入流,再使用getWidth();
与getHeight();
方法获取图片属性进行判断
BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
int width = bufferedImage.getWidth();
int height = bufferedImage.getHeight();
if (width == 0 || height == 0) {
return null;
}
- 将文件名分目录处理
- 3.1将文件按照后缀名分配,效率提升不能满足要求
- 京文件按照上传日期分配 yyyy/MM/dd/HH 可以
- 根据商品分类进行分配,由分布不均现象
- 根据名称hash 之后截串,弊端hash码可能出现分布不均现象。
使用日期格式化方法将日期按照年月日进行格式化,然后与文件上传后的路径进行拼接,若该文件不存在,将会创建文件夹。
String dateDir = new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());
String localDirPath = localDir + dateDir;
File dirFile = new File(localDirPath);
if (!dirFile.exists()) {
dirFile.mkdirs();
}
- 使用uuid替换文件名防止重名
使用字符串的lastIndexOf();
方法获取文件名的最后一个“.”的位置方便截取文件类型,
获取到文件类型后,使用uuid将文件名进行替换,替换完毕后与文件类型进行拼接,组成完整的文件名
String uuid = UUID.randomUUID().toString().replace("-", "");
//截取文件后缀
int index = fileName.lastIndexOf(".");
String fileType = fileName.substring(index);
String newFileName = uuid + fileType;
完整代码实现:
package com.jt.service.impl;
import com.jt.service.FileService;
import com.jt.vo.ImageVO;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
@Service
public class FileServiceImpl implements FileService {
private String localDir = "E:/images";
@Override
public ImageVO upload(MultipartFile file) {
String fileName = file.getOriginalFilename();
//windows大小写不敏感,将文件后缀名字母转换为全小写
fileName = fileName.toLowerCase();
if (!fileName.matches("^.+\\.(jpg|png|gif)$")) {
return null;
}
try {
BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
int width = bufferedImage.getWidth();
int height = bufferedImage.getHeight();
if (width == 0 || height == 0) {
return null;
}
//根据时间进行目录创建
String dateDir = new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());
String localDirPath = localDir + dateDir;
File dirFile = new File(localDirPath);
if (!dirFile.exists()) {
dirFile.mkdirs();
}
//uuid的唯一只是系统内部唯一
String uuid = UUID.randomUUID().toString().replace("-", "");
//截取文件后缀
int index = fileName.lastIndexOf(".");
String fileType = fileName.substring(index);
String newFileName = uuid + fileType;
//实现文件上传
String realFilePath = localDirPath + newFileName;
file.transferTo(new File(realFilePath));
//6.封装返回值
/*
6.1封装虚拟路径,在各个系统中灵活切换,只保存动态变化的路径
path = 时间/uuid.type
*/
String virtualPath = dateDir + newFileName;
String url = "https://img.alicdn.com/tfs/TB1FjZ7VWL7gK0jSZFBXXXZZpXa-520-280.png";
return new ImageVO(virtualPath, url, newFileName);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}