mirror of
https://gitee.com/anji-plus/report.git
synced 2026-02-02 09:27:47 +08:00
file
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
package com.anjiplus.template.gaea.business.modules.file.controller;
|
||||
|
||||
import com.anji.plus.gaea.bean.ResponseBean;
|
||||
import com.anji.plus.gaea.curd.service.GaeaBaseService;
|
||||
import com.anjiplus.template.gaea.business.base.BaseController;
|
||||
import com.anjiplus.template.gaea.business.modules.file.controller.dto.GaeaFileDTO;
|
||||
import com.anjiplus.template.gaea.business.modules.file.controller.param.GaeaFileParam;
|
||||
import com.anjiplus.template.gaea.business.modules.file.entity.GaeaFile;
|
||||
import com.anjiplus.template.gaea.business.modules.file.service.GaeaFileService;
|
||||
import io.swagger.annotations.Api;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* (GaeaFile)实体类
|
||||
*
|
||||
* @author peiyanni
|
||||
* @since 2021-02-18 14:48:33
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/file")
|
||||
@Api(value = "/file", tags = "")
|
||||
public class GaeaFileController extends BaseController<GaeaFileParam, GaeaFile, GaeaFileDTO> {
|
||||
@Autowired
|
||||
private GaeaFileService gaeaFileService;
|
||||
|
||||
@PostMapping("/upload")
|
||||
public ResponseBean upload(@RequestParam("file") MultipartFile file) {
|
||||
return ResponseBean.builder().message("success").data((gaeaFileService.upload(file))).build();
|
||||
}
|
||||
|
||||
@GetMapping(value = "/download/{fileId}")
|
||||
public ResponseEntity<byte[]> download(HttpServletRequest request, HttpServletResponse response, @PathVariable("fileId") String fileId) {
|
||||
return gaeaFileService.download(request, response, fileId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实际服务类
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public GaeaBaseService<GaeaFileParam, GaeaFile> getService() {
|
||||
return gaeaFileService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前Controller数据库实体Entity
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public GaeaFile getEntity() {
|
||||
return new GaeaFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前Controller数据传输DTO
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public GaeaFileDTO getDTO() {
|
||||
return new GaeaFileDTO();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.anjiplus.template.gaea.business.modules.file.controller.dto;
|
||||
|
||||
import com.anji.plus.gaea.curd.dto.GaeaBaseDTO;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
/**
|
||||
* (GaeaFile)实体类
|
||||
*
|
||||
* @author peiyanni
|
||||
* @since 2021-02-18 14:48:27
|
||||
*/
|
||||
@ApiModel(value = "")
|
||||
public class GaeaFileDTO extends GaeaBaseDTO {
|
||||
|
||||
/**
|
||||
* 文件uuid
|
||||
*/
|
||||
private String fileId;
|
||||
/**
|
||||
* 文件在linux中的完整目录,比如/app/dist/export/excel/${fileid}.xlsx
|
||||
*/
|
||||
@ApiModelProperty(value = "文件在linux中的完整目录,比如/app/dist/export/excel/${fileid}.xlsx")
|
||||
private String filePath;
|
||||
/**
|
||||
* 通过接口的下载完整http路径
|
||||
*/
|
||||
@ApiModelProperty(value = "通过接口的下载完整http路径")
|
||||
private String urlPath;
|
||||
/**
|
||||
* 文件内容说明,比如 对账单(202001~202012)
|
||||
*/
|
||||
@ApiModelProperty(value = "文件内容说明,比如 对账单(202001~202012)")
|
||||
private String fileInstruction;
|
||||
|
||||
public String getFilePath() {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
public void setFilePath(String filePath) {
|
||||
this.filePath = filePath;
|
||||
}
|
||||
|
||||
public String getUrlPath() {
|
||||
return urlPath;
|
||||
}
|
||||
|
||||
public void setUrlPath(String urlPath) {
|
||||
this.urlPath = urlPath;
|
||||
}
|
||||
|
||||
public String getFileInstruction() {
|
||||
return fileInstruction;
|
||||
}
|
||||
|
||||
public void setFileInstruction(String fileInstruction) {
|
||||
this.fileInstruction = fileInstruction;
|
||||
}
|
||||
|
||||
public String getFileId() {
|
||||
return fileId;
|
||||
}
|
||||
|
||||
public void setFileId(String fileId) {
|
||||
this.fileId = fileId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.anjiplus.template.gaea.business.modules.file.controller.param;
|
||||
|
||||
|
||||
import com.anji.plus.gaea.annotation.Query;
|
||||
import com.anji.plus.gaea.constant.QueryEnum;
|
||||
import com.anji.plus.gaea.curd.params.PageParam;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* (GaeaFile)param
|
||||
*
|
||||
* @author peiyanni
|
||||
* @since 2021-02-18 14:48:29
|
||||
*/
|
||||
public class GaeaFileParam extends PageParam implements Serializable {
|
||||
|
||||
/**
|
||||
* 文件在linux中的完整目录,比如/app/dist/export/excel/${fileid}.xlsx
|
||||
*/
|
||||
@Query(QueryEnum.LIKE)
|
||||
private String filePath;
|
||||
|
||||
public String getFilePath() {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
public void setFilePath(String filePath) {
|
||||
this.filePath = filePath;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.anjiplus.template.gaea.business.modules.file.dao;
|
||||
|
||||
import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper;
|
||||
import com.anjiplus.template.gaea.business.modules.file.entity.GaeaFile;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* (GaeaFile)Mapper
|
||||
*
|
||||
* @author peiyanni
|
||||
* @since 2021-02-18 14:48:24
|
||||
*/
|
||||
@Mapper
|
||||
public interface GaeaFileMapper extends GaeaBaseMapper<GaeaFile> {
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.anjiplus.template.gaea.business.modules.file.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.anji.plus.gaea.curd.entity.GaeaBaseEntity;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* (GaeaFile)实体类
|
||||
*
|
||||
* @author peiyanni
|
||||
* @since 2021-02-18 14:48:20
|
||||
*/
|
||||
@TableName("gaea_file")
|
||||
public class GaeaFile extends GaeaBaseEntity implements Serializable {
|
||||
|
||||
/**
|
||||
* 文件uuid
|
||||
*/
|
||||
private String fileId;
|
||||
/**
|
||||
* 文件在linux中的完整目录,比如/app/dist/export/excel/${fileid}.xlsx
|
||||
*/
|
||||
private String filePath;
|
||||
/**
|
||||
* 通过接口的下载完整http路径
|
||||
*/
|
||||
private String urlPath;
|
||||
/**
|
||||
* 文件内容说明,比如 对账单(202001~202012)
|
||||
*/
|
||||
private String fileInstruction;
|
||||
|
||||
public String getFilePath() {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
public void setFilePath(String filePath) {
|
||||
this.filePath = filePath;
|
||||
}
|
||||
|
||||
public String getUrlPath() {
|
||||
return urlPath;
|
||||
}
|
||||
|
||||
public void setUrlPath(String urlPath) {
|
||||
this.urlPath = urlPath;
|
||||
}
|
||||
|
||||
public String getFileInstruction() {
|
||||
return fileInstruction;
|
||||
}
|
||||
|
||||
public void setFileInstruction(String fileInstruction) {
|
||||
this.fileInstruction = fileInstruction;
|
||||
}
|
||||
|
||||
public String getFileId() {
|
||||
return fileId;
|
||||
}
|
||||
|
||||
public void setFileId(String fileId) {
|
||||
this.fileId = fileId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.anjiplus.template.gaea.business.modules.file.service;
|
||||
|
||||
import com.anji.plus.gaea.curd.service.GaeaBaseService;
|
||||
import com.anjiplus.template.gaea.business.modules.file.entity.GaeaFile;
|
||||
import com.anjiplus.template.gaea.business.modules.file.controller.param.GaeaFileParam;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* (GaeaFile)Service
|
||||
*
|
||||
* @author peiyanni
|
||||
* @since 2021-02-18 14:48:25
|
||||
*/
|
||||
public interface GaeaFileService extends GaeaBaseService<GaeaFileParam, GaeaFile> {
|
||||
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
*
|
||||
* @param file
|
||||
* @return 文件访问路径
|
||||
*/
|
||||
String upload(MultipartFile file);
|
||||
|
||||
/**
|
||||
* 根据fileId显示图片或者下载文件
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param fileId
|
||||
* @return
|
||||
*/
|
||||
ResponseEntity<byte[]> download(HttpServletRequest request, HttpServletResponse response, String fileId);
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
package com.anjiplus.template.gaea.business.modules.file.service.impl;
|
||||
|
||||
import com.anji.plus.gaea.constant.BaseOperationEnum;
|
||||
import com.anji.plus.gaea.exception.BusinessException;
|
||||
import com.anjiplus.template.gaea.business.modules.file.dao.GaeaFileMapper;
|
||||
import com.anjiplus.template.gaea.business.modules.file.entity.GaeaFile;
|
||||
import com.anjiplus.template.gaea.business.modules.file.service.GaeaFileService;
|
||||
import com.anjiplus.template.gaea.business.modules.export.dao.GaeaExportMapper;
|
||||
import com.anjiplus.template.gaea.business.modules.export.dao.entity.GaeaExport;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.anjiplus.template.gaea.common.RespCommonCode;
|
||||
import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper;
|
||||
import com.anji.plus.gaea.exception.BusinessExceptionBuilder;
|
||||
import com.anjiplus.template.gaea.common.util.StringPatternUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.CacheControl;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.interceptor.TransactionAspectSupport;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* (GaeaFile)ServiceImpl
|
||||
*
|
||||
* @author peiyanni
|
||||
* @since 2021-02-18 14:48:26
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class GaeaFileServiceImpl implements GaeaFileService {
|
||||
|
||||
@Value("${file.dist-path:''}")
|
||||
private String dictPath;
|
||||
|
||||
@Value("${file.white-list:''}")
|
||||
private String whiteList;
|
||||
|
||||
@Value("${file.excelSuffix:''}")
|
||||
private String excelSuffix;
|
||||
|
||||
@Value("${file.downloadPath:''}")
|
||||
private String fileDownloadPath;
|
||||
|
||||
@Autowired
|
||||
private GaeaFileMapper gaeaFileMapper;
|
||||
@Autowired
|
||||
private GaeaExportMapper gaeaExportMapper;
|
||||
|
||||
@Override
|
||||
public GaeaBaseMapper<GaeaFile> getMapper() {
|
||||
return gaeaFileMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public String upload(MultipartFile file) {
|
||||
try {
|
||||
String fileName = file.getOriginalFilename();
|
||||
if (StringUtils.isBlank(fileName)) {
|
||||
throw BusinessExceptionBuilder.build(RespCommonCode.FILE_EMPTY_FILENAME);
|
||||
}
|
||||
String suffixName = fileName.substring(fileName.lastIndexOf("."));
|
||||
//白名单校验(不区分大小写)
|
||||
List<String> list = new ArrayList<String>(Arrays.asList(whiteList.split("\\|")));
|
||||
list.addAll(list.stream().map(String::toUpperCase).collect(Collectors.toList()));
|
||||
if (!list.contains(suffixName)) {
|
||||
throw BusinessExceptionBuilder.build(RespCommonCode.FILE_SUFFIX_UNSUPPORTED);
|
||||
}
|
||||
// 生成文件唯一性标识
|
||||
String fileId = UUID.randomUUID().toString();
|
||||
String newFileName = fileId + suffixName;
|
||||
// 本地文件保存路径
|
||||
String filePath = dictPath + newFileName;
|
||||
String urlPath = fileDownloadPath + File.separator + fileId;
|
||||
|
||||
GaeaFile gaeaFile = new GaeaFile();
|
||||
gaeaFile.setFilePath(filePath);
|
||||
gaeaFile.setFileId(fileId);
|
||||
gaeaFile.setUrlPath(urlPath);
|
||||
gaeaFileMapper.insert(gaeaFile);
|
||||
|
||||
//写文件 将文件保存/app/dictPath/upload/下
|
||||
File dest = new File(dictPath + newFileName);
|
||||
file.transferTo(dest);
|
||||
// 将完整的http访问路径返回
|
||||
return urlPath;
|
||||
} catch (Exception e) {
|
||||
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
|
||||
log.error("file upload error: {}", e);
|
||||
throw BusinessExceptionBuilder.build(RespCommonCode.FILE_UPLOAD_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<byte[]> download(HttpServletRequest request, HttpServletResponse response, String fileId) {
|
||||
try {
|
||||
String userAgent = request.getHeader("User-Agent");
|
||||
boolean isIEBrowser = userAgent.indexOf("MSIE") > 0;
|
||||
//根据fileId,从gaea_file中读出filePath
|
||||
LambdaQueryWrapper<GaeaFile> queryWrapper = Wrappers.lambdaQuery();
|
||||
queryWrapper.eq(GaeaFile::getFileId, fileId);
|
||||
GaeaFile gaeaFile = gaeaFileMapper.selectOne(queryWrapper);
|
||||
if (null == gaeaFile) {
|
||||
throw BusinessExceptionBuilder.build(RespCommonCode.FILE_ONT_EXSIT);
|
||||
}
|
||||
//解析文件路径、文件名和后缀
|
||||
String filePath = gaeaFile.getFilePath();
|
||||
if (StringUtils.isBlank(filePath)) {
|
||||
throw BusinessExceptionBuilder.build(RespCommonCode.FILE_ONT_EXSIT);
|
||||
}
|
||||
String filename = filePath.substring(filePath.lastIndexOf(File.separator));
|
||||
String fileSuffix = filename.substring(filename.lastIndexOf("."));
|
||||
//特殊处理:如果是excel文件,则从t_export表中查询文件名
|
||||
List list = Arrays.asList(excelSuffix.split("\\|"));
|
||||
if (list.contains(fileSuffix)) {
|
||||
LambdaQueryWrapper<GaeaExport> exportWrapper = Wrappers.lambdaQuery();
|
||||
exportWrapper.eq(GaeaExport::getFileId, fileId);
|
||||
GaeaExport exportPO = gaeaExportMapper.selectOne(exportWrapper);
|
||||
if (null != exportPO) {
|
||||
filename = exportPO.getFileTitle() + fileSuffix;
|
||||
}
|
||||
}
|
||||
//根据文件后缀来判断,是显示图片\视频\音频,还是下载文件
|
||||
File file = new File(filePath);
|
||||
ResponseEntity.BodyBuilder builder = ResponseEntity.ok();
|
||||
builder.contentLength(file.length());
|
||||
if (StringPatternUtil.StringMatchIgnoreCase(fileSuffix, "(.png|.jpg|.jpeg|.bmp|.gif|.icon)")) {
|
||||
builder.cacheControl(CacheControl.noCache()).contentType(MediaType.IMAGE_PNG);
|
||||
} else if (StringPatternUtil.StringMatchIgnoreCase(fileSuffix, "(.flv|.swf|.mkv|.avi|.rm|.rmvb|.mpeg|.mpg|.ogg|.ogv|.mov|.wmv|.mp4|.webm|.wav|.mid|.mp3|.aac)")) {
|
||||
builder.header("Content-Type", "video/mp4; charset=UTF-8");
|
||||
} else {
|
||||
//application/octet-stream 二进制数据流(最常见的文件下载)
|
||||
builder.contentType(MediaType.APPLICATION_OCTET_STREAM);
|
||||
filename = URLEncoder.encode(filename, "UTF-8");
|
||||
if (isIEBrowser) {
|
||||
builder.header("Content-Disposition", "attachment; filename=" + filename);
|
||||
} else {
|
||||
builder.header("Content-Disposition", "attacher; filename*=UTF-8''" + filename);
|
||||
}
|
||||
}
|
||||
return builder.body(FileUtils.readFileToByteArray(file));
|
||||
} catch (Exception e) {
|
||||
log.error("file download error: {}", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批处理操作后续处理
|
||||
* 删除本地已经存在的文件
|
||||
*
|
||||
* @param entities
|
||||
* @param operationEnum 操作类型
|
||||
* @throws BusinessException 阻止程序继续执行或回滚事务
|
||||
*/
|
||||
@Override
|
||||
public void processBatchAfterOperation(List<GaeaFile> entities, BaseOperationEnum operationEnum) throws BusinessException {
|
||||
if (operationEnum.equals(BaseOperationEnum.DELETE_BATCH)) {
|
||||
// 删除本地文件
|
||||
entities.forEach(gaeaFile -> {
|
||||
String filePath = gaeaFile.getFilePath();
|
||||
File file = new File(filePath);
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user