项目中有用到Java调用python的需求,经过各种坑之后,根据业务需求,最终实现Java调用Python的各种情况,现在将总结如下,当然调用的也是Jython,具体原因,下面会介绍,先将代码贴出来。
这种方法是调用python文件的函数 ,并且需要将函数中的参数由Java数据类型转换为python的数据类型
public class JythonExecPyFile {
private static Log logger = LogFactory.getLog(JythonExecPyFile.class);
public static PythonInterpreter getPythonEnterpreter(String jythonHome,String jythonJsonHome,String pythonRuleDir){
Properties props = new Properties();
//props.put("python.home", "path to the Lib folder");
props.put("python.home", jythonHome);
props.put("python.console.encoding", "UTF-8");
props.put("python.security.respectJavaAccessibility", "false");
props.put("python.import.site", "false");
Properties preprops = System.getProperties();
PythonInterpreter.initialize(preprops, props, new String[0]);
PythonInterpreter pythonInterpreter = new PythonInterpreter();
PySystemState sys = Py.getSystemState();
sys.path.add(jythonJsonHome);
sys.path.add(pythonRuleDir);
//logger.info("jythonHome: " + jythonHome +" jythonJsonHome: " + jythonJsonHome + " pythonRuleDir: " + pythonRuleDir);
return pythonInterpreter;
}
public static void addPythonThirdPartLib(String thirdLibPath){
PySystemState sys = Py.getSystemState();
sys.path.add(thirdLibPath);
sys.path.add(SettingConfiguration.getValue("pythonDir"));
}
public static void cleanup(PythonInterpreter interpreter){
if(interpreter != null){
interpreter.close();
}
}
public static void main(String[] args) {
PythonInterpreter pythonEnterpreter = getPythonEnterpreter(SettingConfiguration.getValue("jPythonHome"),SettingConfiguration.getValue("jythonJsonHome"),SettingConfiguration.getValue("pythonDir"));
System.out.println("-----------------------------调用有参数python方法执行方法-----------------------------");
String fileNameWithParams = "D:\\Java\\python344\\age.py";
pythonEnterpreter.execfile(fileNameWithParams);
PyFunction func = (PyFunction) pythonEnterpreter.get("judge_age",PyFunction.class);
PyObject pyobj = func.__call__(new PyString("2000-11-11"),new PyInteger(1));
System.out.println("pyObj: " + pyobj);
System.out.println("-----------------------------调用无参数python方法执行方法-----------------------------");
String fileNameNoParams = "D:\\svnProject\\testConnectDB.py";
pythonEnterpreter.execfile(fileNameNoParams);
PyFunction func2 = (PyFunction) pythonEnterpreter.get("say",PyFunction.class);
PyObject pyobj2 = func2.__call__();
System.out.println("pyObj: " + pyobj2);
JythonExecPyFile.cleanup(pythonEnterpreter);
}
而为了更好的封装,将调用python的参数放到list中,而将返回的数据放到dict中,python将dict转换为json串,然后在java接受到返回结果之后,将json串在转换成java的map类型即可。
public class RuleAndModelExecuteFunction {
private static Log logger = LogFactory.getLog(RuleAndModelExecuteFunction.class);
/**
* 规则一 根据文件名、函数名称 参数列表 执行对应的规则或者模型 0 pass 1 reject 2 nodata
* param :fileName, functionName,params,params where from the params of python ,And
* if contact 为null,或者长度为0,或者为空字符串 则 empty_contacts=1 (反欺诈规则结果)anti_fraud_rules_result='reject'
* else anti_fraud_rules_result=‘pass' empty_contacts=0 0 pass 1
*/
public static String ruleExecuteMethod(String fileName,String functionName,Object... params){
logger.info("ruleExecuteMethod param------ fileName: " + fileName + " functionName: " + functionName);
String returnResult = "";
List
}
public static Map
JsonFactory factory = new JsonFactory();
ObjectMapper mapper = new ObjectMapper(factory);
TypeReference
};
try {
return mapper.readValue(json, typeRef);
} catch (JsonParseException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
通过这种封装之后,完成了最终的封装,并作为工具类进行调用。
Java调用python由三种方式,分别如下:
第一种方式:
public class HelloPython {
public static void main(String[] args) {
PythonInterpreter interpreter = new PythonInterpreter();
interpreter.exec("print('hello')");
}
}
什么是 PythonInterpreter 呢?它的中文意思即“ Python 解释器”。我们知道 Python 程序都是通过解释器执行的,上面的代码就是在 JVM 中创建一个“ Python 解释器”对象,模拟 Python 解释器的行为,通过 exec(" Python 语句") 直接在 JVM 中执行 Python 代码,代码的输出结果为:hello,需要提醒各位的是,该程序运行速度相较正常的 Java or Python 程序都要慢那么一点。
第二种方式:在项目中实际用到,执行的是python文件中的函数,见上面
第三种方式:通过解释器直接执行python文件
#open files
print
'hello'
number=[
3
,
5
,
2
,
0
,
6
]
print number
number.sort()
print number
number.append(
0
)
print number
print number.count(
0
)
print number.index(
5
)
import
org.python.util.PythonInterpreter;
public
class
FirstJavaScript {
public
static
void
main(String args[]) {
PythonInterpreter interpreter =
new
PythonInterpreter();
interpreter.execfile(
"C:\\Python27\\programs\\input.py"
);
}
// main
}
第四种方式:该方式是否可以调用python的第三方模块,没有运行,用需求的朋友可以执行一个程序就可以验证
由于 Jython 运行过慢并且不支持第三方的 Python 模块,通过 Java 代码执行一段终端命令来调用 Python 脚本,根据具体问题决定如何交互可能才是实际中真正会用到的方式(详见下面的举例代码)。
举例代码:下面是一个可以识别很粗的手写数字写的一个小程序,界面上引用了 core java 上的一段代码:
import java.io.*;
class PyCaller {
private static final String DATA_SWAP = "temp.txt";
private static final String PY_URL = System.getProperty("user.dir") + "\\test.py";
public static void writeImagePath(String path) {
PrintWriter pw = null;
try {
pw = new PrintWriter(new FileWriter(new File(DATA_SWAP)));
} catch (IOException e) {
e.printStackTrace();
}
pw.print(path);
pw.close();
}
public static String readAnswer() {
BufferedReader br;
String answer = null;
try {
br = new BufferedReader(new FileReader(new File(DATA_SWAP)));
answer = br.readLine();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return answer;
}
public static void execPy() {
Process proc = null;
try {
proc = Runtime.getRuntime().exec("python " + PY_URL);
proc.waitFor();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 测试码
public static void main(String[] args) throws IOException, InterruptedException {
writeImagePath("D:\\labs\\mytest\\test.jpg");
execPy();
System.out.println(readAnswer());
}
}
运行流程:Java Swing 界面接收用户输入 --> Java 将用户输入写到本地文件中 --> Java 调用本地 Python 脚本 --> Python 从本地文件拿到用户输入 --> Python 处理用户输入得到最终结果 --> Python 把最终结果写到本地文件 --> Java 对 Python 脚本的调用结束 --> Java 从本地文件中取出最终结果 --> Java 把最终结果返回给用户
完整代码链接:http://pan.baidu.com/s/1sl4l68H