本文为大家介绍如何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进行调用。
优点:
-
多线程的事不用调用方头疼了,而是交给了WebService服务器
-
以soap格式传参,相对来说参数格式选择还算自由
缺点:
-
又需要多部署一个WebService服务器
-
以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();
}
}
来源:https://blog.csdn.net/qq_29797697/article/details/99414291?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-6.base&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-6.base