项目中用到了一个文件模板的上传,百度了一阵后自己写了个工具类实现了,记录下来以后可能用到,文件打包上传与文件下载工具类,zip打包上传,上传后自动解压到服务器,但路径需要自己拼接。
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
/**
* @author modify by Jintao
*/
public class CompressUtil {
/**
* zip文件压缩
*
* @param inputFile 待压缩文件夹/文件名
* @param outputFile 生成的压缩包名字
*/
public static void zipCompress(String inputFile, String outputFile) throws IOException {
//创建zip输出流
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(outputFile));
//创建缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(out);
File input = new File(inputFile);
compress(out, bos, input, null);
bos.close();
out.close();
}
/**
* 递归压缩
*
* @param name 压缩文件名,可以写为null保持默认
*/
private static void compress(ZipOutputStream out, BufferedOutputStream bos, File input, String name) throws IOException {
if (name == null) {
name = input.getName();
System.out.println("输入文件名:"+input.getName());
}
//如果路径为目录(文件夹)
if (input.isDirectory()) {
//取出文件夹中的文件(或子文件夹)
File[] fList = input.listFiles();
if (fList != null) {
if (fList.length == 0) {
//如果文件夹为空,则只需在目的地zip文件中写入一个目录进入
out.putNextEntry(new ZipEntry(name + "/"));
} else {
//如果文件夹不为空,则递归调用compress,文件夹中的每一个文件(或文件夹)进行压缩
for (File file : fList) {
compress(out, bos, file, name + "/" + file.getName());
}
}
}
} else {
//如果不是目录(文件夹),即为文件,则先写入目录进入点,之后将文件写入zip文件中
out.putNextEntry(new ZipEntry(name));
FileInputStream fos = new FileInputStream(input);
BufferedInputStream bis = new BufferedInputStream(fos);
int len;
//将源文件写入到zip文件中
byte[] buf = new byte[1024];
while ((len = bis.read(buf)) != -1) {
out.write(buf, 0, len);
}
bis.close();
fos.close();
}
}
/**
* zip压缩文 解压
*
* @param path 压缩文件的完整路径,如:f://test.zip
*/
public static void deCompress(String path) throws IOException {
File file = new File(path);
String toPath = file.getParent() + "/decompressFiles";
File createPath = new File(file.getParent(), "/decompressFiles");
if (createPath.exists()) {
deleteFilesDir(createPath);
System.out.println("----已经存在先删除目录:" + toPath);
}
boolean mkdirp = createPath.mkdirs();
System.out.println(mkdirp + "----成功创建目录:" + toPath);
zipDecompress(path, toPath);
}
public static void deleteFilesDir(File deleteFile) {
if (!deleteFile.exists()) {
return;
}
if (deleteFile.isFile()) {
String path = deleteFile.getPath();
boolean delete = deleteFile.delete();
System.out.println(delete + "----删除文件:" + path);
return;
}
File[] files = deleteFile.listFiles();
if (files != null) {
for (File file : files) {
deleteFilesDir(file);
}
}
String path = deleteFile.getPath();
boolean delete = deleteFile.delete();
System.out.println(delete + "----删除目录:" + path);
}
/**
* zip文件解压
*
* @param inputFile 待解压文件夹/文件
* @param destDirPath 解压路径
*/
private static void zipDecompress(String inputFile, String destDirPath) throws IOException {
//获取当前压缩文件
File srcFile = new File(inputFile);
// 判断源文件是否存在
if (!srcFile.exists()) {
throw new IOException(srcFile.getPath() + "所指文件不存在");
}
//创建压缩文件对象
ZipFile zipFile = new ZipFile(srcFile, Charset.forName("GBK"));
//开始解压
Enumeration<?> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = (ZipEntry) entries.nextElement();
// 如果是文件夹,就创建个文件夹
if (entry.isDirectory()) {
String dirPath = destDirPath + "/" + entry.getName();
boolean mkdirp = srcFile.mkdirs();
System.out.println(mkdirp + "创建目录:" + dirPath);
} else {
// 如果是文件,就先创建一个文件,然后用io流把内容copy过去
File targetFile = new File(destDirPath + "/" + entry.getName());
// 保证这个文件的父文件夹必须要存在
if (!targetFile.getParentFile().exists()) {
boolean madeira = targetFile.getParentFile().mkdirs();
System.out.println(madeira + "父目录:" + destDirPath + "/" + entry.getName());
}
boolean newFile = targetFile.createNewFile();
System.out.println(newFile + "创建文件:" + destDirPath + "/" + entry.getName());
// 将压缩文件内容写入到这个文件中
InputStream is = zipFile.getInputStream(entry);
FileOutputStream fos = new FileOutputStream(targetFile);
int len;
byte[] buf = new byte[1024];
while ((len = is.read(buf)) != -1) {
fos.write(buf, 0, len);
}
// 关流顺序,先打开的后关闭
fos.close();
is.close();
}
}
}
}
使用实例:
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@Controller
@RequestMapping("/template")
public class TemplateController extends BaseController {
@Resource
private TemplateAS templateAS;
private String uploadPath="/home/template/";
/**
* 保存
*/
@RequestMapping(value = "/save/{fileUploadFlg}/{actionType}", method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ResponseDto doSave(HttpServletRequest request,
@Valid @RequestBody TemplateDto templateDto,
@PathVariable() String actionType,
@PathVariable() String fileUploadFlg,
BindingResult result) {
// 返回值
ResponseDto ret = new ResponseDto();
// 继承的BaseController中的方法,分析附带的请求是否存在异常
analysisBindResult(request, result);
// 框架继承的类转换,相当于BeanUtils的复制属性
Template template = BeanMapper.map(templateDto, Template.class);
// 判断操作类型:新增or更新
if ("add".equals(actionType)) {
template.setTemplateCode(StringUtils.isEmpty(template.getTemplateCode()) ? getTemplateCode() : template.getTemplateCode());
template.setIsDelete(YesOrNoConstants.NO);
dealUser(template, request, actionType);
templateAS.create(template);
} else if ("update".equals(actionType)) {
dealUser(template, request, actionType);
templateAS.updateById(template);
}
if ("upload".equals(fileUploadFlg)) {
// 解压缩文件
try {
String path = getPath(template);
CompressUtil.deCompress(path);
} catch (IOException e) {
e.printStackTrace();
ret.setCode(ResultCodeEnum.FAIL.getCode());
ret.setMessage(e.getMessage());
return ret;
}
}
ret.setCode(ResultCodeEnum.SUCCESS.getCode());
ret.setMessage(ResultCodeEnum.SUCCESS.getMessage());
return ret;
}
/**
* 上传文件
*/
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public void uploadPackage(TemplateDto templateDto, @RequestParam("file") MultipartFile file, HttpServletResponse response) throws Exception {
Map<String, Object> map = new HashMap<>(30);
PrintWriter writer;
// 虚拟文件名,uuid
String virtualFileName = getVirtualFileName();
// 模板文件编码
String codePath = StringUtils.isEmpty(templateDto.getTemplateCode()) ? "default" : templateDto.getTemplateCode();
String filePath = uploadPath + codePath + "/" + virtualFileName;
File createPath = new File(uploadPath, codePath);
// 校验目录是否存在,因首次服务器可能不存在对应目录,需创建目录
if (!createPath.exists()) {
boolean mkdirp = createPath.mkdirs();
System.out.println(mkdirp + "--成功创建目录:" + filePath);
}
try {
// 转存文件,Spring的MultipartFile类中transferTo方法实现了文件存储过程
file.transferTo(new File(filePath));
// 返回相应信息
map.put("url", filePath);
String realName = file.getOriginalFilename();
map.put("fileName", realName != null ? realName.replace(".zip", "") : null);
map.put("virtualFileName", virtualFileName);
map.put("error", 0);
map.put("path", filePath);
map.put("result", true);
map.put("message", "上传成功");
} catch (IOException e) {
e.printStackTrace();
map.put("error", 1);
map.put("message", e.getMessage());
map.put("result", false);
} finally {
response.setContentType("text/html");
// 添加头部信息,避免跨域拦截
response.addHeader("Access-Control-Allow-Origin", "*");
writer = response.getWriter();
writer.println(JSON.toJSONString(map));
writer.close();
}
}
/**
* 下载文件
*/
@RequestMapping(value = "/download/{templateId}")
public void download(@PathVariable() String templateId, HttpServletResponse response) throws IOException {
// 获取路径
Template template = templateAS.getTemplateById(templateId);
String codePath = StringUtils.isEmpty(template.getTemplateCode()) ? "default" : template.getTemplateCode();
String path = uploadPath + codePath + "/" + template.getVirtualFileName();
File tempFile = new File(path);
// 读取文件信息
InputStream fis = new BufferedInputStream(new FileInputStream(path));
byte[] buffer = new byte[fis.available()];
int read = fis.read(buffer);
System.out.println(read);
fis.close();
// 响应请求,文件信息放入响应的outputStream中
response.reset();
response.addHeader("Content-Disposition", "attachment;filename=" + tempFile.getName());
response.addHeader("Content-Length", "" + tempFile.length());
OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
response.setContentType("application/octet-stream");
toClient.write(buffer);
toClient.flush();
toClient.close();
}
/**
* 删除文件
*/
@RequestMapping(value = "/delFile", method = RequestMethod.POST)
@ResponseBody
public ResponseDto delFile(@RequestParam("filePath") String filePath) {
ResponseDto ret = new ResponseDto();
if (!StringUtils.isEmpty(filePath)) {
ret.setCode(ResultCodeEnum.FAIL.getCode());
ret.setMessage(ResultCodeEnum.PARAMETER_ERROR.getMessage());
return ret;
}
File delFile = new File(filePath);
CompressUtil.deleteFilesDir(delFile);
ret.setCode(ResultCodeEnum.SUCCESS.getCode());
ret.setMessage(ResultCodeEnum.SUCCESS.getMessage());
return ret;
}
/**
* 已知模板id或编码,获取文件路径
*/
private String getPath(Template template) {
if (template.getId() != null) {
Template result = templateAS.getTemplateById(template.getId() + "");
return uploadPath + result.getTemplateCode() + "/" + result.getVirtualFileName();
}
if (!StringUtils.isEmpty(template.getTemplateCode())) {
Template result = templateAS.getTemplateByCode(template.getTemplateCode());
return uploadPath + result.getTemplateCode() + "/" + result.getVirtualFileName();
}
return "";
}
/**
* 生成编码
*/
private String getTemplateCode() {
Calendar calendar = Calendar.getInstance();
String yearStr = calendar.get(Calendar.YEAR) + "";
int month = calendar.get(Calendar.MONTH) + 1;
String monthStr = month + "";
if (month < 10) {
monthStr = "0" + monthStr;
}
int day = calendar.get(Calendar.DATE);
String dayStr = day + "";
if (day < 10) {
dayStr = "0" + dayStr;
}
String timeStr = yearStr + monthStr + dayStr;
return "TE" + timeStr + SequenceTool.getSequenceNO("seq_template_code", "SYS").toString();
}
/**
* 获取登陆人相关信息
*/
private void dealUser(Template template, HttpServletRequest request, String actionType) {
template.setOrgId(getOrgId(request));
if ("add".equals(actionType)) {
template.setProjectId(SessionUserCommonUtil.getSessionUser().getCurrProjectId());
template.setCreateUser(getUserName(request));
template.setCreateDate(new Date());
template.setModifyUser(getUserName(request));
template.setModifyDate(new Date());
} else if ("update".equals(actionType)) {
template.setModifyUser(getUserName(request));
template.setModifyDate(new Date());
}
}
private String getOrgId(HttpServletRequest request) {
String orgId = AuthSessionFacade.getCurrOrgId(request);
return StringUtils.isEmpty(orgId) ? "1" : orgId;
}
private String getUserName(HttpServletRequest request) {
String currUserCode = AuthSessionFacade.getCurrUserCode(request);
return StringUtils.isEmpty(currUserCode) ? "系统管理员" : currUserCode;
}
/**
* 生成虚拟文件名称
*/
private String getVirtualFileName() {
String uid = UUID.randomUUID().toString();
return uid.replace("-", "");
}
}
前端vue文件,需注意下载时的代码处理:
<template>
<z-modal v-model="modelIsOpen" :title="showTitle" width="600" :mask-closable="false">
<z-form ref="editTemplateForm" :model="formItem" :rules="ruleValidate" :label-width="120" label-position="right">
<z-form-item label="模板名称:" prop="templateName">
<z-input v-model="formItem.templateName" placeholder="请输入"></z-input>
</z-form-item>
<z-form-item label="模板编码:" prop="templateCode">
<z-input v-model="formItem.templateCode" placeholder="请输入" disabled></z-input>
</z-form-item>
<z-form-item label="模板描述:" prop="templateDescribe">
<z-input v-model="formItem.templateDescribe" type="textarea" :autosize="{minRows: 3,maxRows: 5}"
placeholder="请输入"></z-input>
</z-form-item>
<z-form-item label="" v-show="editShow">
<z-upload class="m-t-10" :action="actionUrl" :max-size="10240" name="file" :data="uploadFormItem"
:accept="acceptType" :show-upload-list="false" :on-success="handleUploadSuccess" :on-exceeded-size="handleMaxSize" :before-upload="handleBeforeUpload">
<z-button type="primary" ghost icon="ios-cloud-upload-outline">上传模板</z-button>
</z-upload>
</z-form-item>
<z-form-item label="">
<z-row>
<z-col span="2">
<img src="/static/img/zipPicture.png" width="80%" height="80%">
</z-col>
<z-col span="8">
<div class="m-t-5">{{formItem.fileName}}.zip</div>
</z-col>
<z-col span="4" align="center">
<z-button type="text" @click="downloadTemplate" style="color:blue">下载模板</z-button>
</z-col>
</z-row>
</z-form-item>
</z-form>
<div slot="footer" class="ilead-modal-footer">
<z-button v-show="editShow" :loading="loading" type="primary"
@click="handleSave('editTemplateForm')">保存</z-button>
<z-button @click="handleClose()">关闭</z-button>
</div>
</z-modal>
</template>
<script>
import templateApi from '@/api/template/templateApi'
export default {
name: 'templateEdit',
data: function () {
return {
modelIsOpen: false,
loading: false,
editShow: true,
showTitle: '编辑模板',
actionUrl: '/api/template/upload',
acceptType: '.zip',
initVirtualFileName: '',
formItem: {
templateName: '',
templateCode: '',
templateDescribe: '',
id: ''
},
uploadFormItem: {
templateCode: ''
},
ruleValidate: {
templateName: [
{required: true, message: '模板名称为空', trigger: 'blur'}
]
}
}
},
methods: {
// 保存数据(类型走更新,新增页面会走新增)
handleSave: function (name) {
var that = this
var flg = 'noUpload'
if (that.initVirtualFileName !== that.formItem.virtualFileName) {
flg = 'upload'
}
// 这里我抽了个方法校验,其实可以用vue的ruleValidate校验
var msg = that.checkForm()
if (msg !== '') {
that.$Message.warning({
duration: 3,
content: msg
})
return
}
that.loading = true
templateApi.saveTemplate(flg, 'update', this.formItem).then(function (response) {
console.log(response)
that.$Message.success('保存成功')
// 回调list页方法
that.$emit('queryTemplate')
that.loading = false
that.modelIsOpen = false
}).catch(function (error) {
console.log(error)
that.loading = false
that.$Message.error('更新异常')
})
},
// 校验必填字段
checkForm: function () {
if (this.formItem.templateName === '') {
return '模板名称为空'
}
return ''
},
// 下载 注意Blob的处理,从响应中取出文件信息,不同类型的文件type不一样
downloadTemplate: function (name) {
var that = this
templateApi.downloadTemplate(this.formItem.id).then(function (response) {
const blob = new Blob([response.data], {type: 'application/zip; application/octet-stream'})
const fileName = that.formItem.fileName + '.zip'
// 点击即下载,相当a标签
const elink = document.createElement('a')
elink.download = fileName
elink.style.display = 'none'
elink.href = URL.createObjectURL(blob)
document.body.appendChild(elink)
elink.click()
URL.revokeObjectURL(elink.href)
document.body.removeChild(elink)
}).catch(function (error) {
console.log(error)
that.$Message.error('下载异常')
})
},
// 关闭
handleClose: function () {
this.handleReset()
this.modelIsOpen = false
},
// 文件大小限制的提示信息
handleMaxSize: function (file) {
this.$Message.error('文件 ' + file.name + ' 过大.')
},
// 上传前执行的校验
handleBeforeUpload: function (file) {
if (file.name.indexOf('.zip') === -1) {
this.$Message.warning({content: '只能上传zip文件', duration: 5})
return false
}
},
// 上传成功后的回调
handleUploadSuccess: function (response) {
if (response.error === 0) {
this.$Message.success('上传成功')
this.formItem.fileName = response.fileName
this.formItem.virtualFileName = response.virtualFileName
} else {
this.$Message.warning({content: response.message, duration: 5})
}
},
// 重置
handleReset () {
this.$refs['editTemplateForm'].resetFields()
}
}
}
</script>
以上。