OPC UA JAVA开发笔记(四):数据写入
这一节我们来将如何实现Client端的数据持续写入OPC UA。一下程序均在Spring Boot环境中,请先添加相应的依赖
- 首先,我们准备一个RestController用于提供JSON数据。
@RestController
@RequestMapping("/coors")
public class GreetingController {//主要用于产生随机数final Random random = new Random();@RequestMapping("/relative")public Coordinate relative() {return new Coordinate(random.nextDouble(),random.nextDouble(),random.nextDouble());}@RequestMapping("/machine")public Coordinate machine() {return new Coordinate(random.nextDouble(),random.nextDouble(),random.nextDouble());}
}
我们获取数据的REST API为:http://localhost:8080/coors/machine
为了不断的从REST API中获取JSON数据并解析,首先我们引入fastjson用来解析JSON数据
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.61</version>
</dependency>
我们需要写入的JSON数据格式为(这里可以用GSON生成对应的类):
{ "X": 10.0, "Z": 10.0, "Y": 20.0 }
新建一个Model用于存储数据
@Data
public class Coordinate {/*** X : 10.0* Z : 10.0* Y : 20.0*/private double X;private double Z;private double Y;public List<Variant> getVariants(){return Arrays.asList(new Variant(X), new Variant(Y), new Variant(Z));}
}
其中getVariants方法返回一个包含三个轴坐标值的List集合
接着我们新建一个类,类中添加如下方法,用于将数据写入:
public OpcUaOperation{public void writeNodeValues(List<NodeId> nodeIds, List<Variant> variants) {try {//连接到唯一运行的client,可以根据自己的情况建立一个OpcUAClientOpcUaClient client = ClientGen.getOpcUaClient();//创建连接client.connect().get();List<DataValue> values =variants.stream().map(DataValue::valueOnly).collect(toList());List<StatusCode> statusCodes =client.writeValues(nodeIds, values).get();//如果写入出错则打印错误信息statusCodes.forEach(statusCode -> {if (statusCode.isBad()) log.error("The Writing is wrong");});} catch (Exception e) {log.error(e.getMessage());}}
}
为了不断的从REST API中获取数据,我们采用Spring Boot中的@Scheduled注解
这个注解会使被标记的方法每隔n毫秒执行一次 fixed表示固定的时间间隔
@Slf4j
@Component
@EnableScheduling //通过这个注解开启Scheduled
public class CNCCoorsCollecting {@AutowiredOpcUaOperation opcUaOperation;@AutowiredRestTemplate restTemplate;//必须是http://开头的,不然restTemplate不能解析private static String cncUrl = "http://localhost:8080";@Scheduled(fixedDelay = 50)public void coorsCollecting() {try {String axis_data = cncUrl + "/coors/machine";ResponseEntity<String> responseEntity =restTemplate.exchange(axis_data, HttpMethod.GET, null, String.class);String json = responseEntity.getBody();//获取到JSON对象所封装的数据Coordinate coordinate = JSON.parseObject(json, Coordinate.class);opcUaOperation.writeNodeValues(KND.axises, coordinate.getVariants());} catch (Exception e) {log.error("Axises Data Collecting Wrong");}}
}
其中这一段特别说明一下
ResponseEntity<String> responseEntity =restTemplate.exchange(axis_data, HttpMethod.GET, null, String.class);String json = responseEntity.getBody();//获取到JSON对象所封装的数据Coordinate coordinate = JSON.parseObject(json, Coordinate.class);
- 首先从axis_data这个url拿去对应的JSON对象,并将其装换为JSON字符串,运用的是restTemplate的exchange方法从对应的REST API获取JSON
- 从RepsonceEntity中获取Body,也就是对应的json字符串
- 运用JSON.parseObject(json, Coordinate.class) 将字符串转换为对应的JavaBean对象
其中KND.axises的定义如下,是一个包含了三个轴的Identifier的List集合
public static String KND_AXIS_X = KND_AXIS + prefix + "X";
public static String KND_AXIS_Y = KND_AXIS + prefix + "Y";
public static String KND_AXIS_Z = KND_AXIS + prefix + "Z";//初始化轴集合
public static final List<NodeId> axises = Arrays.asList(new NodeId(CNC, KND_AXIS_X),new NodeId(CNC, KND_AXIS_Y),new NodeId(CNC, KND_AXIS_Z));
接下来我们来改造原本的数据写入程序,有阅读过milo源码的朋友们应该知道,作者Kevin是一个函数式编程的忠实爱好者,他的许多的类都是基于Java 8的各种函数式以及多线程包编写的,我们按照他的思路,对于原本的单线程写入程序进行改造。
CompletableFuture.supplyAsync(() ->restTemplate.exchange(axis_data, HttpMethod.GET, null, String.class)).thenApply(HttpEntity::getBody).thenApply(json -> JSON.parseObject(json, Coordinate.class)).thenAccept(coordinate -> opcUaOperation.writeNodeValues(KND.axises, coordinate.getVariants())).get();
虽然整体写入可以应用多线程的思想,但是整个执行流程有着明确的先后顺序,所以用thenApply方法将前后的结果依次连接。
thenApply可以将上一个CompletableFuture的结果作为输入,并且将这一部分流水线单线程化。
.
注意这里的多线程主要是为了与客户端的其他操作并行,在数据获取这个流水线中它依然需要单线程执行 – 因为有严格的先后顺序关系
这样我们就实现了对于一个有着固定工业IP的设备的OPC UA数据写入。
OPC UA JAVA开发笔记(四):数据写入相关推荐
- Java开发笔记(八十六)通过缓冲区读写文件
前面介绍了利用文件写入器和文件读取器来读写文件,因为FileWriter与FileReader读写的数据以字符为单位,所以这种读写文件的方式被称作"字符流I/O",其中字母I代表输 ...
- Java开发笔记(八十八)文件字节I/O流
前面介绍了如何使用字符流读写文件,并指出字符流工具的处理局限,进而给出随机文件工具加以改进.随机文件工具除了支持访问文件内部的任意位置,更关键的一点是通过字节数组读写文件数据,采取字节方式比起字符方式 ...
- (硅谷课堂项目)Java开发笔记4:前端基础知识(二)
文章目录 (硅谷课堂项目)Java开发笔记4:前端基础知识(二) 一.NPM 1.NPM简介 1.1.什么是NPM 1.2.NPM工具的安装位置 2.使用npm管理项目 2.1.创建文件夹npm 2. ...
- 【Visual C++】游戏开发笔记四十六 浅墨DirectX教程十四 模板测试与镜面特效专场
本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接: http://blog.csdn.net/zhmxy555/article/details/8632184 作者:毛星云( ...
- Java开发笔记(一百一十三)HttpClient实现下载与上传
前面介绍了通过HttpClient实现HTTP接口的GET方式调用和POST方式调用,那么文件下载与文件上传又该如何操作呢?其实在HttpClient看来,文件下载属于特殊的GET调用,只不过应答报文 ...
- Java开发笔记(二十三)数组工具Arrays
数组作为一种组合形式的数据类型,必然要求提供一些处理数组的简便办法,包括数组比较.数组复制.数组排序等等.为此Java专门设计了Arrays工具,该工具包含了几个常用方法,方便程序员对数组进行加工操作 ...
- Java开发笔记(五十六)利用枚举类型实现高级常量
前面介绍了联合利用final和static可实现常量的定义,该方式用于简单的常量倒还凑合,要是用于复杂的.安全性高的常量,那就力不从心了.例如以下几种情况,final结合static的方式便缺乏应对之 ...
- Java开发笔记(五十)几种开放性修饰符
前面介绍子类继承父类的时候,提到了public(公共)和private(私有)两个修饰符,其中public表示它所修饰的实体是允许外部访问的:而private表示它所修饰的实体不允许外部访问,只能在当 ...
- 【Visual C++】游戏开发笔记四十三 浅墨DirectX教程十一 为三维世界添彩:纹理映射技术(二)...
本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 作者:毛星云(浅墨) 邮箱: happylifemxy@163.com 本篇文章里,我们首先对Direct3D之中固定功能流水线中的 ...
最新文章
- 二叉树的基本特性和二叉树的几种基本操作的机制_笃学不倦|二叉树(一)
- python35是什么意思_python -m是什么意思CentOS 升级 Python3 (附带: 一键升级脚本)...
- 学校电用计算机控制的,高等学校适用教材:计算机控制技术
- bzoj1679[Usaco2005 Jan]Moo Volume 牛的呼声*
- windows 2008 R2系统安装拨号v p n详细配置
- 回调函数c++类中实现
- 小白都懂的Python爬虫之网易云音乐下载
- 多仓库带扫描进销存系统(仿电商ERP管理系统源码+数据库)
- 试图将一个数学定理证明到最底层的数哲原理...
- 5+API实现微信分享功能
- 【JQuery】操作 DOM
- 轻量级网络——MobileNet系列学习(理论篇)
- FPGA通过PCIe读写DDR4仿真IP核
- 教授专栏44 | 李家涛:企业高层性别均衡,发展趋势可憧憬
- Python深度优先解决八数码问题
- C++基本功和 Design Pattern系列 Operator 下
- java ee学生管理系统_javaEE 学生基本信息管理系统
- Spring AOP 学习笔记
- 【华为云技术分享】一文看懂什么是汽车OTA
- 802.11ax 的OFDMA资源分配详解