当前位置: 首页 > news >正文

JavaWeb后端实战(事务文件上传[本地上传与阿里云OSS上传])

文章目录

  • 一、新增员工
    • 1.1 数据准备
    • 1.2 步骤
    • 1.3 基本信息保存
      • 1.3.1 Controller层
      • 1.3.2 Service层
      • 1.3.3 Mapper层
    • 1.4 保存员工经历
      • 1.4.1 分析
      • 1.4.2 Controller层
      • 1.4.3 Service层
      • 1.4.3 Mapper层
  • 二、事务管理
    • 2.1 存在的问题
    • 2.2 介绍
    • 2.2 操作
    • 2.3 Spring事物管理
    • 2.4 进阶
      • 2.4.1 rollbackFor属性
      • 2.4.2 propagation属性
      • 2.4.3 事物的四大特性
  • 三、文件上传
    • 3.1 简介
      • 3.1.1 前端三要素
      • 3.1.2 后端
    • 3.2 本地上传
    • 3.3 阿里云OSS
  • 四、配置文件
    • 4.1 参数配置化
    • 4.2 yml配置文件
    • 4.3 @ConfigurationProperties

一、新增员工

1.1 数据准备

emp表
emp_expr表:

create table emp_expr
(id      int unsigned auto_increment primary key comment 'ID, 主键',emp_id  int unsigned null comment '员工ID',begin   date         null comment '开始时间',end     date         null comment '结束时间',company varchar(50)  null comment '公司名称',job     varchar(50)  null comment '职位'
)comment '工作经历';

1.2 步骤

①完成准备工作,引入实体类EmpExpr及对应的Mapper接口、XML映射文件,及接收请求参数的实体类
②保存员工的基本信息
③批量保存员工的工作经历信息

1.3 基本信息保存

1.3.1 Controller层

    /*** 新增员工* @param emp* @return*/@PostMapping("/emps")public Result save(@RequestBody Emp emp){log.info("emp,{}",emp);empService.save(emp);return Result.success();}

注解:@RequestBody——把前端传递的json数据填充到实体类中

1.3.2 Service层

    /*** 新增数组* @param emp*/@Overridepublic void save(Emp emp) {// 补充数据 emp.setCreateTime(LocalDateTime.now());emp.setUpdateTime(LocalDateTime.now());empMapper.insert(emp);}

1.3.3 Mapper层

    /*** 新增数据* @param emp*/@Options(useGeneratedKeys = true, keyProperty = "id")@Insert("insert into emp(username,name,gender,phone,job,salary,image,entry_date,dept_id,create_time,update_time) values(#{username},#{name},#{gender},#{phone},#{job},#{salary},#{image},#{entryDate},#{deptId},#{createTime},#{updateTime})")void insert(Emp emp);

注解:@Options(userGenerateKeys = true, keyProperty = "id")——主键返回
由于稍后我们在保存工作经历信息的时候需要记录是哪位员工的工作经历,所以,保存完员工信息之后,是需要获取到员工的ID的,那这里就需要通过MyBatis中提供的主键返回功能来获取

1.4 保存员工经历

1.4.1 分析

一个员工是可以有多段员工经历的,所以在添加员工经历时候是需要批量添加

1.4.2 Controller层

    /*** 新增员工* @param emp* @return*/@PostMapping("/emps")public Result save(@RequestBody Emp emp){log.info("emp,{}",emp);empService.save(emp);return Result.success();}

1.4.3 Service层

    /*** 新增数组* @param emp*/@Overridepublic void save(Emp emp) {// 保存员工基本信息emp.setCreateTime(LocalDateTime.now());emp.setUpdateTime(LocalDateTime.now());empMapper.insert(emp);// 保存员工作经历信息// 获取添加员工的IDInteger empId = emp.getId();List<EmpExpr> exprList = emp.getExprList();// 判断经历是否为空,如果不是空在添加if(!CollectionUtils.isEmpty(exprList)){exprList.forEach((e)->{// 添加员工的IDe.setEmpId(empId);});}empMapper.insertBatch(exprList);}

1.4.3 Mapper层

    /*** 添加员工工作经历* @param exprList*/void insertBatch(@Param("exprList") List<EmpExpr> exprList);
  <!--添加工作经历--><insert id="insertBatch">insert into emp_expr (emp_id, begin, end, company, job)values<foreach collection="exprList" item="expr" separator=",">(#{expr.empId}, #{expr.begin}, #{expr.end}, #{expr.company}, #{expr.job})</foreach></insert>

注意:
这里用到MyBatis中的动态SQL里提供的标签,改标签的作用,是用来遍历循环,常见的属性说明
①controller:集合名称
②item:集合遍历出来的元素/项
③separator:每次遍历使用的分隔符
④open:遍历开始钱拼接的片段
⑤close:遍历结束后拼接的片段
上面的属性是可选的,并不是所有都是必须的,可以根据自己的实际需求,来指定对应的属性

二、事务管理

2.1 存在的问题

目前我们实现的新增员工功能中,操作了两次数据库,执行了两次insert
①第一次:保存员工基本信息到emp表中
②第二次:保存员工的工作经历信息到emp_expr表中
如果说员工的基本信息保存成功了,而员工的工作经历出错了,那么就会出现一系列问题,就会导致数据库中的数据不完整,不一致

2.2 介绍

概念:事物是一组操作的集合,他是不可分割的工作单位,事物会把所有操作作为一个整体像系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败
就拿添加员工这个业务为例,在这个业务逻辑中,包含了两个操作,那这两个操作是一个不可分割的工作单位
默认MySQL的事物是自动提交的,也就是说,当执行一条DML语句,MySQL会立即隐式的提交事物

2.2 操作

事务控制主要三步操作:开启事物、提交事务/回滚事务
①需要在这组操作执行前开启事物(start transaction;/ begin;)
②所有操作如果全部都执行成功,则提交事务(commit)
③如果这组操作中,有任何一个操作执行失败,都应该回滚事物

-- 开启事务
start transaction; / begin;
-- 1. 保存员工基本信息insert into emp values (39, 'Tom', '123456', '汤姆', 1,'13300001111', 1, 4000, '1.jpg', '2023-11-01', 1, now(), now());
-- 2. 保存员工的工作经历信息
insert into emp_expr(emp_id, begin, end, company, job) values(39,'2019-01-01', '2020-01-01', '百度', '开发'),(39,'2020-01-10', '2022-02-01', '阿里', '架构');
-- 提交事务(全部成功)
commit;
-- 回滚事务(有一个失败)
rollback;

2.3 Spring事物管理

注解@Transactional——将当前方法交给spring进行事物管理,方法执行前,开启事务;成功执行完毕,提交事务,出现异常,回滚事务;位置:业务(Service)层的方法上、类上、接口上
说明:可以在配置文件中开启事物管理日志,这样子就可以在控台看到和事物相关的日志信息了(开始、提交、回滚,相关日志信息)

logging.level.org.springframework.jdbc.support.JdbcTransactionManager = debug

2.4 进阶

2.4.1 rollbackFor属性

①默认情况下,只有出现RuntimeException,才会回滚
②rollbackFor属性用于控制出现何种异常类型,回滚事物

    @Transactional(rollbackFor = {Exception.class})

2.4.2 propagation属性

事物传播行为:指的就是当一个事物方法被另一个事物方法调用时,这个事物方法应该如何进行事物控制
在这里插入图片描述
主要有以下参数
在这里插入图片描述

2.4.3 事物的四大特性

①原子性(Atomicity):十五时不可分割的最小单元,要么全部成功,要么全部失败
②一致性(Consistency):事物完成时,必须使所有的数据保持一致状态
③隔离性(Isolation):数据库系统提供的隔离机制,保证事物在不受外部并发操作影响的独立环境下运行
④持久性(Durability):事物一旦提交或回滚,它对数据库中的数据的改变就永久的。
事物的四大特性:ACID

三、文件上传

3.1 简介

文件上传,是指将本地图片、视频、音频等文件上传到服务器,供其他用户浏览或下载的过程
想要完成文件上传这个功能需要涉及到两个部分:
①前端程序
②服务端程序
前端:

<form action="/upload" method="post" enctype="multipart/formdata">姓名: <input type="text" name="username"><br>年龄: <input type="text" name="age"><br>头像: <input type="file" name="file"><br><input type="submit" value="提交">
</form>

3.1.1 前端三要素

①表单必须有flie域,用于选择要上传的文件

 	头像: <input type="file" name="file"><br>

②表单提交方式必须为POST
通常上传的文件比较大,所以需要使用POST提交方式
③表单的编码类型enctype必须设置为multipart/formdata
普通的默认编码格式是不是和传输大型的二进制数据的,所以在文件上传时,表单的编码格式必须设置为multipart/formdata

3.1.2 后端

①首先在服务端定义一个controller,用来进行文件上传,然后再controller中定义一个方法来处理/upload
②在定义的方法中接收提交过来的数据(方法中的形参和请求参数名字保持一致)
Spring中提供了一个API:MultipartFile,使用这个API就可以接收到上传的文件
MultipartFile常用方法:
①String getOriginalFilename(); //获取原始文件名
②void transferTo(File dest); //将接收的文件转存到磁盘文件中
③long getSize(); //获取文件的大小,单位:字节
④byte[] getBytes(); //获取文件内容的字节数组
⑤InputStream getInputStream(); //获取接收到的文件内容的输入流

3.2 本地上传

    @PostMapping("/upload")public Result upload(MultipartFile file) throws Exception {empService.upload(file);return Result.success();}
    @Overridepublic void upload(MultipartFile file) throws IOException {//获取原始文件名String originalFilename = file.getOriginalFilename();//构建新的文件名String newFileName =UUID.randomUUID().toString()+originalFilename.substring(originalFilename.lastIndexOf("."));//将文件保存在服务器端 D:/images/ 目录下file.transferTo(new File("D:/images/"+newFileName));}

在这里插入图片描述
解决办法:

#配置单个文件最大上传大小
spring.servlet.multipart.max-file-size=10MB
#配置单个请求最大上传大小(一次请求可以上传多个文件)
spring.servlet.multipart.max-request-size=100MB

3.3 阿里云OSS

阿里云对象存储OSS(Object Storage Service),是一款海量、安全、低成本、高可靠的云服务存储。使用OSS可以通过网络随时存储和调用包括文本、图片、音频和视频等再内的各种文件。
在这里插入图片描述
在这里插入图片描述
SKD: Software Development Kit的缩写,软件开发工具包,包括辅助软件开发的依赖(jar包)、代码示例等,都可以叫做SDK
在这里插入图片描述
Bucket: 存储空间是用户用于存储对象(Object,就是文件)的容器,所有的对象必须隶属于某个存储空间
注意: 在使用第三方提供的云服务或技术是,一定要参照对应的官方文档进行开发和测试
配置文件:

        <dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.17.4</version></dependency>
package com.chenxd.until;import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import lombok.extern.slf4j.Slf4j;import java.io.ByteArrayInputStream;
import java.util.UUID;/*** 阿里云OSS操作工具类*/
@Slf4j
public class AliyunOSSUtils {/*** 上传文件* @param endpoint endpoint域名* @param bucketName 存储空间的名字* @param content 内容字节数组*/public static String upload(String endpoint, String bucketName, byte[] content, String extName) throws Exception {// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
//        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。// 填写RAM用户的Access Key ID和Access Key SecretString accessKeyId = "xxx";String accessKeySecret = "xxxx";// 使用DefaultCredentialProvider方法直接设置AK和SKCredentialsProvider credentialsProvider = new DefaultCredentialProvider(accessKeyId, accessKeySecret);String objectName = UUID.randomUUID() + extName;// 创建OSSClient实例。OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);try {// 创建PutObjectRequest对象。PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new ByteArrayInputStream(content));// 创建PutObject请求。PutObjectResult result = ossClient.putObject(putObjectRequest);} catch (OSSException oe) {log.error("Caught an OSSException, which means your request made it to OSS, but was rejected with an error response for some reason.");log.error("Error Message:" + oe.getErrorMessage());log.error("Error Code:" + oe.getErrorCode());log.error("Request ID:" + oe.getRequestId());log.error("Host ID:" + oe.getHostId());} catch (ClientException ce) {log.error("Caught an ClientException, which means the client encountered a serious internal problem while trying to communicate with OSS, such as not being able to access the network.");log.error("Error Message:" + ce.getMessage());} finally {if (ossClient != null) {ossClient.shutdown();}}return endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + objectName;}}
 private String endpoint = "https://oss-cnbeijing.aliyuncs.com";private String bucketName = "web01";@PostMapping("/upload")public Result upload(MultipartFile file) throws Exception {log.info("文件上传: {}", file.getOriginalFilename());// 截取文件扩展名String extName =file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));String url = AliyunOSSUtils.upload(endpoint, bucketName,file.getBytes(), extName);return Result.success(url);}

注意:不要将自己的String accessKeyId = "xxx";和String accessKeySecret = "xxxx";暴漏出来

四、配置文件

4.1 参数配置化

的是将一些需要灵活变化的参数,配置在配置文件中
在这里插入图片描述
在这里插入图片描述
注解:@Value——通常用于外部配置的属性注入,具体用法为@Value("${配置文件中的key}")

4.2 yml配置文件

格式;
①数值前边必须有空格,作为分隔符
②使用缩进技术表示层级关系,缩进时,不允许使用Tab键,只能用空格(Idea中会自动将Tab转为空格)
③缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
④# 表示注释,从这个字符一直到行尾,都会被解析器忽略
注意:在yml格式的配置文件中,如果配置项的值是以0开头的,值需要使用' '引起来,因为以0开头的在yml中表示8进制的数据

4.3 @ConfigurationProperties

问题分析:使用@Value注解注入的配置文件配置项,如果配置项多,注入繁琐,不便于维护管理和复用
Spring提供的简化方式套路
①创建一个实体类,且实体类中的属性名和配置文件当中key的名字必须要一致,另外实体类中还需要体哦公告呢get和set方法
②需要将实体类交给Spring的IOC容器进行管理,成为IOC容器当中的bean对象
③在实体类上加上@ConfigurationProperties注解,并通过perfect属性来指定配置参数项的前缀

@Component
@Data
@ConfigurationProperties
public class AliyunOSSConfig {private String endpoint;private String bucketName;}
    @Autowiredprivate AliyunOSSConfig aliyunOSSConfig;@PostMapping("/upload")public Result upload(MultipartFile file) throws Exception {log.info("文件上传: {}", file.getOriginalFilename());String extName =file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));String url = AliyunOSSUtils.upload(aliyunOSSConfig.getEndpoint(), aliyunOSSConfig.getBucketName(),file.getBytes(), extName);return Result.success(url);}
http://www.dtcms.com/a/478082.html

相关文章:

  • USB通讯学习
  • 成都哪里可以做网站涿州网站建设天峰
  • 最新MPAS跨尺度、可变分辨率模式实践技术应用及典型案例分析
  • DSP EDMA3使用
  • 做网站在哪里租服务器家用电脑做网站服务器
  • 第四篇《通信的“世界语“:为什么网络需要HTTP、FTP、DNS等协议?》
  • Helm 与 Ansible 深度对比解析文档
  • 网站域名使用费多少集客crm
  • 阜新市建设小学网站wordpress php 5.2.17
  • 2025年--Lc182--sql(排序和分组)--Java版
  • 生产环境下,前端项目为什么要部署
  • 免费图片素材网站推荐怎样建立一个免费的网站
  • [论文阅读] AI | PynguinML——破解ML库自动化测试难题,覆盖率最高提升63.9%
  • 【HarmonyOS AI赋能】AI字幕AICaption详解
  • 极海APM32F107V6 + 合宙Air780E
  • 做欧洲电商看哪个网站网站建设开发案例教程视频教程
  • C++11(可变参数模板、新的类功能和STL中的一些变化)
  • 医疗运营管理系统编程可靠性、安全性与动态性融合路径
  • 昂瑞微——以创新驱动未来,用芯连接世界
  • 网站承建商有哪些济南seo外贸网站建设
  • Flink1.20 CEP【水位线异常原因深度分析】
  • 30个酷炫HTML+CSS特效源码
  • vtkGaussianBlurPass代码解析
  • 网站制作过程合理的步骤是福州网站推广优化
  • 牛客算法基础noob71 学生综合评估系统
  • 如何清除 Yarn 缓存 ?
  • 做听书网站怎么做用动易建设网站教程
  • 东丽开发区做网站公司响应式网站源码下载
  • RabbitMQ为什么使用AMQP协议
  • 阜新本地网站建设平台百度竞价推广价格