Springboot项目中加载Groovy脚本并调用其内部方代码实现

news2024/11/26 5:33:20

前言

项目中部署到多个煤矿的上,每一种煤矿的情况都相同,涉及到支架的算法得写好几套,于是想到用脚本实现差异变化多的算法!一开始想到用java调用js脚本去实现,因为这个不需要引入格外的包,js对我来说也没啥学习成本,后来发现js的方法的参数中没办法使用java的对象传参。如果要把java对象分解成多个基本类型的参数传递的话,js的代码实现就变复杂和臃肿了。于是改用groovy脚本去实现,后来经过两个小时的实现,终于调通!groovy的语法和java类似,学习成本很低,且groovy可以引入java的类使用java的对象,调用java的方法也很简单,下面给出实现的代码图文教程。

Groovy简介

Groovy是一种基于JVM(Java虚拟机)的动态编程语言,它具有Java的兼容性和许多强大的功能,可以用来快速开发Java应用程序。

以下是Groovy的一些主要特点:

  • 静态类型:Groovy是静态类型的语言,这意味着你可以在编译时检测到许多常见的错误,从而提高代码的质量和可维护性。
  • 动态类型:同时,Groovy也是动态类型的语言,这意味着你可以在运行时动态地改变变量的类型,这使得Groovy代码更加灵活和易读。
  • 强大的语法:Groovy的语法比Java更简洁、更易读。它支持多种编程范式,如面向对象编程和函数式编程。
  • 与Java无缝集成:Groovy可以与Java代码无缝集成,这意味着你可以在Groovy代码中使用Java类库,反之亦然。这使得Groovy成为Java开发者的强大工具。
  • 简洁的语法:与Java相比,Groovy的语法更为简洁。它支持许多Java不支持的特性,如可选的括号、可选的类型声明等。
  • 强大的元编程能力:Groovy具有强大的元编程能力,它允许你在运行时动态地修改代码。这使得Groovy成为快速开发原型或快速实现想法的有力工具。
  • 测试驱动开发:Groovy支持测试驱动开发(TDD),它使得你可以快速编写测试代码并以此驱动你的业务逻辑代码。
  • 闭包:Groovy支持闭包,这是一种可以包含代码块的语法结构,可以作为参数传递给函数,也可以赋值给变量。
  • 运行时类型检查:虽然Groovy是动态类型的语言,但它也支持运行时类型检查,这使得你可以在运行时捕获许多类型错误。
  • AST变换:Groovy允许你直接操作Java字节码,这使得你可以在编译时对代码进行修改。这是许多静态类型语言无法提供的功能。

总的来说,Groovy是一种强大、灵活且易于使用的编程语言,无论你是一个Java开发者还是一个想要使用JVM的语言的人,你都可以从Groovy中受益。

教程

引入依赖

首先在springboot项目中引入groovy的依赖,maven引入配置如下:

        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>2.4.11</version>
        </dependency>

java加载使用脚本工具类

新建一个ScriptProvider脚本使用类,代码如下:


import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyObject;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.util.List;

/**
 * @author Lenovo
 */
@Component
@Slf4j
public class ScriptProvider {

    private GroovyObject groovyObject;

    @Value("${app.work-face}")
    private  void loadScript(String name){
        try (GroovyClassLoader classLoader = new GroovyClassLoader()) {
            Class<?> groovyClass = classLoader.parseClass(new File("etc/"+name+".groovy"));
            groovyObject= (GroovyObject) groovyClass.newInstance();
        } catch (InstantiationException | IOException | IllegalAccessException e) {
            log.error(e.getMessage());
        }
    }

    public  void overloadScript(String filePath){
        try (GroovyClassLoader classLoader = new GroovyClassLoader()) {
            Class<?> groovyClass = classLoader.parseClass(new File(filePath));
            groovyObject= (GroovyObject) groovyClass.newInstance();
        } catch (InstantiationException | IOException | IllegalAccessException e) {
            log.error(e.getMessage());
        }
    }

    public double calStentHeight(int i, List<DataValue> dataValues){
        Object[] objects = new Object[]{i,dataValues};
        Object result=groovyObject.invokeMethod("calStentHeight",objects);
        return Double.parseDouble(result.toString());
    }

    public double revisedStentHeight(int i, List<DataValue> dataValues){
        Object[] objects = new Object[]{i,dataValues};
        Object result=groovyObject.invokeMethod("revisedStentHeight",objects);
        return Double.parseDouble(result.toString());
    }

    public Object revisedStentStroke(int i, List<DataValue> dataValues) {
        Object[] objects = new Object[]{i,dataValues};
        Object result=groovyObject.invokeMethod("revisedStentStroke",objects);
        return Double.parseDouble(result.toString());
    }
}

代码解析

  • 在spring配置文件中配置不同的脚本名,通过@Value(“${app.work-face}”) 注解 ,在项目启动时加载对应的groovy脚本文件。
  • invokeMethod(“calStentHeight”,objects); calStentHeight 是groovy脚本中定义的方法,objects数组是groovy脚本中方法的参数,objects数组数组的元素顺序和方法的参数保持一致。
  • new File(“etc/”+name+“.groovy”) 是读入项目根目录下,etc文件夹下的某个groovy脚本文件,打成jar运行的时候,读取的是jar同级目录下,etc文件夹下的某个groovy脚本文件。

在这里插入图片描述

groovy脚本

创建一个groovy脚本,以4703.groovy为例,代码如下:

import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue


def calStentHeight(int i,List<DataValue> dataValues){
    return dataValues.get(i).getValue().getValue();
}

def revisedStentHeight(int i,List<DataValue> dataValues){
    double d=dataValues.get(i).getValue().getValue();
    int stentNo=i+1;
    if(stentNo<=2||stentNo>=92){
        if(d>3.6){
            d=3.6;
        }
        if(d<=0){
            d=3.3;
        }
    }else{
        if(d>1.9){
            d=stentNo==3?1.9:dataValues.get(i-1).getValue().getValue();
        }
        if(d<=0){
            d=1.9;
        }
    }
    return d;
}

def revisedStentStroke(int i,List<DataValue> dataValues){
    double d=dataValues.get(i).getValue().getValue();
    int stentNo=i+1;
    if(stentNo<=2||stentNo>=92){
        if(d>900D){
            d=900D;
        }
        if(d<=0D){
            d=0D;
        }
    }else{
        if(d>900D||d<=0D){
            d=dataValues.get(i-1).getValue().getValue();;
        }
    }
    return d;
}

代码解析:

  • DataValue对象是java opc开源工具获取,opc点位对应值返回的对象。
  • groovy的方法内部可以向java一样编写

java调用groovy脚本的方法

在springboot中调用groovy脚本中的方法,示例代码如下:

    @Resource
    private ScriptProvider scriptProvider;

    StentsDTO.putStentHeight(key.getPointAddress(),scriptProvider.calStentHeight(i,dataValues));
    objValue= scriptProvider.revisedStentHeight(i,dataValues);

代码解析

  • 通过@Resource注解将ScriptProvider类注入到spring的容器中,通过ScriptProvider的实例对象,调用内部方法。

groovy脚本修改监听类实现

java无法是实现对具体某个文件操作事件的监听,只能实现文件夹和文件夹下的文件的事件的监听。我们可以通过监听文件夹监听实现对文件的监听。代码如下(代码中只有文件修改事件的监听):


import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.nio.file.*;

/**
 * @author tarzan
 */
@Component
@AllArgsConstructor
@Slf4j
public class FileSystemWatcher {

    private final ScriptProvider scriptProvider;

    public void modifyWatch(){
        try {
            watch(StandardWatchEventKinds.ENTRY_MODIFY);
        } catch (IOException | InterruptedException e) {
            log.error(e.getMessage());
        }
    }

    private  void watch(WatchEvent.Kind<Path> eventKind) throws IOException, InterruptedException {
        // 定义你想要监听的路径
        Path path = Paths.get("etc");
        // 创建 WatchService
        WatchService watchService = FileSystems.getDefault().newWatchService();
        // 将路径注册到 WatchService,并指定你想要监听的事件类型
        path.register(watchService, eventKind);

        while (true) {
            // 获取下一个文件系统事件
            WatchKey key = watchService.take();
            for (WatchEvent<?> event : key.pollEvents()) {
                // 获取事件类型
                WatchEvent.Kind<?> kind = event.kind();
                if (kind == StandardWatchEventKinds.OVERFLOW) {
                    continue;
                }
                // 获取发生事件的文件
                WatchEvent<Path> ev = (WatchEvent<Path>) event;
                Path fileName = ev.context();
                // 打印出发生事件的文件名和事件类型
                boolean eventFlag=!fileName.toFile().getName().endsWith("~");
                if(eventFlag){
                    log.info("etc/"+fileName +" be modified");
                    scriptProvider.overloadScript("etc/"+fileName);
                }
            }
            //睡眠1秒
            Thread.sleep(1000);
            // 重置 WatchKey,以便接收下一个事件
            boolean valid = key.reset();
            if (!valid) {
                break;
            }
        }

    }

}

代码解析

  • 代码通过监听etc文件,当监听到etc文件夹下的文件进行修改操作或者覆盖操作的事件,就会重新加载修改后的grooy脚本文件。

结语

如果你对文章有疑问或者更好的见解,请在评论区留言!如果文章对你有帮助,请点赞收藏!!!

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

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

相关文章

【Java基础面试一】、为什么Java代码可以实现一次编写、到处运行?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;为什么Java代码可以实现…

uniapp(uncloud) 使用生态开发接口详情(1简单的创建)

开发接口对比时间: 用java开发接口周期太长, 大概5-6个月左右 用php 开发接口周期同样太长, 大概3-4个月左右 用node.js 开发接口周期相对短一点, 大概1-2个月左右 用uniapp 开发接口, 可以不到 1-2周的时间 这里我使用 uniapp 开发接口, 废话不多说了,直接开干 HBuilder官网(…

头像Css

现有如下的图标&#xff0c;他这外层的白色圆圈是border,你敢信 .top-bar__img {margin: 0 8px 0 5px;padding: 2px;width: 30px;height: 30px;border-radius: 100%;box-sizing: border-box;border: 1px solid #eee;vertical-align: middle; }

《软件方法》2023版第1章(08)使用UML的理由,挑破乱七八糟图的脓包

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 1.3 UML 1.3.2 使用UML的理由 在开发团队中&#xff0c;不乏刻意排斥UML的人。这些人如果只是不使用UML&#xff0c;改为使用其他标准的图形表示法&#xff08;如BPMN&#xff09;&a…

城市综合管廊运维的系统集成方案

摘 要&#xff1a;从网络拓扑结构、开放式实时以太网协议、控制层系统配置方面介绍了综合管廊的系统网络架构设计&#xff0c;分析了无线网络特性&#xff0c;阐述了基于HTML5架构所能实现的功能的初步构想&#xff0c;以便于综合管廊运维人员巡检&#xff0c;确保管廊本体安全…

NodeMCU ESP8266 基于Arduino IDE的串口图形化调试教程(超详细)

NodeMCU ESP8266 基于Arduino IDE的串口图形化调试教程 文章目录 NodeMCU ESP8266 基于Arduino IDE的串口图形化调试教程前言Serial Plotter测试前期准备打开工具方法 1方法 2 测试代码 总结 前言 在嵌入式的开发过程中&#xff0c;我们经常会采集一些传感器的数据&#xff0c…

MVCC与BufferPool缓存机制

MVCC多版本并发控制机制 Mysql在可重复读隔离级别下如何保证事务较高的隔离性&#xff0c;我们上节课给大家演示过&#xff0c;同样的sql查询语句在一个事务里多次执行查询结果相同&#xff0c;就算其它事务对数据有修改也不会影响当前事务sql语句的查询结果。 这个隔离性就是…

游戏开发年度报告 | 2023年游戏开发团队最流行的制作和发行的方式

近期&#xff0c;Perforce发布了《2023游戏开发与设计现状报告》。此报告调查了来自全球各地的游戏开发专业人士&#xff0c;了解他们面临的主要开发挑战、使用的工具和流程&#xff0c;以及目前最让他们对这个行业感到兴奋的方面。 龙智作为Perforce授权合作伙伴&#xff0c;将…

wifi指纹室内定位系统 计算机竞赛

简介 今天来介绍一下室内定位相关的原理以及实现方法; WIFI全称WirelessFidelity&#xff0c;在中文里又称作“行动热点”&#xff0c;是Wi-Fi联盟制造商的商标做为产品的品牌认证&#xff0c;是一个创建于IEEE 802.11标准的无线局域网技术。基于两套系统的密切相关&#xff…

MBR10100CT-ASEMI肖特基二极管MBR10100CT

编辑&#xff1a;ll MBR10100CT-ASEMI肖特基二极管MBR10100CT 型号&#xff1a;MBR10100CT 品牌&#xff1a;ASEMI 芯片个数&#xff1a;2 封装&#xff1a;TO-220 恢复时间&#xff1a;&#xff1e;50ns 工作温度&#xff1a;-65C~175C 浪涌电流&#xff1a;150A 正向…

【微前端】single-spa 到底是个什么鬼

前言 说起微前端框架&#xff0c;很多人第一反应就是 single-spa。但是再问深入一点&#xff1a;它是干嘛的&#xff0c;它有什么用&#xff0c;可能就回答不出来了。 一方面没多少人研究和使用微前端。可能还没来得及用微前端扩展项目&#xff0c;公司就已经倒闭了。 另一方…

关于京东API数据接口业务的详细介绍

参数说明 通用参数说明 url说明 https://…….cn/平台/API类型/ 平台&#xff1a;淘宝&#xff0c;京东等&#xff0c; API类型:[item_search,item_get,item_search_shop等]version:API版本key:调用key,测试key:test_api_keysecret:调用secret,测试secret:(不用填写)cache:[ye…

长沙上市公司董秘联谊会,来啦!

上市公司的数量&#xff0c;是判断一座城市经济实力的重要指标。 在当前复杂的竞争环境中&#xff0c;提升上市公司的数量和质量&#xff0c;以产业思维促进城市内外的上市公司合作交流&#xff0c;是城市提升经济综合实力的有效举措。 10月13日&#xff0c;在由长沙市委统战…

2023年中国电信运营商IT支撑系统市场规模及销量、均价分析[图]

电信运营商IT支撑系统能够为最终用户管理服务&#xff0c;并且管理与底层网络功能有关的服务――涵盖跨众多网络的服务设计、履行和保证&#xff0c;针对各个客户群。电信运营商IT支撑系统有助于跨不同类型的网络&#xff08;包括物理网络、虚拟网络和混合网络&#xff09;交付…

代理现货白银有什么手续

成为现货白银代理商的好处有很多&#xff0c;一方面打理依然可以像普通投资者那样&#xff0c;采用平台的交易服务&#xff0c;直接在市场上通过交易&#xff0c;赚取高杠杆所带来的高回报&#xff0c;另一方面还可以根据自己客户的交易量&#xff0c;从平台获得一定的返佣&…

Linux下企业级夜莺监控分析工具的远程访问设置【内网穿透】

文章目录 前言1. Linux 部署Nightingale2. 本地访问测试3. Linux 安装cpolar4. 配置Nightingale公网访问地址5. 公网远程访问Nightingale管理界面6. 固定Nightingale公网地址 前言 夜莺监控是一款开源云原生观测分析工具&#xff0c;采用 All-in-One 的设计理念&#xff0c;集…

【计算机毕设选题推荐】蛋糕甜品店管理系统SpringBoot+SSM+Vue

前言&#xff1a;我是IT源码社&#xff0c;从事计算机开发行业数年&#xff0c;专注Java领域&#xff0c;专业提供程序设计开发、源码分享、技术指导讲解、定制和毕业设计服务 项目名 基于SpringBoot的蛋糕甜品店管理系统 技术栈 SpringBootSSMVueMySQLMaven 文章目录 一、蛋糕…

java springboot VUE美术外包平台系统前后端分离开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 springboot VUE 美术外包平台系统是一套完善的完整信息管理类型系统&#xff0c;结合springboot框架和VUE完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用springboot框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码…

【Overload游戏引擎细节分析】视图投影矩阵计算与摄像机

本文只罗列公式&#xff0c;不做具体的推导。 OpenGL本身没有摄像机(Camera)的概念&#xff0c;但我们为了产品上的需求与编程上的方便&#xff0c;一般会抽象一个摄像机组件。摄像机类似于人眼&#xff0c;可以建立一个本地坐标系。相机的位置是坐标原点&#xff0c;摄像机的朝…

《企业应用架构模式》2023中译本修正摘录

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 近期&#xff0c;机械工业出版社将出《企业应用架构模式》的修订中译本。 《企业应用架构模式》的英文原书为Martin Fowler写的“Patterns of Enterprise Application Architecture”…