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

SpringBoot_02

Web后端开发_07

SpringBoot_02

SpringBoot原理

1.配置优先级

1.1配置

  • SpringBoot中支持三种格式的配置文件:
    • application.properties
    • application.yml
    • application.yaml

image-20231203174648048

properties、yaml、yml三种配置文件,优先级最高的是properties

image-20231204121549012

配置文件优先级排名(从高到低):

  1. properties配置文件
  2. yml配置文件
  3. yaml配置文件

image-20231204122239508.png

注意事项

  • 虽然springboot支持多种格式配置文件,但是在项目开发时,推荐统一使用一种格式的配置(yml是主流
  • SpringBoot除了支持配置文件属性配置,还支持Java系统属性命令参数的方式进行属性配置
#Java系统属性
-Dserver.port=9000
#命令行参数
--server.port=10010

image-20231203183101694

image-20231203183232809

重启服务,同时配置Tomcat端口(三种配置文件、系统属性、命令行参数),测试哪个Tomcat端口号生效:

image-20231204131824502

优先级: 命令行参数 > 系统属性参数 > properties参数 > yml参数 > yaml参数

1.2问题引出

如果项目已经打包上线了,这个时候我们又如何来设置Java系统属性和命令行参数呢?

java -Dserver.port=9000 -jar XXXXX.jar --server.port=10010

下面我们来演示下打包程序运行时指定Java系统属性和命令行参数:

  1. 执行maven打包指令package,把项目打成jar文件
  2. 使用命令:java -jar 方式运行jar文件程序

注意事项

  • SpringBoot项目进行打包时,需要引入插件spring-boot-maven-plugin(基于官方骨架创建的项目,会自动添加该插件)

  • <skip>true</skip>需要改为false

    原因:
    这是一个 Java 项目的 Maven 配置文件 pom.xml 的一部分。 元素指定了项目的主类,也就是在执行项目时会调用的入口程序。在这个示例中,主类是com.bowen.SpringbootWebConfigApplication,也就是 Spring Boot 项目的启动类。

    skip 元素设置为 true 时,Maven 会跳过这个项目的构建过程,也就是说项目不会被编译打包。这个设置通常在调试或测试阶段使用,可以避免重复构建和打包,加快开发速度。

我的是用阿里云镜像构建的springboot项目,使用的JDK1.8/Java8

<plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version><configuration><mainClass>com.bowen.SpringbootWebConfigApplication</mainClass><skip>false</skip></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions>
</plugin>

<skip>true</skip>,运行打包后的文件时,会出现以下报错

E:\java_study\020-Maven\springboot-web-config\target>java -jar springboot-web-config-0.0.1-SNAPSHOT.jar
springboot-web-config-0.0.1-SNAPSHOT.jar中没有主清单属性

1.3项目打包

image-20231204142109762

运行jar程序:

  • 直接运行

image-20231204140911125

  • 同时设置Java系统属性和命令行参数
  • 仅设置Java系统属性

image-20231204141810748

1.4配置优先级

在SpringBoot项目当中,常见的属性配置方式有5种, 3种配置文件,加上2种外部属性的配置(Java系统属性、命令行参数)。通过以上的测试,得出了优先级(从低到高):

优先级(从低到高)

  • application.yaml(忽略)
  • application.yml
  • application.properties
  • java系统属性(-Dxxx=xxx)
  • 命令行参数(–xxx=xxx)

2.Bean管理

2.1获取bean

默认情况下,SpringBoot项目在启动的时候会自动的创建IOC容器(也称为Spring容器),并且在启动的过程当中会自动的将bean对象都创建好,存放在IOC容器当中。应用程序在运行时需要依赖什么bean对象,就直接进行依赖注入就可以了。

而在Spring容器中提供了一些方法,可以主动从IOC容器中获取到bean对象,下面介绍3种常用方式:

  1. 根据name获取bean

    Object getBean(String name)
    
  2. 根据类型获取bean

    <T> T getBean(Class<T> requiredType)
    
  3. 根据name获取bean(带类型转换)

    <T> T getBean(String name, Class<T> requiredType)
    

思考:要从IOC容器当中来获取到bean对象,需要先拿到IOC容器对象,怎么样才能拿到IOC容器呢?

  • 想获取到IOC容器,直接将IOC容器对象注入进来就可以了

控制器:DeptController

@RestController
@RequestMapping("/depts")
public class DeptController {@Autowiredprivate DeptService deptService;public DeptController(){System.out.println("DeptController constructor ....");}@GetMappingpublic Result list(){List<Dept> deptList = deptService.list();return Result.success(deptList);}@DeleteMapping("/{id}")public Result delete(@PathVariable Integer id)  {deptService.delete(id);return Result.success();}@PostMappingpublic Result save(@RequestBody Dept dept){deptService.save(dept);return Result.success();}
}

业务实现类:DeptServiceImpl

@Slf4j
@Service
public class DeptServiceImpl implements DeptService {@Autowiredprivate DeptMapper deptMapper;@Overridepublic List<Dept> list() {List<Dept> deptList = deptMapper.list();return deptList;}@Overridepublic void delete(Integer id) {deptMapper.delete(id);}@Overridepublic void save(Dept dept) {dept.setCreateTime(LocalDateTime.now());dept.setUpdateTime(LocalDateTime.now());deptMapper.save(dept);}
}

Mapper接口:

@Mapper
public interface DeptMapper {//查询全部部门数据@Select("select * from dept")List<Dept> list();//删除部门@Delete("delete from dept where id = #{id}")void delete(Integer id);//新增部门@Insert("insert into dept(name, create_time, update_time) values (#{name},#{createTime},#{updateTime})")void save(Dept dept);
}

测试类:

@SpringBootTest
class SpringbootWebConfig2ApplicationTests {@Autowiredprivate ApplicationContext applicationContext; //IOC容器对象//获取bean对象@Testpublic void testGetBean(){//根据bean的名称获取DeptController bean1 = (DeptController) applicationContext.getBean("deptController");System.out.println(bean1);//根据bean的类型获取DeptController bean2 = applicationContext.getBean(DeptController.class);System.out.println(bean2);//根据bean的名称 及 类型获取DeptController bean3 = applicationContext.getBean("deptController", DeptController.class);System.out.println(bean3);}
}

程序运行后控制台日志:

image-20231204150221123

输出的bean对象地址值是一样的,说明IOC容器当中的bean对象只有一个(默认情况下,IOC中的bean对象是单例

如何将bean对象设置为非单例的(每次获取的bean都是一个新对象)?使用bean作用域

注意事项:

  • 上述所说的 【Spring项目启动时,会把其中的bean都创建好】还会受到作用域及延迟初始化影响,这里主要针对于默认的单例非延迟加载的bean而言。

2.2bean作用域

  • spring支持五种作用域,后三种在web环境才生效
作用域说明
singleton容器内同名称的bean只有一个实例(单例)(默认)
prototype每次使用该bean时会创建新的实例(非单例)
request每个请求范围内会创建新的实例(web环境中,了解)
session每个会话范围内会创建新的实例(web环境中,了解)
application每个应用范围内会创建新的实例(web环境中,了解)
  • 可以通过@Scope注解来进行配置作用域

image-20231204150828667

注意事项:

  • 默认singleton的bean,在容器启动时被创建,可以使用@Lazy注解来延迟初始化(延迟到第一次使用时)
  • prototype的bean,每一次使用该bean的时候都会创建一个新的实例
  • 实际开发当中,绝大部分的Bean是单例的,也就是说绝大部分Bean不需要配置scope属性
2.2.1测试一
//bean的作用域
@Test
public void testScope(){for (int i = 0; i < 10; i++) {DeptController deptController = applicationContext.getBean(DeptController.class);System.out.println(deptController);}
}

在项目启动的时候DeptController的构造方法已经运行了,说明这个bean对象已经实例化了,是在容器启动的时候实例化的,这时已经将实例化的对象放到了IOC容器当中。

image-20231204151721684

放行后,输出了同一个对象十次,因为没有设置Scope默认Scope的取值是singleton单例的

image-20231204152028041

2.2.2测试二

在DeptController里加个注解@Lazy延迟初始化

image-20231204152744051

image-20231204152856355

放行

image-20231204153026806

2.2.3测试三

在DeptController里加个注解@Scope("prototype")设置为非单例的

image-20231204153227134

2.3第三方bean

2.3.1@Bean
  • 如果要管理的bean对象来自于第三方(不是自定义的),是无法用@Component及衍生注解声明bean的,就需要用到@Bean注解
  • 若要管理的第三方bean对象,建议对这些bean进行集中分类配置,可以通过@Configuration注解声明一个配置类。

使用最快速的方法声明第三方Bean对象,即在启动类创建(不建议这样使用)

image-20231204160205159

注意事项 :

  • 通过@Bean注解的name或value属性可以声明bean的名称,如果不指定,默认bean的名称就是方法名。

  • 如果第三方bean需要依赖其它bean对象,直接在bean定义方法中设置形参即可,容器会根据类型自动装配。

在启动类定义一个saxReader方法

@SpringBootApplication
public class SpringbootWebConfig2Application {public static void main(String[] args) {SpringApplication.run(SpringbootWebConfig2Application.class, args);}//声明第三方bean@Bean //将当前方法的返回值对象交给IOC容器管理, 成为IOC容器beanpublic SAXReader saxReader(){return new SAXReader();}
}

测试类

    @Autowiredprivate SAXReader saxReader;//第三方bean的管理@Testpublic void testThirdBean() throws Exception {
//        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);}

加断点debug

image-20231204160529993

image-20231204160720804

2.3.2单独建立一个配置类

image-20231204161132654

在config包下创建CommonConfig.java

@Configuration //配置类
public class CommonConfig {//声明第三方bean@Bean //将当前方法的返回值对象交给IOC容器管理, 成为IOC容器bean//通过@Bean注解的name/value属性指定bean名称, 如果未指定, 默认是方法名public SAXReader reader(DeptService deptService){System.out.println(deptService);return new SAXReader();}}

完成自动装配

image-20231204161738827

2.3.3关于Bean只需要保持一个原则
  • 如果是在项目当中我们自己定义的类,想将这些类交给IOC容器管理,直接使用@Component以及它的衍生注解来声明就可以。
  • 如果这个类它不是我们自己定义的,而是引入的第三方依赖当中提供的类,而且我们还想将这个类交给IOC容器管理。此时我们就需要在配置类中定义一个方法,在方法上加上一个@Bean注解,通过这种方式来声明第三方的bean对象。

3.SpringBoot原理

3.1spring

image-20231204163151718

3.2启动依赖

起步依赖原理

Spring框架需要引入的依赖,各个依赖的版本还需要匹配

spring-webmvc依赖:这是Spring框架进行web程序开发所需要的依赖

servlet-api依赖:Servlet基础依赖

jackson-databind依赖:JSON处理工具包

如果要使用AOP,还需要引入aop依赖、aspect依赖

项目中所引入的这些依赖,还需要保证版本匹配,否则就可能会出现版本冲突问题。

image-20231204163449304

使用SpringBoot仅需要引入一个依赖即可,web开发的起步依赖:springboot-starter-web。主要使用的就是依赖传递。

image-20231204163743504

为什么我们只需要引入一个web开发的起步依赖,web开发所需要的所有的依赖都有了呢?

  • 因为Maven的依赖传递。
  • 在SpringBoot给我们提供的这些起步依赖当中,已提供了当前程序开发所需要的所有的常见依赖(官网地址:https://docs.spring.io/spring-boot/docs/2.7.7/reference/htmlsingle/#using.build-systems.starters)。

  • 比如:springboot-starter-web,这是web开发的起步依赖,在web开发的起步依赖当中,就集成了web开发中常见的依赖:json、web、webmvc、tomcat等。我们只需要引入这一个起步依赖,其他的依赖都会自动的通过Maven的依赖传递进来。

结论:起步依赖的原理就是Maven的依赖传递。

3.3自动配置

  • SpringBoot的自动配置就是当spring容器启动后,一些配置类、bean对象就自动存入到了IOC容器中,不需要手动去声明,从而简化了开发,省去了繁琐的配置

image-20231204172519225

自动配置示例

image-20231204172050348

3.3.1自动配置原理

image-20231204174637509

3.3.1.1 概述

准备工作:在Idea中导入"资料\03. 自动配置原理"下的itheima-utils工程

1、在SpringBoot项目 spring-boot-web-config2 工程中,通过坐标引入itheima-utils依赖

添加模块

image-20231204175831776

image-20231204180551677

image-20231204180719458

image-20231204180803313

我在做的时候,该模块重复导入了三次,才引入成功

在本项目中引入模拟的第三方依赖

<dependency><groupId>com.example</groupId><artifactId>itheima-utils</artifactId><version>0.0.1-SNAPSHOT</version>
</dependency>

2、在测试类中,添加测试方法

@SpringBootTest
public class AutoConfigurationTests {@Autowiredprivate Gson gson;@Autowiredprivate ApplicationContext applicationContext;@Testpublic void testJson() {String json = gson.toJson(Result.success());System.out.println(json);}//获取TokenParser@Testpublic void testTokenParser() {System.out.println(applicationContext.getBean(TokenParser.class));}//获取HeaderParser@Testpublic void testHeaderParser() {System.out.println(applicationContext.getBean(HeaderParser.class));}//获取HeaderGenerator@Testpublic void testHeaderGenerator() {System.out.println(applicationContext.getBean(HeaderGenerator.class));}}

3、执行测试方法

image-20231204204233203

异常信息描述: 没有com.example.HeaderParser类型的bean

说明:在Spring容器中没有找到com.example.HeaderParser类型的bean对象

思考:引入进来的第三方依赖当中的bean以及配置类为什么没有生效?

  • 原因在我们之前讲解IOC的时候有提到过,在类上添加@Component注解来声明bean对象时,还需要保证@Component注解能被Spring的组件扫描到。
  • SpringBoot项目中的@SpringBootApplication注解,具有包扫描的作用,但是它只会扫描启动类所在的当前包以及子包。
  • 当前包:com.itheima, 第三方依赖中提供的包:com.example(扫描不到)

那么如何解决以上问题的呢?

  • 方案1:@ComponentScan 组件扫描
  • 方案2:@Import 导入(使用@Import导入的类会被Spring加载到IOC容器中)
3.3.1.2 方案一

@ComponentScan组件扫描

在启动类加上注解@ComponentScan({"com.example","com.bowen"})

@ComponentScan({"com.example","com.bowen"})
@SpringBootApplication
public class SpringbootWebConfig2Application {public static void main(String[] args) {SpringApplication.run(SpringbootWebConfig2Application.class, args);}
}

image-20231204204928629

如果采用以上这种方式来完成自动配置,那我们进行项目开发时,当需要引入大量的第三方的依赖,就需要在启动类上配置N多要扫描的包,这种方式会很繁琐。而且这种大面积的扫描性能也比较

缺点:

  1. 使用繁琐
  2. 性能低

结论:SpringBoot中并没有采用以上这种方案。

3.3.1.3 方案二

@Import导入

  • 导入形式主要有以下几种:
    1. 导入普通类
    2. 导入配置类
    3. 导入ImportSelector接口实现类

1). 使用@Import导入普通类:

@Import({TokenParser.class})//导入普通类,交给IOC容器管理
@SpringBootApplication
public class SpringbootWebConfig2Application {public static void main(String[] args) {SpringApplication.run(SpringbootWebConfig2Application.class, args);}
}

image-20231204205520619

2). 使用@Import导入配置类:

  • 配置类
@Configuration
public class HeaderConfig {@Beanpublic HeaderParser headerParser(){return new HeaderParser();}@Beanpublic HeaderGenerator headerGenerator(){return new HeaderGenerator();}
}
  • 启动类
@Import({HeaderConfig.class})//导入配置类,交给IOC容器管理
@SpringBootApplication
public class SpringbootWebConfig2Application {public static void main(String[] args) {SpringApplication.run(SpringbootWebConfig2Application.class, args);}
}
  • 测试类
@SpringBootTest
public class AutoConfigurationTests {@Autowiredprivate ApplicationContext applicationContext;//获取HeaderParser@Testpublic void testHeaderParser() {System.out.println(applicationContext.getBean(HeaderParser.class));}//获取HeaderGenerator@Testpublic void testHeaderGenerator() {System.out.println(applicationContext.getBean(HeaderGenerator.class));}}
  • 执行测试方法

image-20231204210053875

image-20231204210019648

3). 使用@Import导入ImportSelector接口实现类:

  • ImportSelector接口实现类
public class MyImportSelector implements ImportSelector {public String[] selectImports(AnnotationMetadata importingClassMetadata) {//返回值字符串数组(数组中封装了全限定名称的类)return new String[]{"com.example.HeaderConfig"};}
}
  • 启动类
@Import(MyImportSelector.class) //导入ImportSelector接口实现类
@SpringBootApplication
public class SpringbootWebConfig2Application {public static void main(String[] args) {SpringApplication.run(SpringbootWebConfig2Application.class, args);}
}
  • 执行测试方法

image-20231204210557315

使用@Import注解通过这三种方式都可以导入第三方依赖中所提供的bean或者是配置类。

思考:如果基于以上方式完成自动配置,当要引入一个第三方依赖时,是不是还要知道第三方依赖中有哪些配置类和哪些Bean对象?

  • 答案:是的。 (对程序员来讲,很不友好,而且比较繁琐)

思考:当我们要使用第三方依赖,依赖中到底有哪些bean和配置类,谁最清楚?

  • 答案:第三方依赖自身最清楚。

结论:我们不用自己指定要导入哪些bean对象和配置类了,让第三方依赖它自己来指定。

怎么让第三方依赖自己指定bean对象和配置类?

  • 比较常见的方案就是第三方依赖给我们提供一个注解,这个注解一般都以@EnableXxxx开头的注解,注解中封装的就是@Import注解

4). 使用第三方依赖提供的 @EnableXxxxx注解

  • 第三方依赖中提供的注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyImportSelector.class)
public @interface EnableHeaderConfig {
}
  • 在使用时只需在启动类上加上@EnableXxxxx注解即可
@EnableHeaderConfig
@SpringBootApplication
public class SpringbootWebConfig2Application {public static void main(String[] args) {SpringApplication.run(SpringbootWebConfig2Application.class, args);}
}
  • 执行测试方法

image-20231204211159178

以上四种方式都可以完成导入操作,但是第4种方式会更方便优雅,而这种方式也是SpringBoot当中所采用的方式。

  • 源码跟踪

过程略

image-20231205103633078

@SpringBootApplication注解

@SpringBootApplication

  • 该注解标识在SpringBoot工程引导类上,是SpringBoot中最重要的注解。该注解由三个部分组成:
    • @SpringBootConfiguration:该注解与@Configuration注解作用相同,用来声明当前也是一个配置类。
    • @CommponentScan:组件扫描,默认扫描当前引导类所在包及其子包。
    • @EnableAutoConfiguration:SpringBoot实现自动化配置的核心注解。

image-20231205104317399

@Conditional注解

@Conditional

  • 作用:按照一定的条件进行判断,在满足给定条件后,才会注册对应的bean对象到Spring IOC容器中。
  • 位置:方法、类
  • @Conditional本身是一个父注解,派生出大量的子注解:
    • @ConditionalOnClass:判断环境中是否有对应字节码文件,才注册bean到IOC容器。
    • @ConditionalOnMissingBean:判断环境中没有对应的bean(类型 或 名称),才注册bean到IOC容器。
    • @ConditionalOnProperty:判断配置文件中有对应的属性和值,才注册到bean和IOC容器。

image-20231205125343395

3.4案例(自定义starter)

3.4.1场景

前面解析了SpringBoot中自动配置的原理,下面就通过一个自定义starter案例来加深大家对于自动配置原理的理解。首先介绍一下自定义starter的业务场景,再来分析一下具体的操作步骤。

所谓starter指的就是SpringBoot当中的起步依赖。在SpringBoot当中已经给我们提供了很多的起步依赖了,我们为什么还需要自定义 starter 起步依赖?这是因为在实际的项目开发当中,我们可能会用到很多第三方的技术,并不是所有的第三方的技术官方都给我们提供了与SpringBoot整合的starter起步依赖,但是这些技术又非常的通用,在很多项目组当中都在使用。

业务场景:

  • 我们前面案例当中所使用的阿里云OSS对象存储服务,现在阿里云的官方是没有给我们提供对应的起步依赖的,这个时候使用起来就会比较繁琐,我们需要引入对应的依赖。我们还需要在配置文件当中进行配置,还需要基于官方SDK示例来改造对应的工具类,我们在项目当中才可以进行使用。
  • 大家想在我们当前项目当中使用了阿里云OSS,我们需要进行这么多步的操作。在别的项目组当中要想使用阿里云OSS,是不是也需要进行这么多步的操作,所以这个时候我们就可以自定义一些公共组件,在这些公共组件当中,我就可以提前把需要配置的bean都提前配置好。将来在项目当中,我要想使用这个技术,我直接将组件对应的坐标直接引入进来,就已经自动配置好了,就可以直接使用了。我们也可以把公共组件提供给别的项目组进行使用,这样就可以大大的简化我们的开发。

在SpringBoot项目中,一般都会将这些公共组件封装为SpringBoot当中的starter,也就是我们所说的起步依赖。

  • 在实际开发中,经常会定义一些公共组件,提供给各个项目团队使用。而在SpringBoot的项目中,一般会将这些公共组件封装为SpringBoot的Starter。

image-20231205130148655

Mybatis提供了配置类,并且也提供了springboot会自动读取的配置文件。当SpringBoot项目启动时,会读取到spring.factories配置文件中的配置类并加载配置类,生成相关bean对象注册到IOC容器中。

结果:可以直接在SpringBoot程序中使用Mybatis自动配置的bean对象。

image-20231205130504180

在自定义一个起步依赖starter的时候,按照规范需要定义两个模块:

  1. starter模块(进行依赖管理[把程序开发所需要的依赖都定义在starter起步依赖中])
  2. autoconfigure模块(自动配置)

将来在项目当中进行相关功能开发时,只需要引入一个起步依赖就可以了,因为它会将autoconfigure自动配置的依赖给传递下来。

3.4.2需求

需求:自定义aliyun-oss-spring-boot-starter,完成阿里云OSS操作工具类AliyunOSSUtils的自动配置。

目标:引入起步依赖引入之后,要想使用阿里云OSS,注入AliyunOSSUtils直接使用即可。

步骤
  1. 创建aliyun-oss-spring-boot-starter模块
  2. 创建aliyun-oss-spring-boot-autoconfigure模块,在starter中引入该模块
  3. 在aliyun-oss-spring-boot-autoconfigure模块中的定义自动配置功能,并定义自动配置文件META-INF/spring/xxx.imports

image-20231205150318261

示例
  • 创建aliyun-oss-spring-boot-starter模块

image-20231205180010612

  • 选择SpringBoot版本2.7.6

image-20231205180037963

  • 删除不必要的文件,留下pom.xml文件,不要学黑马教程随便删pom.xml(看不懂不要删,看明白了在删)

  • 创建aliyun-oss-spring-boot-autoconfigure模块,在starter中引入该模块

image-20231205152600229

  • 选择SpringBoot版本2.7.6

image-20231205152616174

aliyun-oss-spring-boot-autoconfigure模块删除不必要的文件,留下srcpom.xml文件,

aliyun-oss-spring-boot-autoconfigure模块中的定义自动配置功能,

  • 在这个pom.xml文件中引入阿里云的依赖和配置文件的依赖
<!--阿里云OSS-->
<dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.15.1</version>
</dependency>
<!--配置文件的依赖-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><version>2.7.16</version>
</dependency>
  • aliyun-oss-spring-boot-autoconfigure模块下,复制AliOSS工具包
  • AliOSSUtils.java该工具包直接从上一个项目中拷贝即可
package com.aliyun.oss;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;/*** 阿里云 OSS 工具类*/@Componentpublic class AliOSSUtils {private AliOSSProperties aliOSSProperties;public AliOSSProperties getAliOSSProperties() {return aliOSSProperties;}public void setAliOSSProperties(AliOSSProperties aliOSSProperties) {this.aliOSSProperties = aliOSSProperties;}/*** 实现上传图片到OSS*/public String upload(MultipartFile file) throws IOException {//获取阿里云OSS参数String endpoint = aliOSSProperties.getEndpoint();String accessKeyId = aliOSSProperties.getAccessKeyId();String accessKeySecret = aliOSSProperties.getAccessKeySecret();String bucketName = aliOSSProperties.getBucketName();// 获取上传的文件的输入流InputStream inputStream = file.getInputStream();// 避免文件覆盖String originalFilename = file.getOriginalFilename();String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));//上传文件到 OSSOSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);ossClient.putObject(bucketName, fileName, inputStream);//文件访问路径String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;// 关闭ossClientossClient.shutdown();return url;// 把上传到oss的路径返回}}
  • AliOSSAutoConfiguration.java
package com.aliyun.oss;import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @ClassName AliOSSAutoConfiguration* @Description TODO* @Author Bowen* @Date 2023/12/5 16:36* @Version 1.0**/
@Configuration
@EnableConfigurationProperties(AliOSSProperties.class)
public class AliOSSAutoConfiguration {@Beanpublic AliOSSUtils aliOSSUtils(AliOSSProperties aliOSSProperties){AliOSSUtils aliOSSUtils = new AliOSSUtils();aliOSSUtils.setAliOSSProperties(aliOSSProperties);return aliOSSUtils;}
}
  • AliOSSProperties.java
package com.aliyun.oss;import org.springframework.boot.context.properties.ConfigurationProperties;/*** @ClassName AliOSSProperties* @Description 阿里云OSS的实体类* @Author Bowen* @Date 2023/11/29 23:27* @Version 1.0**/@ConfigurationProperties(prefix = "aliyun.oss")
public class AliOSSProperties {private String endpoint;private String accessKeyId;private String accessKeySecret;private String bucketName;public String getEndpoint() {return endpoint;}public void setEndpoint(String endpoint) {this.endpoint = endpoint;}public String getAccessKeyId() {return accessKeyId;}public void setAccessKeyId(String accessKeyId) {this.accessKeyId = accessKeyId;}public String getAccessKeySecret() {return accessKeySecret;}public void setAccessKeySecret(String accessKeySecret) {this.accessKeySecret = accessKeySecret;}public String getBucketName() {return bucketName;}public void setBucketName(String bucketName) {this.bucketName = bucketName;}
}
  • 定义自动配置文件META-INF/spring/xxx.imports,在aliyun-oss-spring-boot-autoconfigure模块的resources目录下创建

    META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

com.aliyun.oss.AliOSSAutoConfiguration

image-20231205182253583

  • aliyun-oss-spring-boot-starter模块的pom.xml文件引入aliyun-oss-spring-boot-autoconfigure
<dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-oss-spring-boot-autoconfigure</artifactId><version>0.0.1-SNAPSHOT</version>
</dependency>
  • 最后使用黑马提供的资料中的测试工程

image-20231205182511438

  • 导入springboot-autoconfiguration-test模块
  • 引入自定义的阿里云OSS依赖
<dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-oss-spring-boot-starter</artifactId><version>0.0.1-SNAPSHOT</version>
</dependency>

这里只需引入aliyun-oss-spring-boot-starter依赖即可,根据依赖传递功能,相当于同时引入了aliyun-oss-spring-boot-autoconfigure依赖

image-20231205182815251

  • UploadController.java中使用@Autowired注入AliOSSUtils,最终上传到阿里云OSS存储,拿到并返回url
@RestController
public class UploadController {@Autowiredprivate AliOSSUtils aliOSSUtils;@PostMapping("/upload")public String upload(MultipartFile image) throws Exception {//上传文件到阿里云 OSSString url = aliOSSUtils.upload(image);return url;}}
  • 在启动该项目前,需要配置阿里云的AS
#阿里云配置
aliyun:oss:endpoint: 地域节点accessKeyId: AccessKey IDaccessKeySecret: AccessKey SecretbucketName: 存储空间名称
  • springboot启动~~~

image-20231205183539486

  • 测试图片

image-20231205183859857

  • 使用Apipost进行测试

image-20231205183830346

  • 在阿里云OSS控制台查看

image-20231205184030282

相关文章:

SpringBoot_02

Web后端开发_07 SpringBoot_02 SpringBoot原理 1.配置优先级 1.1配置 SpringBoot中支持三种格式的配置文件&#xff1a; application.propertiesapplication.ymlapplication.yaml properties、yaml、yml三种配置文件&#xff0c;优先级最高的是properties 配置文件优先级…...

实验报告-实验四(时序系统实验)

软件模拟电路图 说明 SW&#xff1a;开关&#xff0c;共六个Q1~Q3&#xff1a;输出Y0~Y3&#xff1a;输出 74LS194 首先&#xff0c;要给S1和S0高电位&#xff0c;将A~D的数据存入寄存器中&#xff08;如果开始没有存入数据&#xff0c;那么就是0000在里面移位&#xff0c;不…...

PHP+ajax+layui实现双重列表的动态绑定

需求&#xff1a;商户下面有若干个门店&#xff0c;每个门店都需要绑定上收款账户 方案一&#xff1a;每个门店下面添加页面&#xff0c;可以选择账户去绑定。&#xff08;难度&#xff1a;简单&#xff09; 方案二&#xff1a;从商户进入&#xff0c;可以自由选择门店&#…...

菜鸟学习日记(python)——条件控制

Python 中的条件语句是通过一条或多条语句的执行结果&#xff08;True 或者 False&#xff09;来决定执行的代码块。 它的一般格式为&#xff1a;if...elif...else if condition1: #条件1CodeBlock1 #代码块1 elif condition2:CodeBlock2 else:CodeBlock3 如果con…...

RabbitMQ 笔记

Message durability 确保消息在server 出现问题或者recovery能恢复&#xff1a; declare it as durable in the producer and consumer code. boolean durable true; channel.queueDeclare("hello", durable, false, false, null);Queue 指定 //使用指定的queue&…...

DNS协议(DNS规范、DNS报文、DNS智能选路)

目录 DNS协议基本概念 DNS相关规范 DNS服务器的记录 DNS报文 DNS域名查询的两种方式 DNS工作过程 DNS智能选路 DNS协议基本概念 DNS的背景 我们知道主机通信需要依靠IP地址&#xff0c;但是每次通过输入对方的IP地址和对端通信不够方便&#xff0c;IP地址不好记忆 因此提…...

Python基础知识-变量、数据类型(整型、浮点型、字符类型、布尔类型)详解

1、基本的输出和计算表达式&#xff1a; prinit(12-3) printf(12*3) printf(12/3) prinit(12-3) printf(12*3) printf(12/3) 形如12-3称为表达式 这个表达式的运算结果称为 表达式的返回值 1 2 3 这样的数字&#xff0c;叫做 字面值常量 - * /称为 运算符或者操作符 在C和j…...

信息化,数字化,智能化是3种不同概念吗?与机械化,自动化矛盾吗?

先说结论&#xff1a; 1、信息化、数字化、智能化确实是3种不同的概念&#xff01; 2、这3种概念与机械化、自动化并不矛盾&#xff0c;它们是制造业中不同发展阶段和不同层次的概念。 机械化&#xff1a;是指在生产过程中使用机械技术来辅助人工完成一些重复性、单一性、劳…...

C# WPF上位机开发(倒计时软件)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 生活当中&#xff0c;我们经常会遇到倒计时的场景&#xff0c;比如体育运动的时候、考试的时候等等。正好最近我们学习了c# wpf开发&#xff0c;完…...

Mysql timestamp和datetime区别

文章目录 一、存储范围和精度二、默认值和自动更新三、时区处理四、索引和性能五、存储空间和数据复制六、使用场景和注意事项七、时区转换 MySQL是一个常用的关系型数据库管理系统&#xff0c;其内置了多种数据类型用于存储和操作数据。其中&#xff0c;timestamp和datetime是…...

新手村之SQL——分组与子查询

1.GROUP BY GROUP BY 函数就是 SQL 中用来实现分组的函数&#xff0c;其用于结合聚合函数&#xff0c;能根据给定数据列的每个成员对查询结果进行分组统计&#xff0c;最终得到一个分组汇总表。 mysql> SELECT country, COUNT(country) AS teacher_count-> FROM teacher…...

【hacker送书第9期】算法训练营(入门篇)

第9期图书推荐 内容简介作者简介精彩书评图书目录概述参与方式 内容简介 本书以海量图解的形式&#xff0c;详细讲解常用的数据结构与算法&#xff0c;又融入大量的竞赛实例和解题技巧。通过对本书的学习&#xff0c;读者可掌握12种初级数据结构、15种常用STL函数、10种二叉树和…...

微服务链路追踪组件SkyWalking实战

概述 微服务调用存在的问题 串联调用链路&#xff0c;快速定位问题&#xff1b;理清服务之间的依赖关系&#xff1b;微服务接口性能分析&#xff1b;业务流程调用处理顺序&#xff1b; 全链路追踪&#xff1a;对请求源头到底层服务的调用链路中间的所有环节进行监控。 链路…...

ubuntu 更换国内镜像

备份 cd /etc/aptcp sources.list sources.list.bakup修改源为清华源 sed -i s/archive.ubuntu.com/mirrors.aliyun.com/g sources.list更新软件源 apt-get update其他源如下&#xff1a; mirrors.ustc.edu.cn 中科大 mirrors.163.com 163 mirrors.aliyun.com 阿里云...

树模型与深度模型对比

表格型数据为什么那么神奇&#xff0c;能让树模型在各种真实场景的表格数据中都战胜深度学习呢&#xff1f;作者认为有以下三种可能&#xff1a; 神经网络倾向于得到过于平滑的解冗余无信息的特征更容易影响神经网络 所以一定程度的特征交叉是不是必要的&#xff0c;因为one-ho…...

测试类运行失败:TestEngine with ID ‘junit-jupiter‘ failed to discover tests

背景&#xff1a;原本我的项目是可以运行的&#xff0c;然后我用另外一台电脑拉了下来&#xff0c;也是可以用的&#xff0c;但是很奇怪&#xff0c;用着用着就不能用了。报了以下错误&#xff1a; /Library/Java/JavaVirtualMachines/openjdk-11.jdk/Contents/Home/bin/java …...

nodejs使用node-cron实现定时任务功能

ChatGPT国内站点&#xff1a;海鲸AI 在Node.js中&#xff0c;node-cron是一个轻量级的任务调度库&#xff0c;它允许你根据类似于Cron的时间表来安排任务的执行。如果你想要每十分钟执行一次任务&#xff0c;你可以按照以下步骤来设置&#xff1a; 安装node-cron&#xff1a; 如…...

【1day】蓝凌OA 系统datajson.js接口远程命令执行漏洞学习

注:该文章来自作者日常学习笔记,请勿利用文章内的相关技术从事非法测试,如因此产生的一切不良后果与作者无关。 目录 一、漏洞概述 二、影响版本 三、资产测绘 四、漏洞复现...

ABCDE类网络的划分及保留网段

根据IP地址的分类&#xff0c;IP地址被分为A、B、C、D和E五类。下面是对ABCDE类网络的划分及保留网段的详细描述&#xff1a; A类网络&#xff1a;范围从1.0.0.0到127.0.0.0&#xff0c;网络地址的最高位必须是“0”&#xff0c;可用的A类网络有127个&#xff0c;每个网络能容…...

营销系统规则引擎

一、系统介绍 规则引擎是一个用于执行营销规则的模块&#xff0c;其包括营销规则配置、规则校验等功能。规则引擎可以根据预先设定的条件和逻辑&#xff0c;自动化地执行特点的营销策略&#xff0c;帮助企业更好地吸引客户&#xff0c;增加销售和提高客户满意度。 规则引擎功能…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】

微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来&#xff0c;Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...

Objective-C常用命名规范总结

【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名&#xff08;Class Name)2.协议名&#xff08;Protocol Name)3.方法名&#xff08;Method Name)4.属性名&#xff08;Property Name&#xff09;5.局部变量/实例变量&#xff08;Local / Instance Variables&…...

全球首个30米分辨率湿地数据集(2000—2022)

数据简介 今天我们分享的数据是全球30米分辨率湿地数据集&#xff0c;包含8种湿地亚类&#xff0c;该数据以0.5X0.5的瓦片存储&#xff0c;我们整理了所有属于中国的瓦片名称与其对应省份&#xff0c;方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲&#xff1a;队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

蓝桥杯 冶炼金属

原题目链接 &#x1f527; 冶炼金属转换率推测题解 &#x1f4dc; 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V&#xff0c;是一个正整数&#xff0c;表示每 V V V 个普通金属 O O O 可以冶炼出 …...

初探Service服务发现机制

1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能&#xff1a;服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源&#xf…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时&#xff0c;Again增益0db变化为6DB&#xff0c;画面的变化只有2倍DN的增益&#xff0c;比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析&#xff1a; 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

PAN/FPN

import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...