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;
}
}