图片上传服务业务流程
接口信息如下
返回结果VO
CourseCategoryTreeVO@Data @EqualsAndHashCode(callSuper = true) public class UploadFileResultVO extends MediaFiles {
}
|
参数DTO
UploadFileParamDTO@Data public class UploadFileParamDTO implements Serializable {
private static final long serialVersionUID = 1L;
private String filename;
private String fileType;
private Long fileSize;
private String tags;
private String username;
private String remark; }
|
定义Service
文件存储操作
定义上传媒体文件的方法,找到com.swx.media.service
包下的FileStorageService
接口,定义如下方法:
FileStorageService
public Map<String, String> uploadMediaFile(String prefix, String filename, String mineType, InputStream inputStream);
|
实现该方法
MinIOFileStorageServiceprivate final MinioClient minioClient; private final MinIOConfigProperties minIOConfigProperties;
public MinIOFileStorageService(MinioClient minioClient, MinIOConfigProperties minIOConfigProperties) { this.minioClient = minioClient; this.minIOConfigProperties = minIOConfigProperties; }
@Override public Map<String, String> uploadMediaFile(String prefix, String filename, String mineType, InputStream inputStream) { String filepath = builderFilePath(prefix, filename); String bucket = minIOConfigProperties.getBucket().get("files"); try { PutObjectArgs putObjectArgs = PutObjectArgs.builder() .object(filepath) .contentType(mineType) .bucket(bucket) .stream(inputStream, inputStream.available(), -1) .build(); minioClient.putObject(putObjectArgs); Map<String, String> map = new HashMap<>(); map.put("path", filepath); map.put("bucket", bucket); return map; } catch (Exception ex) { log.error("minio put file error.", ex); throw new RuntimeException("上传文件失败"); } }
|
文件上传方法
定义上传文件的方法,找到com.swx.media.service
包下的MediaFilesService
接口,定义如下方法:
MediaFilesServicepublic interface MediaFilesService extends IService<MediaFiles> {
public UploadFileResultVO uploadFile(Long companyId, UploadFileParamDTO dto, MultipartFile multipartFile);
public MediaFiles saveAfterStore(UploadFileParamDTO dto, Long companyId, String prefix, String bucket, String path); }
|
实现该方法:
@Slf4j @Service public class MediaFilesServiceImpl extends ServiceImpl<MediaFilesMapper, MediaFiles> implements MediaFilesService {
private final FileStorageService fileStorageService; private final TransactionTemplate transactionTemplate;
public MediaFilesServiceImpl(FileStorageService fileStorageService, TransactionTemplate transactionTemplate) { this.fileStorageService = fileStorageService; this.transactionTemplate = transactionTemplate; }
@Override public UploadFileResultVO uploadFile(Long companyId, UploadFileParamDTO dto, MultipartFile multipartFile) {
String filename = dto.getFilename(); String suffix = filename.substring(filename.lastIndexOf(".")); try { String prefix = getFileMd5(multipartFile.getInputStream()); MediaFiles dbMediaFile = getById(prefix); if (dbMediaFile != null) { UploadFileResultVO resultVO = new UploadFileResultVO(); BeanUtils.copyProperties(dbMediaFile, resultVO); return resultVO; } String mineType = getMineType(suffix); Map<String, String> result = fileStorageService.uploadMediaFile("", prefix + suffix, mineType, multipartFile.getInputStream()); String bucket = result.get("bucket"); String path = result.get("path");
MediaFiles mediaFiles = transactionTemplate.execute(transactionStatus -> { try { return saveAfterStore(dto, companyId, prefix, bucket, path); } catch (Exception e) { log.error("文件入库失败: ", e); transactionStatus.setRollbackOnly(); } return null; });
UploadFileResultVO resultVO = new UploadFileResultVO(); if (mediaFiles == null) return resultVO; BeanUtils.copyProperties(mediaFiles, resultVO); return resultVO; } catch (IOException e) { log.info("MediaFilesServiceImpl-上传文件失败", e); throw new BizException("文件上传失败"); } }
@Override public MediaFiles saveAfterStore(UploadFileParamDTO dto, Long companyId, String fileMd5, String bucket, String path) { MediaFiles mediaFiles = new MediaFiles(); BeanUtils.copyProperties(dto, mediaFiles); mediaFiles.setId(fileMd5); mediaFiles.setCompanyId(companyId); mediaFiles.setBucket(bucket); mediaFiles.setFilePath(path); mediaFiles.setFileId(fileMd5); mediaFiles.setUrl("/" + bucket + "/" + path); mediaFiles.setCreateDate(LocalDateTime.now()); mediaFiles.setStatus(MediaFileStatusEnum.NORMAL.status()); mediaFiles.setAuditStatus("002003"); boolean save = save(mediaFiles); if (!save) { log.error("想数据库保存文件失败,bucket: {},文件名: {}", bucket, path); return null; } return mediaFiles; }
private String getMineType(String suffix) { if (suffix == null) suffix = ""; ContentInfo extensionMatch = ContentInfoUtil.findExtensionMatch(suffix); String mimeType = MediaType.APPLICATION_OCTET_STREAM_VALUE; if (extensionMatch != null) { mimeType = extensionMatch.getMimeType(); } return mimeType; }
private String getFileMd5(InputStream inputStream) { try { return DigestUtils.md5DigestAsHex(inputStream); } catch (IOException e) { throw new RuntimeException(e); } } }
|
什么情况Spring事务会失效?
- 在方法中捕获异常没有抛出
- 非事务方法调用事务方法
- @Transactional标记的方法不是public
- 抛出的异常与rollbackFor指定的异常不匹配,默认rollbackFor指定的异常为RuntimeException
- 数据库不支持事务,比如MySQL的MyISAM
- Spring的传播行为导致事务失效,比如:PROPAGATION_NEVER、PROPAGATION_NOT_SUPPORTED
PROPAGATION_REQUIRED -- 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 PROPAGATION_SUPPORT -- 支持当前事务,如果当前没有事务,就以非事务方式执行。 PROPAGATION_MANDATORY -- 支持当前事务,如果当前没有事务,就抛出异常。 PROPAGATION_REQUIRES_NEW -- 新建事务,如果当前存在事务,把当前事务挂起。 PROPAGATION_NOT_SUPPORTED -- 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 PROPAGATION_NEVER -- 以非事务方式执行,如果当前存在事务,则抛出异常。 PROPAGATION_NESTED -- 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则与PROPAGATION_REQUIRED类似的操作。
|
分块文件清理问题?
上传一个文件进行分块上传,上传一半不传了,之前上传到minio的分块文件要清理吗? 怎么做的?
1、在数据库中有一张文件表记录minio中存储的文件信息。
2、文件开始上传时会亏入文件表,状志为上传中,上传完成会更新状态为上传成。
3、当一个文件传了一半不再上传了说明该文件没有上传完成,会有定时任务去查询文件表中的记录,如果文件末上传完成则删除minio中没有上传成功的文件目录。
定义Controller
MediaFilesUploadController
@Api(value = "媒资文件上传管理接口", tags = "媒资文件上传管理接口") @RestController @ResponseResult @RequestMapping("/upload") public class MediaFilesUploadController {
private final MediaFilesService mediaFilesService;
public MediaFilesUploadController(MediaFilesService mediaFilesService) { this.mediaFilesService = mediaFilesService; }
@ApiOperation("上传文件") @PostMapping(value = "/coursefile", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public UploadFileResultVO uploadImage(@RequestPart("filedata") MultipartFile filedata) { Long companyId = 1232141425L; UploadFileParamDTO dto = new UploadFileParamDTO(); dto.setFilename(filedata.getOriginalFilename()); dto.setFileSize(filedata.getSize()); dto.setFileType("001001"); return mediaFilesService.uploadFile(companyId, dto, filedata); } }
|
Push到Git