简单实现:1.获取上传文件的输入流后生产MD5值;
2.用MD5值与源文件扩展名生成新的文件名;
3.在判断上传的目标路径下是否有这个文件名,若存在则直接返回该文件的访问路径,不存在则上传。
准备工作
1.创建数据表
DROP TABLE IF EXISTS `tb_file`;
CREATE TABLE `tb_file` (
`file_id` varchar(200) NOT NULL COMMENT '文件id',
`MD5` varchar(255) NOT NULL COMMENT '文件md5值',
`file_url` varchar(255) DEFAULT NULL COMMENT '虚拟文件路径',
`file_path` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '文件真实路径',
`file_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '文件名,MD5值+文件后缀',
`create_time` datetime NOT NULL COMMENT '创建时间',
`is_delete` int DEFAULT '0' COMMENT '是否删除 0否 1是',
`version` int DEFAULT NULL COMMENT '版本',
PRIMARY KEY (`file_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2.相关类
File实体类:
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("tb_file")
public class File implements Serializable {
@TableId("file_id")
private String fileId;
@TableField("MD5")
private String md5;
@TableField("file_url")
private String fileUrl;
@TableField("file_path")
private String filePath;
@TableField("file_name")
private String fileName;
@TableField(value = "create_time", fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableLogic
private Integer isDelete;
@Version
private Integer version;
}
FIleUtils工具类
/**
* 获取文件md5值
*/
public static String getFileMD5(InputStream inputStream) {
try {
MessageDigest md5 = MessageDigest.getInstance("md5");
byte[] buffer = new byte[8192];
int length;
while ((length = inputStream.read(buffer)) != -1) {
md5.update(buffer, 0, length);
}
return new String(Hex.encodeHex(md5.digest()));
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
具体实现
文件上传抽象类
@Service
@RequiredArgsConstructor
public abstract class AbstractUploadStrategy {
public String uploadFile(MultipartFile file, String path) {
try {
//获取文件md5值
String fileMd5 = FileUtils.getFileMD5(file.getInputStream());
//获取文件扩展名
String fileName = file.getOriginalFilename();
String expandedName = fileName.substring(fileName.lastIndexOf("."));
//重新生成文件名
fileName = fileMd5 + expandedName;
if (!exists(path + fileName)) {
// 不存在则继续上传
upload(path, fileName, file.getInputStream(), fileMd5);
}
//返回文件路径
return getFileAccessUrl(path + fileName);
} catch (IOException e) {
e.printStackTrace();
throw new BusinessExceptions("文件上传失败。");
}
}
/**
* 判断文件是否存在
*
* @param filePath 文件路径
* @return {@link Boolean}
*/
public abstract Boolean exists(String filePath);
/**
* 上传
*
* @param path 路径
* @param fileName 文件名
* @param inputStream 输入流
* @param fileMd5 文件md5值
* @throws IOException io异常
*/
public abstract void upload(String path, String fileName, InputStream inputStream, String fileMd5) throws IOException;
/**
* 获取文件访问url
*
* @param filePath 文件路径
* @return {@link String}
*/
public abstract String getFileAccessUrl(String filePath);
}
上传文件的具体实现
@Service("localUploadStrategyImpl")
@RequiredArgsConstructor
public class LocalUploadFileStrategyImpl extends AbstractUploadStrategy {
private final FileMapper fileMapper;
private final SnowFlakeIdWorker snowFlakeIdWorker;
/**
* 本地路径
*/
@Value("${spring.upload.local.path}")
private String localPath;
/**
* 访问url
*/
@Value("${spring.upload.local.url}")
private String localUrl;
@Override
public Boolean exists(String filePath) {
return new File(localPath + filePath).exists();
}
@Override
@Transactional(rollbackFor = Exception.class)
public void upload(String path, String fileName, InputStream inputStream, String fileMd5) throws IOException {
// 判断目录是否存在
File directory = new File(localPath + path);
if (!directory.exists()) {
if (!directory.mkdirs()) {
throw new BusinessExceptions("创建目录失败");
}
}
// 写入文件
File file = new File(localPath + path + fileName);
if (file.createNewFile()) {
BufferedInputStream bis = new BufferedInputStream(inputStream);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
byte[] bytes = new byte[1024];
int length;
while ((length = bis.read(bytes)) != -1) {
bos.write(bytes, 0, length);
}
bos.flush();
inputStream.close();
bis.close();
bos.close();
}
com.basil.entity.File fileFromDb = com.basil.entity.File.builder()
.fileId(String.valueOf(snowFlakeIdWorker.nextId()))
.fileName(fileName)
.md5(fileMd5)
.fileUrl(localUrl + path)
.filePath(localPath + path)
.isDelete(CommonConst.FALSE)
.build();
fileMapper.insert(fileFromDb);
}
@Override
public String getFileAccessUrl(String filePath) {
HttpServletRequest request = getRequest();
String ip = null;
try {
ip = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
e.printStackTrace();
}
return request.getScheme() + "://" + ip + ":" + request.getServerPort() + localUrl + filePath;
}
/**
* 获取request
*/
public HttpServletRequest getRequest() {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
return attributes.getRequest();
}
}