最近项目中经常需要将 JavaScript 或者 Python 中的算法发布为服务, 而发布 Tomcat 服务则需要在 Java 中调用这些算法, 因此就不免要进行跨语言调用算法. 不管是调用 JavaScript 文件还是 python 脚本, 都需要将原来的算法文件进行适当的更改, 以便可以在 Java 中传入参数, 并且得到算法运算结果.
一, Java 调用 JavaScript
需要注意的是 JavaScript 是弱类型语言, 定义变量只需要一个 var 就可以搞定, 但是在 Java 中却要注意变量类型, 不同的输入参数会有不同的类型.
调用 JS 文件时, 需要对其进行调整, 设置好需要调用的 function 和相关参数, 使用的 JS 文件代码如下 (其中有些核心算法不能展示):
- function get3DCode(Latitude,Longitude,Height,level){
- var latcode=[];var lngcode=[];
- latcode=GeoSOTCode1D(Latitude,level);
- lngcode=GeoSOTCode1D(Longitude,level);
- var heicode=[];var geosot3Dcode=[];
- heicode=Altcode(Height,level);
- geosot3Dcode=GeoSOT3D(latcode,lngcode, heicode,level);// 三维网格编码
- var d3code=[];
- d3code=getQuantcodeString(geosot3Dcode);
- return d3code;
- }
在 Java 中使用对应的接口就可以调用, 需要设置 JS 文件路径和输入参数, 调用的代码如下;
- package whu.get.three.beidou;
- import java.io.FileReader;
- import javax.script.Invocable;
- import javax.script.ScriptEngine;
- import javax.script.ScriptEngineManager;
- /** * Java 调用并执行 JS 文件, 传递参数, 并获得返回值 */
- public class ThreeD_GetBeidouCode {
- // 获取经纬度及高度, 返回三维码
- public static String main(String Latitude,String Longitude,String Height,int CodeSize) throws Exception {
- // 获取经纬度及高度, 保存为 double 类型
- Double latitude = Double.parseDouble(Latitude);
- Double longitude = Double.parseDouble(Longitude);
- Double height = Double.parseDouble(Height);
- int level = CodeSize;
- // 调用 JS 文件
- ScriptEngineManager manager = new ScriptEngineManager();
- ScriptEngine engine = manager.getEngineByName("javascript");
- String jsFileName = System.getProperty("catalina.home") + "/webapps/3DBeiDouCode/WEB-INF/classes/3Dcode.js"; // 读取 JS 文件
- FileReader reader = new FileReader(jsFileName); // 执行指定脚本
- engine.eval(reader);
- String c = "";
- if(engine instanceof Invocable) {
- Invocable invoke = (Invocable)engine; // 调用 merge 方法, 并传入两个参数
- c = String.valueOf(invoke.invokeFunction("get3DCode", latitude, longitude, height, level));
- }
- reader.close();
- return c; // 返回三维码
- }
- }
这里的 ThreeD_GetBeidouCode 类只是一个普通的类, 需要在其他可运行的主函数中调用这个类的 main 方法, 传入运行参数就可以得到结果.
二, Java 调用 Python
Java 调用 python 脚本有好几种方法, 最简单的是通过 Jython 来直接运行 python 代码, 但是这种方法不支持 python 中引用的第三方库, 因此我使用了 Runtime 来调用的方法, 这也相当于是在控制台执行脚本.
需要注意的是, Java 调用 python 时, 不能通过 return 语句来获取返回值, 而只能通过 print 将结果写入到标准输出流中, 然后在 Java 中通过标准输入流来读取到返回结果.
如果对 python 环境有要求, 比如在特定的环境中安装了需要引用的第三方库, 则还要在 Java 工程中添加运行环境, 在 eclipse 中点击 Run->Run Configurations->environment, 添加 Path, 值设置为 python 安装的路径.
在 python 程序中做适当修改: 添加引用 import sys, 将调用的函数参数设定为 sys.argv[1],sys.argv[2]... 注意必须是从 1 开始计数, 将需要返回的结果用 print 函数打印.
本例中 python 代码如下:
- # -*- coding:utf-8 -*-
- import BaseFunction
- import numpy as np
- import itertools
- import math
- import sys
- #计算中心要素
- def cal_central_feature(path,x,y):
- sf = BaseFunction.open_shpfile(path)
- x_records = BaseFunction.get_attr_records(sf,x)
- y_records = BaseFunction.get_attr_records(sf,y)
- dis = []
- for x0,y0 in zip(x_records,y_records):
- distance = 0
- for x1,y1 in zip(x_records,y_records):
- distance = distance + get_distance(x0,y0,x1,y1)
- dis.append(distance)
- i = dis.index(np.min(dis))
- result = [x_records[i],y_records[i]]
- return result
- #计算两点之间的距离
- def get_distance(x0,y0,x1,y1):
- xd = x1 - x0
- yd = y1 - y0
- distance = math.sqrt(xd**2+yd**2)
- return distance
- if __name__ == '__main__':
- result = cal_central_feature(sys.argv[1],sys.argv[2],sys.argv[3])
- print(result[0])
- print(result[1])
Java 中调用的代码如下:
- package whu.get.three.beidou;
- import java.io.BufferedReader;
- import java.io.InputStreamReader;
- /** * Java 调用并执行 JS 文件, 传递参数, 并活动返回值 */
- public class CalCentralFeatureClass {
- // 输入 shp 路径, 获取坐标
- public static String main(String filepath) {
- String pyPath = System.getProperty("catalina.home") + "/webapps/CalCentralFeature/WEB-INF/classes/CalCentralFeature.py"; //python 文件路径
- String[] args = new String[] { "python", pyPath, filepath, "x","y"};
- String c = ""; // 记录返回值
- try {
- Process proc = Runtime.getRuntime().exec(args); // 执行 py 文件
- BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
- String line = null;
- while ((line = in.readLine()) != null) {
- c = c+line+' ';
- }
- in.close();
- proc.waitFor();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return c; // 返回结果
- }
- }
得到的运算结果中, 每一个 python 中 print 的结果, 对应一个 in.readLine(), 可以按照需要获取自己想要的结果.
如果需要将调用 python 的程序用 tomcat 发布为服务, 也需要配置 tomcat 的运行环境, 同样是添加一个 Path, 赋值为 python 安装路径.
来源: https://www.cnblogs.com/MatthewHome/p/10783002.html