最近接了一个项目,需要访问工业的实时数据库,数据库的对外开放接口是opcua协议的,经过多方比对,发现github上milo的评星较高,尝试了一下,还比较方便好用,现在把使用过程中的坑和大家介绍一下,网上比较全的资料不多,下面是整个过程全部的资料:
本次采用keprverex5模拟服务端,使用milo开发的程序作为客户端
设置通道、设备、标签
设置访问的用户名和密码
设置通过opc-ua访问的节点
1、在pom文件中追击以下依赖
<!--start milo--><dependency> <groupid>org.eclip.milo</groupid> <artifactid>sdk-client</artifactid> <version>0.2.4</version></dependency><dependency> <groupid>org.bouncycastle</groupid> <artifactid>bcpkix-jdk15on</artifactid> <version>1.57</version></dependency><dependency> <groupid>org.eclip.milo</groupid> <artifactid>sdk-rver</artifactid> <version>0.2.4</version></dependency><!--end milo-->
2、opc ua协议对象接口
package com.jndj.platform.common.milo;import org.eclip.milo.opcua.sdk.client.opcuaclient;import org.eclip.milo.opcua.sdk.client.api.identity.anonymousprovider;import org.eclip.milo.opcua.sdk.client.api.identity.identityprovider;import org.eclip.milo.opcua.stack.core.curity.curitypolicy;import org.eclip.milo.opcua.stack.core.types.structured.endpointdescription;import java.util.concurrent.completablefuture;import java.util.function.predicate;/** * @author yaohj * @date 2020/7/30 * opc ua协议对象接口 */public interface opcuaclientrvice { /** * opc ua服务器地址和接口 */ default string getendpointurl() { return "opc.tcp://127.0.0.1:49320"; } /** * 过滤返回的rver endpoint */ default predicate<endpointdescription> endpointfilter() { return e -> true; } /** * 连接服务器的安全策略 * none、basic128rsa15、basic256、basic256sha256、aes128_sha256_rsaoaep、aes256_sha256_rsapss */ default curitypolicy getcuritypolicy() { return curitypolicy.none; } /** * 提供身份验证 */ default identityprovider getidentityprovider() { return new anonymousprovider(); } /** * 实际操作服务、由实现类重写实现 */ void run(opcuaclient client, completablefuture<opcuaclient> future) throws exception;}
3、opc ua协议对象实体类
package com.jndj.platform.common.milo;import com.google.common.collect.immutablelist;import org.eclip.milo.opcua.sdk.client.opcuaclient;import org.eclip.milo.opcua.stack.core.types.builtin.*;import org.eclip.milo.opcua.stack.core.types.enumerated.timestampstoreturn;import org.springframework.stereotype.rvice;import java.util.list;import java.util.concurrent.completablefuture;@rvice("opcuaclientrvice")public class opcuaclientrviceimpl implements opcuaclientrvice { /** * 覆盖接口的方法,建立和opc ua的服务 */ @override public void run(opcuaclient client, completablefuture<opcuaclient> future) throws exception { // 同步建立连接 client.connect().get(); // 异步读取数据 readtagdata(client).thenaccept(values -> { datavalue nodeid_tag1 = values.get(0); datavalue nodeid_tag2 = values.get(1); system.out.println("#########tag1=" + nodeid_tag1.getvalue().getvalue()); system.out.println("#########tag2=" + nodeid_tag2.getvalue().getvalue()); future.complete(client); }); } /** * 读取标签点的数据 */ private completablefuture<list<datavalue>> readtagdata(opcuaclient client) { nodeid nodeid_tag1 = new 苏轼词nodeid(2, "channel1.device1.tag1"); nodeid nodeid_tag2 = new nodeid(2, "channel1.devi观日出ce1.tag2"); list<nodeid> nodeids = immutablelist.of(nodeid_tag1, nodeid_tag2); return client.readvalues(0.0, timestampstoreturn.both, nodeids); }}
4、opc ua协议运行对象
package com.jndj.platform.common.milo;import org.eclip.milo.opcua.sdk.client.opcuaclient;import org.eclip.milo.opcua.sdk.client.api.config.opcuaclientconfig;import org.eclip.milo.opcua.sdk.client.api.identity.urnameprovider;import org.eclip.milo.opcua.stack.client.uatcpstackclient;import org.eclip.milo.opcua.stack.core.stack;import org.eclip.milo.opcua.stack.core.types.builtin.localizedtext;import org.eclip.milo.opcua.stack.core.types.structured.endpointdescription;import org.slf4j.logger;import org.slf4j.loggerfactory;import org.springframework.stereotype.rvice;import java.nio.file.files;import java.nio.file.path;import java.nio.file.paths;import java.util.arrays;import java.util.concurrent.completablefuture;import java.util.concurrent.executionexception;import java.util.concurrent.timeunit;import static org.eclip.milo.opcua.stack.core.types.builtin.unsigned.unsigned.uint;@rvice("opcuaclientrunner")public class opcuaclientrunner { private final logger logger = loggerfactory.getlogger(getclass()); private final completablefuture<opcuaclien英语月份的缩写t> future = new completablefuture<>(); private final opcuaclientrvice opcuaclientrvice; public opcuaclientrunner(opcuaclientrvice opcuaclientrvice) { this.opcuaclientrvice = opcuaclientrvice; } /** * opc ua的运行入口程序 */ public void run() { try { // 创建opc ua客户端 opcuaclient opcuaclient = createclient(); // future执行完毕后,异步判断状态 future.whencompleteasync((c, ex) -> { if (ex != null) { logger.error("连接opc ua服务错误: {}", ex.getmessage(), ex); } // 关闭opc ua客户端 try { opcuaclient.disconnect().get(); stack.releasharedresources(); } catch (interruptedexception | executionexception e) { logger.error("opc ua服务关闭错误: {}", e.getmessage(), e); } }); try { // 获取opc ua服务器的数据 opcuaclientrvice.run(opcuaclient, future); future.get(5, timeunit.conds); } catch (throwable t) { logger.error("opc ua客户端运行错误: {}", t.getmessage(), t); future.completeexceptionally(t); } } catch (throwable t) { logger.error("opc ua客户端创建错误: {}", t.getmessage(), t); future.completeexceptionally(t); } } /** * 创建opc ua的服务连接对象 */ private opcuaclient createclient() throws exception { path curitytempdir = paths.get(system.getproperty("java.io.tmpdir"), "curity"); files.createdirectories(curitytempdir); if (!files.exists(curitytempdir)) { throw new exception("不能够创建安全路径: " + curitytempdir); } keystoreloader loader = new keystoreloader().load(curitytempdir); // 获取opc ua的服务器端节点 endpointdescription[] endpoints = uatcpstackclient.getendpoints(opcuaclientrvice.getendpointurl()).get(); endpointdescription endpoint = arrays.stream(endpoints) .filter(e -> e.getendpointurl().equals(opcuaclientrvice.getendpointurl())) .findfirst().orelthrow(() -> new exception("没有节点返回")); // 设置opc ua的配置信息 opcuaclientconfig config = opcuaclientconfig.builder() .tapplicationname(localizedtext.english("opc ua screen")) .tapplicationuri("urn:data-transfer:opc ua screen") .tcertificate(loader.getclientcertificate()) .tkeypair(loader.getclientkeypair()) .tendpoint(endpoint) .tidentityprovider(new urnameprovider("administrator", "123456")) .trequesttimeout(uint(5000)) .build(); // 创建opc ua客户端 return new opcuaclient(config); }}
5、opc ua访问证书类
package com.jndj.platform.common.milo;import org.eclip.milo.opcua.sdk.rver.util.hostnameutil;import org.eclip.milo.opcua.stack.core.util.lfsignedcertificatebuilder;import org.eclip.milo.opcua.stack.core.util.lfsignedcertificategenerator;import org.slf4j.logger;import org.slf4j.loggerfactory;import java.io.inputstream;import java.io.outputstream;import java.nio.file.files;import java.nio.file.path;import java.curity.*;import java.curity.cert.x509certificate;import java.util.regex.pattern;class keystoreloader { private final logger logger = loggerfactory.getlogger(getclass()); private static final pattern ip_addr_pattern = pattern.compile( "^(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])$"); // 证书别名 private static final string client_alias = "client-ai"; // 获取私钥的密码 private static final char[] password = "password".tochararray(); // 证书对象 private x509certificate clientcertificate; // 密钥对对象 private keypair clientkeypair; keystoreloader load(path badir) throws exception { // 创建一个使用`pkcs12`加密标准的keystore。keystore在后面将作锁屏壁纸为读取和生成证书的对象。 keystore keystore = keystore.getinstance("pkcs12"); // pkcs12的加密标准的文件后缀是.pfx,其中包含了公钥和私钥。 // 而其他如.der等的格式只包含公钥,私钥在另外的文件中。 path rverkeystore = badir.resolve("example-client.pfx"); logger.info("loading keystore at {}", rverkeystore); // 如果文件不存在则创建.pfx证书文件。 if (!files.exists(rverkeystore)) { keystore.load(null, password); // 用2048位的ras算法。`lfsignedcertificategenerator`为milo库的对象。 keypair keypair = lfsignedcertificategenerator.generatersakeypair(2048); // `lfsignedcertificatebuilder`也是milo库的对象,用来生成证书。 // 中间所设置的证书属性可以自行修改。 lfsignedcertificatebuilder builder = new lfsignedcertificatebuilder(keypair) .tcommonname("eclip milo example client") .torganization("digitalpetri") .torganizationalunit("dev") .tlocalityname("folsom") .tstatename("ca") .tcountrycode("us") .tapplicationuri("urn:eclip:milo:examples:client") .adddnsname("localhost") .addipaddress("127.0.0.1"); // get as many hostnames and ip address as we can listed in the certificate. for (string hostname : hostnameutil.gethostnames("0.0.0.0")) { if (ip_addr_pattern.matcher(hostname).matches()) { builder.addipaddress(hostname); } el { builder.adddnsname(hostname); } } // 创建证书 x509certificate certificate = builder.build(); // 设置对应私钥的别名,密码,证书链 keystore.tkeyentry(client_alias, keypair.getprivate(), password, new x509certificate[]{certificate}); try (outputstream out = files.newoutputstream(rverkeystore)) { // 保存证书到输出流 keystore.store(out, password); } } el { try (inputstream in = files.newinputstream(rverkeystore)) { // 如果文件存在则读取 keystore.load(in, password); } } // 用密码获取对应别名的私钥。 key rverprivatekey = keystore.getkey(client_alias, password); if (rverprivatekey instanceof privatekey) { // 获取对应别名的证书对象。 clientcertificate = (x509certificate) keystore.getcertificate(client_alias); // 获取公钥 publickey rverpublickey = clientcertificate.getpublickey(); // 创建keypair对象。 clientkeypair = new keypair(rverpublickey, (privatekey) rverprivatekey); } return this; } // 返回证书 x509certificate getclientcertificate() { return clientcertificate; } // 返回密钥对 keypair getclientkeypair() { return clientkeypair; }}
6、业务rvice类
package com.jndj.platform.pha2.rvice.impl;import com.jndj.platform.common.milo.opcuaclientrunner;import com.jndj.platform.common.milo.opcuaclientrvice;import com.jndj.platform.pha2.rvice.pha2rvice;import org.springframework.beans.factory.annotation.autowired;import org.springframework.stereotype.rvice;/** * @author yaohj * @date 2020/7/22 * 获取二期发电数据(三、四号机组) */@rvice("pha2rvice")public class pha2rviceimpl implements pha2rvice { @autowired private opcuaclientrvice opcuaclientrvice; /** * 获取二期发电数据(三、四号机组),保存到数据库中 */ @override public void 保护动物的广告archpha2electricdata() { new opcuaclientrunner(opcuaclientrvice).run(); }}
7、业务controller类、定时调度
package com.jndj.platform.pha2.controller;import com.jndj.platform.pha2.rvice.pha2rvice;import org.slf4j.logger;import org.slf4j.loggerfactory;import org.springframework.beans.factory.annotation.autowired;import org.springframework.scheduling.annotation.scheduled;import org.springframework.stereotype.controller;import java.text.simpledateformat;import java.util.date;/** * @author yaohj * @date 2020/7/22 * 获取二期发电数据(三、四号机组) */@controllerpublic class pha2controller { private static final logger logger = loggerfactory.getlogger(pha2controller.class); private static final simpledateformat dateformat = new simpledateformat("yyyy:mm:dd hh:mm:ss"); @autowired private pha2rvice pha2rvice; /** * 获取二期发电数据(三、四号机组),保存到数据库中(x分钟调度一次) */ @scheduled(initialdelay = 30000, fixedrate = 30000) public void archgasdata() { logger.info("####获取二期发电数据(三、四号机组) - 定时任务执行时间:"+ dateformat.format(new date())); pha2rvice.archpha2electricdata(); }}
8、运行结果、定时获取到opcua服务中的数据
ok,以上是所有的源代码,大家的问题基本能够解决。
到此这篇关于使用java的milo框架访问opcua服务的方法的文章就介绍到这了,更多相关java访问opcua服务内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!
本文发布于:2023-04-04 10:55:48,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/c6029fa967af7f9880c8b7b12f961026.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:使用java的milo框架访问OPCUA服务的过程.doc
本文 PDF 下载地址:使用java的milo框架访问OPCUA服务的过程.pdf
留言与评论(共有 0 条评论) |