Spring提供的SPEL表达式
SPEL
1. 概述
SpEL是Spring框架中用于表达式语言的一种方式。它类似于其他编程语言中的表达式语言,用于在运行时计算值或执行特定任务。
SpEL提供了一种简单且强大的方式来访问和操作对象的属性、调用对象的方法,以及实现运算、条件判断等操作。它可以被用于XML和注解配置中,可以用于许多Spring框架中的特性,如依赖注入、AOP、配置文件等。
SpEL表达式可以在字符串中进行定义,使用特殊的语法和符号来表示特定的操作。例如,可以使用${expression}来表示一个SpEL表达式,其中expression是具体的SpEL语句。
SpEL支持各种操作和函数,包括算术运算、逻辑运算、条件判断、正则表达式匹配、集合操作等。它还支持访问上下文中的变量和参数,以及调用对象的方法
2. 基础语法学习案例
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.Test;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
import org.springframework.expression.spel.support.StandardEvaluationContext;import java.util.*;/*** SPEL表达式案例** @author xuyuan* @see EvaluationContext* @see SimpleEvaluationContext 定制化提供特定的上下文对象,控制读写权限,可以只读如下的SimpleEvaluationContext.forReadOnlyDataBinding().build()* SimpleEvaluationContext.forReadOnlyDataBinding().build():* 适用于简单的、只读的数据绑定场景。* 性能较好,但功能有限。* 不支持复杂的表达式操作。* <p>* new StandardEvaluationContext(obj):* 适用于复杂的表达式求值场景。* 功能全面,支持所有SPEL特性。* 可以设置根对象和其他上下文信息,灵活性高。*/
public class SpelExam {/*** 操作字面量*/@Testpublic void test() {ExpressionParser parser = new SpelExpressionParser();// 获取字符串 "Hello World"String helloWorld = parser.parseExpression("'Hello World'").getValue(String.class);System.out.println(helloWorld);// double类型 6.0221415E23double avogadrosNumber = parser.parseExpression("6.0221415E+23").getValue(Double.class);System.out.println(avogadrosNumber);// int类型 2147483647int maxValue = parser.parseExpression("0x7FFFFFFF").getValue(Integer.class);System.out.println(maxValue);// trueboolean trueValue = parser.parseExpression("true").getValue(Boolean.class);System.out.println(trueValue);// nullObject nullValue = parser.parseExpression("null").getValue();System.out.println(nullValue);}/*** 操作对象*/@Testpublic void test2() {// 定义Parser,可以定义全局的parserExpressionParser parser = new SpelExpressionParser();// 注意!属性名的第一个字母不区分大小写。 birthdate.year等效于Birthdate.Year// 取出Inventor 中,birthdate属性的year属性Inventor zhangsan = new Inventor("zhangsan", new Date(), "China");// 定义StandardEvaluationContext ,传入一个操作对象StandardEvaluationContext zhangsanContext = new StandardEvaluationContext(zhangsan);int year = parser.parseExpression("birthdate.year + 1900").getValue(zhangsanContext, Integer.class);System.out.println(year); // 2025// 取出Inventor的placeOfBirth的city属性PlaceOfBirth placeOfBirth = new PlaceOfBirth("长沙", "中国");zhangsan.setPlaceOfBirth(placeOfBirth);String city = parser.parseExpression("placeOfBirth.City").getValue(zhangsanContext, String.class);System.out.println(city); // 长沙}/*** 操作数组和List*/@Testpublic void test3() {// 定义Parser,可以定义全局的parserExpressionParser parser = new SpelExpressionParser();EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();// 省略数据初始化Society ieee = new Society();Inventor tesla = new Inventor("Tesla", "USA");ieee.getMembers().add(tesla);ieee.getMembers().add(new Inventor("BYD", "CN"));ieee.getMembers().add(new Inventor("BMW", "GE"));ieee.getMembers().add(new Inventor("FLL", "FR"));tesla.setInventions(new String[]{"Lightning", "Telephone", "Computer", "Electricity", "Electric Motor", "Electric Engine", "Electric Car"});String value = parser.parseExpression("inventions[3]").getValue(context, tesla, String.class);System.out.println("取出tesla对象的inventions 第四个数据:" + value);String name = parser.parseExpression("Members[0].Name").getValue(context, ieee, String.class);System.out.println("取出ieee对象的第一个Member的name属性:" + name);String invention = parser.parseExpression("Members[0].Inventions[6]").getValue(context, ieee, String.class);System.out.println("取出ieee对象的第一个Member的第七个Inventions:" + invention);}/*** 操作Map*/@Testpublic void test4() {ExpressionParser parser = new SpelExpressionParser();EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();Society ieee = new Society();ieee.getOfficers().put("president", new Inventor("Tesla", "USA"));ieee.getOfficers().put("advisors", new Inventor("BYD", "CN"));ieee.getOfficers().put("secretary", new Inventor("BMW", "GE"));ieee.getOfficers().put("treasurer", new Inventor("FLL", "FR"));String name = parser.parseExpression("officers['advisors'].name").getValue(context, ieee, String.class);System.out.println("取出ieee对象的advisors的name属性:" + name);}/*** 内嵌List/Map*/@Testpublic void test5() {// 定义Parser,可以定义全局的parserExpressionParser parser = new SpelExpressionParser();// [1, 2, 3, 4]List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue();System.out.println(numbers);// 嵌套: [[a, b], [x, y]]List listOfLists = (List) parser.parseExpression("{{'a','b'},{'x','y'}}").getValue();System.out.println(listOfLists);// {name=Nikola, dob=10-July-1856}Map inventorInfo = (Map) parser.parseExpression("{name:'Nikola',dob:'10-July-1856'}").getValue();System.out.println(inventorInfo);// 嵌套:{name={first=Nikola, last=Tesla}, dob={day=10, month=July, year=1856}}Map mapOfMaps = (Map) parser.parseExpression("{name:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:1856}}").getValue();System.out.println(mapOfMaps);// List与Map可以嵌套使用,互相结合。// 嵌套:[{name={first=Nikola, last=Tesla}}, {dob={day=10, month=July, year=1856}}]List listOfMaps = (List) parser.parseExpression("{{name:{first:'Nikola',last:'Tesla'}},{dob:{day:10,month:'July',year:1856}}}").getValue();System.out.println(listOfMaps);}/*** 构建数组*/@Testpublic void test6() {ExpressionParser parser = new SpelExpressionParser();int[] numbers1 = parser.parseExpression("new int[4]").getValue(int[].class);// 数组并初始化int[] numbers2 = parser.parseExpression("new int[]{1,2,3}").getValue(int[].class);// 多维数组int[][] numbers3 = parser.parseExpression("new int[4][5]").getValue(int[][].class);}/*** 调用方法*/@Testpublic void test7() {ExpressionParser parser = new SpelExpressionParser();// 调用substring方法System.out.println(parser.parseExpression("'abc'.substring(1, 3)").getValue(String.class));// 调用societyContext中对象的isMember方法,并传值。StandardEvaluationContext societyContext = new StandardEvaluationContext(new Society());boolean isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue(societyContext, Boolean.class);}/*** 关系运算* 每个符号操作符也可以被指定为纯字母的等价物。这避免了所使用的符号对于嵌入表达式的文档类型具有特殊含义的问题(例如在XML文档中)。所有文本操作符都不区分大小写。对应的文本是:* lt (<)* gt (>)* le (<=)* ge (>=)* eq (==)* ne (!=)* div (/)* mod (%)* not (!)*/@Testpublic void test8() {ExpressionParser parser = new SpelExpressionParser();boolean trueValue = parser.parseExpression("2 == 2").getValue(Boolean.class);boolean falseValue = parser.parseExpression("2 < -5.0").getValue(Boolean.class);boolean trueValue1 = parser.parseExpression("'black' < 'block'").getValue(Boolean.class);}/*** instanceof 和 正则表达式的匹配操作符* 使用基本类型时要小心,因为它们会立即被装箱为包装器类型,所以1 instanceof T(int)会计算为false,而1 instanceof T(Integer)会计算为true。*/@Testpublic void test9() {ExpressionParser parser = new SpelExpressionParser();boolean value = parser.parseExpression("'xyz' instanceof T(Integer)").getValue(Boolean.class);boolean trueValue = parser.parseExpression("'5.00' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);boolean falseValue = parser.parseExpression("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);}/*** 逻辑运算符:and, or, not*/@Testpublic void test10() {ExpressionParser parser = new SpelExpressionParser();StandardEvaluationContext societyContext = new StandardEvaluationContext(new Society());boolean value = parser.parseExpression("true and false").getValue(Boolean.class);String expression1 = "isMember('Nikola Tesla') and isMember('Mihajlo Pupin')";boolean value1 = parser.parseExpression(expression1).getValue(societyContext, Boolean.class);boolean value2 = parser.parseExpression("true or false").getValue(Boolean.class);String expression2 = "isMember('Nikola Tesla') or isMember('Albert Einstein')";boolean valu3 = parser.parseExpression(expression2).getValue(societyContext, Boolean.class);boolean value4 = parser.parseExpression("!true").getValue(Boolean.class);String expression3 = "isMember('Nikola Tesla') and !isMember('Mihajlo Pupin')";boolean value5 = parser.parseExpression(expression3).getValue(societyContext, Boolean.class);}/*** 数学计算符*/@Testpublic void test11() {ExpressionParser parser = new SpelExpressionParser();parser.parseExpression("1 + 1").getValue(Integer.class); // 2parser.parseExpression("'test' + ' ' + 'string'").getValue(String.class); // 'test string'parser.parseExpression("1 - -3").getValue(Integer.class); // 4parser.parseExpression("1000.00 - 1e4").getValue(Double.class); // -9000parser.parseExpression("-2 * -3").getValue(Integer.class); // 6parser.parseExpression("6 / -3").getValue(Integer.class); // -2parser.parseExpression("8.0 / 4e0 / 2").getValue(Double.class); // 1.0parser.parseExpression("7 % 4").getValue(Integer.class); // 3parser.parseExpression("8 / 5 % 2").getValue(Integer.class); // 1parser.parseExpression("1+2-3*8").getValue(Integer.class); // -21}/*** 类型获取符:T()* T(Type):用于引用静态类型。* T(Type).staticMethod():用于调用静态方法。* T(Type).STATIC_FIELD:用于访问静态字段。* instanceof T(Type):用于类型检查。*/@Testpublic void test12() {ExpressionParser parser = new SpelExpressionParser();Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class);Class stringClass = parser.parseExpression("T(String)").getValue(Class.class);boolean trueValue = parser.parseExpression("T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR").getValue(Boolean.class);}/*** 调用构造函数*/@Testpublic void test13() {System.out.println(Inventor.class.getName());ExpressionParser parser = new SpelExpressionParser();StandardEvaluationContext societyContext = new StandardEvaluationContext(new Society());Inventor einstein = parser.parseExpression("new com.xuyuan.spring.spel.SpelExam.Inventor('Albert Einstein', 'German')").getValue(Inventor.class);// 创建一个新的Inventor,并且添加到members的list中parser.parseExpression("Members.add(com.xuyuan.spring.spel.SpelExam.Inventor('Albert Einstein', 'German'))").getValue(societyContext);System.out.println(societyContext.getRootObject().getValue());}/*** Spel变量* #variableName语法在表达式中引用变量*/@Testpublic void test14() {ExpressionParser parser = new SpelExpressionParser();EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();context.setVariable("newName", "Mike Tesla"); // 设置变量Inventor tesla = new Inventor("Nikola Tesla", "Serbian");// 获取变量newName,并将其赋值给name属性parser.parseExpression("Name = #newName").getValue(context, tesla);System.out.println(tesla.getName()); // "Mike Tesla"}/*** #this变量引用当前的评估对象(根据该评估对象解析非限定引用)。* #root变量总是被定义并引用根上下文对象。虽然#this可能会随着表达式的组成部分的计算而变化,但是#root总是指根。*/@Testpublic void test15() {// 创建一个Integer数组List<Integer> primes = new ArrayList<Integer>();primes.addAll(Arrays.asList(2, 3, 5, 7, 11, 13, 17));ExpressionParser parser = new SpelExpressionParser();EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();context.setVariable("primes", primes);List<Integer> primesGreaterThanTen = (List<Integer>) parser.parseExpression("#primes.?[#this>10]").getValue(context);System.out.println(primesGreaterThanTen);}/*** 三元表达式*/@Testpublic void test16() {ExpressionParser parser = new SpelExpressionParser();String expression = "10 > 5 ? 'ten is greater than five' : 'ten is not greater than five'";parser.parseExpression(expression).getValue(String.class);}/*** Elvis操作符*/@Testpublic void test17() {ExpressionParser parser = new SpelExpressionParser();String name = "Elvis Presley";String displayName = (name != null ? name : "Unknown");String name1 = parser.parseExpression("name?:'Unknown'").getValue(String.class);System.out.println(name1); // 'Unknown'}/*** 安全导航运算符:obj?.prop* 安全导航操作符用于避免NullPointerException,来自Groovy语言。* 通常,当引用一个对象时,可能需要在访问该对象的方法或属性之前验证它不为null。为了避免这种情况,安全导航运算符返回null,而不是引发异常。以下示例显示了如何使用安全导航运算符*/@Testpublic void test18() {ExpressionParser parser = new SpelExpressionParser();EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();Inventor tesla = new Inventor("Nikola Tesla", "Serbian");tesla.setPlaceOfBirth(new PlaceOfBirth("Smiljan", "Croatia"));String city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, tesla, String.class);System.out.println(city); // Smiljantesla.setPlaceOfBirth(null);city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, tesla, String.class);System.out.println(city); // null - does not throw NullPointerException!!!}/*** 集合选择:?[predicate]*/@Testpublic void test19() {Society ieee = new Society();ieee.getMembers().add(new Inventor("Tesla", "USA"));ieee.getMembers().add(new Inventor("BYD", "CN"));ieee.getMembers().add(new Inventor("BMW", "GE"));ieee.getMembers().add(new Inventor("FLL", "FR"));ExpressionParser parser = new SpelExpressionParser();StandardEvaluationContext context = new StandardEvaluationContext(ieee);// 语法.?[selectionExpression]List<Inventor> list = parser.parseExpression("Members.?[Nationality == 'Serbian']").getValue(context, List.class);Map<String, Integer> map = new HashMap<>();context.setVariable("map", map);map.put("Tesla0", 28);map.put("Tesla1", 26);map.put("Tesla2", 25);// 返回value小于27的值// 使用参数化的 Map 类型Map<String, Integer> newMap = parser.parseExpression("#map.?[value < 27]").getValue(context, Map.class);System.out.println(newMap); // 输出符合条件的键值对}/*** 集合投影:![expression]*/@Testpublic void test20() {Society ieee = new Society();ieee.getMembers().add(new Inventor("Tesla", "USA"));ieee.getMembers().add(new Inventor("BYD", "CN"));ieee.getMembers().add(new Inventor("BMW", "GE"));ieee.getMembers().add(new Inventor("FLL", "FR"));ExpressionParser parser = new SpelExpressionParser();StandardEvaluationContext context = new StandardEvaluationContext(ieee);List placesOfBirth = parser.parseExpression("Members.![placeOfBirth?.city]").getValue(context, List.class);}/*** 表达式模板:#{expression}* 通常使用#{}作为模板,与字符串拼接*/@Testpublic void test21() {ExpressionParser parser = new SpelExpressionParser();// 通常使用#{}作为模板,与字符串拼接起来String randomPhrase = parser.parseExpression("random number is #{T(java.lang.Math).random()}", new TemplateParserContext()).getValue(String.class);System.out.println(randomPhrase); // "random number is 0.7038186818312008"}@Data@AllArgsConstructor@NoArgsConstructorclass PlaceOfBirth {private String city;private String country;}@Data@AllArgsConstructor@NoArgsConstructorclass Society {private String name;public String Advisors = "advisors";public String President = "president";private List<Inventor> members = new ArrayList<>();private Map officers = new HashMap();public boolean isMember(String name) {for (Inventor inventor : members) {if (inventor.getName().equals(name)) {return true;}}return false;}}@Data@NoArgsConstructor@AllArgsConstructorclass Inventor {private String name;private String nationality;private String[] inventions;private Date birthdate;private PlaceOfBirth placeOfBirth;public Inventor(String name, String nationality) {GregorianCalendar c = new GregorianCalendar();this.name = name;this.nationality = nationality;this.birthdate = c.getTime();}public Inventor(String name, Date birthdate, String nationality) {this.name = name;this.nationality = nationality;this.birthdate = birthdate;}}}
相关文章:
Spring提供的SPEL表达式
SPEL 1. 概述 SpEL是Spring框架中用于表达式语言的一种方式。它类似于其他编程语言中的表达式语言,用于在运行时计算值或执行特定任务。 SpEL提供了一种简单且强大的方式来访问和操作对象的属性、调用对象的方法,以及实现运算、条件判断等操作。它可以…...

JAVA编程【jvm垃圾回收的差异】
jvm垃圾回收的差异 JVM(Java Virtual Machine)的垃圾回收(GC)机制是自动管理内存的一种方式,能够帮助开发者释放不再使用的内存,避免内存泄漏和溢出等问题。不同的垃圾回收器(GC)有…...

Elasticsearch:“Your trial license is expired”
目录标题 问题原因解决方案 问题 原因 ES的X-pack许可证是提供免费一个月的试用,到期之后就会报这个错误。 解决方案 查看license GET _license 开启试用license POST _xpack/license/start_trial?acknowledgetrue修改为基础license POST _xpack/license/start_…...

fmql之Linux WDT
正点原子第52章。 基础知识 正点原子教程 fmql-dts 代码 APP代码(不需要编写驱动代码) static int dw_wdt_drv_probe(struct platform_device *pdev) {struct device *dev &pdev->dev;struct watchdog_device *wdd;struct dw_wdt *dw_wdt; …...

【算法学习之路】7.链表算法
链表算法 前言一.原地逆置思路一:头插法思路二:双指针法思路3:递归 例题:1.头插法2.双指针法3,递归 二.双指针快慢指针:一个指针快一个指针慢例题1例题2 前言 我会将一些常用的算法以及对应的题单给写完&am…...

IDEA Commit 模态提交界面关闭VS开启对比
IDEA Commit 模态提交界面关闭VS开启对比 前言开启模态提交界面优点快捷且灵活的选择需要commit文件显示文件修改内容多(主观) 缺点在模态提交界面选择文件,临时关闭模态框重新打开会重置选择的commit文件 关闭模态提交界面优点允许在commit选择文件时查看其它没有修…...
【AI赋能】AI 工具生成视频教材:从创意到成品的全流程指南
AI 工具生成视频教材:从创意到成品的全流程指南 目标 通过本教材,您将学会如何利用 AI 工具(Grok、Sora、Speechify 和 CapCut)生成一个完整的视频,包括脚本生成、视频片段制作、字幕添加、音频生成以及最终剪辑合成…...
qt 操作多个sqlite文件
qt 操作多个sqlite文件 Chapter1 qt 操作多个sqlite文件1. 引入必要的头文件2. 创建并连接多个SQLite数据库3. 代码说明4. 注意事项 Chapter2 qt 多线程操作sqlite多文件1. 引入必要的头文件2. 创建数据库操作的工作线程类3. 在主线程中创建并启动多个工作线程4. 代码说明5. 运…...

WSL with NVIDIA Container Toolkit
一、wsl 下安装 docker 会提示安装 docekr 桌面版,所以直接安装 docker 桌面版本即可 二、安装 NVIDIA Container Toolkit NVIDIA Container Toolkit仓库 https://github.com/NVIDIA/nvidia-container-toolkitgithub.com/NVIDIA/nvidia-container-toolkit 安装…...

Vue 系列之:组件通讯
子组件调用父组件方法 1、直接在子组件中通过 this.$parent.event 来调用父组件的方法 父组件: <template><p><child></child></p> </template> <script>import child from ./child;export default {components: {chi…...

【Linux实践系列】:用c语言实现一个shell外壳程序
🔥本文专栏:Linux Linux实践项目 🌸博主主页:努力努力再努力wz 那么今天我们就要进入Linux的实践环节,那么我们之前学习了进程控制相关的几个知识点,比如进程的终止以及进程的等待和进程的替换,…...
STL map 的 lower_bound(x)、upper_bound(x) 等常用函数
【STL map 简介】 ● STL map 是一种关联容器,存储键值对,每个键(key value)是唯一的,而值(mapped value)可以重复。构建 STL map 时,无论元素插入顺序如何,STL map 中的…...

【A2DP】SBC 编解码器互操作性要求详解
目录 一、SBC编解码器互操作性概述 二、编解码器特定信息元素(Codec Specific Information Elements) 2.1 采样频率(Sampling Frequency) 2.2 声道模式(Channel Mode) 2.3 块长度(Block Length) 2.4 子带数量(Subbands) 2.5 分配方法(Allocation Method) 2…...
Computational Linguistics期刊全解析:领域顶刊的投稿指南与学术价值
在人工智能与语言学交叉融合的浪潮中,《Computational Linguistics》(CL)作为该领域的标杆期刊,始终是研究者发表前沿成果的首选平台。本文将从期刊影响力、投稿策略、收稿方向等角度,为学者提供一份全面的指南。 一、…...
【量化科普】Sharpe Ratio,夏普比率
【量化科普】Sharpe Ratio,夏普比率 🚀量化软件开通 🚀量化实战教程 在量化投资领域,夏普比率(Sharpe Ratio)是一个非常重要的风险调整后收益指标。它由诺贝尔经济学奖得主威廉F夏普(William…...

运行OpenManus项目(使用Conda)
部署本项目需要具备一定的基础:Linux基础、需要安装好Anaconda/Miniforge(Python可以不装好,直接新建虚拟环境的时候装好即可),如果不装Anaconda或者Miniforge,只装过Python,需要确保Python是3.…...

TikTok Shop欧洲市场爆发,欧洲TikTok 运营网络专线成运营关键
TikTok在欧洲的影响力还在持续攀升,日前,TikTok发布了最新的欧盟执行和使用数据报告,报告中提到: 2024年7~12月期间,TikTok在欧盟地区的月活用户达1.591亿,较上一报告期(2024年10月发布…...

基于YOLO11深度学习的电瓶车进电梯检测与语音提示系统【python源码+Pyqt5界面+数据集+训练代码】
《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…...

计算机毕业设计SpringBoot+Vue.js制造装备物联及生产管理ERP系统(源码+文档+PPT+讲解)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...

微服务保护:Sentinel
home | Sentinelhttps://sentinelguard.io/zh-cn/ 微服务保护的方案有很多,比如: 请求限流 线程隔离 服务熔断 服务故障最重要原因,就是并发太高!解决了这个问题,就能避免大部分故障。当然,接口的并发…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...

Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...

C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...

Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...

GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...