Spring Boot 2 入门基础

学习要求
● 熟悉Spring基础
● 熟悉Maven使用

环境要求
● Java8及以上
● Maven 3.3及以上:https://docs.spring.io/spring-boot/docs/current/reference/html/getting-started.html#getting-started-system-requirements

学习资料
● 文档地址: https://www.yuque.com/atguigu/springboot
○ 文档不支持旧版本IE、Edge浏览器,请使用chrome或者firefox
● 视频地址: http://www.gulixueyuan.com/ https://www.bilibili.com/video/BV19K4y1L7MT?p=1
● 源码地址:https://gitee.com/leifengyang/springboot2

01、Spring与SpringBoot

1、Spring能做什么

1.1、Spring的能力

在这里插入图片描述

1.2、Spring的生态

https://spring.io/projects/spring-boot

覆盖了:
web开发
数据访问
安全控制
分布式
消息服务
移动开发
批处理

1.3、Spring5重大升级

1.3.1、响应式编程

在这里插入图片描述

1.3.2、内部源码设计

基于Java8的一些新特性,如:接口默认实现。重新设计源码架构。

2、为什么用SpringBoot

Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run".
能快速创建出生产级别的Spring应用

2.1、SpringBoot优点

Create stand-alone Spring applications
创建独立Spring应用
Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)
内嵌web服务器
Provide opinionated 'starter' dependencies to simplify your build configuration
自动starter依赖,简化构建配置
Automatically configure Spring and 3rd party libraries whenever possible
自动配置Spring以及第三方功能
Provide production-ready features such as metrics, health checks, and externalized configuration
提供生产级别的监控、健康检查及外部化配置
Absolutely no code generation and no requirement for XML configuration
无代码生成、无需编写XML
SpringBoot是整合Spring技术栈的一站式框架
SpringBoot是简化Spring技术栈的快速开发脚手架

2.2、SpringBoot缺点

人称版本帝,迭代快,需要时刻关注变化
封装太深,内部原理复杂,不容易精通

3、时代背景

3.1、微服务

James Lewis and Martin Fowler (2014)  提出微服务完整概念。
https://martinfowler.com/microservices/
In short, the microservice architectural style is an approach to developing a single application 
as a suite of small services, each running in its own process and communicating with lightweight mechanisms, 
often an HTTP resource API. These services are built around business capabilities and independently deployable 
by fully automated deployment machinery. 
There is a bare minimum of centralized management of these services, which may be written in different 
programming languages and use different data storage technologies.-- James Lewis and Martin Fowler (2014)
微服务是一种架构风格
一个应用拆分为一组小型服务
每个服务运行在自己的进程内,也就是可独立部署和升级
服务之间使用轻量级HTTP交互
服务围绕业务功能拆分
可以由全自动部署机制独立部署
去中心化,服务自治。服务可以使用不同的语言、不同的存储技术

3.2、分布式

在这里插入图片描述

分布式的困难

  • 远程调用
  • 服务发现
  • 负载均衡
  • 服务容错
  • 配置管理
  • 服务监控
  • 链路追踪
  • 日志管理
  • 任务调度

分布式的解决

  • SpringBoot + SpringCloud

3.3、云原生

原生应用如何上云。 Cloud Native

上云的困难

  • 服务自愈
  • 弹性伸缩
  • 服务隔离
  • 自动化部署
  • 灰度发布
  • 流量治理

上云的解决
在这里插入图片描述

4、如何学习SpringBoot

4.1、官网文档架构

查看版本新特性;
https://github.com/spring-projects/spring-boot/wiki#release-notes

02、SpringBoot2入门

1、Maven设置

<mirrors><mirror><id>nexus-aliyun</id><mirrorOf>central</mirrorOf><name>Nexus aliyun</name><url>http://maven.aliyun.com/nexus/content/groups/public</url></mirror></mirrors><profiles><profile><id>jdk-1.8</id><activation><activeByDefault>true</activeByDefault><jdk>1.8</jdk></activation><properties><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion></properties></profile></profiles>

2、需求:浏览器发送/hello请求,响应Hello,Spring Boot 2!

2.1、创建Maven工程

在这里插入图片描述

2.2、 引入依赖

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId> <!--spring boot 框架--><version>2.3.4.RELEASE</version>
</parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> <!--web服务的依赖,会导入Tomcat等一些列的库--></dependency></dependencies>

2.3、串讲主程序

package com.atguigu.boot;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*** 主程序* @SpringBootApplication:这是一个SpringBoot应用*/
@SpringBootApplication
public class MainApplication {public static void main(String[] args) {SpringApplication.run(MainApplication.class, args);}
}

2.4、编写业务代码

package com.atguigu.boot.Controller;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;//@ResponseBody
//@Controller@RestController
public class HelloControaller {@RequestMapping("/hello")public String handle01() {return "Hello,Spring Boot 2!";}
}

2.5、测试

直接运行main方法,然后在浏览器发起请求,浏览器应显示“Hello,Spring Boot 2!”。
在这里插入图片描述
在这里插入图片描述

2.6、简化配置

配置文件由application.properties统一管理

server.port=8888

2.7、简化部署

以往我们在部署web应用时,会将项目打成war包,再部署到服务器上,现在可以直接将项目打成可以执行的jar包,直接在服务器执行即可。

 <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>

在这里插入图片描述
在这里插入图片描述

03、自动装配及原理

1、SpringBoot的特点

1.1、依赖管理

  • 父项目做依赖管理
<!--一般父项目都是用来做依赖管理的-->
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.4.RELEASE</version>
</parent><!--spring-boot-starter-parent--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.3.4.RELEASE</version></parent><!--spring-boot-dependencies中几乎声明了所有开发中常用的依赖的版本号,这种机制称为自动版本仲裁机制-->
  • 导入starter场景启动器
<!--
1、见到很多 spring-boot-starter-* : *就某种场景
2、只要引入starter,这个场景的所有常规需要的依赖我们都自动引入
3、SpringBoot所有支持的场景
https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter
4、见到的  *-spring-boot-starter: 第三方为我们提供的简化开发的场景启动器。
5、所有场景启动器最底层的依赖为spring-boot-starter
-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>2.3.4.RELEASE</version><scope>compile</scope>
</dependency>
  • 版本冲裁及版本管理

<!--
1、引入依赖默认都可以不写版本
2、引入非版本仲裁的jar,要写版本号。
查看spring-boot-dependencies里面规定当前依赖的版本用的key。
在当前项目里面重写配置。
--><properties><mysql.version>5.1.43</mysql.version></properties>

1.2、自动配置

  • 自动配好Tomcat
    • 引入Tomcat依赖。
    • 配置Tomcat
  • 自动配好SpringMVC
    • 引入SpringMVC全套组件
    • 自动配好SpringMVC常用组件(功能)
  • 自动配好Web常见功能,如:字符编码问题
    • SpringBoot帮我们配置好了所有web开发的常见场景
  • 默认的包结构
    • 主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来
    • 无需以前的包扫描配置
    • 想要改变扫描路径,@SpringBootApplication(scanBasePackages=“com.atguigu”)
      • 或者@ComponentScan 指定扫描路径
        @SpringBootApplication
        等同于
        @SpringBootConfiguration
        @EnableAutoConfiguration
        @ComponentScan("com.atguigu.boot")
        
  • 各种配置拥有默认值
    • 默认配置最终都是映射到某个类上,如:MultipartProperties
    • 配置文件的值最终会绑定每个类上,这个类会在容器中创建对象
  • 按需加载所有自动配置项
    • 非常多的starter
    • 引入了哪些场景这个场景的自动配置才会开启
    • SpringBoot所有的自动配置功能都在 spring-boot-autoconfigure 包里面

2、容器功能

2.1、组件添加

  • @Configuration
    基本使用

    • Full模式,配置类组件之间有依赖关系,方法会被调用得到之前的单实力组件。
    • Lite模式,配置类组件之间无依赖关系,用Lite模式加速器启动过程,减少判断。
    //#############################Configuration使用示例######################################################
    /*** 1、配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的* 2、配置类本身也是组件* 3、proxyBeanMethods:代理bean的方法*      Full(proxyBeanMethods = true)、【保证每个@Bean方法被调用多少次返回的组件都是单实例的】*      Lite(proxyBeanMethods = false)【每个@Bean方法被调用多少次返回的组件都是新创建的】*      组件依赖必须使用Full模式默认。其他默认是否Lite模式****/
    @Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
    public class MyConfig {/*** Full:外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象* @return*/@Bean //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例public User user01(){User zhangsan = new User("zhangsan", 18);//user组件依赖了Pet组件zhangsan.setPet(tomcatPet());return zhangsan;}@Bean("tom")public Pet tomcatPet(){return new Pet("tomcat");}
    }//################################@Configuration测试代码如下########################################
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan("com.atguigu.boot")
    public class MainApplication {public static void main(String[] args) {//1、返回我们IOC容器ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);//2、查看容器里面的组件String[] names = run.getBeanDefinitionNames();for (String name : names) {System.out.println(name);}//3、从容器中获取组件Pet tom01 = run.getBean("tom", Pet.class);Pet tom02 = run.getBean("tom", Pet.class);System.out.println("组件:"+(tom01 == tom02));//4、com.atguigu.boot.config.MyConfig$$EnhancerBySpringCGLIB$$51f1e1ca@1654a892MyConfig bean = run.getBean(MyConfig.class);System.out.println(bean);//如果@Configuration(proxyBeanMethods = true)代理对象调用方法。SpringBoot总会检查这个组件是否在容器中有。//保持组件单实例User user = bean.user01();User user1 = bean.user01();System.out.println(user == user1);User user01 = run.getBean("user01", User.class);Pet tom = run.getBean("tom", Pet.class);System.out.println("用户的宠物:"+(user01.getPet() == tom));}
    }
    
  • @Bean-用于将一个方法标记为Spring容器中的一个Bean。具体来说,@Bean注解可以用于方法上,该方法返回一个对象,该对象将被Spring容器管理和提供给其他程序组件使用,让IOC容器知道这个组件存在。(相当于创建对象);@Component-注解表明一个类会作为组件类,并告知Spring要为这个类创建bean,使用 @Component注解在一个类上,表示将此类标记为Spring容器中的一个Bean。(相当于创建对象)、@Controller-代表是一个控制器;@Service-代表是一个业务逻辑组件;@Repository-代表是一个数据库层组件

  • @ComponentScan-包扫描、@Import-为容器添加组件

    /** 4、@Import({User.class, DBHelper.class})*      给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名****/@Import({User.class, DBHelper.class})
    @Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
    public class MyConfig {
    }
    

    @Import 高级用法: https://www.bilibili.com/video/BV1gW411W7wy?p=8
    注解的解释及用法:http://t.csdnimg.cn/ASzxy

  • @Conditional-条件装配:满足Conditional指定的条件,则进行组件注入
    在这里插入图片描述

    //=====================测试条件装配==========================
    @Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
    //@ConditionalOnBean(name = "tom") //当容器中有组件tom组件时,则生成对应组件(myconfig、user01、tom22)
    @ConditionalOnMissingBean(name = "tom") //当容器中没有tmo组件时,则生成对应组件(myconfig、user01、tom22)
    // 组件的位置决定了会生成哪些组件,如果@ConditionalOnMissingBean位置在tomcatPet方法上,则只生成tom22
    public class MyConfig {/*** Full:外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象* @return*/@Bean //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例public User user01(){User zhangsan = new User("zhangsan", 18);//user组件依赖了Pet组件zhangsan.setPet(tomcatPet());return zhangsan;}@Bean("tom22")public Pet tomcatPet(){return new Pet("tomcat");}
    }public static void main(String[] args) {//1、返回我们IOC容器ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);//2、查看容器里面的组件String[] names = run.getBeanDefinitionNames();for (String name : names) {System.out.println(name);}boolean tom = run.containsBean("tom");System.out.println("容器中Tom组件:"+tom);boolean user01 = run.containsBean("user01");System.out.println("容器中user01组件:"+user01);boolean tom22 = run.containsBean("tom22");System.out.println("容器中tom22组件:"+tom22);}
    

2.2、 原生配置文件引入

  • @ImportResource 导入资源文件中配置的组件
    <!--======================beans.xml=========================-->
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><bean id="haha" class="com.atguigu.boot.bean.User"><property name="name" value="zhangsan"></property><property name="age" value="18"></property></bean><bean id="hehe" class="com.atguigu.boot.bean.Pet"><property name="name" value="tomcat"></property></bean>
    </beans>
    
    @ImportResource("classpath:beans.xml")
    public class MyConfig {}//======================测试=================boolean haha = run.containsBean("haha");boolean hehe = run.containsBean("hehe");System.out.println("haha:"+haha);//trueSystem.out.println("hehe:"+hehe);//true
    

2.3、配置绑定

  • 使用Java读取到properties文件中的内容,并且把它封装到JavaBean中,以供随时使用;
    例子:

    public class getProperties {public static void main(String[] args) throws FileNotFoundException, IOException {Properties pps = new Properties();pps.load(new FileInputStream("a.properties"));Enumeration enum1 = pps.propertyNames();//得到配置文件的名字while(enum1.hasMoreElements()) {String strKey = (String) enum1.nextElement();String strValue = pps.getProperty(strKey);System.out.println(strKey + "=" + strValue);//封装到JavaBean。}}}
    
  • @Component + @ConfigurationProperties

    /*** 只有在容器中的组件,才会拥有SpringBoot提供的强大功能*/
    @Component
    @ConfigurationProperties(prefix = "mycar")
    public class Car {private String brand;private Integer price;public String getBrand() {return brand;}public void setBrand(String brand) {this.brand = brand;}public Integer getPrice() {return price;}public void setPrice(Integer price) {this.price = price;}@Overridepublic String toString() {return "Car{" +"brand='" + brand + '\'' +", price=" + price +'}';}
    }
    
    @RestController
    public class Hello {@AutowiredCar car;@RequestMapping("/car")public Car car() {return car;}@RequestMapping("/hello")public String handle01() {return "Hello,Spring boot 2!";}
    }
    

    application.properties

    mycar.brand=BYD
    mycar.price=100000
    

    在这里插入图片描述

    使用@Component注解,将组件注册到容器中,使用@ConfigurationProperties(prefix = “mycar”)注解,读取application.properties以mycar开头的配置项

  • @EnableConfigurationProperties + @ConfigurationProperties

    package com.atguigu.boot.bean;import org.springframework.boot.context.properties.ConfigurationProperties;//@Component
    @ConfigurationProperties(prefix = "mycar")
    public class Car {private String brand;private Integer price;public Car() {}public String getBrand() {return brand;}public void setBrand(String brand) {this.brand = brand;}public Integer getPrice() {return price;}public void setPrice(Integer price) {this.price = price;}public Car(String brand, Integer price) {this.brand = brand;this.price = price;}@Overridepublic String toString() {return "Car{" +"brand='" + brand + '\'' +", price=" + price +'}';}
    }
    
    package com.atguigu.boot.config;import com.atguigu.boot.bean.Car;
    import com.atguigu.boot.bean.Pet;
    import com.atguigu.boot.bean.User;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;@ConditionalOnMissingBean(name = "tmo")
    @Configuration(proxyBeanMethods = false)
    @EnableConfigurationProperties(Car.class)
    public class Myconfig {@Bean(name = "UserZS")public User user00() {return new User("zhangsan",5,new Pet("tom"));}@Bean(name = "TomCat")public Pet pet00() {return new Pet("tom");}@Beanpublic Pet Pet01() {return new Pet("jerry");}
    }
    

    在这里插入图片描述

    如果要注入的JavaBean是第三方或者无法添加注解@Component,则可以在控制类中使用@EnableConfigurationProperties注解来实现配置绑定

3、自动配置原理入门

3.1、引导加载自动配置类

@SpringBootApplication注解相当于下面三个注解的集合

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication{}    
  • @SpringBootConfiguration
    @Configuration。代表当前是一个配置类
  • @ComponentScan
    指定扫描哪些,Spring注解;
  • @EnableAutoConfiguration
    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {}
    
    • @AutoConfigurationPackage
      自动配置包?指定了默认的包规则

      @Import(AutoConfigurationPackages.Registrar.class)  //给容器中导入一个组件
      public @interface AutoConfigurationPackage {}//利用Registrar给容器中导入一系列组件
      //将指定的一个包下的所有组件导入进来?MainApplication 所在包下。
      

      在这里插入图片描述
      在这里插入图片描述

    • @Import(AutoConfigurationImportSelector.class)

      1、利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件
      2、调用List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类
      3、利用工厂加载 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件
      4、从META-INF/spring.factories位置来加载一个文件。默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories
      

      在这里插入图片描述

C:\Users\Untifa.m2\repository\org\springframework\boot\spring-boot-autoconfigure\2.6.10\spring-boot-autoconfigure-2.6.10.jar!\META-INF\spring.factories 文件里列出了spring-boot一启动就要加载到容器中的所有类,一共133个类,与debug时的数量一致

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
...
org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration

3.2、按需开启自动配置项

虽然我们133个场景的所有自动配置启动的时候默认全部加载。xxxxAutoConfiguration
按照条件装配规则(@Conditional),最终会按需配置。

3.3、修改默认配置

@Bean
@ConditionalOnBean(MultipartResolver.class)  //容器中有这个类型组件
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) //容器中没有这个名字 multipartResolver 的组件
public MultipartResolver multipartResolver(MultipartResolver resolver) {//给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找。//SpringMVC multipartResolver。防止有些用户配置的文件上传解析器不符合规范// Detect if the user has created a MultipartResolver but named it incorrectlyreturn resolver;
}
//给容器中加入了文件上传解析器;

SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先
在这里插入图片描述

@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {}

总结:

  • SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration
  • 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定
  • 生效的配置类就会给容器中装配很多组件
  • 只要容器中有这些组件,相当于这些功能就有了
  • 定制化配置
    • 用户直接自己@Bean替换底层的组件
    • 用户去看这个组件是获取的配置文件什么值就去修改。

xxxxxAutoConfiguration ---> 组件 ---> xxxxProperties里面取值 ----> application.properties

3.4、最佳实践

  • 引入场景依赖
    • https://docs.spring.io/spring-boot/reference/using/build-systems.html
  • 查看自动配置了哪些(选做)
    • 自己分析,引入场景对应的自动配置一般都生效了
    • 配置文件中debug=true开启自动配置报告。Negative(不生效)\Positive(生效)
  • 是否需要修改
    • 参照文档修改配置项
      https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#common-application-properties
      自己分析。xxxxProperties绑定了配置文件的哪些。
    • 自定义加入或者替换组件
      @Bean、@Component。。。
      自定义器 XXXXXCustomizer;

4、开发小技巧

4.1、Lombok

简化JavaBean开发

<!--1.首先引入依赖--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>
<!--2.idea中搜索安装lombok插件并安装 -->

在这里插入图片描述

package com.atguigu.boot.bean;import lombok.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;//@Component
@Data // 生成getter、setter方法
@ToString // 生成ToString方法
@AllArgsConstructor // 生成全参构造方法
@NoArgsConstructor // 生成无参构造方法
@EqualsAndHashCode // 生成hash值和equal方法
@Slf4j // 注入日志
@ConfigurationProperties(prefix = "mycar")
public class Car {private String brand;private Integer price;
}

4.2、dev-tools

	<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency>

Ctrl+F9来重新编译项目

4.3、Spring Initailizr(项目初始化向导)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

解决application.properties文件中文乱码问题

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

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

相关文章

前端从零到一开发vscode插件并发布到插件市场

前端从零到一开发vscode插件并发布到插件市场 背景目标成果展示一条龙实现过程安装插件脚手架和工具创建项目运行调试打包第一次打包前的必要操作 发布第一次发布前账号准备注册Azure DevOps发布账号-获取token注册vscode开发者账号终端登录vsce 发布方式2-手动上传插件 进阶开…

深入分析 Android Service (三)

文章目录 深入分析 Android Service (三)1. Service 与 Activity 之间的通信2. 详细示例&#xff1a;通过绑定服务进行通信2.1 创建一个绑定服务2.2 绑定和通信 3. 优化建议4. 使用场景5. 总结 深入分析 Android Service (三) 1. Service 与 Activity 之间的通信 在 Android …

115道MySQL面试题(含答案),从简单到深入!

1. 什么是数据库事务&#xff1f; 数据库事务是一个作为单个逻辑工作单元执行的一系列操作。事务具有ACID属性&#xff0c;即原子性&#xff08;Atomicity&#xff09;、一致性&#xff08;Consistency&#xff09;、隔离性&#xff08;Isolation&#xff09;和持久性&#xf…

手机站怎么推广

随着手机的普及和移动互联网的快速发展&#xff0c;越来越多的人开始使用手机进行在线购物、社交娱乐、阅读资讯等&#xff0c;同时也催生了越来越多的手机站的出现。但是&#xff0c;在海量的手机站中&#xff0c;要让自己的手机站脱颖而出&#xff0c;吸引更多用户访问和使用…

CSS 【实战】 “四合院”布局

效果预览 页面要求&#xff1a; 上下固定高度左右固定宽度中间区域自适应宽高整个页面内容撑满全屏&#xff0c;没有滚动条 技术要点 使用 html5 语义化标签 header 网页内的标题区域nav 导航区域aside 侧边栏footer 页脚区域section 内容分区article 文章区域 清除浏览器默…

微信小程序区分运行环境

wx.getAccountInfoSync() 是微信小程序的一个 API&#xff0c;它可以同步获取当前账号信息。返回对象中包含小程序 AppID、插件的 AppID、小程序/插件版本等信息。 返回的对象结构如下&#xff1a; 小程序运行环境&#xff0c;可选值有&#xff1a;develop&#xff08;开发版&…

主备切换大揭秘:保证系统永不停机的秘密

Hello,大家好!我是小米,一个积极活泼、热爱分享技术的小伙伴。今天我们来聊聊一个很重要的主题:分布式分区容错性中的主备切换。无论你是一个经验丰富的开发者,还是刚刚入门的小白,这篇文章都将为你揭开分布式系统的神秘面纱,带你深入了解其中的关键技术。让我们开始吧!…

【赠书第26期】AI绘画教程:Midjourney使用方法与技巧从入门到精通

文章目录 前言 1 Midjourney入门指南 1.1 注册与登录 1.2 界面熟悉 1.3 基础操作 2 Midjourney进阶技巧 2.1 描述词优化 2.2 参数调整 2.3 迭代生成 3 Midjourney高级应用 3.1 创意启发 3.2 团队协作 3.3 商业应用 4 总结与展望 5 推荐图书 6 粉丝福利 前言 在…

污水净化之旅:可视化技术揭秘城市“血液”的循环奥秘

在繁华的都市背后&#xff0c;有一个默默守护着我们的“肾脏”——污水处理厂。它悄无声息地处理着每天产生的污水&#xff0c;确保我们的生活环境洁净美好。但你知道这个“肾脏”是如何工作的吗&#xff1f;今天&#xff0c;就让我们一起走进污水处理的神秘世界&#xff0c;通…

Leetcode:寻找两个正序数组的中位数

题目链接&#xff1a;4. 寻找两个正序数组的中位数 - 力扣&#xff08;LeetCode&#xff09; 题目分析 1、当只有一个有序数组时&#xff0c;该数组的中位数会将该数组分为两份&#xff1a;左子数组 和 右子数组 2、当有两个有序数组时&#xff0c; 我们仍然可以通过一条分隔…

社区供稿丨GPT-4o 对实时互动与 RTC 的影响

以下文章来源于共识粉碎机 &#xff0c;作者AI芋圆子 前面的话&#xff1a; GPT-4o 发布当周&#xff0c;我们的社区伙伴「共识粉碎机」就主办了一场主题为「GPT-4o 对实时互动与 RTC 的影响」讨论会。涉及的话题包括&#xff1a; GPT-4o 如何降低延迟&#xff08;VAD 模块可…

LabVIEW中进行步进电机的位置控制

在LabVIEW中进行步进电机的位置控制&#xff0c;通常涉及以下几个关键步骤&#xff1a;设置硬件、配置通信、编写控制算法和实施反馈控制。以下是一个详细的介绍。 硬件设置 步进电机&#xff1a;选择合适的步进电机&#xff0c;根据负载和应用需求选择适当的步数和转矩。 驱…

FL Studio21.2.8中文版让你的音乐创作如鱼得水

在音乐的世界里&#xff0c;我们都是探索者&#xff0c;追求着无尽的创新和可能性。而在这个过程中&#xff0c;我们往往会遇到各种挑战和困扰。如何快速高效地创作出满意的音乐作品&#xff1f;如何将我们的创意完美地呈现出来&#xff1f;这些问题可能一直困扰着你。今天&…

成都欣丰洪泰文化传媒有限公司助力品牌快速崛起

在当今数字化浪潮汹涌的时代&#xff0c;电商行业作为新经济的代表&#xff0c;正以其独特的魅力和无限的潜力&#xff0c;引领着商业模式的创新与变革。在这个充满机遇与挑战的领域里&#xff0c;成都欣丰洪泰文化传媒有限公司凭借其专业的电商服务能力和前瞻性的战略眼光&…

如何在.htaccess文件创建一个自定义404页面

本周有一个客户&#xff0c;购买Hostease的虚拟主机&#xff0c;询问我们的在线客服&#xff0c;如何在.htaccess文件创建一个自定义404页面&#xff1f;我们为用户提供相关教程&#xff0c;用户很快解决了遇到的问题。在此&#xff0c;我们分享这个操作教程&#xff0c;希望可…

MVC和MVVM

MVC Model层&#xff1a;用于处理应用程序数据逻辑的部分&#xff0c;通常负责在数据库中存取数据 View&#xff08;视图&#xff09;处理数据显示的部分。通常视图是依据模型数据创建的 Controller&#xff08;控制器&#xff09;是处理用户交互的部分。通常控制器负责从视…

从零开始学Vue3--环境搭建

1.搭建环境 下载nodejs nodejs下载地址 更新npm npm install -g npm 设置npm源&#xff0c;加快下载速度 npm config set registry https://registry.npmmirror.com 使用脚手架创建项目 npm create vuelatest 根据你的需要选择对应选项 进入新建的项目下载依赖 npm in…

Tasker+SendSilentMail实现钉钉自动打卡

Tasker 允许用户根据自定义的“配置文件”(Profiles)&#xff0c;在特定的“背景”(Contexts)下&#xff0c;执行指定的“任务”(Tasks)。以下是关于Tasker的详细介绍&#xff1a; 强大的自定义能力&#xff1a;用户可以根据自己的需求&#xff0c;创建各种配置文件和任务&…

【BUG】流式响应requests得到: ping - 和时间戳

前情提要 运行Langchain-Chatchat项目&#xff0c;使用自定义请求访问API Server流式输出 报错展示 b: ping - 2024-05-22 00:46:04.83252000:00\r\n\r\n报错原因 这通常是由于 Server-Sent Events (SSE) 实现中使用的“心跳”机制&#xff0c;以确保连接保持活跃。一些 SSE…

Java 在Word文档中添加、删除页面

在排版或者编辑Word文档时&#xff0c;可能会需要增加新页面或删除某个已有页面&#xff0c;以便更好地呈现内容。下面将介绍如何使用国产Java控件来实现在Word文档中增删页面的功能。 目录 Java 在Word文档末尾新增一页 Java 在Word文档指定位置插入一页 Java 删除Word文档…