springboot 集成断点续传实例

package com.hivekion.file.controller;

import com.hivekion.common.annotation.AutoLog;
import com.hivekion.common.enums.OperationTypeEnum;
import com.hivekion.common.exception.BusinessException;
import com.hivekion.common.file.FileUtil;
import com.hivekion.common.file.RangeHeader;
import com.hivekion.file.domain.FileEntity;
import com.hivekion.file.domain.vo.FileSearchInputVo;
import com.hivekion.file.domain.vo.file.*;
import com.hivekion.file.service.IFileService;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.google.common.io.Files.getFileExtension;

/**
 * @author admin
 */
@RestController
@RequestMapping("/file")
@Slf4j
public class FileController {

    @Autowired
    private IFileService fileService;

    @Value("${uploadPath.temporary}")
    private String uploadPath;


    private final static int BUFFER_SIZE = 1024 * 1024;

    @PostMapping("/verifyFile")
    @ApiOperation("验证文件是否存在")
    @AutoLog(value = "验证文件是否存在", operationType = OperationTypeEnum.SELECT, module = "文件服务")
    public VerifyUploadResult verifyUpload(@RequestParam(value = "fileHash", required = true) String fileHash, String fileName) {
        VerifyUploadResult result = new VerifyUploadResult();
        List<String> files = new ArrayList<>();
        FileModelVo fileInfo = fileService.getFile(fileHash);
        if (fileInfo != null) {
            result.setShouldUpload(true);
            FileModelVo file = fileService.getFile(fileHash, fileName);
            //根据hash和filename 在判断是否存在,如果存在 直接返回fileId; 如果不存在,创建file,返回fileId
            if (Objects.isNull(file)) {
                FileEntity fileEntity = new FileEntity();
                BeanUtils.copyProperties(fileInfo, fileEntity);
                fileEntity.setFileName(fileName);
                fileService.save(fileEntity);
                result.setFileId(fileEntity.getId());
            } else {
                result.setFileId(file.getId());
            }
        } else {
            String filePath = uploadPath + File.separator + fileHash;
            File dir = new File(filePath);
            // 目录不存在
            if (!dir.exists()) {
                dir.mkdirs();
            } else {
                // 获取目录下所有文件
                File[] array = dir.listFiles();
                for (int i = 0; i < array.length; i++) {
                    if (array[i].isFile()) {
                        files.add(array[i].getName());
                    }
                }
            }
            result.setShouldUpload(false);
            result.setUploadedList(files);
        }

        return result;
    }

    @PostMapping("/UploadFile")
    @ApiOperation(value = "上传文件")
    @AutoLog(value = "上传文件", operationType = OperationTypeEnum.UNKNOWN, module = "文件服务")
    public String uploadFile(@RequestPart(value = "chunk", required = true) MultipartFile chunk,
                             @RequestParam(value = "hash", required = true) String hash,
                             @RequestParam(value = "filename", required = true) String filename) {
        // 获取文件名
        String fileName = chunk.getOriginalFilename();
        String fileDir = uploadPath + File.separator + hash;
        File dir = new File(fileDir);
        try {
            // 目录不存在
            if (!dir.exists()) {
                dir.mkdirs();
            }
            String newFileName = fileDir + File.separator + filename;
            File newFile = new File(newFileName);
            chunk.transferTo(newFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return fileName;
    }

    @PostMapping("/mergeFile")
    @ApiOperation(value = "合并切片")
    @AutoLog(value = "合并切片", operationType = OperationTypeEnum.UNKNOWN, module = "文件服务")
    public MergeFileResult mergeFile(String fileHash, String fileName) {
        MergeFileResult result = new MergeFileResult();
        String fileDir = uploadPath + File.separator + fileHash;

        File dir = new File(fileDir);
        // 目录不存在
        if (!dir.exists()) {
            throw new BusinessException(500, "未找到切片保存路径");
        }
        // 创建合并后的文件
        String newFileName = uploadPath + File.separator + fileName;
        File file = new File(newFileName);
        if (file.exists()) {
            file.delete();
        }
        try {

            BufferedOutputStream destOutputStream = new BufferedOutputStream(new FileOutputStream(newFileName));
            // 获取目录下所有文件
            File[] array = dir.listFiles();

            for (int i = 0; i < array.length; i++) {
                //todo 排序
                File partFile = new File(fileDir, i + "");
                if (partFile.isFile()) {
                    // 循环将每个分片的数据写入目标文件
                    // 文件读写缓存
                    byte[] fileBuffer = new byte[1024];
                    // 每次读取字节数
                    int readBytesLength = 0;
                    BufferedInputStream sourceInputStream =
                            new BufferedInputStream(new FileInputStream(partFile));
                    while ((readBytesLength = sourceInputStream.read(fileBuffer)) != -1) {
                        destOutputStream.write(fileBuffer, 0, readBytesLength);
                    }
                    sourceInputStream.close();
                }
            }
            destOutputStream.flush();
            destOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            String hash = FileUtil.getHash(newFileName);
            if (!hash.equals(fileHash)) {
                todo文件哈希不一致,删除 哈希文件夹, 让用户重新上传
                log.info("原hash:{}, 转换hash:{}", fileHash, hash);
                //try {
                //    //FileUtils.cleanDirectory(new File(fileDir));
                //} catch (IOException e) {
                //    e.printStackTrace();
                //}
                log.error("{}文件上传失败,重新上传{}", fileName, fileDir);
                throw new BusinessException(500, "文件上传异常,hash值不一致");
            }
            result.setFileHash(hash);
            FileCreateInputVo fileVo = new FileCreateInputVo();
            // 设定文件名称
            fileVo.setFileName(fileName);
            // 设定文件MD5值
            fileVo.setMd5Value(hash);
            // 设定文件夹ID(默认没有文件夹)
            fileVo.setFolderId("");
            // 设定文件磁盘路径
            fileVo.setFilePath(newFileName);
            //上传文件到minio
            // 创建临时文件Id
            String fileId = fileService.add(fileVo);
            result.setFileId(fileId);

        }
        return result;
    }

    @PostMapping("/updateFolder")
    @ApiOperation(value = "调整文件所属文件夹")
    @AutoLog(value = "调整文件所属文件夹", operationType = OperationTypeEnum.UPDATE, module = "文件服务")
    public boolean updateFolder(String fileId, String folderId) {
        return fileService.updateFolder(fileId, folderId);
    }

    @GetMapping("/filesize")
    @ApiOperation(value = "获取文件的大小")
    @AutoLog(value = "获取文件的大小", operationType = OperationTypeEnum.SELECT, module = "文件服务")
    public long getFileSize(String fileId, HttpServletResponse resp) {
        FileEntity file = fileService.getById(fileId);
        if (file == null) {
            throw new BusinessException(500, "该文件不存在");
        }
        String filePath = file.getFilePath();
        File newFile = new File(filePath);
        if (!newFile.exists()) {
            throw new BusinessException(500, "该文件不存在");
        }
        if (newFile.exists()) {
            return newFile.length();
        }
        return 0;
    }

    @GetMapping("/download")
    @ApiOperation(value = "下载文件(断点续传)")
    @AutoLog(value = "下载文件(断点续传)", operationType = OperationTypeEnum.DOWNLOAD, module = "文件服务")
    public void download(String fileId, HttpServletRequest req,
                         HttpServletResponse resp) {

        FileEntity file = fileService.getById(fileId);
        if (file == null) {
            throw new BusinessException(500, "该文件不存在");
        }
        String filePath = file.getFilePath();
        File newFile = new File(filePath);


        if (newFile.exists()) {
            long length = newFile.length();
            long lastModifiedLong = newFile.lastModified();
            String rangeStr = req.getHeader(HttpHeaders.RANGE);
            resp.setHeader(HttpHeaders.LAST_MODIFIED, String.valueOf(lastModifiedLong));
            try {
                InputStream is = new FileInputStream(newFile);
                ServletOutputStream os = resp.getOutputStream();
                //判断是第一次请求,还是后续的请求
                if (StringUtils.isBlank(rangeStr)) {
                    //第一次收到请求,提取文件信息,返回给浏览器
                    System.out.println("请求中没有range头信息");
                    resp.setStatus(HttpStatus.OK.value());
                    resp.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
                } else {
                    //有range 返回206
                    resp.setStatus(HttpStatus.OK.value());
                    RangeHeader rangeHeader = new RangeHeader(rangeStr, length);
                    String contentRange = rangeHeader.toContentRange();
                    resp.setHeader(HttpHeaders.CONTENT_RANGE, contentRange);
                    resp.setCharacterEncoding("utf-8");
                    //下面读取的内容的长度与range的end没有对比,会不会有影响

                    is.skip(rangeHeader.getStart());
                    byte[] bs = new byte[BUFFER_SIZE];
                    if (rangeHeader.getEnd() + 1 == rangeHeader.getFileLength()) {
                        long len = (rangeHeader.getFileLength()) - rangeHeader.getStart();
                        bs = new byte[Integer.valueOf((int) len)];
                        while (is.read(bs) != -1) {
                            os.write(bs);
                        }
                    } else {
                        long len = rangeHeader.getEnd() - rangeHeader.getStart();
                        long tail = len % BUFFER_SIZE;
                        long count = len / BUFFER_SIZE;
                        if (len < BUFFER_SIZE) {
                            count = 1;
                        }
                        length = 0;
                        System.out.println("count:" + count);
                        while (is.read(bs) != -1 && count > 0) {
                            os.write(bs);
                            length += bs.length;
                            count--;
                            System.out.println("使用count读取的次数:" + count);
                            if (count == 0L && tail != 0L) {
                                count++;
                                int tailBuffer = (int) tail;
                                bs = new byte[Integer.valueOf(tailBuffer)];
                                tail = 0L;
                            }
                        }
                    }
                    resp.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(length));
                }
                os.close();
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            throw new BusinessException(500, "该文件不存在");
        }
    }

    @GetMapping("/downloadById")
    @ApiOperation(value = "下载文件(直接下载)")
    @AutoLog(value = "下载文件(直接下载)", operationType = OperationTypeEnum.DOWNLOAD, module = "文件服务")
    public void downloadById(String fileId, HttpServletRequest req,
                             HttpServletResponse response) {


        FileEntity fileEntity = fileService.getById(fileId);
        if (fileEntity == null) {
            response.setStatus(HttpStatus.NOT_FOUND.value());
            return;
        }
        String filePath = fileEntity.getFilePath();
        File file = new File(filePath);

        if (file.exists()) {
            //转换为绝对路径
            try {
                InputStream ins = new FileInputStream(file);
                response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
                OutputStream os = response.getOutputStream();
                byte[] b = new byte[1024];
                int len;
                while ((len = ins.read(b)) > 0) {
                    os.write(b, 0, len);
                }
                os.flush();
                os.close();
                ins.close();
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
        } else {
            response.setStatus(HttpStatus.NOT_FOUND.value());
        }
    }

    @PostMapping("list")
    @ApiOperation("获取文件列表")
    @AutoLog(value = "获取文件列表", operationType = OperationTypeEnum.SELECT, module = "文件服务")
    public List<FileViewVo> getList(@RequestBody(required = false) FileSearchInputVo fileSearchInputVo) {
        return fileService.getFileList(fileSearchInputVo);
    }

    @PostMapping("/upload")
    public String upload(@RequestPart(value = "file", required = true) MultipartFile file) {
        String returnUrl = "";
        // 使用UUID给图片重命名,并去掉四个“-”
        String fileName = UUID.randomUUID().toString().trim().replaceAll("-", "");
        // 获取原始文件名
        String originalFilename = file.getOriginalFilename();
        // 获取文件扩展名
        String fileExtension = getFileExtension(originalFilename);
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        String folderName = dateFormat.format(new Date());
        // 获取文件名
        String fileDir = uploadPath + "/" + folderName;
        returnUrl = "/" + folderName;
        File dir = new File(fileDir);
        try {
            if (!dir.exists()) {
                dir.mkdirs();
            }
            String newFileName = fileDir + "/" + fileName + "." + fileExtension;
            returnUrl += "/" + fileName + "." + fileExtension;
            File dest = new File(newFileName);
            file.transferTo(dest);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return returnUrl;
    }

}
package com.hivekion.file.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.hivekion.file.domain.FileEntity;
import com.hivekion.file.domain.vo.FileSearchInputVo;
import com.hivekion.file.domain.vo.file.FileCreateInputVo;
import com.hivekion.file.domain.vo.file.FileModelVo;
import com.hivekion.file.domain.vo.file.FileViewVo;

import java.io.File;
import java.util.List;

/**
 * @author admin
 */
public interface IFileService extends IService<FileEntity> {

    /**
     * 文件夹创建
     *
     * @param vo vo
     * @return id
     */
    String add(FileCreateInputVo vo);


    /**
     * 更新文件夹
     *
     * @param id       id
     * @param folderId 文件夹id
     * @return 更新结果
     */
    boolean updateFolder(String id, String folderId);


    /**
     * 获取文件vo
     *
     * @param md5Hash md5值
     * @return 文件vo
     */
    FileModelVo getFile(String md5Hash);

    /**
     * 获取文件vo
     *
     * @param md5Hash  md5值
     * @param fileName 文件名
     * @return 文件vo
     */
    FileModelVo getFile(String md5Hash, String fileName);

    /**
     * 获取文件集合
     *
     * @param folderId 文件夹id
     * @param filter   过滤条件
     * @return 文件结合
     */
    List<FileViewVo> getFiles(String folderId, String filter);


    /**
     * 查询文件列表
     * @param fileSearchInputVo 搜索vo
     * @return 结果
     */
    List<FileViewVo> getFileList(FileSearchInputVo fileSearchInputVo);
}
package com.hivekion.file.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hivekion.common.exception.BusinessException;
import com.hivekion.common.file.FileUtil;
import com.hivekion.file.domain.FileEntity;
import com.hivekion.file.domain.vo.FileSearchInputVo;
import com.hivekion.file.domain.vo.file.FileCreateInputVo;
import com.hivekion.file.domain.vo.file.FileModelVo;
import com.hivekion.file.domain.vo.file.FileViewVo;
import com.hivekion.file.mapper.FileMapper;
import com.hivekion.file.service.IFileService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author admin
 */
@Service
public class FileServiceImpl extends ServiceImpl<FileMapper, FileEntity> implements IFileService {

    @Override
    public String add(FileCreateInputVo vo) {
        FileEntity model = new FileEntity();
        BeanUtils.copyProperties(vo, model);
        File file = new File(model.getFilePath());
        model.setFileSize((double) file.length());
        String fileExt = FileUtil.getFileSuffix(file);
        String fileType = FileUtil.getFileType(fileExt);
        model.setFileExt(fileExt);
        model.setFileType(fileType);
        this.save(model);
        return model.getId();
    }


    @Override
    public boolean updateFolder(String id, String folderId) {
        FileEntity file = this.getById(id);
        if (file == null) {
            throw new BusinessException(500, "未找到文件");
        }
        file.setFolderId(folderId);
        return this.saveOrUpdate(file);
    }


    @Override
    public FileModelVo getFile(String md5Hash) {
        LambdaQueryWrapper<FileEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(FileEntity::getMd5Value, md5Hash);
        FileEntity one = this.getOne(queryWrapper.last("limit 1"));
        if (one == null) {
            return null;
        }
        FileModelVo vo = new FileModelVo();
        BeanUtils.copyProperties(one, vo);
        return vo;
    }

    @Override
    public FileModelVo getFile(String md5Hash, String fileName) {
        LambdaQueryWrapper<FileEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper
                .eq(FileEntity::getMd5Value, md5Hash)
                .eq(FileEntity::getFileName, fileName);
        FileEntity one = this.getOne(queryWrapper);
        if (one == null) {
            return null;
        }
        FileModelVo vo = new FileModelVo();
        BeanUtils.copyProperties(one, vo);
        return vo;
    }

    @Override
    public List<FileViewVo> getFiles(String folderId, String filter) {
        LambdaQueryWrapper<FileEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(FileEntity::getFolderId, folderId);
        queryWrapper.and(StringUtils.isNotBlank(filter),
                t -> t.like(FileEntity::getFileName, filter)
                        .or()
                        .like(FileEntity::getFileExt, filter)
                        .or().like(FileEntity::getFileType, filter));
        List<FileViewVo> collect = this.list(queryWrapper).stream().map(item -> {
            FileViewVo vo = new FileViewVo();
            BeanUtils.copyProperties(item, vo);
            vo.setIfFolder(false);
            return vo;
        }).collect(Collectors.toList());
        return collect;
    }


    @Override
    public List<FileViewVo> getFileList(FileSearchInputVo fileSearchInputVo) {
        return this.lambdaQuery()
                .like(StringUtils.isNotBlank(fileSearchInputVo.getFileName()), FileEntity::getFileName, fileSearchInputVo.getFileName())
                .list()
                .stream().map(item -> {
                    FileViewVo vo = new FileViewVo();
                    BeanUtils.copyProperties(item, vo);
                    vo.setIfFolder(false);
                    return vo;
                }).collect(Collectors.toList());
    }
}
package com.hivekion.file.domain;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnComment;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnType;
import com.gitee.sunchenbin.mybatis.actable.annotation.DefaultValue;
import com.gitee.sunchenbin.mybatis.actable.annotation.TableComment;
import com.gitee.sunchenbin.mybatis.actable.constants.MySqlTypeConstant;
import com.hivekion.common.entity.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;

import java.io.Serializable;

/**
 * @author admin
 */
@Data
@TableName(value = "f_file")
@TableComment("文件")
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class FileEntity extends BaseEntity implements Serializable {

    @TableField
    @ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
    @ColumnComment("文件名称")
    private String fileName;

    @TableField
    @ColumnType(value = MySqlTypeConstant.VARCHAR, length = 250)
    @ColumnComment("文件存储磁盘路径")
    private String filePath;

    @TableField
    @ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
    @ColumnComment("文件夹ID")
    private String folderId;

    @TableField
    @ColumnType(value = MySqlTypeConstant.DOUBLE, length = 20)
    @ColumnComment("文件大小,单位Kb")
    private Double fileSize;

    @TableField
    @ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
    @ColumnComment("文件类型")
    private String fileType;

    @TableField
    @ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
    @ColumnComment("后缀格式")
    private String fileExt;

    @TableField
    @ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
    @ColumnComment("加密密钥")
    private String secretKey;

    @TableField
    @ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
    @ColumnComment("文件MD5值")
    private String md5Value;

    @TableField
    @ColumnType(value = MySqlTypeConstant.INT, length = 4)
    @ColumnComment("下载次数")
    private Integer downLoadCount;


    @TableField
    @ColumnType(value = MySqlTypeConstant.INT, length = 4)
    @ColumnComment("删除标识")
    @DefaultValue("0")
    private Integer deleteMark;


    // 版本号
}
package com.hivekion.file.domain.vo.file;

import lombok.Data;

import java.io.Serializable;

/**
 * @author admin
 */
@Data
public class MergeFileResult implements Serializable {

    private String fileHash;
    private String fileId;
}
package com.hivekion.file.domain.vo.file;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.util.List;

/**
 * @author admin
 */
@Data
public class VerifyUploadResult {
    @ApiModelProperty("如果不存在,返回已存在的切片列表")
    private List<String> uploadedList;
    @ApiModelProperty("是否已经存在")
    private Boolean shouldUpload;
    @ApiModelProperty("文件Id")
    private String fileId;
}
package com.hivekion.file.domain.vo.file;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;

/**
 * @author admin
 */
@Data
public class FileCreateInputVo implements Serializable {

    @ApiModelProperty("文件名称")
    private String fileName;
    @ApiModelProperty("md5值")
    private String md5Value;
    @ApiModelProperty("文件夹ID")
    private String folderId;
    @ApiModelProperty("文件存储磁盘路径")
    private String filePath;
}
package com.hivekion.common.file;

import com.hivekion.common.exception.BusinessException;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Locale;

/**
 * @author admin
 */
@Component
public class FileUtil {
    public static final int SIZE = 1024 * 2;

    private static final char ENCRYPTED_KEY = '9';


    public String fileEnc(String filePath) throws IOException {
        File file = new File(filePath);
        String name = file.getName();
        String fileDir = file.getParentFile().getCanonicalPath();
        String newFilePath = fileDir + "enc" + name;
        File newFile = new File(newFilePath);
        if (!newFile.exists()) {
            newFile.createNewFile();
        }
        OutputStream oss = new FileOutputStream(newFile);
        InputStream ins = new FileInputStream(file);
        fileXor(ins, oss);
        return newFilePath;
    }

    public String fileDec(String filePath) throws IOException {
        File file = new File(filePath);
        String name = file.getName();
        String fileDir = file.getParentFile().getCanonicalPath();
        String newFilePath = fileDir + "dec" + name;
        File newFile = new File(newFilePath);
        if (!newFile.exists()) {
            newFile.createNewFile();
        }
        InputStream ins = new FileInputStream(file);
        OutputStream os = new FileOutputStream(newFile);
        fileXor(ins, os);
        return newFilePath;
    }

    /**
     * 文件 加密存储 操作 (异或)
     *
     * @param file    上传文件
     * @param newFile 新文件
     */
    private void fileEnc(MultipartFile file, File newFile) {
        try (OutputStream os = new FileOutputStream(newFile);
             InputStream ins = file.getInputStream()) {
            fileXor(ins, os);
        } catch (Exception e) {
//            logger.error("文件【{}】加密存储 操作,出现异常,", file.getOriginalFilename(), e);
        }
    }

    /**
     * 文件 解密获取 操作 (异或)
     *
     * @param file     原始文件(已加密)
     * @param response 待输出文件
     */
    private void fileDec(File file, HttpServletResponse response) {
        try (InputStream ins = new FileInputStream(file);
             OutputStream os = response.getOutputStream()) {
            fileXor(ins, os);
        } catch (Exception e) {
//            logger.error("文件下载操作【文件输出】,出现异常,", e);
        }
    }

    /**
     * 文件 异或 操作
     */
    private void fileXor(InputStream ins, OutputStream os) throws IOException {
        int length;
        byte[] buffer = new byte[SIZE];
        // 每次读2048个字节然后遍历每个字节进行位异或运算
        while ((length = ins.read(buffer, 0, SIZE)) != -1) {
            for (int i = 0; i < buffer.length; i++) {
                // 通过异或运算某个数字或字符串
                buffer[i] = (byte) (buffer[i] ^ ENCRYPTED_KEY);
            }
            os.write(buffer, 0, length);
        }
    }


    public static String getHash(String filePath) {
        try {
            File file = new File(filePath);
            if (file.exists()) {
                return DigestUtils.md5Hex(new FileInputStream(filePath));
            } else {
                return "";
            }
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }

    public static String getHash2(String filePath) {
        try {
            return DigestUtils.md5Hex(new FileInputStream(filePath));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }

    public static String getHash(File file) {
        try {
            System.out.println("--------------------------------------------");
            System.out.println("当前文件名称" + file.getName());
            System.out.println("当前文件大小" + (file.length() / 1024 / 1024) + "MB");
            System.out.println("当前文件路径(绝对)" + file.getAbsolutePath());
            System.out.println("当前文件路径(---)" + file.getCanonicalPath());
            System.out.println("--------------------------------------------");
            BigInteger bi = null;
            InputStream input = new FileInputStream(file);
            byte[] buffer = new byte[8192];
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            int len;
            while ((len = input.read(buffer)) != -1) {
                md5.update(buffer, 0, len);
            }
            input.close();
            byte[] b = md5.digest();
            bi = new BigInteger(1, b);
            return bi.toString(16);
        } catch (IOException | NoSuchAlgorithmException e) {
            throw new BusinessException(500, "获取文件MD5加密异常!");
        }
    }

    public static String md5HashCode(MultipartFile file) {
        try {
            InputStream fis = file.getInputStream();
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] buffer = new byte[1024];
            int length = -1;
            while ((length = fis.read(buffer, 0, 1024)) != -1) {
                md.update(buffer, 0, length);
            }
            fis.close();
            byte[] md5Bytes = md.digest();
            BigInteger bigInt = new BigInteger(1, md5Bytes);
            return bigInt.toString();
        } catch (NoSuchAlgorithmException | IOException e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * 获取文件后缀名
     *
     * @param file
     * @return
     */
    public static String getFileSuffix(File file) {
        if (file == null) {
            return null;
        }
        String suffix = null;
        String fileName = file.getName();

        if (fileName.lastIndexOf(".") != -1 && fileName.lastIndexOf(".") != 0) {
            suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
        }
        return suffix;
    }

    public static String getFileType(String fileSuffix) {
        switch (fileSuffix) {
            case "pdf":
                return "PDF";
            case "doc":
            case "docx":
                return "WORD";
            case "JPEG":
            case "JPG":
            case "GIF":
            case "BMP":
            case "PNG":
                return "Image";
            case "xls":
            case "xlsx":
                return "EXCEL";
            case "sql":
                return "SQL";
            case "txt":
                return "TXT";
            default:
                return "*";
        }
    }

    public static String getFileType(File file) {
        String fileSuffix = getFileSuffix(file).toLowerCase(Locale.ROOT);
        return getFileType(fileSuffix);
    }


    public static void saveFile(InputStream inputStream, String filePath) {
        OutputStream outputStream = null;
        try {
            File file = new File(filePath);
            outputStream = new FileOutputStream(file);
            int read = 0;
            byte[] bytes = new byte[1024];
            while ((read = inputStream.read(bytes)) != -1) {
                outputStream.write(bytes, 0, read);
            }
            outputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

package com.hivekion.file.domain.vo.file;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.gitee.sunchenbin.mybatis.actable.annotation.DefaultValue;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;

import java.io.Serializable;
import java.util.Date;

/**
 * @author admin
 */
@Data
@ApiModel("文件列表显示对象")
public class FileViewVo implements Serializable {

    private String id;
    @ApiModelProperty("文件名称")
    private String fileName;
    @ApiModelProperty("文件大小")
    private Double fileSize;
    @ApiModelProperty("文件类型")
    private String fileType;
    @ApiModelProperty("文件后缀")
    private String fileExt;
    @ApiModelProperty("md5值")
    private String md5Value;
    @ApiModelProperty("下载次数")
    private Integer downLoadCount;
    @ApiModelProperty("是否为文件夹")
    @DefaultValue("0")
    private boolean ifFolder;
    @ApiModelProperty("是否开放文件夹")
    private Boolean common;
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @ApiModelProperty("创建时间")
    private Date createTime;
    @ApiModelProperty("创建人")
    private String createUserName;
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @ApiModelProperty("修改时间")
    private Date updateTime;
    @ApiModelProperty("最后修改人")
    private String updateUserName;
}
package com.hivekion.common.file;

import org.apache.commons.lang3.StringUtils;

/**
 * @author admin
 */
public class RangeHeader {
    private final String PREFIX = "bytes";
    private final String EQUAL = "=";
    private final String GAP = "-";
    private final String SLASH = "/";

    private Long start;
    private Long end;
    private Long fileLength;

    /**
     * 请求头转换为相应的Content-Range
     *
     * @param rangeStr
     * @param fileLength
     */
    public RangeHeader(String rangeStr, long fileLength) {
        this.start = null;
        this.end = null;
        this.fileLength = fileLength;
        String range = rangeStr.replace(PREFIX + EQUAL, "");
        String[] strs = range.split(GAP);
        //start
        if (!StringUtils.isBlank(strs[0])) {
            this.start = Long.parseLong(strs[0].trim());
        }
        // end
        if (strs.length == 2 && !StringUtils.isBlank(strs[1])) {
            this.end = Long.parseLong(strs[1].trim());
        }
    }

    /**
     * 产生 Content-Range 头信息
     *
     * @return
     */
    public String toContentRange() {
        StringBuilder sb = new StringBuilder(PREFIX);
        sb.append(" ");
        sb.append(this.start == null ? 0 : this.start);
        sb.append(GAP);
        sb.append(this.end == null || this.end >= this.fileLength ? (this.fileLength - 1) : this.end);
        sb.append(SLASH);
        sb.append(this.fileLength);
        return sb.toString();
    }

    public Long getStart() {
        return start;
    }

    public void setStart(Long start) {
        this.start = start;
    }

    public Long getEnd() {
        return end;
    }

    public void setEnd(Long end) {
        this.end = end;
    }

    public Long getFileLength() {
        return fileLength;
    }

    public void setFileLength(Long fileLength) {
        this.fileLength = fileLength;
    }
}
package com.hivekion.common.file;

import org.springframework.stereotype.Component;

import java.io.*;

/**
 * @author admin
 */
@Component
public class FileEncryptAndDecrypt {
    /**
     * * 文件file进行加密
     * * @param fileUrl 文件路径
     * * @param key 密码
     * * @throws Exception
     */
    public void encrypt(String fileUrl, String key) throws Exception {
        File file = new File(fileUrl);
        String path = file.getPath();
        if (!file.exists()) {
            return;
        }
        int index = path.lastIndexOf("\\");
        String destFile = path.substring(0, index) + "\\" + "abc";
        File dest = new File(destFile);
        InputStream in = new FileInputStream(fileUrl);
        OutputStream out = new FileOutputStream(destFile);
        byte[] buffer = new byte[1024];
        int r;
        byte[] buffer2 = new byte[1024];
        while ((r = in.read(buffer)) > 0) {
            for (int i = 0; i < r; i++) {
                byte b = buffer[i];
                buffer2[i] = b == 255 ? 0 : ++b;
            }
            out.write(buffer2, 0, r);
            out.flush();
        }
        in.close();
        out.close();
        file.delete();
        dest.renameTo(new File(fileUrl));
        appendMethodA(fileUrl, key);
        System.out.println("加密成功");
    }

    /**
     * *
     * * @param fileName
     * * @param content 密钥
     */
    public static void appendMethodA(String fileName, String content) {
        try {
            // 打开一个随机访问文件流,按读写方式
            RandomAccessFile randomFile = new RandomAccessFile(fileName, "rw");
            // 文件长度,字节数
            long fileLength = randomFile.length();
            //将写文件指针移到文件尾。
            randomFile.seek(fileLength);
            randomFile.writeBytes(content);
            randomFile.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 解密
     *
     * @param fileUrl   源文件
     * @param tempUrl   临时文件
     * @param keyLength 密码长度
     * @return
     * @throws Exception
     */

    public  String decrypt(String fileUrl, String tempUrl, int keyLength) throws Exception {
        File file = new File(fileUrl);
        if (!file.exists()) {
            return null;
        }
        File dest = new File(tempUrl);
        if (!dest.getParentFile().exists()) {
            dest.getParentFile().mkdirs();
        }
        InputStream is = new FileInputStream(fileUrl);
        OutputStream out = new FileOutputStream(tempUrl);
        byte[] buffer = new byte[1024];
        byte[] buffer2 = new byte[1024];
        byte bMax = (byte) 255;
        long size = file.length() - keyLength;
        int mod = (int) (size % 1024);
        int div = (int) (size >> 10);
        int count = mod == 0 ? div : (div + 1);
        int k = 1, r;
        while ((k <= count && (r = is.read(buffer)) > 0)) {
            if (mod != 0 && k == count) {
                r = mod;
            }
            for (int i = 0; i < r; i++) {
                byte b = buffer[i];
                buffer2[i] = b == 0 ? bMax : --b;
            }
            out.write(buffer2, 0, r);
            k++;
        }
        out.close();
        is.close();
        return tempUrl;
    }

    /**
     * 判断文件是否加密
     *
     * @param fileName
     * @return
     */
    public static String readFileLastByte(String fileName, int keyLength) {
        File file = new File(fileName);
        if (!file.exists()) {
            return null;
        }
        StringBuffer str = new StringBuffer();
        try {
            // 打开一个随机访问文件流,按读写方式
            RandomAccessFile randomFile = new RandomAccessFile(fileName, "r");
            // 文件长度,字节数
            long fileLength = randomFile.length();
            //将写文件指针移到文件尾。
            for (int i = keyLength; i >= 1; i--) {
                randomFile.seek(fileLength - i);
                str.append((char) randomFile.read());
            }
            randomFile.close();
            return str.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值