文件上传与文件下载
在开发中项目难免会遇到文件上传和下载的情况,如果公司有部署文件服务器是再好不过啦,直接调用文件服务器上传和下载的接口,保留返回的文件id即可。
但是如果公司没有文件服务器就比较苦逼了,得手写文件上传和下载的接口把文件存储在服务器的某个位置,以便使用。
直接把代码贴出来以供记录笔记。
首先配置文件定义服务器文件存储路径
uploadfile.extendedstorageperiod.path=/home/szfmimp/uploadfiles/extendedstorageperiod
uploadfile.wzk.path=/home/szfmimp/uploadfiles/wzk
uploadfile.annualappraisal.path=/home/szfmimp/uploadfiles/annualappraisal
uploadfile.emergencydrill.path=/home/szfmimp/uploadfiles/emergencydrill
uploadfile.wzkreservegoal.path=/home/szfmimp/uploadfiles/wzkreservegoal
类似于这样,自己定义路径,这里仅做展示用。
然后定义文件类型枚举,自定义文件支持格式及大小
@Getter
@AllArgsConstructor
public enum FileTypeEnum {
/**
*
*/
INSPECTION_PLAN_ZMWJ("inspection_plan_zmwj", Collections.singletonList("pdf"), 40L, "uploadfile.inspectionplan.path"),
/**
*
*/
INSPECTION_PLAN_ZMCL("inspection_plan_jczmcl", Arrays.asList("jpg", "png", "doc", "docx", "xls", "xlsx", "pdf"), 10L, "uploadfile.inspectionplan.path"),
/**
*
*/
INSPECTION_PLAN_FJXX("inspection_plan_wjxx", Arrays.asList("jpg", "doc", "docx", "xls", "xlsx", "pdf"), 10L, "uploadfile.inspectionplan.path"),
/**
*
*/
USER_FEEDBACK_MECHANISM("user_feedback_cl", Arrays.asList("jpg", "png", "doc", "docx", "xls", "xlsx", "pdf"), 10L, "uploadfile.userfeedback.path"),
/**
*
*/
T_STOCK_AlARM("T_STOCK_AlARM", Arrays.asList("jpg", "png", "doc", "docx", "xls", "xlsx", "pdf"), 10L, "uploadfile.extendedstorageperiod.path"),
/**
*
*/
EXTENDED_STORAGE_PERIOD("extended_storage_period", Arrays.asList("doc", "docx", "xls", "xlsx", "pdf", "zip"), 10L, "uploadfile.extendedstorageperiod.path"),
/**
*
*/
WZK("wzk", Arrays.asList("doc", "docx", "xls", "xlsx", "pdf", "png", "jpg"), 10L, "uploadfile.wzk.path"),
/**
*
*/
ANNUAL_APPRAISAL("annual_appraisal", Arrays.asList("doc", "docx", "xls", "xlsx", "pdf", "png", "jpg"), 10L, "uploadfile.annualappraisal.path"),
/**
*
*/
WZK_RESERVE_GOAL("wzk_reserve_goal", Arrays.asList("doc", "docx", "xls", "xlsx", "pdf", "png", "jpg"), 10L, "uploadfile.wzkreservegoal.path"),
/**
*
*/
emergency_drill("emergency_drill", Arrays.asList("jpg", "png", "pdf", "zip"), 30L, "uploadfile.emergencydrill.path");
/**
* 枚举值
*/
private final String value;
/**
* 允许上传的文件类型
*/
private final List<String> fileTypes;
/**
* 最大文件大小(单位:M)
*/
private final Long fileSize;
/**
* 文件保存路径
*/
private final String savePath;
public static FileTypeEnum getByValue(String value) {
for (FileTypeEnum fileTypeEnum : FileTypeEnum.values()) {
if (fileTypeEnum.value.equals(value)) {
return fileTypeEnum;
}
}
return null;
}
}
然后controller层
@Resource
private FileService fileService;
//从配置文件读取保存路径
@Autowired
private Environment environment;
@ApiOperation(value = "文件上传")
@PostMapping("/uploadFile/{fileType}")
public SwaggerAjaxResult<FileVO> uploadFile(@RequestParam("file") MultipartFile file, @PathVariable String fileType) {
FileTypeEnum fileTypeEnum = FileTypeEnum.getByValue(fileType);
if (fileTypeEnum == null) {
return SwaggerAjaxResult.error(null, "文件类型错误");
}
String savePath = environment.getProperty(fileTypeEnum.getSavePath());
if (StringUtils.isBlank(savePath)) {
return SwaggerAjaxResult.error(null, "未找到文件存储路径");
}
return SwaggerAjaxResult.success(fileService.saveFile(file, fileTypeEnum.getFileTypes(), savePath, fileTypeEnum.getFileSize()));
}
然后服务层
@Override
public FileVO saveFile(MultipartFile uploadFile, List<String> fileTypeList, String savePath, long fileSize) {
log.info("============== 保存上传文件接口 start ==============");
log.info("上传文件保存的路径为:{}", savePath);
Set<String> fileTypeSet = new HashSet<>(fileTypeList);
log.info("上传文件允许的类型为:{}", JSONUtil.toJsonStr(fileTypeSet));
Assert.isTrue(!uploadFile.isEmpty(), "文件不能为空");
long uploadFileSize = uploadFile.getSize();
if (uploadFileSize > (fileSize * 1024 * 1024)) {
log.info("上传文件的大小超过允许上传的大小");
Assert.isTrue(false, "上传文件的大小超过允许上传的大小:" + fileSize + "M");
}
String fileName = uploadFile.getOriginalFilename();
log.info("上传文件的文件名为:{}", fileName);
Assert.isTrue(StringUtils.isNotEmpty(fileName), "上传文件的名称不能为空");
Assert.isTrue(fileName.length() <= 50, "上传文件名的长度不能超过50");
String suffix = fileName.substring(fileName.lastIndexOf('.'));
Assert.isTrue(suffix.length() > 1, "上传文件的扩展名为空");
String extName = suffix.substring(1);
log.info("上传文件的扩展名为:{}", extName);
// 先判断文件名的扩展名是否符合要求
Assert.isTrue(fileTypeSet.contains(extName), "上传的文件类型不允许,上传失败");
String type = "";
try {
// 再根据文件流的头部信息获得文件类型
type = FileTypeUtil.getType(uploadFile.getInputStream(), fileName);
} catch (IOException e) {
log.error(e.getMessage(), e);
}
// 如果允许上传的文件类型包含docx和xlsx,fileTypeSet添加zip类型
// 因为xlsx、docx本质上是各种XML打包为zip的结果,因此会被识别为zip格式
if (fileTypeSet.contains("docx") || fileTypeSet.contains("xlsx")) {
fileTypeSet.add("zip");
}
// 判断根据文件流的头部信息获得的文件类型是否符合要求
Assert.isTrue(fileTypeSet.contains(type), "上传文件的真实文件类型不是允许上传的文件类型,上传失败");
String id = SecureUtil.md5(fileName + System.currentTimeMillis());
String saveName = id + suffix;
log.info("上传文件保存的文件名为:{}", saveName);
Assert.isTrue(StringUtils.isNotEmpty(savePath), "文件保存路径不能为空");
String today = DateUtil.format(new Date(), "yyyy-MM-dd");
String fileLink = savePath + File.separator + today + File.separator + saveName;
InputStream inputStream = null;
OutputStream outputStream = null;
try {
log.info("保存上传附件的路径:{}", fileLink);
File targetFile = new File(fileLink);
if (!targetFile.getParentFile().exists()) {
targetFile.getParentFile().mkdirs();
}
inputStream = uploadFile.getInputStream();
outputStream = new FileOutputStream(targetFile);
FileCopyUtils.copy(inputStream, outputStream);
} catch (IOException e) {
log.error(e.getMessage(), e);
throw new RuntimeException("保存上传附件出错,错误原因:" + e.getMessage());
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
}
TFile entity = new TFile();
Date date = new Date();
entity.setId(id);
entity.setFileName(fileName);
entity.setSaveName(saveName);
entity.setSavePath(savePath);
entity.setFileLink(fileLink);
entity.setExtName(extName);
SysUser sysUser = tenantService.getLoginUser().getSysUser();
entity.setCreateBy(sysUser.getNickName());
entity.setCreateTime(date);
log.info("保存上传文件的记录:{}", JSONUtil.toJsonStr(entity));
save(entity);
FileVO vo = new FileVO();
vo.setId(id);
vo.setFileName(fileName);
vo.setCreateTime(date);
vo.setCreateBy(sysUser.getNickName());
log.info("上传文件保存成功");
log.info("============== 保存上传文件接口 end ==============");
return vo;
}
注:需要注意的是 获取完整文件路径方法中的 uploadFilePath :是文件将要保存在服务器中的位置路径,可以在配置文件中配置好后引用。最后把返回的信息存在在表中使用。整个文件上传就完成了。其中用到了hutool的第三方包我使用的版本为5.8.6
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<version>5.8.6</version>
</dependency>
<!--io常用工具类 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
文件下载
这个就没有什么好说的了,比较简单,就是流的操作而已。传入的参数为文件上传是保存的文件的id即可。
@ApiOperation(value = "通过文件id下载文件")
@PostMapping("/downloadById")
public void downloadFileById(HttpServletRequest request, HttpServletResponse response, @RequestBody @Valid IdDTO idDTO) {
String id = idDTO.getId();
Assert.isTrue(StringUtils.isNotEmpty(id), "主表id不能为空");
TFile tFile = fileService.getById(id);
Assert.notNull(tFile, "要下载的文件不存在");
String fileName = tFile.getFileName();
request.getSession();
//获取页面输出流
try (ServletOutputStream out = response.getOutputStream()) {
String path = tFile.getFileLink();
File file = new File(path);
byte[] bytes = FileUtils.readFileToByteArray(file);
// 设置响应头
response.setHeader("Content-Disposition", "attachment;filename=\"" + fileName + "\"");
response.addHeader("Pargam", "no-cache");
response.addHeader("Cache-Control", "no-cache");
out.write(bytes);
out.flush();
} catch (IOException e) {
log.error(e.getMessage());
throw new RuntimeException("下载文件出错");
}
}
学习笔记仅供参考!
文章详细介绍了在Java中如何实现文件上传和下载的功能。当有文件服务器时,可以直接调用接口,否则需手动编写上传和下载接口,将文件存储在服务器指定路径。文中提供了Controller和Service层的代码示例,利用Hutool库处理文件流,并强调了文件路径配置和下载时的响应头设置。
3309

被折叠的 条评论
为什么被折叠?



