接收文件(文件上传)

前端的请求内容

Content-Type: multipart/form-data;

form-data; name="filedata"; filename="具体的文件名称"

后端定义接口

    @ApiOperation("文件上传接口")@RequestMapping(value = "/upload/coursefile", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)public UploadFileResultDto upload(@RequestPart("filedata") MultipartFile multipartFile){Long companyId=2L;try {//创建临时文件File tempFile = tempFile = File.createTempFile("minio", "temp");//上传的文件拷贝到临时文件multipartFile.transferTo(tempFile);UploadFileParamsDto uploadFileParamsDto = new UploadFileParamsDto();uploadFileParamsDto.setFilename(multipartFile.getOriginalFilename());uploadFileParamsDto.setFileSize(multipartFile.getSize());uploadFileParamsDto.setFileType("001001");String absolutePath = tempFile.getAbsolutePath();UploadFileResultDto uploadFileResultDto =                                 mediaFileService.uploadFile(companyId, uploadFileParamsDto, absolutePath);return  uploadFileResultDto;} catch (IOException e) {e.printStackTrace();}return null;}

 使用minio来完成业务逻辑

minio介绍: 

分布式文件系统minio-CSDN博客

获取文件默认目录名 

//获取文件默认目录名private String getDefaultFolderPath(){//根据时间来生产存储目录LocalDate now = LocalDate.now();String defaultFolderPath = now.toString().replaceAll("-", "/")+"/";return defaultFolderPath;}

获取文件md5值 

//获取文件md5值private  String getFileMd5(File file){try {FileInputStream fileInputStream = new FileInputStream(file);String md5 = DigestUtils.md5Hex(fileInputStream);return md5;} catch (Exception e) {e.printStackTrace();return null;}}

 根据扩展名来获取文件类型

private  String getMimeType(String extension){if(extension==null)extension = "";//根据扩展名取出mimeTypeContentInfo extensionMatch = ContentInfoUtil.findExtensionMatch(extension);//通用mimeType,字节流String mimeType = MediaType.APPLICATION_OCTET_STREAM_VALUE;if(extensionMatch!=null){mimeType = extensionMatch.getMimeType();}return mimeType;}

上传到数据库

  /*** @description 将文件信息添加到文件表* @param companyId  机构id* @param fileMd5  文件md5值* @param uploadFileParamsDto  上传文件的信息* @param bucket  桶* @param objectName 对象名称* @return com.xuecheng.media.model.po.MediaFiles* @author Mr.M* @date 2022/10/12 21:22*/@Transactionalpublic MediaFiles addMediaFilesToDb(Long companyId,String fileMd5,QueryMediaParamsDto uploadFileParamsDto,String bucket,String objectName){//从数据库查询文件MediaFiles mediaFiles = mediaFilesMapper.selectById(fileMd5);if (mediaFiles == null) {mediaFiles = new MediaFiles();//拷贝基本信息BeanUtils.copyProperties(uploadFileParamsDto, mediaFiles);mediaFiles.setId(fileMd5);mediaFiles.setFileId(fileMd5);mediaFiles.setCompanyId(companyId);mediaFiles.setUrl("/" + bucket + "/" + objectName);mediaFiles.setBucket(bucket);mediaFiles.setFilePath(objectName);mediaFiles.setCreateDate(LocalDateTime.now());mediaFiles.setAuditStatus("002003");mediaFiles.setStatus("1");//保存文件信息到文件表int insert = mediaFilesMapper.insert(mediaFiles);if (insert < 0) {log.error("保存文件信息到数据库失败,{}",mediaFiles.toString());XueChengPlusException.cast("保存文件信息失败");}log.debug("保存文件信息到数据库成功,{}",mediaFiles.toString());}return mediaFiles;}

service:

 @AutowiredMediaFilesMapper mediaFilesMapper;//普通文件桶@Value("${minio.bucket.files}")String bucket_Files;@AutowiredMinioClient minioClient;/*** 普通文件上传* @param companyId 机构id* @param queryMediaParamsDto 上传文件信息* @param localFilePath 文件磁盘路径* @return*/@Overridepublic UploadFileResultDto uploadFile(Long companyId, QueryMediaParamsDto queryMediaParamsDto, String localFilePath) {//根据文件路径获取文件对象File file = new File(localFilePath);if (file==null){XueChengPlusException.cast("文件不存在");}//获取文件名称String filename = queryMediaParamsDto.getFilename();//获取文件拓展名String extension = filename.substring(filename.lastIndexOf("."));//获取默认存储目录String defaultFolderPath = getDefaultFolderPath();//获取文件的md5值String fileMd5 = getFileMd5(file);//获取文件类型String mimeType = getMimeType(extension);//存储到minio中的对象名(带目录)String objectName = defaultFolderPath+fileMd5+extension;//上传到miniotry {UploadObjectArgs uploadObjectArgs = UploadObjectArgs.builder().bucket(bucket_Files).object(objectName)//添加子目录.filename(localFilePath).contentType(mimeType)//默认根据扩展名确定文件内容类型,也可以指定.build();minioClient.uploadObject(uploadObjectArgs);log.debug("上传文件到minio成功,bucket:{},objectName:{}",bucket_Files,objectName);} catch (Exception e) {e.printStackTrace();log.error("上传文件到minio出错,bucket:{},objectName:{},错误原因:{}",bucket_Files,objectName,e.getMessage(),e);XueChengPlusException.cast("上传文件到文件系统失败");}//将信息存储到数据库中MediaFiles mediaFiles = addMediaFilesToDb(companyId, fileMd5, queryMediaParamsDto, bucket_Files, objectName);UploadFileResultDto uploadFileResultDto = new UploadFileResultDto();BeanUtils.copyProperties(mediaFiles,uploadFileResultDto);return uploadFileResultDto;}

事务控制优化

在测试中我发现addMediaFilesToDb上加的事务控制失效了:

当一个非事务方法调用同一个类中的事务方法时,事务无法按预期控制的原因通常与事务管理器的代理机制有关。在Spring框架中,事务管理通常是通过AOP(面向切面编程)实现的,这意味着事务是通过动态代理来控制的。

具体来说,Spring使用@TransactionInterceptor来拦截对事务方法的调用,并在方法执行前后添加事务管理的逻辑。但是,这种代理通常只会在外部类(或Spring容器外部)对目标方法进行调用时生效。如果同一个类中的非事务方法直接调用事务方法,那么代理机制不会被触发,因为内部调用会绕过Spring容器注入的代理对象,直接调用目标对象的实例方法。

 总结:当使用代理对象时@TransactionInterceptor才会进行事务

解决方法:

将事务方法移动到一个不同的Spring Bean中,并确保从原始Bean中通过Spring容器注入该Bean的引用。这样,当原始Bean中的非事务方法调用该Bean的事务方法时,Spring的代理机制将被触发,从而应用事务管理。

将bean注入进来,保证事务方法由代理对象来执行

 @AutowiredMediaFileService currentProxy;

 把addMediaFilesToDb提到接口中

 

public MediaFiles addMediaFilesToDb
(Long companyId, String fileMd5, UploadFileParamsDto uploadFileParamsDto, String bucket, String objectName);

 修改serviceimpl

MediaFiles mediaFiles = 
currentProxy.addMediaFilesToDb(companyId, fileMd5, uploadFileParamsDto, bucket_files, objectName);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/832724.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

发挥企业力量,美乐家推动城市绿色发展

在当今时代&#xff0c;环保已成为衡量企业社会责任的重要标准之一。美乐家作为一个具有前瞻性的企业&#xff0c;深刻理解到这一点&#xff0c;并通过其行动积极展示了这种责任感。通过与中华环境保护基金会合作&#xff0c;美乐家开始全国范围内推动了“微行动&#xff0c;守…

C语言 | Leetcode C语言题解之第74题搜索二维矩阵

题目&#xff1a; 题解&#xff1a; bool searchMatrix(int** matrix, int matrixSize, int* matrixColSize, int target) {int m matrixSize, n matrixColSize[0];int low 0, high m * n - 1;while (low < high) {int mid (high - low) / 2 low;int x matrix[mid /…

等保测评—Linux-CentOS标准范例截图

密码输入错误无法登录 用户账户情况包含root、guanli、shenji 查看审计用户权限 身份鉴别&#xff1a; cat /etc/passwd&#xff0c;核查用户名和 UID&#xff0c;是否存在同样的用户名和 UID cat /etc/shadow&#xff0c;查看文件中各用户名状态 &#xff0c; 核查密码一栏为…

Springboot工程创建

目录 一、步骤 二、遇到的问题及解决方案 一、步骤 打开idea,点击文件 ->新建 ->新模块 选择Spring Initializr&#xff0c;并设置相关信息。其中组为域名&#xff0c;如果没有公司&#xff0c;可以默认com.example。点击下一步 蓝色方框部分需要去掉&#xff0c;软件包…

Win11安装Docker Desktop运行Oracle 11g 【详细版】

oracle docker版本安装教程 步骤拉取镜像运行镜像进入数据库配置连接数据库&#xff0c;修改密码Navicat连接数据库 步骤 拉取镜像 docker pull registry.cn-hangzhou.aliyuncs.com/helowin/oracle_11g运行镜像 docker run -d -p 1521:1521 --name oracle11g registry.cn-ha…

MySQL动态列转行

介绍​​ 在实际的数据库查询中&#xff0c;有时候我们需要将表中的动态列&#xff08;即列数不固定&#xff09;转换为行&#xff0c;以便更好地进行数据分析和展示。在MySQL中&#xff0c;可以通过使用一些技巧和函数来实现动态列转行的功能。本文将介绍怎么实现MySQL动态列…

延时任务通知服务的设计及实现(三)-- JDK的延迟队列DelayQueue

一、接着上文 上文我们讲述了使用redisson的RDelayedQueue实现分布式延迟队列&#xff0c;本文我们将自己JDK的延迟队列DelayQueue实现。 相比前者的实现&#xff0c;作为进程内的延迟队列&#xff0c;它会遇到许多技术难点&#xff1a; 如何支持分布式的多个节点部署场景应…

Game Theory In Competitive Programming|Part2(原创)

在上一个Part部分&#xff0c;我们介绍了Bash game、Nim game、Misere Nim game 这三个游戏的玩法、必胜策略&#xff0c;以及必胜策略的证明&#xff0c;并介绍了有关必胜态以及必败态的两条定理&#xff0c;接下来我们会以Part1为基础&#xff0c;深挖其中的理论。 文章目录 …

【Oracle直播课】5月19日Oracle 19c OCM认证大师课 (附课件预览)

Oracle 19c OCM认证大师培训 - 课程体系 - 云贝教育 (yunbee.net) 部分课件预览 OCM部分课件预览 Oracle Database 19c Certified Master Exam (OCM) 认证大师 25 天 / 150课时 什么是Oracle 19c OCM&#xff1f; Oracle Certified Master (OCM)是Oracle认证大师&#xff0c;…

如何使用 iOS系统恢复软件修复 iPhone 问题

苹果公司向世界推出了他们可以拥有的最智能的手机。但即使是 iPhone 也无法避免智能手机常见的损坏和问题。您将熟悉最常见的问题。屏幕黑屏或卡在 Apple 徽标上&#xff1b;冻结或卡在恢复模式的 iPhone。但这样的问题不胜枚举&#xff0c;每天都有 iOS 用户在他们的设备中遇到…

利用傅里叶变换公式理解camera raw中的纹理和清晰度的概念(可惜的是camera raw的计算公式应该不会是这个傅里叶变换,只能说类似于这里的效果)

知乎说&#xff1a;在Adobe官方的解释中&#xff0c;就像图片可以分解成彩色通道&#xff08;如&#xff1a;红绿蓝通道&#xff09;&#xff0c;同样的&#xff0c;图片也可以分解成不同的频率&#xff0c;一张图片可以是由高频&#xff0c;中频和低频组成&#xff0c;例如&am…

VALSE 2024年度进展评述内容分享-视觉基础大模型的进展

2024年视觉与学习青年学者研讨会&#xff08;VALSE 2024&#xff09;于5月5日到7日在重庆悦来国际会议中心举行。本公众号将全方位地对会议的热点进行报道&#xff0c;方便广大读者跟踪和了解人工智能的前沿理论和技术。欢迎广大读者对文章进行关注、阅读和转发。文章是对报告人…

docker安装redis命令及运行

docker安装redis&#xff1a; docker run -d -p 6379:6379 --name redis redis:latest -d: 以 守护进程模式 运行容器&#xff0c;容器启动后会进入后台运行&#xff0c;并脱离当前命令行会话。 -p: 显示端口号。 -p 6379:6379: 将容器内部的 6379 端口映射到宿主机 6379 端…

Redis学习3——Redis应用之缓存

引言 缓存的意义 Redis作为一个NoSql数据库&#xff0c;被广泛的当作缓存数据库使用&#xff0c;所谓缓存&#xff0c;就是数据交换的缓冲区。使用缓存的具体原因有&#xff1a; 缓存数据存储于代码中&#xff0c;而代码运行在内存中&#xff0c;内存的读写性能远高于磁盘&a…

2024年第十三届工程与创新材料国际会议(ICEIM 2024)即将召开!

2024年第十三届工程与创新材料国际会议&#xff08;ICEIM 2024&#xff09;将于2024年9月6-8日在日本东京举行。ICEIM 2024由东京电机大学主办&#xff0c;会议旨在材料科学与工程、材料特性、测量方法和应用等相关领域进行学术交流与合作&#xff0c;在材料的微观世界里&#…

npm install 及使用cordova打包常见错误大全(附解决方案)

问题1、cb() 这是我们在install过程中最最常见问题&#xff0c;网络上的解决方式也都是大同小异&#xff0c;要么就是升级node(误人子弟)&#xff0c;项目里的node是不可以随意升级的&#xff0c;它有可能会导致其他依赖又不适配&#xff0c;起始很多时候就是由于咱们配置的镜像…

【docker】常用的Docker编排和调度平台

常用的Docker编排和调度平台 Kubernetes (K8s): Kubernetes是目前市场上最流行和功能最全面的容器编排和调度平台。它由Google开发并开源&#xff0c;现由CNCF&#xff08;云原生计算基金会&#xff09;维护。Kubernetes设计用于自动化容器部署、扩展和管理&#xff0c;支持跨…

v-for中的key是什么作用

在使用v-for进行列表渲染时&#xff0c;我们通常会给元素或者组件绑定一个key属性。 这个key属性有什么作用呢?我们先来看一下官方的解释&#xff1a; key属性主要用在Vue的虚拟DOM算法&#xff0c;在新Inodes对比时辨识VNodes&#xff1b; 如果不使用key&#xff0c;Vue会使用…

计算机系列之信息安全技术

15、信息安全技术 1、信息安全和信息系统安全 信息安全系统的体系架构 X轴是“安全机制”&#xff0c;为提供某些安全服务&#xff0c;利用各种安全技 术和技巧&#xff0c;所形成的一个较为完善的机构体系。 Y轴是“OSI网络参考模型”。 Z轴是“安全服务”。就是从网络中的各…

Spring框架学习笔记(一):Spring基本介绍(包含容器底层结构)

1 官方资料 1.1 官网 https://spring.io/ 1.2 进入 Spring5 下拉 projects, 进入 Spring Framework 进入 Spring5 的 github 1.3 在maven项目中导入依赖 <dependencies><!--加入spring开发的基本包--><dependency><groupId>org.springframework<…