0
点赞
收藏
分享

微信扫一扫

Java——java语言调用python脚本

_LEON_ 2023-03-21 阅读 111


摘要

本文为大家介绍如何java调用python方法,在实际工程项目中可能会用到Java和python两种语言结合进行,这样就会涉及到一个问题,就是怎么用Java程序来调用已经写好的python脚本呢,一共有三种方法可以实现,具体方法分别为大家介绍:

1. Jython方式调用

Jython是一个Python语言在Java中的完全实现。Jython也有很多从CPython中继承的模块库。最有趣的事情是Jython不像CPython或其他任何高级语言,它提供了对其实现语言的一切存取。所以Jython不仅给你提供了Python的库,同时也提供了所有的Java类(反射使Jython能无缝地使用任何Java类)这使其有一个巨大的资源库。虽然上述网络上对Jython的描述看似很美好,但在实际使用的过程中会遇到很多的问题。最大的问题就是Jython在2015年停止更新,目前最新的是 Jython 2.7.0 Final Released(May 2015)。这就会导致Jython无法使用一些新的CPython库。当你只是想要使用Jython编写一些与Java程序混合的、简单的代码时是比较简单的——但是当你的程序需要导入很多外部库时,Jython总会出现问题。而且Jython的运行效率也不快。
首先加入Jython包,这里就有第一个坑,要注意添加的是​​​jython-2.7-b1.jar​​而不是jython.jar。

import java.io.IOException;

import org.python.core.Py;
import org.python.core.PyFunction;
import org.python.core.PyObject;
import org.python.core.PySystemState;
import org.python.util.PythonInterpreter;

public class JythonMethod {
public static void main(String[] args) throws IOException {
PySystemState sys = Py.getSystemState();
System.out.println(sys.path.toString());
//由于Jython和JVM的ClassPath不一样,所以需要手动加入项目所需的库文件路径

sys.path.add("xxx\\libs");//项目库文件

sys.path.add("xxx\\Lib");//Python自带库文件

System.out.println(sys.path.toString());


// 1. Python面向函数式编程: 在Java中调用Python函数
String pythonFunc = "./xxx/xxx.py";//Python文件路径


//在JVM中创建一个“Python解释器”对象
PythonInterpreter pi1 = new PythonInterpreter();
// 加载python程序
pi1.execfile(pythonFunc);
// 调用Python程序中的函数
PyFunction pyf = pi1.get("methodName", PyFunction.class);
//写入方法所需的参数,注意要转换为Python的相应类型

PyObject Res = pyf.__call__(Py.newString("xxx1"),Py.newString("xxx2"));

System.out.println(Res);
pi1.cleanup();
}
}

2. 终端(命令行)调用

终端(命令行)调用就是老生常谈的东西了,直接使用Java代码执行一段终端(命令行)命令来调用Python文件,简单粗暴。

但这种方式也存在以下问题:

  • 对多线程的支持不好,在部署到服务器的情况下,每次运行都会开启一个终端,消耗资源。
  • 这种方法无法像调用一个方法一样随意传参,毕竟是命令行执行,参数选择无法像内置方法一样随意选择。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

class RunnableDemo implements Runnable {
String name = null;
public RunnableDemo(String name) {
this.name = name;
}
public void run() {
//命令行参数(注意先把Python加入环境变量)

String[] arguments = new String[] { "python", "C:/xxx/xxx.py", "arg1", "arg2"};

try {
Process process = Runtime.getRuntime().exec(arguments);
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
in.close();
int re = process.waitFor();
System.out.println(re);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class RuntimeMethod {
public static void main(String[] args) throws IOException, InterruptedException {
RunnableDemo r1 = new RunnableDemo( "Thread1");
Thread t1 = new Thread(r1);
t1.start();

RunnableDemo r2 = new RunnableDemo( "Thread2");
Thread t2 = new Thread(r2);
t2.start();
RunnableDemo r3 = new RunnableDemo( "Thread3");
Thread t3 = new Thread(r3);
t3.start();
}
}

 3. Python的WebService

最后选择的是这种方法,虽然繁琐了一点,但是这种方法至少是上述三个方法中,部署到项目里最优雅的一种方式了。具体就是将Python算法写成一个WebService发布出去,在JavaWeb项目中使用HttpURLConnection进行调用。

优点:

  1. 多线程的事不用调用方头疼了,而是交给了WebService服务器
  2. 以soap格式传参,相对来说参数格式选择还算自由

缺点:

  1. 又需要多部署一个WebService服务器
  2. 以WebService方式调用,又多走了一步,性能可想而知不会很快。

1. Python使用spyne发布WebService 

from spyne import ServiceBase, Iterable, Unicode, Integer, Application, rpc
from spyne.protocol.soap import Soap11
from spyne.server.wsgi import WsgiApplication
from wsgiref.simple_server import make_server


class HelloWorldService(ServiceBase):
@rpc(Unicode, _returns=Unicode)
def say_hello(self, name):
strArg = 'Hello' + name
return strArg

application = Application([HelloWorldService],
tns='spyne.examples.hello', #设置NameSpace,需要在soap中用到

in_protocol=Soap11(validator='lxml'),
out_protocol=Soap11())
if __name__ == '__main__':

wsgi_app = WsgiApplication(application)
server = make_server('0.0.0.0', 8000, wsgi_app)
server.serve_forever()

Java使用HttpURLConnection调用WebService

import java.io.*;

import java.net.HttpURLConnection;
import java.net.URL;

public class PyWSclient {

public static void main(String[] args) throws Exception
{
String urlString = "http://localhost:8000/?wsdl";//wsdl文档的地址
URL url = new URL(urlString);
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();//打开连接

String xmlFile = "./soapXML/soap.xml";//要发送的soap格式文件
File fileToSend = new File(xmlFile);
byte[] buf = new byte[(int) fileToSend.length()];// 用于存放文件数据的数组

new FileInputStream(xmlFile).read(buf);

//Content-Length长度会自动进行计算
httpConn.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
httpConn.setRequestMethod("POST");
httpConn.setDoOutput(true);
httpConn.setDoInput(true);

OutputStream out = httpConn.getOutputStream();

out.write(buf);
out.close();

if (httpConn.getResponseCode() == HttpURLConnection.HTTP_OK)
{
InputStreamReader is = new InputStreamReader(httpConn.getInputStream());
BufferedReader in = new BufferedReader(is);
String inputLine;
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream("result.xml")));// 将结果存放的位置
while ((inputLine = in.readLine()) != null)
{
System.out.println(inputLine);
System.out.print(inputLine);
bw.write(inputLine);
bw.newLine();
}
bw.close();
in.close();
}
else{
//如果服务器返回的HTTP状态不是HTTP_OK,则表示发生了错误,此时可以通过如下方法了解错误原因。
InputStream is = httpConn.getErrorStream(); //通过getErrorStream了解错误的详情,因为错误详情也以XML格式返回,因此也可以用JDOM来获取。
InputStreamReader isr = new InputStreamReader(is,"utf-8");
BufferedReader in = new BufferedReader(isr);
String inputLine;
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream("result.xml")));// 将结果存放的位置
while ((inputLine = in.readLine()) != null)
{
System.out.println(inputLine);
bw.write(inputLine);
bw.newLine();
bw.close();
}
in.close();

}
httpConn.disconnect();
}
}



举报

相关推荐

0 条评论