优化文件上传逻辑

This commit is contained in:
zhouhao
2017-07-26 12:10:19 +08:00
parent da1cde6717
commit ef96ed01a6
3 changed files with 73 additions and 38 deletions

View File

@@ -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"));
}
}

View File

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

View File

@@ -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();
}
}