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

SpringBoot源码分析

一:简介

  1. 由Pivotal团队提供的全新框架
  2. 其设计目的是用来简化新Spring应用的初始搭建以及开发过程
  3. 使用了特定的方式来进行配置
  4. 快速应用开发领域

二:运行原理以及特点

运行原理:

SpringBoot为我们做的自动配置,确实方便快捷,今天来了解一下它的原理:
在这里插入图片描述
特点:

  1. 可以创建独立的Spring应用程序,并且基于其Maven或Gradle插件,可以创建可执行的JARs和WARs;
  2. 内嵌Tomcat或Jetty等Servlet容器;
  3. 提供自动配置的“starter”项目对象模型(POMS)以简化Maven配置;
  4. 尽可能自动配置Spring容器;
  5. 提供准备好的特性,如指标、健康检查和外部化配置;
  6. 绝对没有代码生成,不需要XML配置。

三:重点了解

  1. 约定优于配置
  2. 开箱即用
  3. 程序和注解

1:约定优于配置

90%以上的项目呢,配置都差不多,所以呢spring团队,就搞出了一个通用的配置,以后我们程序猿就不需要再去配置这些繁杂的配置了. 如果用的ssm,所有的maven依赖,版本,都需要我们程序猿去控制,去找依赖,并且互相配合依赖.依赖没有配合好,jar冲突,,出了问题就需要程序猿去解决,一般非常耗时的.

补充:约定优于配置也被称为习惯优于配置、约定大于配置

提示:全局配置名称,必须是 application 这是spring规定好的,别的识别不了

配置文件生效顺序:properties > yml > yaml

2:开箱即用

说明:
1:内嵌Tomcat或Jetty等Servlet容器;
2:用来简化新Spring应用的初始搭建以及开发过程
3:每一个stater都是一个场景功能

<!--引入web starter启动器 常见的场景--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>

3:注解和程序

/*表明此类是springboot启动类,服务类
@SpringBootApplication是一个复合注解
包括@ComponentScan,和@SpringBootConfiguration,@EnableAutoConfiguration*/
@SpringBootApplication
public class Demo100Application {//main 程序的入口public static void main(String[] args) {/*SpringApplicationrun*/SpringApplication.run(Demo100Application.class, args);}
}
3.1:注解:
3.1.0:总述:
1@ComponentScan: 该注解默认会扫描该类所在的包下所有的配置类,相当于之前的 <context:component-scan>
2@EnableAutoConfiguration  这个注解它所加的组件―就是我们在 pom 中申明的组件﹐以及springBoot默认提供给我用的组件  将组建实例化,交由ioc容器去管理2.1@AutoConfigurationPackage :自动配置包2.2@Import({AutoConfigurationImportSelector.class}):载入selector,识别AutoConfigutaion类并import
3@SpringBootConfiguration3.1@Configuration3.2@Component解释:@SpringBootConfiguration继承自@Configuration,二者功能也一致,标注当前类是配置类,
并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到spring容器中,并且实例名就是方法名
3.1.1:配置类注解:

@SpringBootConfiguration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">	</bean>
</beans>   
@Configuration
public class Config {@Beanpublic Map createMap(){Map map = new HashMap();map.put("username","gxz");map.put("age",27);return map;}
}
@Component
public class test {
}
3.1.2:核心注解

@EnableAutoConfiguration:是我们的核心注解旳开启白动配置/自动装配

@Import({AutoConfigurationImportSelector.class}):(核心中的核心)!!!

	@AutoConfigurationPackage :自动配置包	@Import({AutoConfigurationImportSelector.class}):载入selector,识别AutoConfigutaion类并import 
  • 1
  • 2
  • 3
3.1.3:扫描包注解

@ComponentScan: 该注解默认会扫描该类所在的包下所有的配置类,相当于之前的 context:component-scan

	@ComponentScan

提示:Properties中所有的配置 其实 底层都对应了 一个类的属性

3.2:程序:
3.2.1:实例化SpringApplication

SpringApplication初始化时主要做三件事情:

1.根据classpath下是否存在(ConfigurableWebApplicationContext)判断是否要启动一个web applicationContext
2.SpringFactoriesInstances加载classpath下所有可用的ApplicationContextInitializer
3.SpringFactoriesInstances加载classpath下所有可用的ApplicationListener

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));//1.根据classpath下是否存在(ConfigurableWebApplicationContext)判断是否要启动一个web applicationContextthis.webApplicationType = WebApplicationType.deduceFromClasspath();//2.SpringFactoriesInstances加载classpath下所有可用的ApplicationContextInitializersetInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));//3.SpringFactoriesInstances加载classpath下所有可用的ApplicationListenersetListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));this.mainApplicationClass = deduceMainApplicationClass();
}
3.2.2:实例化完成后调用run()方法

调用run()方法执行的过程主要分为以下几步:

1.遍历SpringApplication初始化过程中加载的SpringApplicationRunListeners
2.调用Starting()监听SpringApplication的启动
3.加载SpringBoot配置环境(ConfigurableEnvironment)
4.设置banner属性
5.创建ConfigurableApplicationContext(应用配置上下文)
6.将listeners、environment、applicationArguments、bannner等重要组件与上下文对象关联
7.bean的实力化完成

public ConfigurableApplicationContext run(String... args) {StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();configureHeadlessProperty();//1.遍历SpringApplication初始化过程中加载的SpringApplicationRunListenersSpringApplicationRunListeners listeners = getRunListeners(args);//2.调用starting()监听SpringApplication的启动listeners.starting();try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);//3.加载SpringBoot配置环境ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);configureIgnoreBeanInfo(environment);//4.设置banner属性Banner printedBanner = printBanner(environment);//5.创建ConfigurableApplicationContext(应用配置上下文)context = createApplicationContext();exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);//6.将listeners、environment、applicationArguments、banner等重要组件与上下文对象关联prepareContext(context, environment, listeners, applicationArguments, printedBanner);//7.实例化beanrefreshContext(context);afterRefresh(context, applicationArguments);stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}listeners.started(context);callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);}try {listeners.running(context);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);}return context;
}
3.2.2.1:遍历SpringApplication初始化过程中加载的SpringApplicationRunListeners
private SpringApplicationRunListeners getRunListeners(String[] args) {Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };return new SpringApplicationRunListeners(logger,getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
3.2.2.2:调用Starting()监听SpringApplication的启动
public void starting() {//遍历所有的SpringApplicationRunListener,调用starting()方法监听SpringApplication的启动for (SpringApplicationRunListener listener : this.listeners) {listener.starting();}
}
3.2.2.3:加载SpringBoot配置环境(ConfigurableEnvironment)
 加载SpringBoot配置环境(configurableEnvironment),如果是通过web容器发布,会加载StandardEnvironment。将配置文件(Environment)加入到监听器对象中(SpringApplicationRunListeners)
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments) {// Create and configure the environment//如果environment不为空直接返回 || 如果是web环境则直接实例化StandardServletEnvironment类 || 如果不是web环境则直接实例化StandardEnvironment类ConfigurableEnvironment environment = getOrCreateEnvironment();//配置环境信息configureEnvironment(environment, applicationArguments.getSourceArgs());//通知所有的监听者,环境已经准备好了listeners.environmentPrepared(environment);bindToSpringApplication(environment);if (!this.isCustomEnvironment) {environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,deduceEnvironmentClass());}ConfigurationPropertySources.attach(environment);return environment;
}
3.2.2.4:设置banner属性
private Banner printBanner(ConfigurableEnvironment environment) {//如果未开启banner打印直接返回if (this.bannerMode == Banner.Mode.OFF) {return null;}//创建ResourceLoader对象ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader: new DefaultResourceLoader(getClassLoader());//创建SpringApplicationBannerPrinter,该对象用来打印bannerSpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);//如果bannerMode模式为LOG,则将bannner打印到log文件中if (this.bannerMode == Mode.LOG) {return bannerPrinter.print(environment, this.mainApplicationClass, logger);}//打印banner到控制台return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}
3.2.2.5:初始化ConfigurableApplicationContext(应用配置上下文)SpringApplicationRunListeners

在SpringBoot中,应用类型分为三类

public enum WebApplicationType {/*** The application should not run as a web application and should not start an* embedded web server.*/// 应用程序不是web应用,也不应该用web服务器去启动NONE,/*** The application should run as a servlet-based web application and should start an* embedded servlet web server.*///应用程序应作为基于servlet的web应用程序运行,并应启动嵌入式servlet web(tomcat)服务器SERVLET,/*** The application should run as a reactive web application and should start an* embedded reactive web server.*///应用程序应作为 reactive web应用程序运行,并应启动嵌入式 reactive web服务器。REACTIVE;
}

根据webEnvironment是否是web环境创建默认的contextClass,AnnotationConfigEnbeddedWebApplicationContext(通过扫描所有注解类来加载bean)和ConfigurableWebApplicationContext),最后通过BeanUtils实例化上下文对象,并返回。

protected ConfigurableApplicationContext createApplicationContext() {//根据webEnvironment是否是web环境创建默认的contextClassClass<?> contextClass = this.applicationContextClass;if (contextClass == null) {try {switch (this.webApplicationType) {case SERVLET://AnnotationConfigServletWebServerApplicationContextcontextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);break;case REACTIVE://AnnotationConfigReactiveWebServerApplicationContextcontextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);break;default://AnnotationConfigApplicationContextcontextClass = Class.forName(DEFAULT_CONTEXT_CLASS);}}catch (ClassNotFoundException ex) {throw new IllegalStateException("Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass",ex);}}//BeanUtils实例化上下文对象return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
3.2.2.6:将listeners、environment、applicationArguments、banner等重要组件与上下文对象关联
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {//设置上下文的environmentcontext.setEnvironment(environment);//应用上下文后处理postProcessApplicationContext(context);//在context refresh之前,对其应用ApplicationContextInitializerapplyInitializers(context);//上下文准备listeners.contextPrepared(context);//打印启动日志和启动应用的profileif (this.logStartupInfo) {logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);}// Add boot specific singleton beansConfigurableListableBeanFactory beanFactory = context.getBeanFactory();//向beanFactory注册单例bean:命令行参数beanbeanFactory.registerSingleton("springApplicationArguments", applicationArguments);if (printedBanner != null) {//向beanFactory注册单例bean:banner beanbeanFactory.registerSingleton("springBootBanner", printedBanner);}if (beanFactory instanceof DefaultListableBeanFactory) {((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}// Load the sources//获取SpringApplication的primarySources属性Set<Object> sources = getAllSources();Assert.notEmpty(sources, "Sources must not be empty");//将bean加载到应用上下文load(context, sources.toArray(new Object[0]));//向上下文添加ApplicationListener,并广播ApplicationPreparedEvent事件listeners.contextLoaded(context);
}
3.2.2.7:bean的实例化完成,刷新应用上下文

相关文章:

SpringBoot源码分析

一&#xff1a;简介 由Pivotal团队提供的全新框架其设计目的是用来简化新Spring应用的初始搭建以及开发过程使用了特定的方式来进行配置快速应用开发领域 二&#xff1a;运行原理以及特点 运行原理&#xff1a; SpringBoot为我们做的自动配置&#xff0c;确实方便快捷&#…...

约数个数和约数之和算法总结

知识概览 约数个数 基于算数基本定理&#xff0c;假设N分解质因数的结果为 可得对于N的任何一个约数d&#xff0c;有 因为N的每一个约数和~的一种选法是一一对应的&#xff0c;根据乘法原理可得&#xff0c; 一个数的约数个数为 约数之和 一个数的约数之和公式为 多项式乘积的…...

数据结构-怀化学院期末题(322)

图的深度优先搜索 题目描述&#xff1a; 图的深度优先搜索类似于树的先根遍历&#xff0c;是树的先根遍历的推广。即从某个结点开始&#xff0c;先访问该结点&#xff0c;然后深度访问该结点的第一棵子树&#xff0c;依次为第二顶子树。如此进行下去&#xff0c;直到所有的结点…...

小手也能用的高性能鼠标,自定义空间还挺高,雷柏VT9Pro mini上手

今年搭载PAW3395传感器的电竞鼠标很受欢迎&#xff0c;雷柏就出了不少型号&#xff0c;满足各种喜好的玩家选择&#xff0c;像是近期新出的搭载3395高定版的VT9Pro和VT9Pro mini&#xff0c;就在轻量化的基础上&#xff0c;满足了各种手型的玩家的使用需要&#xff0c;而且价格…...

CDN加速原理详解

一、CDN加速是什么意思 CDN是Content Delivery Network&#xff09;英文首字母的缩写&#xff0c;中文翻译为内容分发网络&#xff0c;由于CDN是为加快网络访问速度而被优化的网络覆盖层&#xff0c;因此被形象地称为”网络加速器”&#xff0c;即CDN加速。CDN加速是通过将网站…...

sqlachemy orm create or delete table

sqlacehmy one to one ------detial to descript 关于uselist的使用。如果你使用orm直接创建表关系,实际上在数据库中是可以创建成多对多的关系,如果加上uselistFalse 你会发现你的orm只能查询出来一个&#xff0c;如果不要这个参数orm查询的就是多个&#xff0c;一对多的…...

科普小米手机、华为手机、红米手机、oppo手机、vivo手机、荣耀手机、一加手机、realme手机如何设置充电提示音

用空空鱼就可以设置&#xff0c;上面还有很多提示音素材还可以设置满电和低电提醒...

zookeeper应用场景之分布式的ID生成器

1. 分布式ID生成器的使用场景 在分布式系统中&#xff0c;分布式ID生成器的使用场景非常之多&#xff1a; 大量的数据记录&#xff0c;需要分布式ID。大量的系统消息&#xff0c;需要分布式ID。大量的请求日志&#xff0c;如restful的操作记录&#xff0c;需要唯一标识&#x…...

Java--Spring项目生成雪花算法数字(Twitter SnowFlake)

文章目录 前言步骤查看结果 前言 分布式系统常需要全局唯一的数字作为id&#xff0c;且该id要求有序&#xff0c;twitter的SnowFlake解决了这种需求&#xff0c;生成了符合条件的这种数字&#xff0c;本文将提供一个接口获取雪花算法数字。以下为代码。 步骤 SnowFlakeUtils …...

紫光展锐M6780丨画质增强——更炫的视觉体验

智能显示被认为是推动数字化转型和创新的重要技术之一。研究机构数据显示&#xff0c;预计到2035年底&#xff0c;全球智能显示市场规模将达到1368.6亿美元&#xff0c;2023-2035年符合年增长率为36.4%。 随着消费者对高品质视觉体验的需求不断增加&#xff0c;智能手机、平板…...

控制el-table的列显示隐藏

控制el-table的列显示隐藏&#xff0c;一般的话可以通过循环来实现&#xff0c;但是假如业务及页面比较复杂的话&#xff0c;list数组循环并不好用。 在我们的页面中el-table-column是固定的&#xff0c;因为现在是对现有的进行维护和迭代更新。 对需要控制列显示隐藏的页面进…...

2024上海国际冶金及材料分析测试仪器设备展览会

2024上海国际冶金及材料分析测试仪器设备展览会 时间&#xff1a;2024年12月18&#xff5e;20日 地点&#xff1a;上海新国际博览中心 ◆ 》》》组织机构&#xff1a; 主办单位&#xff1a;全联冶金商会、中国宝武钢铁集团有限公司、上海市金属学会 支持单位&#xff…...

商业定位,1元平价商业咨询:豪威尔咨询!平价咨询。

在做生意之前&#xff0c;就需要对企业整体进行一完整的商业定位&#xff0c;才能让商业定位带动企业进行飞速发展。 所以&#xff0c;包含商业定位的有效工作内容就显得极为重要&#xff0c;今天&#xff0c;小编特地为大家整理出了商业定位所需要的筹备的工作&#xff0c;如下…...

2. Presto应用

该笔记来源于网络&#xff0c;仅用于搜索学习&#xff0c;不保证所有内容正确。文章目录 1、Presto安装使用2、事件分析3、漏斗分析4、漏斗分析UDAF开发开发UDF插件开发UDAF插件 5、漏斗测试 1、Presto安装使用 参考官方文档&#xff1a;https://prestodb.io/docs/current/ P…...

工业级安卓PDA超高频读写器手持掌上电脑,RFID电子标签读写器

掌上电脑&#xff0c;又称为PDA。工业级PDA的特点就是坚固&#xff0c;耐用&#xff0c;可以用在很多环境比较恶劣的地方。 随着技术的不断发展&#xff0c;加快了数字化发展趋势&#xff0c;RFID技术就是RFID射频识别及技术&#xff0c;作为一种新兴的非接触式的自动识别技术&…...

Prompt提示工程上手指南:基础原理及实践(一)

想象一下&#xff0c;你在装饰房间。你可以选择一套标准的家具&#xff0c;这是快捷且方便的方式&#xff0c;但可能无法完全符合你的个人风格或需求。另一方面&#xff0c;你也可以选择定制家具&#xff0c;选择特定的颜色、材料和设计&#xff0c;以确保每件家具都符合你的喜…...

Redis如何保证缓存和数据库一致性?

背景 现在我们在面向增删改查开发时&#xff0c;数据库数据量大时或者对响应要求较快&#xff0c;我们就需要用到Redis来拿取数据。 Redis&#xff1a;是一种高性能的内存数据库&#xff0c;它将数据以键值对的形式存储在内存中&#xff0c;具有读写速度快、支持多种数据类型…...

学完C/C++,再学Python是一种什么体验?

你好&#xff0c;我是安然无虞。 文章目录 变量及类型变量类型动态类型特性 注释输入输出通过控制台输出通过控制台输入 运算符算术运算符关系运算符逻辑运算符赋值运算符 条件循环语句条件语句语法格式代码案例缩进和代码块空语句pass 循环语句while循环语法格式代码案例 for…...

ssm基于Java的壁纸网站设计与实现论文

目 录 目 录 I 摘 要 III ABSTRACT IV 1 绪论 1 1.1 课题背景 1 1.2 研究现状 1 1.3 研究内容 2 2 系统开发环境 3 2.1 vue技术 3 2.2 JAVA技术 3 2.3 MYSQL数据库 3 2.4 B/S结构 4 2.5 SSM框架技术 4 3 系统分析 5 3.1 可行性分析 5 3.1.1 技术可行性 5 3.1.2 操作可行性 5 3…...

零基础也可以探索 PyTorch 中的上采样与下采样技术

目录 torch.nn子模块Vision Layers详解 nn.PixelShuffle 用法与用途 使用技巧 注意事项 参数 示例代码 nn.PixelUnshuffle 用法与用途 使用技巧 注意事项 参数 示例代码 nn.Upsample 用法与用途 使用技巧 注意事项 参数 示例代码 nn.UpsamplingNearest2d …...

代码随想录算法训练营Day23|669. 修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树

目录 669. 修剪二叉搜索树 前言 思路 递归法 108.将有序数组转换为二叉搜索树 前言 递归法 538.把二叉搜索树转换为累加树 前言 递归法 总结 669. 修剪二叉搜索树 题目链接 文章链接 前言 本题承接昨天二叉搜索树的插入和删除操作题目&#xff0c;要对整棵二叉搜索树…...

乱 弹 篇(一)

题记 对于“乱弹”这个词汇的释义&#xff0c;《辞海》上仅有“ 戏曲剧种&#xff0c;亦指声腔 ”8个字。而由于“乱弹 ”的“ 弹”谐音谈”&#xff0c;这就容易让人联想到“乱谈”。不过从文体上看&#xff0c;“乱谈”也非乱七八糟之谈&#xff0c;反倒是“东西南北&#x…...

《JVM由浅入深学习【八】 2024-01-12》JVM由简入深学习提升分(JVM的垃圾回收算法)

目录 JVM的垃圾回收算法1. 标记-清除算法&#xff08;Mark-Sweep&#xff09;原理步骤优点缺点 2. 复制算法&#xff08;Copying&#xff09;原理步骤优点缺点 3. 标记-整理算法&#xff08;Mark-Compact&#xff09;原理步骤优点缺点 4. 分代收集算法&#xff08;Generational…...

在矩阵回溯中进行累加和比较的注意点

1 总结 在回溯时&#xff0c;如果递归函数采用void返回&#xff0c;在入口处使用了sum变量&#xff0c;那么一般在初次调用dfs的地方&#xff0c;这个sum的初始值可能不是0,而是数组的对应指针的值&#xff0c;在比较操作的时候&#xff0c;需要在for循环开始之前进行&#xf…...

AI语音机器人的发展

第一代AI语音机器人具体投入研发的开始时间不太清楚&#xff0c;只记得2017年的下半年就已经开始接触到成型的AI语音机器人&#xff0c;并且正式商用。语音识别效果还不多&#xff0c;大多都是接入的科大讯飞或者百度的ASR。 2018年算是AI语音机器人的“青春期”吧&#xff0c;…...

SQL语句错误this is incompatible with sql_mode=only_full_group_by解决方法

一、原理层面 这个错误发生在mysql 5.7.5 版本及以上版本会出现的问题&#xff1a; mysql 5.7.5版本以上默认的sql配置是:sql_mode“ONLY_FULL_GROUP_BY”&#xff0c;这个配置严格执行了"SQL92标准"。 很多从5.6升级到5.7时&#xff0c;为了语法兼容&#xff0c;大部…...

静态长效代理IP和动态短效代理IP有哪些用途?分别适用场景是什么?

静态长效代理IP和动态短效代理IP是两种常见的代理IP类型&#xff0c;它们在用途和适用场景上存在一定的差异。了解它们的特性以及使用场景有助于我们更好地利用代理IP&#xff0c;提高网络访问的效率和安全性。 一、静态长效代理IP 1. 用途 静态长效代理IP是指长期保持稳定的代…...

基于Spring Boot+Vue的课堂管理系统(前后端分离)

该项目完全免费 介绍 基于Spring BootVue的课堂管理系统。前后端分离。包含教师授课管理、学生选退课、聊天室、签到、笔记管理模块等。 技术架构 SpringBoot MyBatis Redis WebSocket VueCLI Axios Element UI 项目特点&#xff1a; 1、后台使用MyBatis连接数据库&…...

供排水管网管理信息化的必要性

供排水管网是城市供水系统的大动脉&#xff0c;它负担者将优质水源输送到最终用户的重要职责&#xff0c;对供水系统有着极其重要的作用。城市供排水管网埋设在地下&#xff0c;规模庞大&#xff0c;仅靠人工难以管理。同时&#xff0c;由于城市的发展&#xff0c;管网连接结构…...

统一格式,无限创意:高效管理不同格式图片批量转换

在数字时代&#xff0c;图片格式的多样性带来了管理上的不便。为了满足不同的需求&#xff0c;我们经常需要将大量图片转换为统一的格式。那么&#xff0c;有没有一种简单、高效的方法来解决这个问题呢&#xff1f;答案是肯定的&#xff01;今天&#xff0c;我们将为您介绍一款…...