MD5 防止文件重复上传

这篇博客介绍了如何通过Java实现MD5校验来防止文件重复上传。首先获取上传文件的MD5值,并结合文件扩展名生成新的文件名。接着检查目标路径下是否存在相同文件名的文件,如果存在则提供已存在文件的访问路径,否则执行上传操作。博客内容包括准备工作,如创建数据表和相关类,以及文件上传的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

​ 简单实现: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();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值