文件上传需要使用流,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;@Servicepublic class FileServiceImpl implements FileService {private String localDir = "E:/images";@Overridepublic 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;}}}
