Groovy系列三 Java SpringBoot 整合 Groovy

news2024/11/17 1:51:58

 

目录

一、概述

一、在Java中使用Groovy:

二、在Groovy中使用Java:

三、几种范式的不同、优缺点

Java调用Groovy的类和方法:

Groovy调用Java的类和方法:

 使用GroovyShell执行Groovy脚本:

使用GroovyClassLoader加载和执行Groovy脚本:

二、实战

第一步、与SpringBoot集成,引入依赖

第二步、编写groovy脚本

第三步、创建测试类使用GroovyShell演示

第四步、查看运行结果

第五步、启动SpringBoot,在Groovy脚本中通过SpringContextUtil获取SpringBoot容器中的Bean

第六步、创建容器中的Bean

第七步、访问代码

第八步、启动、接口测试

三、优化

第一步、创建Groovy脚本,使用GroovyClassLoader实现

第二步、创建Groovy调用Bean

第三步、创建GroovyClassLoader加载类

第四步、创建请求API


上两篇我们系统的学习了Groovy的基础语法和GDK,本篇咱们学习如何将Groovy和Java集成,并且学习集成到SpringBoot项目中。Groovy和Java之间有很好的集成,可以相互调用和使用对方的代码和特性。通过Groovy和Java的集成,可以充分发挥两者的优势,让开发更加灵活和高效。

一、概述

一、在Java中使用Groovy:

  1. 添加Groovy的依赖到Java项目中。
  2. 在Java代码中使用Groovy的类和脚本。Groovy代码可以直接在Java中执行,可以调用Groovy类的方法、访问其属性等。可以使用GroovyShell或GroovyClassLoader来执行Groovy脚本。

二、在Groovy中使用Java:

  1. Groovy天生支持Java,可以直接使用Java类、调用Java方法等。Groovy代码可以与Java代码混合编写。
  2. 在Groovy代码中使用Java类时,不需要额外的导入,直接使用即可。
  3. Groovy还提供了更简洁的语法和更强大的特性,例如闭包、扩展方法、动态类型等,可以更方便地编写代码。

为了实现更好的集成,可以注意以下几点:

  • 使用相同的依赖管理工具,以确保Java和Groovy项目使用的是相同的版本依赖。
  • 确保Java类被编译并将其生成的字节码文件和Groovy代码放在相同的classpath下,以便彼此访问。
  • 在使用GroovyShell或GroovyClassLoader执行Groovy脚本时,将Java类的路径包含在class path中,以便Groovy代码可以访问Java类。

三、几种范式的不同、优缺点

在Groovy和Java之间实现集成有多种方式,下面我会描述其中几种常见的方式,以及它们的不同、优缺点。

Java调用Groovy的类和方法:

  • 描述:Java可以直接通过类路径访问Groovy的类和方法,将Groovy代码视为Java代码的一部分。可以调用Groovy类的方法、访问其属性等。
  • 不同:Java可以无缝地调用Groovy类和方法,就像调用Java代码一样。
  • 优点:简单直接,Groovy与Java代码混合编写非常方便。
  • 缺点:对于Groovy独有的特性,如闭包、动态类型等,Java可能无法完全理解。

Groovy调用Java的类和方法:

  • 描述:Groovy天生支持Java,可以直接使用Java类、调用Java方法等。Groovy代码可以与Java代码混合编写,无需额外导入。
  • 不同:Groovy与Java的集成非常融洽,可以自动导入Java类,直接使用Java的语法。
  • 优点:无缝集成,可以充分利用Java的生态系统和已有的库。
  • 缺点:Groovy在某些方面可能比Java更“动态”,这意味着在一些情况下可能会有性能和类型安全性的损失。

 使用GroovyShell执行Groovy脚本:

  • 描述:在Java代码中使用GroovyShell执行Groovy脚本代码块。可以动态加载和执行Groovy脚本。
  • 不同:通过GroovyShell的evaluate方法,可以在Java中执行动态的Groovy脚本代码。
  • 优点:能够在运行时动态执行Groovy脚本,灵活性高,方便快捷。
  • 缺点:动态执行脚本可能会带来一定的性能影响,并且需要额外的语法检查。

使用GroovyClassLoader加载和执行Groovy脚本:

  • 描述:在Java中通过GroovyClassLoader加载和执行Groovy脚本,可以实现更灵活的脚本执行。
  • 不同:通过GroovyClassLoader加载Groovy脚本,可以获得对应的Class对象,并根据需要进行实例化和调用。
  • 优点:可以灵活地加载和执行Groovy脚本,并与Java代码进行交互。缺点:相对于GroovyShell,使用GroovyClassLoader需要更多的代码来实现加载和执行。

综上所述,不同的Groovy和Java集成方式具有不同的优缺点。我们可以根据具体需求选择合适的方式。使用Java调用Groovy类和方法以及Groovy调用Java类和方法是最直接、无缝的集成方式。而使用GroovyShell或GroovyClassLoader执行Groovy脚本则更灵活,适用于需要动态执行脚本的场景。

二、实战

那么接下来介绍SpringBoot如何集成Groovy脚本,并应用到实际开发中。

第一步、与SpringBoot集成,引入依赖

<dependency>
   <groupId>org.codehaus.groovy</groupId>
   <artifactId>groovy-all</artifactId>
   <version>3.0.17</version>
   <type>pom</type>
</dependency>

第二步、编写groovy脚本

package script

import com.example.groovy.GroovyInvokeJavaDemo
import com.example.groovy.groovyshell.ShellGroovyDTO
import com.example.groovy.utils.SpringContextUtil

/**
 * @Author: lly
 * @Date: 2023/7/1
 */

def helloWord() {
    return "hello groovy"
}

helloWord()

def cal(int a, int b) {
    ShellGroovyDTO dto = new ShellGroovyDTO()
    dto.setA(a)
    dto.setB(b)
    if (b > 0) {
        dto.setNum(a + b)
    } else {
        dto.setNum(a)
    }
    return dto
};

cal(a, b)

/** 定义静态变量 **/
class Globals {
    static String PARAM1 = "静态变量"
    static int[] arrayList = [1, 2]
}

def groovyInvokeJavaMethod(int a, int b) {
    GroovyInvokeJavaDemo groovyInvokeJavaDemo = SpringContextUtil.getBean("groovyInvokeJavaDemo")
//    return groovyInvokeJavaDemo.groovyInvokeJava();

    return groovyInvokeJavaDemo.groovyInvokeJavaParam(a, b);
}

groovyInvokeJavaMethod(a, b)

第三步、创建测试类使用GroovyShell演示

* // 创建GroovyShell实例

* // 创建Binding对象,用于传递参数和接收结果

* // 设置参数

* // 执行Groovy脚本

* // 获取结果

package com.example.groovy.groovyshell;

import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.lang.Script;

/**
 * @Author: lly
 * @Date: 2023/7/1
 * <p>
 * 下面这段测试类包含两个,一个是有参数的调用,一个是无参数的调用
 * // 创建GroovyShell实例
 * // 创建Binding对象,用于传递参数和接收结果
 * // 设置参数
 * // 执行Groovy脚本
 * // 获取结果
 */
public class GroovyShellApp {
    /**
     * GroovyShell 无参数 demo
     **/
    public static void main(String[] args) {
        String groovyStr = "package script\n" +
                "\n" +
                "import com.example.groovy.groovyshell.ShellGroovyDTO\n" +
                "\n" +
                "/**\n" +
                " * @Author: lly\n" +
                " * @Date: 2023/7/1\n" +
                " */\n" +
                "\n" +
                "def helloWord() {\n" +
                "    return \"hello groovy\"\n" +
                "}\n" +
                "\n" +
                "helloWord()\n" +
                "\n" +
                "def cal(int a, int b) {\n" +
                "    ShellGroovyDTO dto = new ShellGroovyDTO()\n" +
                "    dto.setA(a)\n" +
                "    dto.setB(b)\n" +
                "    if (b > 0) {\n" +
                "        dto.setNum(a + b)\n" +
                "    } else {\n" +
                "        dto.setNum(a)\n" +
                "    }\n" +
                "    return dto\n" +
                "};\n" +
                "\n" +
                "cal(a , b)";

        // 创建GroovyShell实例
        GroovyShell shell = new GroovyShell();
        Script script = shell.parse(groovyStr);
        Object helloWord = script.invokeMethod("helloWord", null);
        System.out.println(helloWord);

    }

    /** GroovyShell 有参数 demo **/
//    public static void main(String[] args) {
//
//        String groovyStr = "package script\n" +
//                "\n" +
//                "import com.example.groovy.groovyshell.ShellGroovyDTO\n" +
//                "\n" +
//                "/**\n" +
//                " * @Author: lly\n" +
//                " * @Date: 2023/7/1\n" +
//                " */\n" +
//                "def cal(int a, int b) {\n" +
//                "    ShellGroovyDTO dto = new ShellGroovyDTO()\n" +
//                "    dto.setA(a)\n" +
//                "    dto.setB(b)\n" +
//                "    if (b > 0) {\n" +
//                "        dto.setNum(a + b)\n" +
//                "    } else {\n" +
//                "        dto.setNum(a)\n" +
//                "    }\n" +
//                "    return dto\n" +
//                "};\n" +
//                "\n" +
//                "cal(a, b)";
//
//        // 创建Binding对象,用于传递参数和接收结果
//        Binding binding = new Binding();
//
//        // 创建GroovyShell实例
//        GroovyShell shell = new GroovyShell(binding);
//
//
//        // 设置参数
//        binding.setVariable("a", 10);
//        binding.setVariable("b", 20);
//
//        // 执行Groovy脚本
//        Object result = shell.evaluate(groovyStr);
//
//        // 获取结果
//        ShellGroovyDTO dto = (ShellGroovyDTO) result;
//        System.out.println(dto);
//    }
}

package com.example.groovy.groovyshell;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Author: lly
 * @Date: 2023/7/1
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ShellGroovyDTO {
    private Integer a;
    private Integer b;
    private Integer num;

}

第四步、查看运行结果

第五步、启动SpringBoot,在Groovy脚本中通过SpringContextUtil获取SpringBoot容器中的Bean

上面几步都是纯Java代码中调用Groovy,其实在开发的过程中,我们通常会Groovy和Java代码互调,接下来咱们看看如何使实现Groovy中通过SpringContextUtil获取SpringBoot容器中的Bean并且调用目标方法。

package com.example.groovy.utils;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;

/**
 * @Author: lly
 * @Date: 2023/7/2
 */
@Service
public class SpringContextUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringContextUtil.applicationContext = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * 通过name获取 Bean.
     *
     * @param name
     * @return
     */
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    /**
     * 通过class获取Bean.
     *
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    /**
     * 通过name,以及Clazz返回指定的Bean
     *
     * @param name
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }

}

第六步、创建容器中的Bean

咱们创建一个“GroovyInvokeJavaDemo“bean,并交给Spring管理。其中有两个目标方法,一个是需要参数的,一个不需要参数,需要参数的咱们通过Java调用Groovy的时候传入的参数在Groovy中调用Java方法的时候传入。

package com.example.groovy;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author: lly
 * @Date: 2023/7/2
 */
@Service
@Slf4j
public class GroovyInvokeJavaDemo {

    public String groovyInvokeJava() {
        List<String> lits = new ArrayList<>();
        log.info("this is SpringBoot class, groovy script invoke this method ...");
        return "this is SpringBoot class, groovy script invoke this method ...";
    }

    public String groovyInvokeJavaParam(int a, int b) {
        List<String> lits = new ArrayList<>();
        log.info("this is SpringBoot class, groovy script invoke this method ,param is a:{}, b:{}", a, b);
        return "this is SpringBoot class, groovy script invoke this method , a:" + a + ", b:" + b;
    }
}

第七步、访问代码

package com.example.groovy;

import com.example.groovy.classloader.GroovyClassLoaderRule;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @Author: lly
 * @Date: 2023/7/2
 */
@RestController
@RequestMapping("/groovy")
public class GroovyInvokeJavaSpringController {

    @Resource
    private GroovyClassLoaderRule groovyClassLoaderRule;

    @RequestMapping("/groovy-shell/spring")
    public String groovyInvokeJavaMethodTest() {
        String groovyStr = "package script\n" +
                "\n" +
                "import com.example.groovy.GroovyInvokeJavaDemo\n" +
                "import com.example.groovy.groovyshell.ShellGroovyDTO\n" +
                "import com.example.groovy.utils.SpringContextUtil\n" +
                "\n" +
                "/**\n" +
                " * @Author: lly\n" +
                " * @Date: 2023/7/1\n" +
                " */\n" +
                "\n" +
                "def helloWord() {\n" +
                "    return \"hello groovy\"\n" +
                "}\n" +
                "\n" +
                "helloWord()\n" +
                "\n" +
                "def cal(int a, int b) {\n" +
                "    ShellGroovyDTO dto = new ShellGroovyDTO()\n" +
                "    dto.setA(a)\n" +
                "    dto.setB(b)\n" +
                "    if (b > 0) {\n" +
                "        dto.setNum(a + b)\n" +
                "    } else {\n" +
                "        dto.setNum(a)\n" +
                "    }\n" +
                "    return dto\n" +
                "};\n" +
                "\n" +
                "cal(a , b)\n" +
                "\n" +
                "/** 定义静态变量 **/\n" +
                "class Globals {\n" +
                "    static String PARAM1 = \"静态变量\"\n" +
                "    static int[] arrayList = [1, 2]\n" +
                "}\n" +
                "\n" +
                "def groovyInvokeJavaMethod(int a, int b) {\n" +
                "    GroovyInvokeJavaDemo groovyInvokeJavaDemo = SpringContextUtil.getBean(\"groovyInvokeJavaDemo\")\n" +
                "//    return groovyInvokeJavaDemo.groovyInvokeJava();\n" +
                "    return groovyInvokeJavaDemo.groovyInvokeJavaParam(a, b);\n" +
                "}\n" +
                "\n" +
                "groovyInvokeJavaMethod(a, b)";

        Binding binding = new Binding();
        binding.setVariable("a", 100);
        binding.setVariable("b", 100);

        GroovyShell groovyShell = new GroovyShell(binding);

        Object evaluate = groovyShell.evaluate(groovyStr);

        groovyShell.getClassLoader().clearCache();

        return (String) evaluate;

    }

}

第八步、启动、接口测试

访问“http://localhost:8080/groovy/groovy-shell/spring”即可看到效果。

三、优化

以上我们就将Groovy集成到Java中来了,但是上面的代码有很大的问题,主要体现在两个方面:

第一个方面:通过第五步中我们可以看到,在Groovy中是可以获取到SpringBoot容器对象的,能拿到容器对象就可以获取到容器中所有的东西。这虽然很方便、灵活,但是非常的危险。如果没有做好权限控制,Groovy脚本将会成为攻击你系统最有力的武器!

第二个方面:Groovy脚本用不好,会导致OOM,最终服务器宕机。每次调用这个方法都创建了GroovyShell、Script等实例,随着调用次数的增加,必然会出现OOM。

解决方案是通过GroovyClassLoader的clearCache()函数在调用完毕销毁GroovyShell、Script等实例,但是其实这样仅仅是不够的,导致OOM的原因并不止GroovyShell、Script等实例过多,经过查阅资料得知,如果脚本中的Java代码也创建了对象或者new了实例,即使销毁了GroovyShell也不会销毁脚本中的对象。所以Groovy代码最好是使用缓存管理。

第一步、创建Groovy脚本,使用GroovyClassLoader实现

GroovyClassLoad_1.groovy

package script

import com.example.groovy.GroovyInvokeJavaDemo
import com.example.groovy.groovyshell.ShellGroovyDTO
import com.example.groovy.utils.SpringContextUtil

/**
 * @Author: lly
 * @Date: 2023/7/1
 */

def groovyInvokeJavaMethod(int a, int b) {
    GroovyInvokeJavaDemo groovyInvokeJavaDemo = SpringContextUtil.getBean("groovyInvokeJavaDemo")
//    return groovyInvokeJavaDemo.groovyInvokeJava();

    return groovyInvokeJavaDemo.groovyInvokeJavaParam(a, b)
}

groovyInvokeJavaMethod(a, b)

GroovyClassLoad_2.groovy

package script

import com.example.groovy.GroovyInvokeJavaDemo
import com.example.groovy.groovyshell.ShellGroovyDTO
import com.example.groovy.utils.SpringContextUtil

/**
 * @Author: lly
 * @Date: 2023/7/1
 */

def groovyInvokeJavaMethod(int a, int b) {
    GroovyInvokeJavaDemo groovyInvokeJavaDemo = SpringContextUtil.getBean("groovyInvokeJavaDemo")
//    return groovyInvokeJavaDemo.groovyInvokeJava();

    return groovyInvokeJavaDemo.groovyInvokeJavaParam(a, b)
}

groovyInvokeJavaMethod(a, b)

第二步、创建Groovy调用Bean

package com.example.groovy;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author: lly
 * @Date: 2023/7/2
 */
@Service
@Slf4j
public class GroovyInvokeJavaDemo {

    public String groovyInvokeJava() {
        List<String> lits = new ArrayList<>();
        log.info("this is SpringBoot class, groovy script invoke this method ...");
        return "this is SpringBoot class, groovy script invoke this method ...";
    }

    public String groovyInvokeJavaParam(int a, int b) {
        List<String> lits = new ArrayList<>();
        log.info("this is SpringBoot class, groovy script invoke this method ,param is a:{}, b:{}", a, b);
        return "this is SpringBoot class, groovy script invoke this method , a:" + a + ", b:" + b;
    }
}

第三步、创建GroovyClassLoader加载类

package com.example.groovy.classloader;

/**
 * @Author: lly
 * @Date: 2023/7/1
 *
 * 定义 Groovy 执行的接口
 */
public interface GroovyClassLoaderRule {

    String run();
}
package com.example.groovy.classloader;

import groovy.lang.Binding;
import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyObject;
import groovy.lang.Script;
import lombok.extern.slf4j.Slf4j;
import org.apache.groovy.parser.antlr4.util.StringUtils;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: lly
 * @Date: 2023/7/1
 */
@Slf4j
@Service
public class GroovyClassLoaderRuleImpl implements GroovyClassLoaderRule {

    /**
     * 脚本容器 :缓存Script,避免创建太多
     **/
    private static final Map<String, GroovyObject> SCRIPT_MAP = new HashMap<>();

    private static final GroovyClassLoader CLASS_LOADER = new GroovyClassLoader();

    public static GroovyObject loadScript(String key, String rule) {
        if (SCRIPT_MAP.containsKey(key)) {
            return SCRIPT_MAP.get(key);
        }
        GroovyObject groovyObject = loadScript(rule);
        SCRIPT_MAP.put(key, groovyObject);
        return groovyObject;
    }

    public static GroovyObject loadScript(String rule) {
        if (StringUtils.isEmpty(rule)) {
            return null;
        }
        try {
            Class ruleClazz = CLASS_LOADER.parseClass(rule);
            if (ruleClazz != null) {
                log.info("load rule:" + rule + " success!");
                GroovyObject groovyObject = (GroovyObject) ruleClazz.newInstance();
                return groovyObject;
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            CLASS_LOADER.clearCache();
        }

        log.error("load rule error, can not load Script");
        return null;
    }


    @Override
    public String run() {
        // 业务逻辑执行,方便配置
        String groovyClassLoader1 = "package script\n" +
                "\n" +
                "import com.example.groovy.GroovyInvokeJavaDemo\n" +
                "import com.example.groovy.groovyshell.ShellGroovyDTO\n" +
                "import com.example.groovy.utils.SpringContextUtil\n" +
                "\n" +
                "/**\n" +
                " * @Author: lly\n" +
                " * @Date: 2023/7/1\n" +
                " */\n" +
                "\n" +
                "def groovyInvokeJavaMethod(int a, int b) {\n" +
                "    GroovyInvokeJavaDemo groovyInvokeJavaDemo = SpringContextUtil.getBean(\"groovyInvokeJavaDemo\")\n" +
                "//    return groovyInvokeJavaDemo.groovyInvokeJava();\n" +
                "\n" +
                "    return groovyInvokeJavaDemo.groovyInvokeJavaParam(a, b)\n" +
                "}\n" +
                "\n" +
                "groovyInvokeJavaMethod(a, b)";

        String groovyClassLoader2 = "package script\n" +
                "\n" +
                "import com.example.groovy.GroovyInvokeJavaDemo\n" +
                "import com.example.groovy.groovyshell.ShellGroovyDTO\n" +
                "import com.example.groovy.utils.SpringContextUtil\n" +
                "\n" +
                "/**\n" +
                " * @Author: lly\n" +
                " * @Date: 2023/7/1\n" +
                " */\n" +
                "\n" +
                "def groovyInvokeJavaMethod(int a, int b) {\n" +
                "    GroovyInvokeJavaDemo groovyInvokeJavaDemo = SpringContextUtil.getBean(\"groovyInvokeJavaDemo\")\n" +
                "//    return groovyInvokeJavaDemo.groovyInvokeJava();\n" +
                "\n" +
                "    return groovyInvokeJavaDemo.groovyInvokeJavaParam(a, b)\n" +
                "}\n" +
                "\n" +
                "groovyInvokeJavaMethod(a, b)";

        Binding binding = new Binding();
        binding.setVariable("a", 300);
        binding.setVariable("b", 400);

//        Script classLoader1 = loadScript("groovyClassLoader1", groovyClassLoader1, binding);
        GroovyObject groovyObject = loadScript("groovyClassLoader2", groovyClassLoader2);

        Object groovyInvokeJavaMethod = groovyObject.invokeMethod("groovyInvokeJavaMethod", new Object[]{100, 200});

        return (String) groovyInvokeJavaMethod;
    }
}

第四步、创建请求API


@RequestMapping("/groovy-class-loader/spring")
public String groovyClassLoaderRuleTest() {
    String result = groovyClassLoaderRule.run();
    return result;

}

第五步、启动验证

至此,咱们的Groovy系列就结束啦,代码大家需要的话可以访问我的gitHub网站获取或者留言,我私信发给大家,希望可以帮助到大家。

https://github.com/576403061lly/groovy

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

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

相关文章

4.0ORBSLAM3之局部建图线程概述

1.简介 局部建图线程是ORBSLAM3的核心线程之一&#xff0c;在初始化SLAM系统时被创建和启动&#xff0c;主要作用是为跟踪线程(跟踪局部地图)以及回环检测线程(回环检测)服务&#xff0c;并进行局部地图优化以及时消除轨迹的累计误差。局部建图线程主要维护一个由共视图Covisi…

JSP网上订餐管理系统用eclipse定制开发mysql数据库BS模式java编程jdbc

一、源码特点 JSP 网上订餐管理系统是一套完善的web设计系统&#xff0c;对理解JSP java SERLVET mvc编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,eclipse开发&#xff0c;数据库为Mysql5.0&a…

java压测工具 Jmeter初使用

一. 下载及安装教程 1. 有博主总结的很好&#xff0c;这里直接放传送门&#xff1a; 【Jmeter】win 10 / win 11&#xff1a;Jmeter 下载、安装、汉化、新机迁移、版本更新&#xff08;Jmeter 4 以上版本均适用&#xff09; 2. Jmeter 自定义创建桌面快捷方式 3. JMeter插件…

手写vue-diff算法(三)updateChildren

前文回顾 上一篇提到&#xff0c;新老儿子节点比对可能存在的 3 种情况及对应的处理方法&#xff1a; 情况 1&#xff1a;老的有儿子&#xff0c;新的没有儿子 处理方法&#xff1a;直接将多余的老dom元素删除即可&#xff1b; 情况 2&#xff1a;老的没有儿子&#xff0c;…

基础知识--客户端·服务端·代理

目录 一、客户端 1.什么是客户端 2.客户端分类 二、服务端 1.什么是服务器 2.服务器的作用 3.服务器工作原理 4.服务器的组成 服务器硬件 服务器软件 5.补充 三、代理 1.代理的分类 正向代理 反向代理 两者的区别与联系 2.总结 一、客户端 1.什么是客户端 …

【八股】【C++】(二)函数、类、模板

这里写目录标题 形参与实参的区别函数调用过程指针和引用当函数参数回调函数友元函数重载匹配运算符重载直接初始化与拷贝初始化函数指针C中struct&#xff08;结构&#xff09;和class&#xff08;类&#xff09;的区别C有哪几种构造函数构造函数的执行顺序析构函数的执行顺序…

设计消息模块的业务层Web层

目录 业务层 一、定义Message业务接口 二、定义Message业务实现类 Web层 一、获取分页消息列表 二、根据ID查询消息 三、把未读消息更新成已读消息 四、删除消息 业务层 一、定义Message业务接口 创建 MessageService.java 类 public interface MessageService {pub…

mybatis-plus使用@Delete注解批量删除实战

使用Delete注解批量删除 1、控制器调用 // test // http://localhost:3000/function/test // 删除操作按钮权限 Transactional GetMapping("/test") public JSONObject testBatch() {// Arrays.asList(1, 2, 3)JSONObject result new JSONObject();try {functionM…

Django+vue3权限菜单rabc设计和动态路由

本次是基于Django和vue实现 github源码&#xff1a;nineaiyu/xadmin-server: xadmin-基于Djangovue3的rbac权限管理系统 (github.com) 服务器设计及部分代码 权限控制的话&#xff0c;可以基于Django的permission进行控制&#xff0c;并通过访问api的URL操作 核心代码如下 …

stable-diffusion使用openpose报错

依据教程 &#xff1a; https://post.smzdm.com/p/awz2l2xg/ 使用 stable-diffusion教学之ControlNetlora换脸 报错&#xff1a; urllib.error.URLError: <urlopen error [WinError 10054] 远程主机强迫关闭了一个现有的连接。> File "E:\ai\sd-webui-aki-v4\ext…

【数据挖掘】时间序列教程【五】

(说明:本文接上回:【数据挖掘】时间序列教程【四】_无水先生的博客-CSDN博客) 上面介绍的傅里叶变换的问题在于,无论是正弦/余弦回归模型形式还是复指数形式,它都需要 操作以计算所有傅里叶系数。有n 数据点和有n/2 可以计算傅里叶系数的频率。每个频率系…

Springboot3新特性异常信息ProblemDetail详解

环境&#xff1a;Springboot3.0.5 概述 RFC 7807定义了为HTTP响应中错误的可读详细信息&#xff0c;以避免需要为HTTP API定义新的错误响应格式。HTTP [RFC7230]状态码有时不足以传达关于错误的足够信息。 RFC 7807 定义了简单的JSON[RFC7159]和XML[W3C.REC-XML-20081126]文…

7.MHA高可用配置及故障切换

文章目录 MHA高可用配置及故障切换MHA概念实验配置时间同步与主从复制安装MHA服务SSH免交互认证验证MHA服务是否开启启动服务 故障模拟恢复故障过程 MHA高可用配置及故障切换 MHA概念 MHA&#xff08;MasterHigh Availability&#xff09;是一套优秀的MySQL高可用环境下故障切…

计网实验第四章:IP

问题集1&#xff1a; 1.192.168.31.7 2. 上层协议为ICMP&#xff0c;并且其字段值为1 3. 20字节 56字节 - 20字节 36字节 解释&#xff1a;如图所示 4. 这个报文段没有分段发送 原因如图&#xff1a;按照下图所示 标志位显示没有更多的分段。 5. 同一地址发送的这两个…

1.计算机是如何工作的(下)

文章目录 4.编程语言&#xff08;Program Language&#xff09;4.1程序&#xff08;Program&#xff09;4.2早期编程4.3编程语言发展 5.操作系统&#xff08;Operating System&#xff09;5.1操作系统的定位5.2什么是进程/任务&#xff08;Process/Task&#xff09;5.3进程控制…

[LangChain]简介快速入门

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;人工智能。 目录 1、简介2、快速入门2.1、LLMs2.2、聊天模型2.3、提示模板2.4、链2.5、代理2.6、内存 1、简介 …

1758_C语言通过预处理的eror输出异常信息

全部学习汇总&#xff1a; GreyZhang/c_basic: little bits of c. (github.com) 这个功能我一直没有使用过&#xff0c;能够想到它完全是因为之前从某些代码中看了一眼。或许&#xff0c;这就是我跟这个小小知识点的缘分。 最近想处理一个可以适配多种情况的程序&#xff0c;…

领域驱动设计(DDD,Domain-Driven Design)

领域驱动设计 前言正文领域驱动设计基本概念什么是领域模型&#xff1f;什么是领域服务&#xff08;Domain Service&#xff09;&#xff1f;什么是领域事件&#xff1f; 秒杀项目中的领域分析一、秒杀活动领域设计秒杀活动领域模型领域服务领域事件 二、秒杀品领域设计领域模型…

开源自动化测试框架介绍

开源自动化测试框架介绍 一、Junit&#xff08;白盒测试、API自动化、UI自动化&#xff09;【官网】【简介】【使用场景】 二、Selenium&#xff08;Web自动化、爬虫&#xff09;【官网】【简介】【使用场景】 三、TestNG&#xff08;白盒测试、API自动化、UI自动化&#xff09…

Linux文件系统架构和共享文件方法

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天来聊聊 Linux文件系统架构和共享文件方法。 在Linux环境中使用文件和目录是工作中不可回避的环节。当然&#xff0c;在我的博客里成立windows程序员看linux这个专题&#xff0c;主要还是因为微软也发布了…