当前位置: 首页 > news >正文

在nodejs中使用Java方法

将Java类封装成JSON RPC 2.0服务,通过标准输入输出流发布。在nodejs中启动服务子进程,读写标准输入输出流,实现接口调用。

1. 方案

将现有Java库封装为JSON-RPC 2.0服务。假设现有Javalib.jar库,提供Javalib类和方法 String hello(String name) 。编写封装类,将Java方法封装成JSON-RPC 2.0接口。

代码1  将Java方法封装成JSON-RPC 2.0接口

private JSONObject serve(JSONObject request) {String method = request.getString("method");int id = request.getInt("id");JSONObject params = request.getJSONObject("params");JSONObject response = new JSONObject();response.put("jsonrpc", "2.0");response.put("id", id);JSONObject error = new JSONObject();switch (String.valueOf(method)) {case "hello": {String name = params.getString("name");Javalib javalib = new Javalib();String result = javalib.hello(name);response.put("result", result);break;}case "exit": response.put("result", "exit");running = false;break;default:error.put("code", -32601);error.put("messsage", "method not found");response.put("error", error);break;}return response;
}

编写命令行程序,通过标准输入输出发布JSON-RPC 2.0服务。

代码2  通过标准输入输出发布JSON-RPC 2.0服务

private String serve(String jsonStr) {JSONObject request = new JSONObject(jsonStr);JSONObject response = serve(request);return response.toString();
}public static void main(String[] args) throws IOException {JsonRpcServer server = new JsonRpcServer();Scanner scanner = new Scanner(System.in);while (server.running) {String jsonStr = scanner.nextLine();System.out.println(server.serve(jsonStr));}
}

在nodejs中启动服务程序,通过标准输入输出实现远程调用

代码3  在nodejs中通过标准输入输出实现远程调用

import { spawn } from 'child_process';class JsonRpcClient {constructor() {this.counter = 0;this.listeners = new Map();this.javaProcess = spawn('java', ['-cp', 'Javalib.jar;json-20250517.jar;.', 'JsonRpcServer']);this.javaProcess.stdout.on('data', (data) => {const jsonStr = data.toString();try {const { id, result } = JSON.parse(jsonStr);if (this.listeners.has(id)) {this.listeners.get(id)(jsonStr);this.listeners.delete(id);}} catch (err) {console.error('Failed to parse response:', err);}});this.javaProcess.stderr.on('data', (data) => {console.error('Java process error:', data.toString());});}async call(method, params = {}) {const id = ++this.counter;const request = {jsonrpc: "2.0",id,method,params,};const jsonStr = JSON.stringify(request);console.log(`发送 ${jsonStr}`);this.javaProcess.stdin.write(`${jsonStr}\n`);const { promise, resolve } = Promise.withResolvers();this.listeners.set(id, resolve);return promise;}
}

上述步骤完成后,就可以在nodejs中通过JSON-RPC 2.0调用Java方法了。

代码4  通过JSON-RPC 2.0调用Java方法

(async () => {const client = new JsonRpcClient();try {let response = await client.call('hello', { name: 'Bob' })console.log(`接收 ${response}`);response = await client.call('non_exist');console.log(`接收 ${response}`);response = await client.call('exit');console.log(`接收 ${response}`);} catch (err) {console.error('RPC call failed:', err);}
})();

2. 适用场景、局限和扩展

用于对性能要求不高的nodejs程序(如cli),快速对接现有Java库中的方法。如果对性能要求较高,或调用的Java方法需要支持复杂对象,可以使用node-java实现nodejs和Java的互操作。

由于使用了标准输入输出,上述方案对请求和应答对象的数据类型和大小存在一定限制。如果需要传输少量二进制数据,可以使用十六进制编码或base64编码。如果要传输大量数据,可以首先生成临时文件,将临时文件名作为参数传递。上述方案也可以扩展到“发布-订阅”模式。

3. 示例代码

代码5  Javalib.java

public class Javalib {public String hello(String name) {return "Hello " + name + " from Java!";}
}

代码6  JsonRpcServer.java

// 需要下载org.json包。https://repo1.maven.org/maven2/org/json/json/20250517/json-20250517.jar
import java.io.*;
import java.util.Scanner;
import java.util.Objects;
import org.json.JSONObject;
import org.json.JSONArray;public class JsonRpcServer {public boolean running = true;private JSONObject serve(JSONObject request) {String method = request.getString("method");int id = request.getInt("id");JSONObject params = request.getJSONObject("params");JSONObject response = new JSONObject();response.put("jsonrpc", "2.0");response.put("id", id);JSONObject error = new JSONObject();switch (String.valueOf(method)) {case "hello": {String name = params.getString("name");Javalib javalib = new Javalib();String result = javalib.hello(name);response.put("result", result);break;}case "exit": response.put("result", "exit");running = false;break;default:error.put("code", -32601);error.put("messsage", "method not found");response.put("error", error);break;}return response;}private String serve(String jsonStr) {JSONObject request = new JSONObject(jsonStr);JSONObject response = serve(request);return response.toString();}public static void main(String[] args) throws IOException {JsonRpcServer server = new JsonRpcServer();Scanner scanner = new Scanner(System.in);while (server.running) {String jsonStr = scanner.nextLine();System.out.println(server.serve(jsonStr));}}
}

代码7  app.js

import { spawn } from 'child_process';class JsonRpcClient {constructor() {this.counter = 0;this.listeners = new Map();this.javaProcess = spawn('java', ['-cp', 'Javalib.jar;json-20250517.jar;.', 'JsonRpcServer']);this.javaProcess.stdout.on('data', (data) => {const jsonStr = data.toString();try {const { id, result } = JSON.parse(jsonStr);if (this.listeners.has(id)) {this.listeners.get(id)(jsonStr);this.listeners.delete(id);}} catch (err) {console.error('Failed to parse response:', err);}});this.javaProcess.stderr.on('data', (data) => {console.error('Java process error:', data.toString());});}async call(method, params = {}) {const id = ++this.counter;const request = {jsonrpc: "2.0",id,method,params,};const jsonStr = JSON.stringify(request);console.log(`发送 ${jsonStr}`);this.javaProcess.stdin.write(`${jsonStr}\n`);const { promise, resolve } = Promise.withResolvers();this.listeners.set(id, resolve);return promise;}
}(async () => {const client = new JsonRpcClient();try {let response = await client.call('hello', { name: 'Bob' })console.log(`接收 ${response}`);response = await client.call('non_exist');console.log(`接收 ${response}`);response = await client.call('exit');console.log(`接收 ${response}`);} catch (err) {console.error('RPC call failed:', err);}
})();

代码8  测试输入input.text

{"jsonrpc": "2.0", "id": 1, "method": "hello", "params": {"name": "Alex"}}
{"jsonrpc": "2.0", "id": 1, "method": "exit", "params": {}}

代码9  测试脚本

# 编译Javalib
javac Javalib.java && jar cvf Javalib.jar Javalib.class# 编译JsonRpcServer
javac -cp "Javalib.jar;json-20250517.jar" JsonRpcServer.java# 测试JsonRpcServer
gc input.txt | java -cp "Javalib.jar;json-20250517.jar;." JsonRpcServer # 测试app.js
node app.js

4. 附录:JSON-RPC 2.0简介

JSON-RPC 2.0是一种轻量级、无状态的远程过程调用(RPC)协议,使用JSON作为数据交换格式。

表1  请求对象
字段名类型必填说明
jsonrpcstring固定为 "2.0"
methodstring方法名
paramsarray/object参数
idstring/number请求标识符

代码10  请求对象示例

{"jsonrpc": "2.0","method": "subtract","params": [42, 23],"id": 1
}
表2  响应对象
字段名类型必填说明
jsonrpcstring固定为 "2.0"
resultany结果
error错误对象错误信息
idstring/number与请求标识符一致
表3  错误对象
字段名类型必填说明
codenumber错误码
messagestring错误简介
dataany详细信息
表4  预定义错误码
错误码说明
-32700Parse error语法解析错误
-32600Invalid Request无效请求
-32601Method not found找不到方法
-32602Invalid params无效的参数
-32603Internal error内部错误
-32000 到 -32099Server error服务端错误
表5  编程语言支持
语言库/框架
JavaScriptjson-rpc-protocol
Pythonjsonrpcserver
Gojsonrpc2
Javajsonrpc4j

5. 参考资料

  • JSON-RPC 2.0 Specification
  • (译) JSON-RPC 2.0 规范(中文版) - wiki . leozvc
http://www.xdnf.cn/news/1269829.html

相关文章:

  • windows、linux应急响应入侵排查
  • React中实现完整的登录鉴权与权限控制系统
  • 云服务器--阿里云OSS(2)【Springboot使用阿里云OSS】
  • 原生Vim操作大全
  • Python映射合并技术:多源数据集成的高级策略与工程实践
  • Jmeter性能测试之安装及启动Jmeter
  • [Oracle] TRUNC()函数
  • imx6ull-驱动开发篇15——linux自旋锁
  • OpenAI开源大模型 GPT-OSS 开放权重语言模型解析:技术特性、部署应用及产业影响
  • Ubuntu系统忘记密码怎么办?
  • 《TypeScript搭建的认知桥梁:游戏化学习应用的深层架构》
  • 数据结构(一)顺序表
  • CVPR中深度学习新范式:通用性、鲁棒性与多模态的创新突破
  • 【软考中级网络工程师】知识点之 RMON 技术深度剖析
  • dify离线插件安装
  • Android MediaMetadataRetriever取视频封面,Kotlin(1)
  • 密集遮挡场景识别率↑31%!陌讯轻量化部署方案在智慧零售的实战解析
  • 力扣(轮转数组)
  • Python基础教程(六)条件判断:引爆思维Python条件判断的九层境界
  • 网站站长如何借助php推送示例提交网站内容加速百度收录?
  • web应用服务器tomcat
  • 代码随想录算法训练营23天 | ​​
  • 力扣热题100-----118.杨辉三角
  • 信息安全简要
  • Python自动化测试断言详细实战代码
  • [激光原理与应用-202]:光学器件 - 增益晶体 - Nd:YVO₄增益晶体的制造过程与使用过程
  • 本地连接跳板机
  • 算法_python_学习记录_02
  • 32Nginx配置与多业务部署指南
  • [ MySQL 数据库 ] 多表关联查询