提交 96165440 authored 作者: 孙洁清's avatar 孙洁清

Merge branch 'lj-project' of git.yfzx.zjtys.com.cn:912-system/monitor/inspect into lj-project

......@@ -151,6 +151,12 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3</version>
</dependency>
</dependencies>
<build>
......
......@@ -10,11 +10,19 @@ import com.zjty.inspect.utils.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.FileItem;
import org.apache.tomcat.util.http.fileupload.FileItemFactory;
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.io.File;
import java.util.*;
......@@ -43,6 +51,8 @@ public class InspectController {
@Autowired
private ConfigParamDao configParamDao;
@Value("${upload.location}")
private String uploadPath;
@Autowired
private AsyncTask asyncTask;
......@@ -379,7 +389,7 @@ public class InspectController {
return ResponseEntity.ok(save.getId());
}
@PostMapping("/uploads")
@PostMapping("/uploadsaaa")
private ResponseEntity uploads(@RequestParam(value = "file") MultipartFile multfile) {
try {
File file = FileUtil.saveToLocal(multfile);
......@@ -393,6 +403,64 @@ public class InspectController {
}
}
@ApiOperation("大文件分片上传")
// @PostMapping("/chunkUpload")
@PostMapping("/uploads")
public ResponseEntity fileChunkUpload(MultipartFileParam param, HttpServletRequest request, HttpServletResponse response){
System.out.println("77777777777777777777");
//自己的业务获取存储路径,可以换成自己的
// OSSInformation ossInformation = ossInformationService.queryOne();
// String root = ossInformation.getRoot();
String root = uploadPath;
//验证文件夹规则,不能包含特殊字符
java.io.File file = new java.io.File(root);
// createDirectoryQuietly(file);
System.out.println("88888888888888");
String path=file.getAbsolutePath();
response.setContentType("text/html;charset=UTF-8");
// response.setStatus对接前端插件
// 200, 201, 202: 当前块上传成功,不需要重传。
// 404, 415. 500, 501: 当前块上传失败,会取消整个文件上传。
// 其他状态码: 出错了,但是会自动重试上传。
try {
/**
* 判断前端Form表单格式是否支持文件上传
*/
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if(!isMultipart){
//这里是我向前端发送数据的代码,可理解为 return 数据; 具体的就不贴了
System.out.println("不支持的表单格式");
return ResponseEntity.status(404).body("不支持的表单格式");
}else {
param.setTaskId(param.getIdentifier());
System.out.println("2222222222222222");
File myfile = inspectService.chunkUploadByMappedByteBuffer(param,path);//service层
System.out.println("666666666666");
if (myfile!=null){
String name = myfile.getName();
String myPath = myfile.getCanonicalPath();
return ResponseEntity.ok(new com.zjty.inspect.entity.File(name, myPath));
}else {
return ResponseEntity.ok("继续断点传续!");
}
}
} catch (Exception e) {
e.printStackTrace();
// System.out.println("上传文件失败");
// response.setStatus(415);
return ResponseEntity.status(415).body("上传文件失败");
}
}
@PostMapping("/gitdownload")
private ResponseEntity gitDownloads(String gitAddress, String username, String password) {
try {
......
package com.zjty.inspect.entity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.web.multipart.MultipartFile;
@ApiModel("大文件分片入参实体")
public class MultipartFileParam {
@ApiModelProperty("文件传输任务ID")
private String taskId;
@ApiModelProperty("当前为第几分片")
private int chunkNumber;
@ApiModelProperty("每个分块的大小")
private long chunkSize;
@ApiModelProperty("分片总数")
private int totalChunks;
@ApiModelProperty("文件唯一标识")
private String identifier;
@ApiModelProperty("分块文件传输对象")
private MultipartFile file;
public String getTaskId() {
return taskId;
}
public void setTaskId(String taskId) {
this.taskId = taskId;
}
public int getChunkNumber() {
return chunkNumber;
}
public void setChunkNumber(int chunkNumber) {
this.chunkNumber = chunkNumber;
}
public long getChunkSize() {
return chunkSize;
}
public void setChunkSize(long chunkSize) {
this.chunkSize = chunkSize;
}
public int getTotalChunks() {
return totalChunks;
}
public void setTotalChunks(int totalChunks) {
this.totalChunks = totalChunks;
}
public MultipartFile getFile() {
return file;
}
public void setFile(MultipartFile file) {
this.file = file;
}
public String getIdentifier() {
return identifier;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
}
\ No newline at end of file
package com.zjty.inspect.service;
import com.zjty.inspect.entity.InspectParameter;
import com.zjty.inspect.entity.Report;
import com.zjty.inspect.entity.MultipartFileParam;
import com.zjty.inspect.entity.ReportVo;
import java.io.File;
import java.io.IOException;
import java.util.Map;
public interface InspectService {
/**
* 评估
*
* @param inspectParameter
* @return
*/
ReportVo inspect(ReportVo reportVo,InspectParameter inspectParameter) throws IOException;
String generateHtml(String templateContent, Map model );
ReportVo inspect(ReportVo reportVo, InspectParameter inspectParameter) throws IOException;
String generateHtml(String templateContent, Map model);
String freemakerData(ReportVo inspect, int count, int support);
}
File chunkUploadByMappedByteBuffer(MultipartFileParam param, String filePath) throws Exception;
}
\ No newline at end of file
......@@ -13,15 +13,29 @@ import com.zjty.inspect.utils.TimeUtil;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import java.io.IOException;
import java.io.*;
import java.io.File;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* 解析
......@@ -41,6 +55,166 @@ public class InspectServiceImpl implements InspectService {
@Autowired
private ParameterService parameterService;
@Override
public File chunkUploadByMappedByteBuffer(MultipartFileParam param, String filePath) throws Exception{
System.out.println("============================");
if(param.getTaskId() == null || "".equals(param.getTaskId())){
param.setTaskId(UUID.randomUUID().toString());
}
/**
*
* 1:创建临时文件,和源文件一个路径
* 2:如果文件路径不存在重新创建
*/
String fileName = param.getFile().getOriginalFilename();
String tempFileName = param.getTaskId() + fileName.substring(fileName.lastIndexOf(".")) + "_tmp";
java.io.File fileDir = new java.io.File(filePath);
if(!fileDir.exists()){
fileDir.mkdirs();
}
java.io.File tempFile = new java.io.File(filePath,tempFileName);
//第一步
RandomAccessFile raf = new RandomAccessFile(tempFile,"rw");
//第二步
FileChannel fileChannel = raf.getChannel();
//第三步 计算偏移量
long position = (param.getChunkNumber()-1) * param.getChunkSize();
//第四步
byte[] fileData = param.getFile().getBytes();
//第五步
long end=position+fileData.length-1;
fileChannel.position(position);
fileChannel.write(ByteBuffer.wrap(fileData));
//使用 fileChannel.map的方式速度更快,但是容易产生IO操作,无建议使用
// MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE,position,fileData.length);
// //第六步
// mappedByteBuffer.put(fileData);
//第七步
// freedMappedByteBuffer(mappedByteBuffer);
// Method method = FileChannelImpl.class.getDeclaredMethod("unmap", MappedByteBuffer.class);
// method.setAccessible(true);
// method.invoke(FileChannelImpl.class, mappedByteBuffer);
fileChannel.force(true);
fileChannel.close();
raf.close();
//第八步
boolean isComplete = checkUploadStatus(param,fileName,filePath);
if(isComplete){
System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaa");
renameFile(tempFile,fileName);
java.io.File realFile = new java.io.File(filePath,fileName);
FileItem fileItem = createFileItem(realFile, filePath);
MultipartFile mfile = new CommonsMultipartFile(fileItem);
return FileUtil.saveToLocal(mfile);
}
System.out.println("qqqqqqqqqqqqqqqqqqqq");
// return param.getTaskId();
return null;
}
/*
创建FileItem
*/
private FileItem createFileItem(File file, String fieldName) {
FileItemFactory factory = new DiskFileItemFactory(16, null);
FileItem item = factory.createItem(fieldName, "text/plain", true, file.getName());
int bytesRead = 0;
byte[] buffer = new byte[8192];
try {
FileInputStream fis = new FileInputStream(file);
OutputStream os = item.getOutputStream();
while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
return item;
}
/**
* 文件重命名
* @param toBeRenamed 将要修改名字的文件
* @param toFileNewName 新的名字
* @return
*/
public void renameFile(java.io.File toBeRenamed, String toFileNewName) {
//检查要重命名的文件是否存在,是否是文件
if (!toBeRenamed.exists() || toBeRenamed.isDirectory()) {
System.out.println("文件不存在");
return;
}
String p = toBeRenamed.getParent();
java.io.File newFile = new java.io.File(p + java.io.File.separatorChar + toFileNewName);
//修改文件名
toBeRenamed.renameTo(newFile);
}
/**
* 检查文件上传进度
* @return
*/
public boolean checkUploadStatus(MultipartFileParam param,String fileName,String filePath) throws IOException {
java.io.File confFile = new java.io.File(filePath,fileName+".conf");
RandomAccessFile confAccessFile = new RandomAccessFile(confFile,"rw");
//设置文件长度
confAccessFile.setLength(param.getTotalChunks());
//设置起始偏移量
confAccessFile.seek(param.getChunkNumber()-1);
//将指定的一个字节写入文件中 127,
confAccessFile.write(Byte.MAX_VALUE);
byte[] completeStatusList = FileUtils.readFileToByteArray(confFile);
confAccessFile.close();//不关闭会造成无法占用
//这一段逻辑有点复杂,看的时候思考了好久,创建conf文件文件长度为总分片数,每上传一个分块即向conf文件中写入一个127,那么没上传的位置就是默认的0,已上传的就是Byte.MAX_VALUE 127
for(int i = 0; i<completeStatusList.length; i++){
if(completeStatusList[i]!=Byte.MAX_VALUE){
return false;
}
}
//如果全部文件上传完成,删除conf文件
confFile.delete();
return true;
}
/**
* 在MappedByteBuffer释放后再对它进行读操作的话就会引发jvm crash,在并发情况下很容易发生
* 正在释放时另一个线程正开始读取,于是crash就发生了。所以为了系统稳定性释放前一般需要检 查是否还有线程在读或写
* @param mappedByteBuffer
*/
public static void freedMappedByteBuffer(final MappedByteBuffer mappedByteBuffer) {
try {
if (mappedByteBuffer == null) {
return;
}
mappedByteBuffer.force();
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
try {
Method getCleanerMethod = mappedByteBuffer.getClass().getMethod("cleaner", new Class[0]);
//可以访问private的权限
getCleanerMethod.setAccessible(true);
//在具有指定参数的 方法对象上调用此 方法对象表示的底层方法
sun.misc.Cleaner cleaner = (sun.misc.Cleaner) getCleanerMethod.invoke(mappedByteBuffer,
new Object[0]);
cleaner.clean();
} catch (Exception e) {
e.printStackTrace();
System.out.println("清理缓存出错!!!"+e.getMessage());
}
System.out.println("缓存清理完毕!!!");
return null;
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
@Transactional
@Override
public ReportVo inspect(ReportVo reportVo,InspectParameter inspectParameter) throws IOException {
......
......@@ -74,4 +74,6 @@ address=120.55.57.35
thread.pool.corePoolSize=10
thread.pool.maxPoolSize=40
thread.pool.keepAliveSeconds=300
thread.pool.queueCapacity=50
\ No newline at end of file
thread.pool.queueCapacity=50
# 上传文件地址
upload.location=static/uplaods/
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论