? ? 不管什么技术,不管什么问题,只要努力就能解决。
? ? 最近在做项目的时候,需要java 调用 python 接口,在网上找了一些方法,但是总碰到一些问题,索性将网上的方法和自己的理解总结一下,希望对各位博友有所帮助,也请各位大神不吝赐教。
一:创建环境 Python 环境
import org.python.core.PySystemState;
import org.python.util.PythonInterpreter;
/**
* Jython环境,生存python解释器
* @author webim
*
*/
public final class JythonEnvironment
{
private static JythonEnvironment INSTANCE = new JythonEnvironment();
/**
* 私有构造方法
*/
private JythonEnvironment()
{
}
/**
* 获取单例
* @return JythonEnvironment
*/
public static JythonEnvironment getInstance()
{
return INSTANCE;
}
/**
* 获取python系统状态,可根据需要指定classloader/sys.stdin/sys.stdout等
* @return PySystemState
*/
private PySystemState getPySystemState()
{
PySystemState.initialize();
final PySystemState py = new PySystemState();
py.setClassLoader(getClass().getClassLoader());
return py;
}
/**
* 获取python解释器
* @return PythonInterpreter
*/
public PythonInterpreter getPythonInterpreter(){
PythonInterpreter inter = new PythonInterpreter(null, getPySystemState());
// PythonInterpreter inter = new PythonInterpreter();
return inter;
}
}
二:调用 python 的接口
添加 JPython 依赖
<dependency>
<groupId>org.python</groupId>
<artifactId>jython</artifactId>
<version>2.7.0</version>
</dependency>
上面这个依赖有问题,可用下面依赖避免各种问题。
<dependency>
<groupId>org.python</groupId>
<artifactId>jython-standalone</artifactId>
<version>2.7.0</version>
</dependency>
因为 python 和 java是两种不同的语言,因此在项目的 controller 、service 和 mapper 中直接出现 Python 的接口,因此
自己封装 ExecPython 类,
封装python的接口,目的让 python 接口和java程序分隔开。
import org.python.core.PyFunction;
import org.python.core.PyObject;
import org.python.util.PythonInterpreter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import java.util.Map;
/*enum的这个用法,可以作为变种的安全单例,值得借鉴哦 ^_^ */
@Service
@Component
public class ExecPython {
public static final Logger logger = LoggerFactory.getLogger(Exception.class);
//定义 python 解释器
private static PythonInterpreter inter;
public ExecPython() {
this.inter = JythonEnvironment.getInstance().getPythonInterpreter();
this.inter.execfile("C:\\test.py");
}
//设置 python 脚本的路径
public void setPythonPath (String pythonPath){
this.inter.execfile(pythonPath);
}
public void execute(String scriptFile, Map<String,String> properties)
{
logger.info("获取解释器");
try
{
PyFunction getNetInfo = (PyFunction) inter.get("getNetInfo", PyFunction.class);
PyObject netInfo = getNetInfo.__call__();
System.out.println("anwser = " + netInfo.toString());
}
catch (Exception e)
{
e.printStackTrace();
logger.info("Python 脚本文件执行失败");
}
}
//获取 Python 字符串
public String getString(){
//获取到python 脚本中的接口
PyFunction func = (PyFunction) inter.get("adder", PyFunction.class);
PyObject pyobj = func.__call__();
System.out.println("anwser = " + pyobj.toString());
return pyobj.toString();
}
// 获取当前数组
public String getArr() {
PyFunction getArr = (PyFunction) inter.get("getArr", PyFunction.class);
PyObject pyobjTwo = getArr.__call__();
pyobjTwo.__len__();
System.out.println("anwser = " + pyobjTwo.toString()+" len:"+pyobjTwo.__len__());
//将 PyObject 对象转换成 java 对象
//Object object = pyobjTwo.__tojava__(List.class);
//List<String> list = (List<String>) object;
//将查询到数据转换成一个 JSON 字符串
String result = pyobjTwo.toString();
String JsonStr = "{" + result + "}";
logger.info(JsonStr);
logger.info("将查询的结果转换成 JSON 字符串:",JsonStr);
return pyobjTwo.toString();
}
}
?
三: python 脚本
def adder():? ??
? ?return "{'name':'leilei','age':'18'}"??
? ?
def getArr():
return ['aaa','bbb']
def getNetInfo():
return [{'DNS':'192.168.12.3','ip':'45.23.16.0'},{'DNS2':'192.168.12.2','ip2':'45.23.16.2'}]
问题:
2019-12-09 20:11:17.070 ERROR 4620 --- [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'execPython' defined in file [D:\Lenovo\LenovoWorkspace\code\ip-modify\target\classes\cn\lenovo\ipmodify\service\ExecPython.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [cn.lenovo.ipmodify.service.ExecPython]: Constructor threw exception; nested exception is ImportError: Cannot import site module and its dependencies: No module named site
Determine if the following attributes are correct:
* sys.path: ['C:\\Users\\31307\\.m2\\repository\\org\\python\\jython\\2.7.0\\Lib', '__classpath__', '__pyclasspath__/']
This attribute might be including the wrong directories, such as from CPython
* sys.prefix: C:\Users\31307\.m2\repository\org\python\jython\2.7.0
This attribute is set by the system property python.home, although it can
be often automatically determined by the location of the Jython jar file
You can use the -S option or python.import.site=false to not import the site module
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1320) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1214) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:879) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at cn.lenovo.ipmodify.IpmodifyApplication.main(IpmodifyApplication.java:13) [classes/:na]
主要是这句话:
You can use the -S option or python.import.site=false to not import the site module
可以使用-S选项或python.import.site=false不导入站点模块
像是设置 python 解释器的环境变量。
因此在创建解释器时,设置环境变量。
修改??JythonEnvironment 中的? getPythonInterpreter 函数
public PythonInterpreter getPythonInterpreter(){
Properties props = new Properties();
props.put("python.home", "path to the Lib folder");
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 inter = new PythonInterpreter();
return inter;
}
|