04.仿简道云公式函数实战-QLExpress基础语法

1. 前言

小伙伴大家好,在上一篇文章我们简单初探了QLExpress表达式引擎,我们简单写了一个HelloWorld的程序,并成功的运行期望的结果。在本篇文章中我们来熟悉一下QLExpress的语法,因为我们在后面简道云公式实战的时候,需要用到这些语法。废话少说,直接开始。

2. 基础语法

相信大家也下载了QLExpress的源码,在下载的源码中有一个readme文件,在这个文件中,源码作者已经介绍了语法以及QLExpress的用法。大家可以详细阅读,以及运行相应的测试文件。如图所示:

2.1 操作符和java对象

2.1.1 操作符

在readme说明文件中,我们知道QLExpress支持的操作符有:

+,-,*,/,<,>,<=,>=,==,!=,<>,%,++,–-
in 【类似sql】,like【sql语法】,&&,|| 
支持for,break、continue、if then else 等标准的程序控制逻辑

上述的的操作符,笔者都会写测试用例。我们先从简单的四则运算开始:

2.1.1.1 四则运算

四则运算需求提出:
需求1:编写java程序使用QLExpress表达式引擎,计算"1+2-3*4/5" 表达式的结果,并在控制台打印结果
需求2:编写java程序使用QLExpress表达式引擎,计算"1 加 2 减 3 乘 4 除 5"表达式的结果,并在控制台打印结果

当我们拿到需求的时候,首先第一步我们要明确需求,需求是让我们借助QLExpress表达式引擎,来计算表达式的结果。

表达式中包括英文"+-*/"和中文"加 减 乘 除"。需求中并没有提出计算结果精度的问题(虽然需求没有定下来,我们要支持高精度计算)。

基于上述的讨论后,码农就拿起键盘一头扎进了QLExpress代码学习中,以及各种百度,CSDN搜索解决方案。最终码农A编写了需求1如下代码:

/***
 * "1+2-3*4/5"
 */
@Test
public void test1() throws Exception{
    // @param isPrecise 是否需要高精度计算支持
    // @param isTrace   是否跟踪执行指令的过程
    ExpressRunner runner = new ExpressRunner(true, true);
    String expressStr = "1+2-3*4/5";
    // isTrace
    object rst = runner.execute(expressStr, null, null, true, true);
    System.out.println(rst);
}

码农A很自豪的讲起了自己的解决方案,QLExpress引擎提供了isPrecise 和 isTrace两个属性,在ExpressRunner 初始化的时候可以指定isPrecise 是否需要高精度计算支持和isTrace 是否跟踪执行指令的过程。isTrace在调试阶段很有用,可以查看表达式执行指令的整个过程,在程序上线时,建议设置为false避免浪费资源。

如果isPrecise=true代码运行的结果为0.6000000000;如果isPrecise = false代码运行结果为1.代码运行如图所示:

码农A沮丧的说,我解决了需求1,但是需求2没有找到解决方案。项目组中有人找到需求2的解决方案吗?大家可以交流一下。一向低调的码农B开口了。

码农B说:通过阅读QLExpress代码,找到一个方法

addOperatorWithAlias("加","+",null)。

/**
 * 添加操作符和关键字的别名,同时对操作符可以指定错误信息。
 * 例如:addOperatorWithAlias("加","+",null)
 *
 * @param keyWordName
 * @param realKeyWordName
 * @param errorInfo
 * @throws Exception
 */
public void addOperatorWithAlias(String keyWordName, String realKeyWordName, String errorInfo) throws Exception {
    if (errorInfo != null && errorInfo.trim().length() == 0) {
        errorInfo = null;
    }
    //添加函数别名
    if (this.manager.isFunction(realKeyWordName)) {
        this.manager.addFunctionName(keyWordName);
        this.operatorManager.addOperatorWithAlias(keyWordName, realKeyWordName, errorInfo);
        return;
    }
    NodeType realNodeType = this.manager.findNodeType(realKeyWordName);
    if (realNodeType == null) {
        throw new QLException("关键字:" + realKeyWordName + "不存在");
    }
    boolean isExist = this.operatorManager.isExistOperator(realNodeType.getName());
    if (!isExist && errorInfo != null) {
        throw new QLException("关键字:" + realKeyWordName + "是通过指令来实现的,不能设置错误的提示信息,errorInfo 必须是 null");
    }
    if (!isExist || errorInfo == null) {
        //不需要新增操作符号,只需要建立一个关键子即可
        this.manager.addOperatorWithRealNodeType(keyWordName, realNodeType.getName());
    } else {
        this.manager.addOperatorWithLevelOfReference(keyWordName, realNodeType.getName());
        this.operatorManager.addOperatorWithAlias(keyWordName, realNodeType.getName(), errorInfo);
    }
}

此方法作用就是添加操作符和关键字的别名,于是就构思出来如下代码【test2方法运行报错】

@Test
public void test2() throws Exception{
    ExpressRunner runner = new ExpressRunner(true, true);
    String expressStr = "1 加 2 减 3 乘 4 除 5";
    runner.addOperatorWithAlias("加","+","加 的这个操作符有问题");
    runner.addOperatorWithAlias("减","-","减 的这个操作符有问题");
    runner.addOperatorWithAlias("乘","*","乘 的这个操作符有问题");
    runner.addOperatorWithAlias("除","/","除 的这个操作符有问题");
    // isTrace
    object rst = runner.execute(expressStr, null, null, true, true);
    System.out.println(rst);
}

经测试发现程序报错:

com.ql.util.express.exception.QLException: * 不能被设置别名:com.ql.util.express.instruction.op.OperatorMultiplyDivide.<init>(java.lang.String, java.lang.String, java.lang.String) 如下图所示:

通过报错信息可知OperatorMultiplyDivide.<init>方法有问题,于是就进入OperatorMultiplyDivide源码,模仿着写了

OperatorMultiply 类和 OperatorDivide类,即把 OperatorMultiplyDivide类拆分成两个类。

/**
 * 类描述:乘操作
 *
 * @author admin
 * @version 1.0.0
 * @date 2023/11/13 17:17
 */
public class OperatorMultiply extends Operator {

    @Override
    public object executeInner(object[] list) throws Exception {
        return executeInner(list[0], list[1]);
    }

    public object executeInner(object op1, object op2) throws Exception {
        object result = OperatorOfNumber.multiply(op1, op2, this.isPrecise);
        return result;
    }

}

/**
 * 类描述:除操作
 *
 * @author admin
 * @version 1.0.0
 * @date 2023/11/13 17:21
 */
public class OperatorDivide extends Operator {

    @Override
    public object executeInner(object[] list) throws Exception {
        return executeInner(list[0], list[1]);
    }

    public object executeInner(object op1, object op2) throws Exception {
        object result = OperatorOfNumber.divide(op1, op2, this.isPrecise);
        return result;
    }

}

基于上面两个类,又写了test3方法(该方法运行报错)

@Test
public void test3() throws Exception{
    ExpressRunner runner = new ExpressRunner(true, true);
    String expressStr = "1 加 2 减 3 乘 4 除 5";
    runner.addOperator("*",new OperatorMultiply());
    runner.addOperator("/",new OperatorDivide());
    runner.addOperatorWithAlias("加","+","加 的这个操作符有问题");
    runner.addOperatorWithAlias("减","-","减 的这个操作符有问题");
    runner.addOperatorWithAlias("乘","*","乘 的这个操作符有问题");
    runner.addOperatorWithAlias("除","/","除 的这个操作符有问题");
    // isTrace
    object rst = runner.execute(expressStr, null, null, true, true);
    System.out.println(rst);
}

运行报错:java.lang.RuntimeException: 节点类型定义重复:* 定义1=*:TYPE=KEYWORD 定义2=*:TYPE=KEYWORD

根据错误信息猜测应该是runner.addOperator("*",new OperatorMultiply());源码中已经有了,于是就找到OperatorFactory工厂类(笔者删减了其他代码)发现确实在这个工厂类中已经添加addOperator("*", new OperatorMultiplyDivide("*"));addOperator("/", new OperatorMultiplyDivide("/"));

public OperatorFactory(boolean isPrecise) {
    this.isPrecise = isPrecise;
    addOperator("!", new OperatorNot("!"));
    addOperator("*", new OperatorMultiplyDivide("*"));
    addOperator("/", new OperatorMultiplyDivide("/"));
}

既然有了那我就直接用汉字 不就能满足需求了,于是就又写了以下代码test4(运行通过)

@Test
public void test4() throws Exception{
    ExpressRunner runner = new ExpressRunner(true, true);
    String expressStr = "1 加 2 减 3 乘 4 除 5";
    runner.addOperator("乘",new OperatorMultiply());
    runner.addOperator("除",new OperatorDivide());
    runner.addOperatorWithAlias("加","+","加 的这个操作符有问题");
    runner.addOperatorWithAlias("减","-","减 的这个操作符有问题");
    // isTrace
    object rst = runner.execute(expressStr, null, null, true, true);
    System.out.println(rst);
}

如果isPrecise=true代码运行的结果为0.6000000000;如果isPrecise = false代码运行结果为1

2.1.1.2 其余操作符测试案例

取余操作

/***
 * 测试操作符mod
 * isTrace:输出脚本的编译解析过程,一般对于业务系统来说关闭之后会提高性能。
 */
@Test
public void mod() throws Exception{
    ExpressRunner runner = new ExpressRunner(false, true);
    String expressStr = "20 % 5";
    // isTrace
    Object rst = runner.execute(expressStr, null, null, true, true);
    System.out.println(rst);
}

加加操作

注意:++这个操作,分为前加加和后加加 如i++ 和++i,在QLExpress中前加加会报错。

/***
 * 测试++
 * @throws Exception
 */
@Test
public void addPlusAfter() throws Exception{
    ExpressRunner runner = new ExpressRunner(false, true);
    DefaultContext<String, Object> context = new DefaultContext<>();
    context.put("a",11);
    context.put("b",12);
    String expressStr = "a++";
    // isTrace
    Object rst = runner.execute(expressStr, context, null, true, true);
    // 打印此时a的值是多少
    Object a_now = context.get("a");
    System.out.println(a_now);
    System.out.println(rst);
}

/***
 * 测试++ 反例
 * @throws Exception com.ql.util.express.exception.QLCompileException: 程序错误,不满足语法规范,没有匹配到合适的语法,最大匹配致[0:-1]
 */
@Test
public void addPlusBefore() throws Exception{
    ExpressRunner runner = new ExpressRunner(false, true);
    DefaultContext<String, Object> context = new DefaultContext<>();
    context.put("a",11);
    context.put("b",12);
    String expressStr = "++a";
    // isTrace
    Object rst = runner.execute(expressStr, context, null, true, true);
    // 打印此时a的值是多少
    Object a_now = context.get("a");
    System.out.println(a_now);
    System.out.println(rst);
}

减减操作

注意:--这个操作,分为前减减和后减减 如i-- 和--i,在QLExpress中前减减会报错。

/***
 * 测试--
 * @throws Exception
 */
@Test
public void minusPlusAfter() throws Exception{
    ExpressRunner runner = new ExpressRunner(false, true);
    DefaultContext<String, Object> context = new DefaultContext<>();
    context.put("a",11);
    context.put("b",12);
    String expressStr = "a--";
    // isTrace
    Object rst = runner.execute(expressStr, context, null, true, true);

    // 打印此时a的值是多少
    Object a_now = context.get("a");
    System.out.println(a_now);
    System.out.println(rst);
}

/***
 * 测试-- 反例
 * @throws Exception com.ql.util.express.exception.QLCompileException: 程序错误,不满足语法规范,没有匹配到合适的语法,最大匹配致[0:-1]
 */
@Test
public void minusPlusBefore() throws Exception{
    ExpressRunner runner = new ExpressRunner(false, true);
    DefaultContext<String, Object> context = new DefaultContext<>();
    context.put("a",11);
    context.put("b",12);
    String expressStr = "--a";
    // isTrace
    Object rst = runner.execute(expressStr, context, null, true, true);
    // 打印此时a的值是多少
    Object a_now = context.get("a");
    System.out.println(a_now);
    System.out.println(rst);
}

不等于操作符

注意:不等于符号是 != 切记不要使用<>

/***
 * 测试 != 符号
 * @throws Exception
 */
@Test
public void ne() throws Exception{
    ExpressRunner runner = new ExpressRunner(false, true);
    String expressStr = "20 != 5";
    // isTrace
    Object rst = runner.execute(expressStr, null, null, true, true);
    System.out.println(rst);
}

/***
 * 测试 <> 符号 反例
 * @throws Exception com.ql.util.express.exception.QLCompileException: 程序错误,不满足语法规范,没有匹配到合适的语法,最大匹配致[0:1]
 */
@Test
public void ne2() throws Exception{
    ExpressRunner runner = new ExpressRunner(false, true);
    DefaultContext<String, Object> context = new DefaultContext<>();
    context.put("a",11);
    context.put("b",12);
    String expressStr = "a <> b";
    // isTrace
    Object rst = runner.execute(expressStr, null, null, true, true);
    System.out.println(rst);
}

in操作

/***
 * in 测试
 */
@Test
public void in() throws Exception{
    ExpressRunner runner = new ExpressRunner(false, false);
    String expressStr = " 3+4 in (8+3,7,9)";
    Object rst = runner.execute(expressStr, null, null, true, false);
    System.out.println(rst);
}

like操作

注意 ab如果作为一个值的话要用引号包裹,否则QLExpress会把ab当做一个变量

/***
 * like测试
 */
@Test
public void like() throws Exception{

    // 注意ab必须用字符串包裹,不然会把ab当做变量
    ExpressRunner runner = new ExpressRunner(false, false);
    String expressStr = "'ab' like '%a%'";
    Object rst = runner.execute(expressStr, null, null, true, false);
    System.out.println(rst);
}

&&操作

/***
 * &&
 * @throws Exception
 */
@Test
public void and() throws Exception{
    ExpressRunner runner = new ExpressRunner(false, false);
    String expressStr = "false && true";
    Object rst = runner.execute(expressStr, null, null, true, false);
    System.out.println(rst);

}

||操作

/***
 * ||
 * @throws Exception
 */
@Test
public void or() throws Exception{
    ExpressRunner runner = new ExpressRunner(false, false);
    String expressStr = "false || true";
    Object rst = runner.execute(expressStr, null, null, true, false);
    System.out.println(rst);

}

三目表达式测试

/***
 * 测试三目表达式
 */
@Test
public void san() throws Exception{
    ExpressRunner runner = new ExpressRunner(false, false);
    String expressStr = "int a=1;int b=2;a>b?a:b;";
    Object rst = runner.execute(expressStr, null, null, true, false);
    System.out.println(rst);
}

for 循环操作

注意:while循环测试报错

/***
 * 测试循环
 * @throws Exception
 */
@Test
public void loop() throws Exception{

    ExpressRunner runner = new ExpressRunner(false, false);
    String expressStr = "int sum=10;"
            + "for(int i = 0; i < 1; i = i + 1){"
            + "    println(i); sum=sum+i;"
            + "}" +
            "return sum";
    // isTrace
    Object rst = runner.execute(expressStr, null, null, true, false);
    System.out.println(rst);
    System.out.println("--------------java for loop------------");
    int sum=10;
    for (int i=0;i<1;i+=1) {
        System.out.println(i);
        sum = sum + i;
    }
    System.out.println(sum);
}


/***
 * while 循环
 * @throws Exception
 */
@Test
public void loop2() throws Exception {
    ExpressRunner runner = new ExpressRunner(false, true);
    String expressStr ="while(true) {println('1')}";
    Object rst = runner.execute(expressStr, null, null, true, false);
    System.out.println(rst);
}

if_then_else操作符

/***
 * if_then_else 测试
 */
@Test
public void if_then_else() throws Exception{
    ExpressRunner runner = new ExpressRunner(false, false);
    String expressStr = "if 1==1 then {return 10}else{return 100}";
    Object rst = runner.execute(expressStr, null, null, true, false);
    System.out.println(rst);
}

@Test
public void if_() throws Exception{
    ExpressRunner runner = new ExpressRunner(false, false);
    String expressStr = "if(1==1) { return 100;}";
    Object rst = runner.execute(expressStr, null, null, true, false);
    System.out.println(rst);
}

@Test
public void if_else() throws Exception{
    ExpressRunner runner = new ExpressRunner(false, false);
    String expressStr = "if(1==2) { return 100;} else {" +
            "return -1;}";
    Object rst = runner.execute(expressStr, null, null, true, false);
    System.out.println(rst);
}

@Test
public void if_then() throws Exception{
    ExpressRunner runner = new ExpressRunner(false, false);
    String expressStr = "if(1==1) then{ return 100;}";
    Object rst = runner.execute(expressStr, null, null, true, false);
    System.out.println(rst);
}

2.1.1.3 java对象操作

在QLExpress表达式引擎中,是支持操作java对象的,比如我们在一个表达式中需要调用一个java对象的方法作为处理的函数。下面我们还是通过测试用例,来说明java对象操作的知识点

1. 首先创建Bean对象

/**
 * 类描述:
 *
 * @author admin
 * @version 1.0.0
 * @date 2023/11/13 16:03
 */
public class Student {

    // 学号
    private String sn;

    // 姓名
    private String name;

    // 年龄
    private int age;

    public Student(){}

    public Student(String sn, String name, int age) {
        this.sn = sn;
        this.name = name;
        this.age = age;
    }

    public String getSn() {
        return sn;
    }

    public void setSn(String sn) {
        this.sn = sn;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public static String print(String msg) {
        String rst = "Student print method exe::::::"+msg;
        return rst;
    }
}

2.我们都知道java对象的生命周期是从初始化开始的,那么我们就用QLExpress表达式的形式初始化一个对象

/***
 * 测试java对象,测试创建对象
 */
@Test
public void obj_init() throws Exception{
    ExpressRunner runner = new ExpressRunner(false, false);
    String expressStr = "import com.ql.util.express.self.base.Student; Student stu = new Student('000','tom',18); return stu.getName()";
    Object rst = runner.execute(expressStr, null, null, true, false);
    System.out.println(rst);
}

通过表达式我们可知:QLExpress是支持import的关键字

3.测试调用Student对象的print方法

/***
 * 测试调用java对象 addFunctionOfClassMethod
 */
@Test
public void obj_method_addFunctionOfClassMethod() throws Exception{
    ExpressRunner runner = new ExpressRunner(false, false);
    String expressStr = "打印('jim')";
    // 使用QLExpress用于将一个用户自己定义的对象(例如Spring对象)方法转换为一个表达式计算的函数
    runner.addFunctionOfClassMethod("打印",Student.class.getName(),"print", new String[]{"String"},null);
    Object rst = runner.execute(expressStr, null, null, true, false);
    System.out.println(rst);
}

说明:addFunctionOfClassMethod方法含义为

用于将一个用户自己定义的对象(例如Spring对象)方法转换为一个表达式计算的函数。

该方法的源码为:

/**
 * 添加一个类的函数定义,例如:Math.abs(double) 映射为表达式中的 "取绝对值(-5.0)"
 *
 * @param name           函数名称
 * @param className      类名称
 * @param functionName   类中的方法名称
 * @param parameterTypes 方法的参数类型名称
 * @param errorInfo      如果函数执行的结果是false,需要输出的错误信息
 * @throws Exception
 */
public void addFunctionOfClassMethod(String name, String className, String functionName, String[] parameterTypes,
    String errorInfo) throws Exception {
    OperatorSelfDefineClassFunction operatorSelfDefineClassFunction = new OperatorSelfDefineClassFunction(name,
        className, functionName, parameterTypes, null, null, errorInfo);
    this.addFunction(name, operatorSelfDefineClassFunction);
}

4.测试调用java对象的方法2

/***
 * 测试调用java对象 addFunctionOfClassMethod
 */
@Test
public void obj_method_addFunctionOfServiceMethod() throws Exception{
    ExpressRunner runner = new ExpressRunner(false, false);
    String expressStr = "打印('jim')";
    // 使用QLExpress
    runner.addFunctionOfServiceMethod("打印",new Student(),"print", new String[]{"String"},null);
    Object rst = runner.execute(expressStr, null, null, true, false);
    System.out.println(rst);
}

addFunctionOfClassMethod 方法用于将用户定义的对象的方法转换为表达式计算的函数

/**
 * 用于将一个用户自己定义的对象(例如Spring对象)方法转换为一个表达式计算的函数
 *
 * @param name
 * @param serviceObject
 * @param functionName
 * @param parameterTypes
 * @param errorInfo
 * @throws Exception
 */
public void addFunctionOfServiceMethod(String name, Object serviceObject, String functionName,
    String[] parameterTypes, String errorInfo) throws Exception {
    OperatorSelfDefineServiceFunction operatorSelfDefineServiceFunction = new OperatorSelfDefineServiceFunction(
        name, serviceObject, functionName, parameterTypes, null, null, errorInfo);
    this.addFunction(name, operatorSelfDefineServiceFunction);
}

总结:

通过测试QLExpress操作java对象,我们学习了addFunctionOfClassMethod 方法,我们可以把一个java类中的方法,转化为QLExpress表达式函数。

最近笔者创建了一个圈子https://pc.fenchuan8.com/#/index?forum=58055&yqm=9HKS

欢迎大家加入一起交流学习。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java之SpringBoot开发实用篇

MENU SpringBoot开发实用篇KF-1.热部署KF-1-1.手动启动热部署KF-1-2.自动启动热部署KF-1-3.参与热部署监控的文件范围配置KF-1-4.关闭热部署 KF-2.配置高级KF-2-1.ConfigurationPropertiesKF-2-2.宽松绑定/松散绑定KF-2-3.常用计量单位绑定KF-2-4.校验KF-2-5.数据类型转换 KF-3…

MFC CLXHHandleEngine动态库-自定义设置对话框使用

实现的效果如下所示&#xff1a; void CSampleDlg::OnBnClickedButton2() { // TODO: 在此添加控件通知处理程序代码 CSgxMemDialog dlg(180, 100); dlg.SetEnable(true); dlg.SetWindowTitle(_T("自定义对话框")); dlg.AddStatic(1000, //控件资源…

Sbatch, Salloc提交任务相关

salloc 申请计算节点&#xff0c;然后登录到申请到的计算节点上运行指令&#xff1b; salloc的参数与sbatch相同&#xff0c;该部分先介绍一个简单的使用案例&#xff1b;随后介绍一个GPU的使用案例&#xff1b;最后介绍一个跨节点使用案例&#xff1b; 首先是一个简单的例子&a…

SpringBoot整合ZXing创建二维码和条形码

文章目录 1、引入依赖2、Service层实现3、Controller4、效果 之前SpringSecurity时&#xff0c;登录用到了图片验证码辅助登录&#xff1a;【 整合hutool实现集成图片验证码】&#xff0c;以下为整合zxing实现二维码和条形码的生成。 1、引入依赖 引入ZXing依赖的坐标&#x…

探索未来新趋势:鸿蒙系统的崭新时代

探索未来新趋势&#xff1a;鸿蒙系统的崭新时代 随着科技的不断发展&#xff0c;操作系统作为计算机和移动设备的核心&#xff0c;扮演着至关重要的角色。近年来&#xff0c;一种备受瞩目的操作系统——鸿蒙系统&#xff08;HarmonyOS&#xff09;崭露头角&#xff0c;正引领着…

Servlet学习笔记

简介 浏览器请求处理流程&#xff1a;浏览器发请求 > 服务器tomcat( > 应用程序 ( > servlet) ) Servlet应用的三大作用域&#xff1a;request&#xff0c;session&#xff0c;application tomcat存放项目的层级结构 注释&#xff1a;servlet原引用包名 javax.serv…

城市道路积水如何有效预警?内涝积水监测仪效果

在城市中道路积水是一个常见的问题&#xff0c;特别是在暴雨季节还可能形成城市内涝。为了解决这个问题建立一个有效的预警系统是至关重要的。城市内涝积水监测仪应该能够实时监测道路积水情况&#xff0c;并及时向后台工作人员发出警报&#xff0c;以便他们能够采取适当的措施…

mysql中的DQL查询

表格为&#xff1a; DQL 基础查询 语法&#xff1a;select 查询列表 from 表名&#xff1a;&#xff08;查询的结果是一个虚拟表格&#xff09; -- 查询指定的列 SELECT NAME,birthday,phone FROM student -- 查询所有的列 * 所有的列&#xff0c; 查询结果是虚拟的表格&am…

【Spring教程23】Spring框架实战:从零开始学习SpringMVC 之 SpringMVC简介与SpringMVC概述

目录 1&#xff0c;SpringMVC简介2、SpringMVC概述 欢迎大家回到《Java教程之Spring30天快速入门》&#xff0c;本教程所有示例均基于Maven实现&#xff0c;如果您对Maven还很陌生&#xff0c;请移步本人的博文《如何在windows11下安装Maven并配置以及 IDEA配置Maven环境》&…

LANDSAT_7/02/T1/RAW的Landsat7_C2_RAW类数据集

Landsat7_C2_RAW是指Landsat 7卫星的数据集&#xff0c;采用的是Collection 2级别的数据处理方法&#xff0c;对应的是Tier 1级别的原始数据&#xff08;RAW&#xff09;。该数据集包括了Landsat 7卫星从1999年4月15日开始的所有数据&#xff0c;共涵盖了全球范围内的陆地和海洋…

【开源】基于Vue和SpringBoot的森林火灾预警系统

项目编号&#xff1a; S 019 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S019&#xff0c;文末获取源码。} 项目编号&#xff1a;S019&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 系统基础模块2.3 烟…

Aligning Large Multi-Modal Model with Robust Instruction Tuning

Abstract 尽管多模态任务取得了有希望的进展&#xff0c;但当前的大型多模态模型&#xff08;LMM&#xff09;很容易产生与相关图像和人类指令 不一致的描述的幻觉。 LRV-指令。我们通过引入第一个大型且多样化的视觉指令调整数据集来解决这个问题&#xff0c;该数据集名为大…

【项目实现】ResShift:通过残差位移实现图像超分辨率的高效扩散模型(NeurIPS 2023,聚焦)

基于扩散的图像超分辨率&#xff08;SR&#xff09;方法主要受到数百甚至数千个采样步骤要求导致推理速度低的限制。现有的加速度采样技术不可避免地在一定程度上牺牲了性能&#xff0c;导致SR结果过于模糊。为了解决这个问题&#xff0c;我们提出了一种新颖而高效的SR扩散模型…

天池SQL训练营(四)-集合运算-表的加减法和join等

-天池龙珠计划SQL训练营 4.1表的加减法 4.1.1 什么是集合运算 集合在数学领域表示“各种各样的事物的总和”, 在数据库领域表示记录的集合. 具体来说,表、视图和查询的执行结果都是记录的集合, 其中的元素为表或者查询结果中的每一行。 在标准 SQL 中, 分别对检索结果使用 U…

AWS Ubuntu设置DNS解析(解决resolve.conf被覆盖问题)

众所周知&#xff1a; Ubuntu在域名解析时&#xff0c;最直接使用的是/etc/resolve.conf文件&#xff0c;它是/run/systemd/resolve/resolve.conf的软链接&#xff0c;而对于刚装完的ubuntu系统&#xff0c;该文件的内容如下 ubuntuip-172-31-36-184:/etc$ cat resolv.conf #…

02-Nacos和Eureka的区别与联系

Nacos和Eureka的区别 联系 Nacos和Eureka整体结构类似: 都支持服务注册, 服务拉取, 采用心跳方式对服务提供者做健康监测的功能 区别 Nacos支持服务端主动检测服务提供者状态: 临时实例采用心跳模式,非临时实例采用主动检测模式但对服务器压力比较大(不推荐) 心跳模式: 服务…

华为数通方向HCIP-DataCom H12-831题库(多选题:161-180)

第161题 以下关于IS-IS路由渗透的描述,正确的有哪些项? A、若要配置Level-2区域的路由向Level-1区域渗透,则需要在Level-1设备上配置命令import-routeisis level_-2 into level_-1 B、缺省情况下,Level-2区域无Level-1区域的路由信息,需要通过在Level-1-2设备上配置impor…

PPT插件-好用的插件-插入媒体-大珩助手

批量媒体 包含批量视频、批量音频、批量图片&#xff0c;可实现从光标所在的位置开始&#xff0c;每页插入一个视频、一个音频、一张图片&#xff0c;且图片和视频的尺寸与当前幻灯片尺寸一致 插入文本 包含黑字无底、白字红底、白字黛底、白字绿底、白字蓝底预设一键文本&am…

C++12.5

想象一下你去了一家动物园&#xff0c;看到了许多不同种类的动物&#xff0c;如狮子、大象、猴子等。现在&#xff0c;动物园里有一位讲解员&#xff0c;他会为每种动物表演做简单的介绍。 在这个场景中&#xff0c;我们可以将动物比作是不同的类&#xff0c;而每种动物表演则…

三相不平衡电压的正负序分析

1、什么是正负序&#xff1f; ABC 正序 ACB 负序 2、在abc坐标系下 接着利用矢量的旋转消去其它分量。。。 同理&#xff0c;得到其它的所有正负序的分量abc 3、在α/β坐标系下&#xff0c; 依次算出正负序的α/β来表示的abc 有一点需要特别注意&#xff0c;可以看到…