1.事务管理
1.1 事务回顾
- 概念
事务 是一组操作的集合,它是一个不可分割的工作单位,这些操作 要么同时成功,要么同时失败。
- 操作
- 案例:解散部门:删除部门,同时删除该部门下的员工
DeptServiceImpl.java
@Override
public void deleteById(Integer id) {
deptMapper.deleteById(id);
empMapper.deleteByDeptId(id);
}
EmpMapper.java
@Delete("delete from tlias.emp where tlias.emp.dept_id=#{deptId}")
void deleteByDeptId(Integer deptId);
- 问题

即使程序运行抛出了异常,部门依然删除了,但是部门下的员工却没有删除,造成了数据的不一致。
- 解决方案

1.2 spring事务管理
- 注解

- 开启日志
logging:
level:
org.springframework.jdbc.support.JdbcTransactionManager: debug
1.3 事务进阶
1.3.1 rollbackFor
@Transactional(rollbackFor = Exception.class )
@Override
public void deleteById(Integer id) throws Exception {
deptMapper.deleteById(id);
if(true){
throw new Exception("出错啦。。。。");
}
empMapper.deleteByDeptId(id);
}
1.3.2 propagation
| 属性值 | 含义 |
| REQUIRED | 【默认值】需要事务,有则加入,无则创建新事务 |
| REQUIRES_NEW | 需要新事务,无论有无,总是创建新事务 |
| SUPPORTS | 支持事务,有则加入,无则在无事务状态中运行 |
| NOT_SUPPORTED | 不支持事务,在无事务状态下运行,如果当前存在已有事务,则挂起当前事务 |
| MANDATORY | 必须有事务,否则抛异常 |
| NEVER | 必须没事务,否则抛异常 |
| … |
- 案例
需求:解散部门时,无论是成功还是失败,都要记录操作日志。
步骤:
①. 解散部门:删除部门、删除部门下的员工
②. 记录日志到数据库表中
@Transactional
@Override
public void deleteById(Integer id) throws Exception {
try {
deptMapper.deleteById(id);
int t=1/0;
empMapper.deleteByDeptId(id);
} finally {
DeptLog deptLog=new DeptLog();
deptLog.setCreateTime(LocalDateTime.now());
deptLog.setDescription("");
deptLogService.insert(deptLog);
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Service
public class DeptLogServiceImpl implements DeptLogService {
@Autowired
private DeptLogMapper deptLogMapper;
@Override
public void insert(DeptLog deptLog) {
deptLogMapper.insert(deptLog);
}
}
- 场景
2 AOP基础
2.1 AOP基础概述
- AOP:Aspect Oriented Programming(面向切面编程、面向方面编程),其实就是面向特定方法编程。
- 场景:案例部分功能运行较慢,定位执行耗时较长的业务方法,此时需要统计每一个业务方法的执行耗时

- 实现:动态代理是面向切面编程最主流的实现。而SpringAOP是Spring框架的高级技术,旨在管理bean对象的过程中,主要通过底层的动态代理机制,对特定的方法进行编程。
2.2 AOP快速入门
- 导入依赖:在pom.xml中导入AOP的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
- 编写AOP程序:针对于特定方法根据业务需要进行编程
package cn.jxust.tliaswebmanagement.aop;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Component
@Slf4j
@Aspect
public class TimeAspect {
public Object record(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
long begin = System.currentTimeMillis();
Object res = proceedingJoinPoint.proceed();
long end = System.currentTimeMillis();
log.info("执行时间为:{}ms",end-begin);
return res;
}
}
- 场景
记录操作日志、权限控制、事务管理、、、
- 优势
代码无侵入、减少重复代码、提高开发效率、维护方便、、、
2.3 AOP核心概念
- 连接点:JoinPoint,可以被AOP控制的方法(暗含方法执行时的相关信息)
- 通知:Advice,指哪些重复的逻辑,也就是共性功能(最终体现为一个方法)
- 切入点:PointCut,匹配连接点的条件,通知仅会在切入点方法执行时被应用
- 切面:Aspect,描述通知与切入点的对应关系(通知+切入点)
- 目标对象:Target,通知所应用的对象

-
AOP执行流程

代码
3 AOP进阶
3.1 通知类型
- 通知类型
- 注意事项
代码
- @PointCut:该注解的作用是将公共的切点表达式抽取出来,需要用到时引用该切点表达式即可。
@Pointcut("execution(* cn.jxust.springbootaopquickstart.service.impl.DeptServiceImpl.*(..))")
public void pt(){}
无侵入
3.2 通知顺序
当有多个切面的切入点都匹配到了目标方法,目标方法运行时,多个通知方法都会被执行。
- 执行顺序
3.3 切入点表达式
切入点表达式:
- 切入点表达式:描述切入点方法的一种表达式
- 作用:主要用来决定项目中的哪些方法需要加入通知
- 常见形式:
- 1.execution(……):根据方法的签名来匹配
- 2.@annotation(……) :根据注解匹配
3.3.1 切入点表达式--excution
execution 主要根据方法的返回值、包名、类名、方法名、方法参数等信息来匹配,语法为:
execution(访问修饰符? 返回值 包名.类名.?方法名(方法参数) throws 异常?)
- 其中带 ? 的表示可以省略的部分
- 访问修饰符:可省略(比如: public、protected)
- 包名.类名: 可省略
- throws 异常:可省略(注意是方法上声明抛出的异常,不是实际抛出的异常)
- 可以使用通配符描述切入点
- * :单个独立的任意符号,可以通配任意返回值、包名、类名、方法名、任意类型的一个参数,也可以通配包、类、方法名的一部分
execution(* com.*.service.*.update*(*))
- .. :多个连续的任意符号,可以通配任意层级的包,或任意类型、任意个数的参数
execution(* com.itheima..DeptService.*(..))
- 注意事项:根据业务需要,可以使用 且(&&)、或(||)、非(!) 来组合比较复杂的切入点表达式。
- 书写建议
- 所有业务方法名在命名时尽量规范,方便切入点表达式快速匹配。如:查询类方法都是 find 开头,更新类方法都是 update开头。
- 描述切入点方法通常基于接口描述,而不是直接描述实现类,增强拓展性。
- 在满足业务需要的前提下,尽量缩小切入点的匹配范围。如:包名匹配尽量不使用 ..,使用 * 匹配单个包。
3.3.2 切入点表达式-@annotation
- @annotation 切入点表达式,用于匹配标识有特定注解的方法。
@annotation(com.itheima.anno.Log)
package cn.jxust.springbootaopquickstart.aop;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyLog {
}
@Pointcut("@annotation(cn.jxust.springbootaopquickstart.aop.MyLog)")
public void pt(){}
3.4 AOP连接点
- 在Spring中用JoinPoint抽象了连接点,用它可以获得方法执行时的相关信息,如目标类名、方法名、方法参数等。
- 对于 @Around 通知,获取连接点信息只能使用 ProceedingJoinPoint
@Around("execution(* com.itheima.service.DeptService.*(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
String className = joinPoint.getTarget().getClass().getName(); //获取目标类名
Signature signature = joinPoint.getSignature(); //获取目标方法签名
String methodName = joinPoint.getSignature().getName(); //获取目标方法名
Object[] args = joinPoint.getArgs(); //获取目标方法运行参数
Object res = joinPoint.proceed(); //执行原始方法,获取返回值(环绕通知)
return res;
}
- 对于其他四种通知,获取连接点信息只能使用 JoinPoint ,它是 ProceedingJoinPoint 的父类型
@Before("execution(* com.itheima.service.DeptService.*(..))")
public void before(JoinPoint joinPoint) {
String className = joinPoint.getTarget().getClass().getName(); //获取目标类名
Signature signature = joinPoint.getSignature(); //获取目标方法签名
String methodName = joinPoint.getSignature().getName(); //获取目标方法名
Object[] args = joinPoint.getArgs(); //获取目标方法运行参数
}
4 AOP案例
- 要求:将案例中 增、删、改 相关接口的操作日志记录到数据库表中。
- 操作日志:日志信息包含:操作人、操作时间、执行方法的全类名、执行方法名、方法运行时参数、返回值、方法执行时长
- 思路分析:
- 需要对所有业务类中的增、删、改 方法添加统一功能,使用 AOP 技术最为方便
- 由于增、删、改 方法名没有规律,可以自定义 @Log 注解完成目标方法匹配
- 准备:
- 在案例工程中引入AOP的起步依赖
- 导入资料中准备好的数据库表结构,并引入对应的实体类
- 编码:
- 自定义注解 @Log
- 定义切面类,完成记录操作日志的逻辑
- 获取当前登录用户:获取request对象,从请求头中获取到jwt令牌,解析令牌获取出当前用户的id。
- 代码
LogAspect.java
package cn.jxust.tliaswebmanagement.aop;
import cn.jxust.tliaswebmanagement.mapper.OperateLogMapper;
import cn.jxust.tliaswebmanagement.pojo.OperateLog;
import cn.jxust.tliaswebmanagement.utils.JwtUtils;
import com.alibaba.fastjson2.JSONObject;
import io.jsonwebtoken.Claims;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Arrays;
@Slf4j
@Component
@Aspect
public class LogAspect {
@Autowired
private HttpServletRequest request;
@Autowired
private OperateLogMapper operateLogMapper;
@Around("@annotation(cn.jxust.tliaswebmanagement.anno.Log)")
public Object recordLog(ProceedingJoinPoint joinPoint) throws Throwable {
//操作人ID
String jwt = request.getHeader("token");
Claims claims = JwtUtils.parseJWT(jwt);
Integer id = (Integer)claims.get("id");
//操作时间
LocalDateTime now = LocalDateTime.now();
//操作类名
String name = joinPoint.getTarget().getClass().getName();
//操作方法名
String method = joinPoint.getSignature().getName();
//操作方法参数
Object[] args = joinPoint.getArgs();
String s = Arrays.toString(args);
long begin = System.currentTimeMillis();
//方法的返回值
Object result = joinPoint.proceed();
String jsonString = JSONObject.toJSONString(result);
long end = System.currentTimeMillis();
//操作耗时
Long time=end-begin;
OperateLog operateLog=new OperateLog(null,id,now,name,method,s,jsonString,time);
operateLogMapper.insert(operateLog);
return result;
}
}
OperateLog.java
package cn.jxust.tliaswebmanagement.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OperateLog {
private Integer id; //ID
private Integer operateUser; //操作人ID
private LocalDateTime operateTime; //操作时间
private String className; //操作类名
private String methodName; //操作方法名
private String methodParams; //操作方法参数
private String returnValue; //操作方法返回值
private Long costTime; //操作耗时
}
5.配置优先级
- SpringBoot 中支持三种格式的配置文件:
- server.port=8081
-
server:
port: 8082
-
server:
port: 8083
-
注意事项:虽然springboot支持多种格式配置文件,但是在项目开发时,推荐统一使用一种格式的配置 (yml是主流)。
-
SpringBoot 除了支持配置文件属性配置,还支持Java系统属性和命令行参数的方式进行属性配置。

-
优先级(低→高)
- application.yaml(忽略)
- application.yml
- application.properties
- java系统属性(-Dxxx=xxx)
- 命令行参数(--xxx=xxx)
6 Bean管理
6.1 获取bean
- 默认情况下,Spring项目启动时,会把bean都创建好放在IOC容器中,如果想要主动获取这些bean,可以通过如下方式:
- 根据name获取bean:Object getBean(String name)
- 根据类型获取bean:<T> T getBean(Class<T> requiredType)
- 根据name获取bean(带类型转换):<T> T getBean(String name, Class<T> requiredType)
@Autowired
private ApplicationContext applicationContext;
@Test
public void testBean(){
DeptServiceImpl deptServiceImpl = (DeptServiceImpl) applicationContext.getBean("deptServiceImpl");
System.out.println(deptServiceImpl);
DeptServiceImpl bean = applicationContext.getBean(DeptServiceImpl.class);
System.out.println(bean);
DeptServiceImpl bean1 = applicationContext.getBean("deptServiceImpl", DeptServiceImpl.class);
System.out.println(bean1);
}
- 注意事项
上述所说的 【Spring项目启动时,会把其中的bean都创建好】还会受到作用域及延迟初始化影响,这里主要针对于 默认的单例非延迟加载的bean而言。
6.2 Bean的作用域
- Spring支持五种作用域,后三种在web环境才生效:
| 作用域 | 说明 |
| singleton | 容器内同 名称 的 bean 只有一个实例(单例)(默认) |
| prototype | 每次使用该 bean 时会创建新的实例(非单例) |
| request | 每个请求范围内会创建新的实例(web环境中,了解) |
| session | 每个会话范围内会创建新的实例(web环境中,了解) |
| application | 每个应用范围内会创建新的实例(web环境中,了解) |
- 可以通过 @Scope 注解来进行配置作用域:
@Scope("prototype")
@RestController
@RequestMapping("/depts")
public class DeptController {
}
- 注意事项
6.3 第三方Bean
- 如果要管理的bean对象来自于第三方(不是自定义的),是无法用 @Component 及衍生注解声明bean的,就需要用到 @Bean注解。
- 若要管理的第三方bean对象,建议对这些bean进行集中分类配置,可以通过 @Configuration 注解声明一个配置类。
package cn.jxust.tliaswebmanagement.config;
import org.dom4j.io.SAXReader;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CommonConfig {
@Bean
public SAXReader reader(){
return new SAXReader();
}
}
- 通过@Bean注解的name或value属性可以声明bean的名称,如果不指定,默认bean的名称就是方法名。
- 如果第三方bean需要依赖其它bean对象,直接在bean定义方法中设置形参即可,容器会根据类型自动装配。
- @Component 及衍生注解 与 @Bean注解使用场景?
- 项目中自定义的,使用@Component及其衍生注解
- 项目中引入第三方的,使用@Bean注解
6.4 解析XML文件
依赖
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.3</version>
</dependency>
@Autowired
private SAXReader saxReader;
@Test
public void testXML() throws DocumentException {
// SAXReader saxReader=new SAXReader();
Document document = saxReader.read(this.getClass().getClassLoader().getResource("1.xml"));
Element rootElement = document.getRootElement();
String name = rootElement.element("name").getText();
String age = rootElement.element("age").getText();
System.out.println(name+' '+age);
}
7 springboot原理(自动配置)
7.1 自动配置原理
- 方案一:@ComponentScan 组件扫描
@ComponentScan({"com.example","com.itheima"})
@SpringBootApplication
public class SpringbootWebConfig2Application {
}
- 方案二:@Import 导入。使用@Import导入的类会被Spring加载到IOC容器中,导入形式主要有以下几种:
- 导入 普通类
- 导入 配置类
- 导入 ImportSelector 接口实现类
- @EnableXxxx注解,封装@Import注解
@Import({TokenParser.class, HeaderConfig.class})
@SpringBootApplication
public class SpringbootWebConfig2Application {
}
- 源码跟踪
@SpringBootApplication:该注解标识在SpringBoot工程引导类上,是SpringBoot中最最最重要的注解。该注解由三个部分组成:
- @SpringBootConfiguration:该注解与 @Configuration 注解作用相同,用来声明当前也是一个配置类。
- @ComponentScan:组件扫描,默认扫描当前引导类所在包及其子包。
- @EnableAutoConfiguration:SpringBoot实现自动化配置的核心注解。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
/**
* Environment property that can be used to override when auto-configuration is
* enabled.
*/
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};
}
- @Conditional
- 作用:按照一定的条件进行判断,在满足给定条件后才会注册对应的bean对象到Spring IOC容器中。
- 位置:方法、类
- @Conditional 本身是一个父注解,派生出大量的子注解:
- @ConditionalOnClass:判断环境中是否有对应字节码文件,才注册bean到IOC容器。
- @ConditionalOnMissingBean:判断环境中没有对应的bean(类型 或 名称) ,才注册bean到IOC容器。
- @ConditionalOnProperty:判断配置文件中有对应属性和值,才注册bean到IOC容器。
@Bean
@ConditionalOnClass(name = "io.jsonwebtoken.Jwts") //当前环境存在指定的这个类时,才声明该bean
public HeaderParser headerParser(){...}
@Bean
@ConditionalOnMissingBean //当不存在当前类型的bean时,才声明该bean
public HeaderParser headerParser(){...}
@Bean
@ConditionalOnProperty(name = "name",havingValue = "itheima") //配置文件中存在对应的属性和值,才注册bean到IOC容器。
public HeaderParser headerParser(){...}
7.2 案例(自定义starter)
- 场景:在实际开发中,经常会定义一些公共组件,提供给各个项目团队使用。而在SpringBoot的项目中,一般会将这些公共组件封装为SpringBoot 的 starter。
- 需求:
- 需求:自定义aliyun-oss-spring-boot-starter,完成阿里云OSS操作工具类 AliyunOSSUtils 的自动配置。
- 目标:引入起步依赖引入之后,要想使用阿里云OSS,注入 AliyunOSSUtils直接使用即可。
- 步骤:
- 创建 aliyun-oss-spring-boot-starter 模块
- 创建 aliyun-oss-spring-boot-autoconfigure 模块,在starter中引入该模块
- 在 aliyun-oss-spring-boot-autoconfigure 模块中的定义自动配置功能,并定义自动配置文件 META-INF/spring/xxxx.imports
- 依赖管理功能:aliyun-oss-spring-boot-starter
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-oss-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-oss-spring-boot-autoconfigure</artifactId>
</dependency>
</dependencies>
</project>
- 自动配置功能:aliyun-oss-spring-boot-autoconfigure
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-oss-spring-boot-autoconfigure</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--阿里云OSS-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.1</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.3</version>
</dependency>
</dependencies>
</project>
package com.aliyun.oss;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(AliOssProperties.class)
public class AliOSSAutoConfiguration {
@Bean
public AliOSSUtils aliOSSUtils(AliOssProperties aliOssProperties){
AliOSSUtils aliOSSUtils = new AliOSSUtils();
aliOSSUtils.setAliOssProperties(aliOssProperties);
return aliOSSUtils;
}
}
package com.aliyun.oss;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 封装属性键值对值
*/
@Data
@ConfigurationProperties(prefix = "aliyun.oss")
public class AliOssProperties {
private String endpoint; //aliyun.oss.endpoint
private String accessKeyId; //aliyun.oss.access-key-id
private String accessKeySecret;
private String bucketName;
}
package com.aliyun.oss;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;
/**
* 阿里云 OSS 工具类
*/
public class AliOSSUtils {
private AliOssProperties aliOssProperties;
public void setAliOssProperties(AliOssProperties aliOssProperties) {
this.aliOssProperties = aliOssProperties;
}
/**
* 实现上传图片到OSS
*/
public String upload(MultipartFile file) throws IOException {
String endpoint = aliOssProperties.getEndpoint();
String accessKeyId = aliOssProperties.getAccessKeyId();
String accessKeySecret = aliOssProperties.getAccessKeySecret();
String bucketName = aliOssProperties.getBucketName();
// 获取上传的文件的输入流
InputStream inputStream = file.getInputStream();
// 避免文件覆盖
String originalFilename = file.getOriginalFilename();//原始文件名 abc.jpg
//UUID.randomUUID() 保证随机字符串唯一 sfasdfdsfsdgfsdgsdf.jpg
String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));
//上传文件到 OSS
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
ossClient.putObject(bucketName, fileName, inputStream);
//文件访问路径
String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;
// 关闭ossClient
ossClient.shutdown();
return url;// 把上传到oss的路径返回
}
}
com.aliyun.oss.AliOSSAutoConfiguration

8 Web后端开发总结



1309

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



