OPC UA JAVA开发笔记(四):数据写入
這一節(jié)我們來(lái)將如何實(shí)現(xiàn)Client端的數(shù)據(jù)持續(xù)寫(xiě)入OPC UA。一下程序均在Spring Boot環(huán)境中,請(qǐng)先添加相應(yīng)的依賴
我們獲取數(shù)據(jù)的REST API為:http://localhost:8080/coors/machine
為了不斷的從REST API中獲取JSON數(shù)據(jù)并解析,首先我們引入fastjson用來(lái)解析JSON數(shù)據(jù)
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.61</version> </dependency>我們需要寫(xiě)入的JSON數(shù)據(jù)格式為(這里可以用GSON生成對(duì)應(yīng)的類):
{ "X": 10.0, "Z": 10.0, "Y": 20.0 }新建一個(gè)Model用于存儲(chǔ)數(shù)據(jù)
@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));} }其中g(shù)etVariants方法返回一個(gè)包含三個(gè)軸坐標(biāo)值的List集合
接著我們新建一個(gè)類,類中添加如下方法,用于將數(shù)據(jù)寫(xiě)入:
public OpcUaOperation{ public void writeNodeValues(List<NodeId> nodeIds, List<Variant> variants) {try {//連接到唯一運(yùn)行的client,可以根據(jù)自己的情況建立一個(gè)OpcUAClientOpcUaClient client = ClientGen.getOpcUaClient();//創(chuàng)建連接client.connect().get();List<DataValue> values =variants.stream().map(DataValue::valueOnly).collect(toList());List<StatusCode> statusCodes =client.writeValues(nodeIds, values).get();//如果寫(xiě)入出錯(cuò)則打印錯(cuò)誤信息statusCodes.forEach(statusCode -> {if (statusCode.isBad()) log.error("The Writing is wrong");});} catch (Exception e) {log.error(e.getMessage());}} }為了不斷的從REST API中獲取數(shù)據(jù),我們采用Spring Boot中的@Scheduled注解
這個(gè)注解會(huì)使被標(biāo)記的方法每隔n毫秒執(zhí)行一次 fixed表示固定的時(shí)間間隔
@Slf4j @Component @EnableScheduling //通過(guò)這個(gè)注解開(kāi)啟Scheduled public class CNCCoorsCollecting {@AutowiredOpcUaOperation opcUaOperation;@AutowiredRestTemplate restTemplate;//必須是http://開(kāi)頭的,不然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對(duì)象所封裝的數(shù)據(jù)Coordinate coordinate = JSON.parseObject(json, Coordinate.class);opcUaOperation.writeNodeValues(KND.axises, coordinate.getVariants());} catch (Exception e) {log.error("Axises Data Collecting Wrong");}} }其中這一段特別說(shuō)明一下
ResponseEntity<String> responseEntity =restTemplate.exchange(axis_data, HttpMethod.GET, null, String.class);String json = responseEntity.getBody();//獲取到JSON對(duì)象所封裝的數(shù)據(jù)Coordinate coordinate = JSON.parseObject(json, Coordinate.class);其中KND.axises的定義如下,是一個(gè)包含了三個(gè)軸的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));接下來(lái)我們來(lái)改造原本的數(shù)據(jù)寫(xiě)入程序,有閱讀過(guò)milo源碼的朋友們應(yīng)該知道,作者Kevin是一個(gè)函數(shù)式編程的忠實(shí)愛(ài)好者,他的許多的類都是基于Java 8的各種函數(shù)式以及多線程包編寫(xiě)的,我們按照他的思路,對(duì)于原本的單線程寫(xiě)入程序進(jìn)行改造。
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();雖然整體寫(xiě)入可以應(yīng)用多線程的思想,但是整個(gè)執(zhí)行流程有著明確的先后順序,所以用thenApply方法將前后的結(jié)果依次連接。
thenApply可以將上一個(gè)CompletableFuture的結(jié)果作為輸入,并且將這一部分流水線單線程化。
.
注意這里的多線程主要是為了與客戶端的其他操作并行,在數(shù)據(jù)獲取這個(gè)流水線中它依然需要單線程執(zhí)行 – 因?yàn)橛袊?yán)格的先后順序關(guān)系
這樣我們就實(shí)現(xiàn)了對(duì)于一個(gè)有著固定工業(yè)IP的設(shè)備的OPC UA數(shù)據(jù)寫(xiě)入。
總結(jié)
以上是生活随笔為你收集整理的OPC UA JAVA开发笔记(四):数据写入的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: WebRTC教程 - 使用SIPML5
- 下一篇: APUE书