java接口下载zip,不生产中间文件,返回前端文件流
- 程序设计:
- 代码实现:
程序设计:
前端向后端请求zip文件,zip文件中有多个文件压缩而成,后端操作文件流,而不生成中间文件。最后把zip返回给前端。
代码实现:
@ApiOperation(value = "下载Zip", notes = "")
@PostMapping("/getDownLoadZip")
public void getDownLoadZip(@RequestBody GClientManagementVo vo, HttpServletRequest request,HttpServletResponse response) throws Exception {
SysUserEntityVo uc = (SysUserEntityVo) request.getAttribute("UC");
GClientManagementService.getDownLoadZip(vo, uc,response);
}
中间有业务代码,可酌情删减。代码中注意关闭流,避免影响内存。
@Override
public void getDownLoadZip(GClientManagementVo vo, SysUserEntityVo uc, HttpServletResponse response) throws Exception {
String filename = vo.getProjectName();
String encodeFileName = URLEncoder.encode(filename);
ServletOutputStream out = response.getOutputStream();
// 创建一个ByteArrayOutputStream来存放最终的ZIP流
ByteArrayOutputStream zipOutputStream = new ByteArrayOutputStream();
ZipOutputStream zipOut = new ZipOutputStream(zipOutputStream);
try {
//写入文件
createFilePs(vo, zipOut);
//结束写入
zipOut.finish();
// 最终ZIP流的内容
byte[] zipBytes = zipOutputStream.toByteArray();
//设置允许跨域的key
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
//文件名有“,”等特殊字符发送到前端会报错,用""括起来解决
response.addHeader("Content-Disposition", "attachment;filename=\"" + encodeFileName + "\"");
//设置文件大小
response.addHeader("Content-Length", "" + zipBytes.length);
//设置文件名,避免问题,这个也用""括起来
response.setHeader("filename,", "filename=\"" + encodeFileName + "\"");
//设置文件类型
response.setContentType("application/octet-stream");
out.write(zipBytes);
out.flush();
} catch (Exception e) {
throw e;
} finally {
try {
out.close();
} catch (Exception e) {
throw e;
}
try {
zipOutputStream.close();
} catch (Exception e) {
throw e;
}
try {
zipOut.close();
} catch (Exception e) {
throw e;
}
try {
out.close();
} catch (Exception e) {
throw e;
}
}
}
private void createFilePs(GClientManagementVo vo, ZipOutputStream zipOut) throws Exception {
// 创建第一个文件install 或者uninstall
ByteArrayOutputStream file1 = new ByteArrayOutputStream();
//install or uninstall
String str1 = "";
String fileName1 = "";
QueryWrapper<GClientAdmin> queryWrapper = new QueryWrapper();
if (vo.getFunction().equalsIgnoreCase(ParamsEnum.Install.getValue())) {
queryWrapper.eq("sign", ParamsEnum.Install.getValue());
} else {
queryWrapper.eq("sign", ParamsEnum.Uninstall.getValue());
}
queryWrapper.last("limit 1");
GClientAdmin gClientAdmin = gClientAdminDao.selectOne(queryWrapper);
fileName1 = gClientAdmin.getScriptName();
str1 = replaceScriptcode(gClientAdmin.getScriptCode(), vo);
try {
// 创建ByteArrayOutputStream来模拟文件流
writeToFile(file1, str1);
// 将每个文件流添加到ZIP流中
addToZipFile(fileName1, file1.toByteArray(), zipOut);
} catch (IOException ex) {
ex.printStackTrace();
throw ex;
}
//多个已经上传文件
List<GClientManagementScriptVo> scriptList = vo.getScriptList();
if (CollectionUtils.isNotEmpty(scriptList)) {
scriptList.forEach(e -> {
List<ParamsObject> paramslist = e.getParamslist();
if (CollectionUtils.isNotEmpty(paramslist)) {
paramslist.forEach(m -> {
if (ParamsEnum.File.getValue().equalsIgnoreCase(m.getDataType())) {
String str = m.getFileContent();
String fileName = m.getFileName();
//创建ByteArrayOutputStream来模拟文件流
ByteArrayOutputStream file = new ByteArrayOutputStream();
try {
// 创建ByteArrayOutputStream来模拟文件流
writeToFile(file, str);
// 将每个文件流添加到ZIP流中
addToZipFile(fileName, file.toByteArray(), zipOut);
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
}
});
}
}
private String replaceScriptcode(String scriptcode, GClientManagementVo vo) throws Exception {
//查找主参数的字符串
String startParams = ParamsEnum.Params_Replace_Start.getValue();
String endParams = ParamsEnum.Params_Replace_End.getValue();
String resultParams = findSubstringBetween(scriptcode, startParams, endParams);
if (resultParams != null) {
//开始替换主参数
String result = resultParams
//projectName
.replace(ParamsEnum.ProjectName.getValue(), "\"" + vo.getProjectName() + "\"")
//applicationName
.replace(ParamsEnum.MSIApplicationName.getValue(), "\"" + vo.getApplicationName() + "\"")
//cmdRcopt
.replace(ParamsEnum.CmdRCOpt.getValue(), vo.getCmdRcopt())
//maxRunTime
.replace(ParamsEnum.MaxRunTime.getValue(), vo.getMaxRunTime().toString())
//startStopService
.replace(ParamsEnum.StartStopService.getValue(), "\"" + vo.getStartStopService() + "\"")
//debugEnable
.replace(ParamsEnum.DebuggingEnabled.getValue(), "$" + vo.getDebugEnable())
//defaultMsicLine
.replace(ParamsEnum.DefaultMSICmdLine.getValue(), "\"" + vo.getDefaultMsicLine() + "\"")
//uDriveMap
.replace(ParamsEnum.UDriveMap.getValue(), "$" + vo.getuDriveMap())
//function
.replace(ParamsEnum.sFunction.getValue(), "\"" + vo.getFunction().toUpperCase(Locale.ROOT) + "\"")
//ifsScript
.replace(ParamsEnum.bIsIFSScript.getValue(), "$" + vo.getIfsScript());
//替换主脚本字符串
// 使用 replaceAll 方法和正则表达式来替换所有匹配的子字符串
// 注意:这里使用了正则表达式,所以需要对特殊字符进行转义
int startIndex = scriptcode.indexOf(startParams);
if (startIndex != -1) {
int endIndex = scriptcode.indexOf(endParams, startIndex);
if (endIndex != -1) {
scriptcode = scriptcode.substring(0, startIndex) + result + scriptcode.substring(endIndex + endParams.length());
} else {
throw new Exception("End tag not found.");
}
} else {
throw new Exception("Start tag not found.");
}
//查找子参数的字符串
String startCommand = ParamsEnum.Command_Replace_Start.getValue();
String endCommand = ParamsEnum.Command_Replace_End.getValue();
AtomicReference<String> codeStr = new AtomicReference<>("");
if (CollectionUtils.isNotEmpty(vo.getScriptList())) {
vo.getScriptList().forEach(e -> {
AtomicReference<String> finalCode = new AtomicReference<>(e.getScriptCode());
if (CollectionUtils.isNotEmpty(e.getParamslist())) {
e.getParamslist().forEach(m -> {
String value = "";
String name = "";
if (m.getDataType().equalsIgnoreCase(ParamsEnum.Boolean.getValue())) {
value = "$" + m.getValue();
name = "${" + m.getName() + "}";
} else if (m.getDataType().equalsIgnoreCase(ParamsEnum.String.getValue())) {
//CustomParameters特殊情况,全string参数
if(m.getName().equalsIgnoreCase(ParamsEnum.CustomParameters.getValue())){
if(StringUtils.startsWith(m.getValue().toString(),"\"")&&StringUtils.endsWith(m.getValue().toString(),"\"")){
value = m.getValue().toString();
}else {
value = "\"" + m.getValue() + "\"";
}
}else {
value = "\"" + m.getValue() + "\"";
}
name = "${" + m.getName() + "}";
} else if (m.getDataType().equalsIgnoreCase(ParamsEnum.Int.getValue())) {
value = m.getValue().toString();
name = "${" + m.getName() + "}";
} else if (m.getDataType().equalsIgnoreCase(ParamsEnum.File.getValue())) {
value = "\"\\" + m.getFileName() + "\"";
name = "${" + m.getName() + "}";
}
finalCode.set(finalCode.get().replace(name, value));
});
}
codeStr.set(codeStr.get() + "\n" + finalCode.get());
});
}
//子参数替换
int startIndex2 = scriptcode.indexOf(startCommand);
if (startIndex2 != -1) {
int endIndex2 = scriptcode.indexOf(endCommand, startIndex2);
if (endIndex2 != -1) {
scriptcode = scriptcode.substring(0, startIndex2) + codeStr.get() + scriptcode.substring(endIndex2 + endCommand.length());
} else {
throw new Exception("End tag not found.");
}
} else {
throw new Exception("Start tag not found.");
}
} else {
throw new Exception("error");
}
return scriptcode;
}
public static String findSubstringBetween(String source, String start, String end) {
// 找到开始字符串的位置
int startIndex = source.indexOf(start);
// 开始字符串不存在
if (startIndex == -1) {
return null;
}
// 在开始字符串之后找到结束字符串的位置
int endIndex = source.indexOf(end, startIndex + start.length());
// 结束字符串不存在
if (endIndex == -1) {
return null;
}
// 提取并返回子字符串
return source.substring(startIndex + start.length(), endIndex);
}
private void writeToFile(ByteArrayOutputStream out, String content) throws IOException {
try (OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8")) {
writer.write(content);
writer.flush();
} finally {
try {
out.close();
} catch (Exception e) {
throw e;
}
}
}
private void addToZipFile(String fileName, byte[] fileContent, ZipOutputStream zipOut) throws IOException {
ZipEntry zipEntry = new ZipEntry(fileName);
zipOut.putNextEntry(zipEntry);
zipOut.write(fileContent);
zipOut.closeEntry();
}