mirror of
https://github.com/hs-web/hsweb-framework.git
synced 2026-06-02 19:02:44 +08:00
优化文件上传逻辑
This commit is contained in:
@@ -1,13 +1,16 @@
|
||||
package org.hswebframework.web.controller.file;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import org.apache.commons.fileupload.ParameterParser;
|
||||
import org.hswebframework.expands.compress.Compress;
|
||||
import org.hswebframework.expands.compress.zip.ZIPWriter;
|
||||
import org.hswebframework.utils.StringUtils;
|
||||
import org.hswebframework.web.BusinessException;
|
||||
import org.hswebframework.web.NotFoundException;
|
||||
import org.hswebframework.web.WebUtil;
|
||||
import org.hswebframework.web.authorization.Authentication;
|
||||
import org.hswebframework.web.authorization.annotation.Authorize;
|
||||
import org.hswebframework.web.commons.entity.DataStatus;
|
||||
import org.hswebframework.web.controller.message.ResponseMessage;
|
||||
import org.hswebframework.web.entity.file.FileInfoEntity;
|
||||
import org.hswebframework.web.logging.AccessLogger;
|
||||
@@ -16,7 +19,6 @@ import org.hswebframework.web.service.file.FileService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
@@ -26,14 +28,18 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.Optional.ofNullable;
|
||||
|
||||
/**
|
||||
* 文件操作控制器,提供文件上传下载等操作
|
||||
*
|
||||
@@ -126,6 +132,7 @@ public class FileController {
|
||||
@PathVariable("name") String name,
|
||||
HttpServletResponse response,
|
||||
HttpServletRequest request) throws IOException {
|
||||
|
||||
downLoad(id, name, response, request);
|
||||
}
|
||||
|
||||
@@ -149,7 +156,7 @@ public class FileController {
|
||||
HttpServletResponse response, HttpServletRequest request)
|
||||
throws IOException {
|
||||
FileInfoEntity fileInfo = fileInfoService.selectByIdOrMd5(idOrMd5);
|
||||
if (fileInfo == null || fileInfo.getStatus() != 1) {
|
||||
if (fileInfo == null || !DataStatus.STATUS_ENABLED.equals(fileInfo.getStatus())) {
|
||||
throw new NotFoundException("文件不存在");
|
||||
}
|
||||
String fileName = fileInfo.getName();
|
||||
@@ -174,9 +181,9 @@ public class FileController {
|
||||
//尝试判断是否为断点下载
|
||||
try {
|
||||
//获取要继续下载的位置
|
||||
String Range = request.getHeader("Range").replaceAll("bytes=", "").replaceAll("-", "");
|
||||
String Range = request.getHeader("Range").replace("bytes=", "").replace("-", "");
|
||||
skip = StringUtils.toInt(Range);
|
||||
} catch (Exception e) {
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
response.setContentLength((int) fSize);//文件大小
|
||||
response.setContentType(contentType);
|
||||
@@ -205,7 +212,12 @@ public class FileController {
|
||||
.map(this::upload)
|
||||
.map(ResponseMessage::getResult)
|
||||
.collect(Collectors.toList()))
|
||||
.include(FileInfoEntity.class, FileInfoEntity.id, FileInfoEntity.name, FileInfoEntity.md5);
|
||||
.include(FileInfoEntity.class,
|
||||
FileInfoEntity.id,
|
||||
FileInfoEntity.name,
|
||||
FileInfoEntity.md5,
|
||||
FileInfoEntity.size,
|
||||
FileInfoEntity.type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -224,9 +236,21 @@ public class FileController {
|
||||
if (file.isEmpty()) {
|
||||
return ResponseMessage.ok();
|
||||
}
|
||||
if (logger.isInfoEnabled())
|
||||
logger.info("start write file:{}", file.getOriginalFilename());
|
||||
String fileName = file.getOriginalFilename();
|
||||
String contentType = Optional.ofNullable(WebUtil.getHttpServletRequest())
|
||||
.orElseThrow(UnsupportedOperationException::new)
|
||||
.getContentType();
|
||||
ParameterParser parser = new ParameterParser();
|
||||
Map<String, String> params = parser.parse(contentType, ';');
|
||||
if (params.get("charset") == null) {
|
||||
try {
|
||||
fileName = new String(file.getOriginalFilename().getBytes("ISO-8859-1"), "utf-8");
|
||||
} catch (UnsupportedEncodingException ignore) {
|
||||
}
|
||||
}
|
||||
if (logger.isInfoEnabled())
|
||||
logger.info("start write file:{}", fileName);
|
||||
|
||||
FileInfoEntity fileInfo;
|
||||
try {
|
||||
fileInfo = fileService.saveFile(file.getInputStream(), fileName, file.getContentType(), creator);
|
||||
@@ -235,13 +259,17 @@ public class FileController {
|
||||
}
|
||||
fileInfoList.add(fileInfo);
|
||||
return ResponseMessage.ok(fileInfo)
|
||||
.include(FileInfoEntity.class, FileInfoEntity.id, FileInfoEntity.name, FileInfoEntity.md5);
|
||||
.include(FileInfoEntity.class, FileInfoEntity.id,
|
||||
FileInfoEntity.name,
|
||||
FileInfoEntity.md5,
|
||||
FileInfoEntity.size,
|
||||
FileInfoEntity.type);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/upload-static")
|
||||
@AccessLogger("上传静态文件")
|
||||
@Authorize(action = "static")
|
||||
public ResponseMessage<String> uploadStatic(MultipartFile file) throws IOException {
|
||||
public ResponseMessage<String> uploadStatic(@RequestParam("file") MultipartFile file) throws IOException {
|
||||
if (file.isEmpty()) return ResponseMessage.ok();
|
||||
return ResponseMessage.ok(fileService.saveStaticFile(file.getInputStream(), file.getOriginalFilename()));
|
||||
}
|
||||
@@ -249,7 +277,8 @@ public class FileController {
|
||||
@GetMapping(value = "/md5/{md5}")
|
||||
@AccessLogger("根据MD5获取文件信息")
|
||||
public ResponseMessage<FileInfoEntity> uploadStatic(@PathVariable String md5) throws IOException {
|
||||
return ResponseMessage
|
||||
.ok(fileInfoService.selectByMd5(md5));
|
||||
return ofNullable(fileInfoService.selectByMd5(md5))
|
||||
.map(ResponseMessage::ok)
|
||||
.orElseThrow(() -> new NotFoundException("file not found"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public class LocalFileService implements FileService {
|
||||
/**
|
||||
* 静态文件访问地址,上传静态文件后,将返回此地址+文件相对地址,以/结尾
|
||||
*/
|
||||
private String staticLocation = "/upload";
|
||||
private String staticLocation = "/upload/";
|
||||
|
||||
/**
|
||||
* 文件上传目录
|
||||
@@ -45,7 +45,7 @@ public class LocalFileService implements FileService {
|
||||
this.staticFilePath = staticFilePath;
|
||||
}
|
||||
|
||||
@Value("${hsweb.web.upload.static-location:/upload}")
|
||||
@Value("${hsweb.web.upload.static-location:/upload/}")
|
||||
public void setStaticLocation(String staticLocation) {
|
||||
this.staticLocation = staticLocation;
|
||||
}
|
||||
@@ -127,17 +127,10 @@ public class LocalFileService implements FileService {
|
||||
if (!path.exists()) path.mkdirs(); //创建目录
|
||||
String newName = String.valueOf(System.nanoTime()); //临时文件名 ,纳秒的md5值
|
||||
String fileAbsName = absPath.concat("/").concat(newName);
|
||||
//try with resource
|
||||
long fileLength = 0;
|
||||
long fileLength;
|
||||
try (BufferedInputStream in = new BufferedInputStream(fileStream);
|
||||
BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(fileAbsName))) {
|
||||
byte[] buffer = new byte[2048 * 10];
|
||||
int len;
|
||||
while ((len = in.read(buffer)) != -1) {
|
||||
fileLength += len;
|
||||
os.write(buffer, 0, len);
|
||||
}
|
||||
os.flush();
|
||||
FileOutputStream os = new FileOutputStream(fileAbsName)) {
|
||||
fileLength = StreamUtils.copy(in, os);
|
||||
}
|
||||
File newFile = new File(fileAbsName);
|
||||
//获取文件的md5值
|
||||
@@ -146,13 +139,16 @@ public class LocalFileService implements FileService {
|
||||
md5 = DigestUtils.md5Hex(inputStream);
|
||||
}
|
||||
// 判断文件是否已经存在
|
||||
FileInfoEntity resources = fileInfoService.selectByMd5(md5);
|
||||
if (resources != null) {
|
||||
newFile.delete();//文件已存在则删除临时文件不做处理
|
||||
return resources;
|
||||
FileInfoEntity fileInfo = fileInfoService.selectByMd5(md5);
|
||||
if (fileInfo != null) {
|
||||
if (new File(getFilePath() + "/" + fileInfo.getLocation()).exists()) {
|
||||
newFile.delete();//文件已存在则删除临时文件不做处理
|
||||
} else {
|
||||
newFile.renameTo(new File(absPath.concat("/").concat(md5)));
|
||||
}
|
||||
return fileInfo;
|
||||
} else {
|
||||
newName = md5;
|
||||
newFile.renameTo(new File(absPath.concat("/").concat(newName)));
|
||||
newFile.renameTo(new File(absPath.concat("/").concat(md5)));
|
||||
}
|
||||
FileInfoEntity infoEntity = fileInfoService.createEntity();
|
||||
infoEntity.setCreateTimeNow();
|
||||
@@ -170,13 +166,8 @@ public class LocalFileService implements FileService {
|
||||
@Override
|
||||
public void writeFile(String fileId, OutputStream out, long skip) throws IOException {
|
||||
try (InputStream inputStream = readFile(fileId)) {
|
||||
BufferedOutputStream outputStream = out instanceof BufferedOutputStream ? ((BufferedOutputStream) out) : new BufferedOutputStream(out);
|
||||
if (skip > 0) inputStream.skip(skip);
|
||||
byte b[] = new byte[2048 * 10];
|
||||
while ((inputStream.read(b)) != -1) {
|
||||
outputStream.write(b);
|
||||
}
|
||||
outputStream.flush();
|
||||
StreamUtils.copy(inputStream, out);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,20 @@ public class SimpleFileInfoService extends GenericEntityService<FileInfoEntity,
|
||||
@Override
|
||||
@Caching(evict = {
|
||||
@CacheEvict(key = "'md5:'+#entity.md5"),
|
||||
@CacheEvict(key = "'id:'+#entity.id")
|
||||
@CacheEvict(key = "'id:'+#result"),
|
||||
@CacheEvict(key = "'id-or-md5:'+#result"),
|
||||
@CacheEvict(key = "'id-or-md5:'+#result")
|
||||
})
|
||||
public String insert(FileInfoEntity entity) {
|
||||
return super.insert(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Caching(evict = {
|
||||
@CacheEvict(key = "'md5:'+#entity.md5"),
|
||||
@CacheEvict(key = "'id:'+#entity.id"),
|
||||
@CacheEvict(key = "'id-or-md5:'+#entity.id"),
|
||||
@CacheEvict(key = "'id-or-md5:'+#entity.id")
|
||||
})
|
||||
protected int updateByPk(FileInfoEntity entity) {
|
||||
return super.updateByPk(entity);
|
||||
@@ -52,7 +65,9 @@ public class SimpleFileInfoService extends GenericEntityService<FileInfoEntity,
|
||||
@Override
|
||||
@Caching(evict = {
|
||||
@CacheEvict(key = "'md5:'+#target.selectByPk(#id).md5"),
|
||||
@CacheEvict(key = "'id:'+#id")
|
||||
@CacheEvict(key = "'id:'+#id"),
|
||||
@CacheEvict(key = "'id-or-md5:'+#id"),
|
||||
@CacheEvict(key = "'id-or-md5:'+#id")
|
||||
})
|
||||
public int deleteByPk(String id) {
|
||||
return super.deleteByPk(id);
|
||||
@@ -81,6 +96,6 @@ public class SimpleFileInfoService extends GenericEntityService<FileInfoEntity,
|
||||
@Cacheable(key = "'id-or-md5:'+#idOrMd5", condition = "#idOrMd5!=null")
|
||||
public FileInfoEntity selectByIdOrMd5(String idOrMd5) {
|
||||
if (null == idOrMd5) return null;
|
||||
return createQuery().where(FileInfoEntity.md5,idOrMd5).or(FileInfoEntity.id,idOrMd5).single();
|
||||
return createQuery().where(FileInfoEntity.md5, idOrMd5).or(FileInfoEntity.id, idOrMd5).single();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user