修改文件下载模式,完善文件删除逻辑,

This commit is contained in:
WenG 2020-11-19 00:37:59 +08:00
parent cb98c405f4
commit 5bb693e2b7
5 changed files with 186 additions and 13 deletions

View File

@ -65,8 +65,8 @@ public class FileController extends AbstractController {
@ApiImplicitParam(name = "ids", value = "ID列表用下划线分隔", paramType = "path", example = "1_2_3")
})
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
@DeleteMapping("removearticlecategory/{isRemoveSource}/{ids}")
public SuccessResult removeFile(@PathVariable() Integer isRemoveSource, @PathVariable("ids") String ids) throws RemoveException {
@DeleteMapping("removefile/{isRemoveSource}/{ids}")
public synchronized SuccessResult removeFile(@PathVariable() Integer isRemoveSource, @PathVariable("ids") String ids) throws RemoveException {
if (isRemoveSource == 0) {
fileService.removeFile(ids);
}

View File

@ -46,6 +46,14 @@ public interface IFileDao {
*/
void deleteFile(Map<String, Object> params) throws RemoveException;
/**
* 更新文件描述
*
* @param fileParams
* @throws SearchException
*/
void updateFileSummary(Map<String, Object> fileParams) throws SearchException;
/**
* 获取文件详情
*
@ -89,4 +97,6 @@ public interface IFileDao {
* @throws SearchException
*/
List<FileInfoDTO> listFileByMd5(String fileMd5) throws SearchException;
}

View File

@ -42,6 +42,9 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
import java.security.MessageDigest;
import java.util.*;
@ -57,6 +60,14 @@ public class FileServiceImpl extends AbstractService implements IFileService {
private static final Logger LOG = LoggerFactory.getLogger(FileServiceImpl.class);
private static final char[] HEX_CODE = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
/**
* 文件MD5值开头
*/
public static final String FILE_MD5_PREFIX = "MD5:";
/**
* 文件引用值开头
*/
public static final String FILE_REF_PREFIX = "REF:";
@Autowired
private FileProperties fileProperties;
@ -92,23 +103,72 @@ public class FileServiceImpl extends AbstractService implements IFileService {
public void deleteFile(String ids) throws RemoveException {
Map<String, Object> params = getHashMap(2);
params.put("fileIds", Arrays.asList(ids.split("_")));
Map<String, Object> fileParams = getHashMap(4);
List<FileInfoWithPathDTO> fileInfoWithPathDTOs = fileDao.listFileInfoWithPath(params);
// 删除文件
for (FileInfoWithPathDTO fileInfoWithPathDTO : fileInfoWithPathDTOs) {
File file = new File(fileInfoWithPathDTO.getFilePath());
if (file.exists()) {
boolean isDelete = file.delete();
if (isDelete) {
LOG.debug("文件删除成功");
} else {
LOG.debug("文件删除失败");
}
// 如果文件描述为空可以直接删除源文件
if (StringUtils.isBlank(fileInfoWithPathDTO.getFileSummary())) {
deleteSourceFile(fileInfoWithPathDTO.getFilePath());
continue;
}
// 文件描述不为空时需要判断是否删除的是源文件源文件在一个系统中只保留一份
// 如果是引用文件的数据不删除源文件
if (fileInfoWithPathDTO.getFileSummary().startsWith(FILE_REF_PREFIX)) {
continue;
}
// 如果不是MD5源文件略过
if (!fileInfoWithPathDTO.getFileSummary().startsWith(FILE_MD5_PREFIX)) {
continue;
}
// 如果删除的是源文件需要查询系统中是否还存在引用的数据
List<FileInfoDTO> fileInfoDTOs = fileDao.listFileByMd5(FILE_REF_PREFIX + fileInfoWithPathDTO.getFileId());
// 如果不存在对源文件引用的数据则直接删除源文件
if (fileInfoDTOs.size() == 0) {
deleteSourceFile(fileInfoWithPathDTO.getFilePath());
continue;
}
fileParams.clear();
// 如果存在引用数据取出第一个修改为源文件并将其他的引用更新为新的源文件ID
FileInfoDTO fileInfoDTO = fileInfoDTOs.get(0);
fileParams.put("fileSummary", fileInfoWithPathDTO.getFileSummary());
fileParams.put("fileId", fileInfoDTO.getFileId());
fileDao.updateFileSummary(fileParams);
// 获取其他的ID列表更新文件引用关系
List<String> otherFileIds = new ArrayList<>();
for (int i = 1; i < fileInfoDTOs.size(); i++) {
otherFileIds.add(fileInfoDTOs.get(i).getFileId());
}
// 如果不存在其它的引用略过
if (otherFileIds.isEmpty()) {
continue;
}
fileParams.remove("fileId");
fileParams.put("fileSummary", FILE_REF_PREFIX + fileInfoDTO.getFileId());
fileParams.put("fileIds", otherFileIds);
fileDao.updateFileSummary(fileParams);
}
// 删除记录
fileDao.deleteFile(params);
}
/**
* 删除源文件
*
* @param sourceFilePath 源文件路径
*/
private void deleteSourceFile(String sourceFilePath) {
File file = new File(sourceFilePath);
if (file.exists()) {
boolean isDelete = file.delete();
if (isDelete) {
LOG.debug("文件删除成功");
} else {
LOG.debug("文件删除失败");
}
}
}
@Override
public SuccessResultData<String> uploadSingle(MultipartFile uploadFile, UploadTypeEnum uploadTypeEnum, Map<String, Object> params) throws SystemException {
uploadFile(null, uploadFile, uploadTypeEnum, params);
@ -160,7 +220,7 @@ public class FileServiceImpl extends AbstractService implements IFileService {
throw new SaveException("文件上传失败");
}
// 获取MD5相同的文件
List<FileInfoDTO> fileInfoDTOs = fileDao.listFileByMd5("MD5:" + fileMd5);
List<FileInfoDTO> fileInfoDTOs = fileDao.listFileByMd5(FILE_MD5_PREFIX + fileMd5);
if (fileInfoDTOs.size() > 0) {
// 删除新增的文件
File uploadedFile = new File(uploadPath + File.separator + uploadFileName);
@ -266,6 +326,68 @@ public class FileServiceImpl extends AbstractService implements IFileService {
@Override
public void downLoadFile(HttpServletRequest request, HttpServletResponse response, Map<String, Object> params, boolean canRange) throws FileException {
FilePO filePO = fileDao.getFile(params);
if (null == filePO) {
throw new SearchException("文件获取失败");
}
try (
RandomAccessFile randomAccessFile = new RandomAccessFile(filePO.getFilePath(), "r");
FileChannel fileChannel = randomAccessFile.getChannel();
OutputStream outputStream = response.getOutputStream();
WritableByteChannel writableByteChannel = Channels.newChannel(outputStream);
) {
boolean isOpen = Boolean.valueOf(params.get("isOpen").toString());
response.setHeader("Content-Length", filePO.getFileSize());
response.setContentType(getContentType(filePO.getFileType()));
if (!isOpen) {
response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(filePO.getFileName(), "UTF-8"));
} else {
response.setHeader("Content-Disposition", "inline;fileName=" + URLEncoder.encode(filePO.getFileName(), "UTF-8"));
}
String rangeString = null;
if (canRange && request != null) {
rangeString = request.getHeader("Range");
LOG.debug("range: {}", rangeString);
}
long contentLength = Long.valueOf(filePO.getFileSize());
long startRange = 0;
long endRange = contentLength - 1;
if (!StringUtils.isBlank(rangeString)) {
if (!isOpen) {
response.setContentType("multipart/byteranges");
}
String[] rangeArray = rangeString.substring(rangeString.indexOf("=") + 1).split("-");
startRange = Long.valueOf(rangeArray[0]);
if (rangeArray.length > 1) {
endRange = Long.valueOf(rangeArray[1]);
}
setRangeHeader(startRange, endRange, response, filePO.getFileId(), contentLength);
randomAccessFile.seek(startRange);
}
LOG.debug("startRange: {}, endRange: {}", startRange, endRange);
long totalOutputLength = endRange - startRange + 1;
fileChannel.transferTo(startRange, totalOutputLength, writableByteChannel);
outputStream.flush();
} catch (Exception e) {
if (e instanceof ClientAbortException) {
LOG.debug("客户端断开连接");
} else {
throw new FileException("文件输出异常", e);
}
}
}
/**
* 同步下载文件
*
* @param request
* @param response
* @param params
* @param canRange
* @throws FileException
*/
@Deprecated
public void downLoadFileOld(HttpServletRequest request, HttpServletResponse response, Map<String, Object> params, boolean canRange) throws FileException {
FilePO filePO = fileDao.getFile(params);
if (null == filePO) {
throw new SearchException("文件获取失败");

View File

@ -87,7 +87,7 @@
UPDATE
sys_file
SET
is_delete = 0,
is_delete = 1,
modifier = #{modifier},
gmt_modified = #{gmtModified}
WHERE
@ -108,6 +108,24 @@
</foreach>
</delete>
<!-- 更新文件描述 -->
<update id="updateFileSummary" parameterType="map">
UPDATE
sys_file
SET
file_summary = #{fileSummary}
WHERE
<if test="fileId != null and fileId != ''">
file_id = #{fileId}
</if>
<if test="fileIds != null and fileIds.size > 0">
file_id IN
<foreach collection="fileIds" index="index" open="(" separator="," close=")">
#{fileIds[${index}]}
</foreach>
</if>
</update>
<!-- 获取文件 -->
<select id="getFile" parameterType="map" resultMap="filePO">
SELECT

View File

@ -172,6 +172,29 @@
return rowData;
}
},
{field: 'fileSummary', width: 350, title: '文件描述', align:'center',
templet: function(row) {
var rowData = row[this.field];
if(typeof(rowData) === 'undefined' || rowData == null || rowData == '') {
return '-';
}
return rowData;
}
},
{field: 'isSourceFile', width: 100, title: '保存类型', align:'center',
templet: function(row) {
if(!row.fileSummary) {
return '无';
}
if(row.fileSummary.indexOf('MD5:') == 0) {
return '源文件';
}
if(row.fileSummary.indexOf('REF:') == 0) {
return '引用';
}
return '错误';
}
},
]
],
page: true,
@ -216,7 +239,7 @@
// 删除
function removeFile(isRemoveSource, ids) {
var layIndex;
top.restAjax.delete(top.restAjax.path('api/file/removearticlecategory/{isRemoveSource}/{ids}', [isRemoveSource, ids]), {}, null, function (code, data) {
top.restAjax.delete(top.restAjax.path('api/file/removefile/{isRemoveSource}/{ids}', [isRemoveSource, ids]), {}, null, function (code, data) {
top.dialog.msg(top.dataMessage.deleteSuccess, {time: 1000});
reloadTable();
}, function (code, data) {