Java 如何调用执行 Python?图文讲解超详细!

更新时间 2022-04-01 15:06:55

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡 / 赠书活动

目前, 星球 内第一个项目:全栈前后端分离博客项目,演示地址:http://116.62.199.48/, 1.0 版本已经更新完毕,正在更新 2.0 版本。采用技术栈 Spring Boot + Mybatis Plus + Vue 3.x + Vite 4手把手,前端 + 后端全栈开发,从 0 到 1 讲解每个功能点开发步骤,1v1 答疑,陪伴式直到项目上线,目前已更新了 224 小节,累计 35w+ 字,讲解图:1544 张,还在持续爆肝中,后续还会上新更多项目,目标是将 Java 领域典型的项目都整上,如秒杀系统、在线商城、IM 即时通讯、权限管理等等,已有 1000+ 小伙伴加入,欢迎点击围观

Java 如何调用 Python?图文讲解超详细!Java 如何调用 Python?图文讲解超详细!

目录

  • 一、前言
  • 二、Jython 官网地址
  • 三、上手试试
    • 添加依赖
    • 测试执行 Python
      • 在 Java 类中直接执行 Python 语句
      • 在 Java 中调用 Python 脚本文件
      • 另外一种方式: Runtime.getRuntime() 执行 python 脚本文件
      • 调用 Python 脚本发送邮件,并动态传入参数,打印结果
  • 四、结语

一、前言

大家好,我是小哈~

今天给大家分享一下如何在 Java 中执行 Python 脚本,这种需求,小哈在以前参与的定时任务调度平台就遇到过,需要定时去触发某个作业,作业需要支撑业务线丰富的场景,可以是接口调用、Shell 脚本执行、推送 MQ、Python 脚本执行等。

除此以外,大家都知道 Python 拥有非常丰富的第三方类库,有些功能用 Python 来实现的话,可能仅仅需要引入一下包,几行代码就搞定了,用 Java 来实现可能就需要费老鼻子劲了。

好了,废话也不多说,进入今天的正题 !

给大家安利一个优秀的第三方库 Jython, 通过它可以非常方便的执行 Python 脚本。

二、Jython 官网地址

官网地址:https://www.jython.org/

Github 地址: https://github.com/jython/jython

三、上手试试

小哈为了给大家演示,先新建一个 Spring Boot 项目。

3.1 添加依赖

在 maven 的 pom.xml 中添加 Jython 依赖:

<dependency>
    <groupId>org.python</groupId>
    <artifactId>jython-standalone</artifactId>
    <version>2.7.2</version>
</dependency>

3.2 测试执行 Python

注意,需要在你的机器上先安装好 Python 环境。

3.2.1 在 Java 类中直接执行 Python 语句

新建单元测试,通过 Java 代码直接执行 Python 语句:

@Test
void executePython() {
    // 一条简单的 python 语句,打印 Hello world !
    String py = "print('Hello world!')";

    PythonInterpreter interpreter = new PythonInterpreter();
    // 执行 Python 语句
    interpreter.exec(py);
}

输出:

通过Jython执行一条简单的python语句通过Jython执行一条简单的python语句

3.2.2 在 Java 中调用 Python 脚本文件

大多数情况下,需要执行的是具体目录下的 Python 脚本,为了测试,我们在 D 盘的根目录下新建 test.py,将刚刚的 Hello world 代码以文件的形式来运行:

python输出hello world脚本python输出hello world脚本

通过 Jython 去执行这个脚本:

@Test
void executePythonFile() {
    // 定义脚本路径
    String path = "D:\\test.py";

    PythonInterpreter interpreter = new PythonInterpreter();
    // 执行脚本文件
    interpreter.execfile(path);
}

可以看到,执行 Python 脚本也是 ok 的:

在java中执行python脚本在java中执行python脚本

3.2.3 另外一种方式: Runtime.getRuntime() 执行 python 脚本文件

还是刚刚的测试脚本,还可以通过 Runtime.getRuntime() 来执行, 示例代码如下:

@Test
void executePythonFile2() {
    Process proc;
    BufferedReader reader;
    try {
        // 直接执行 python 命令的方式来执行脚本
        proc = Runtime.getRuntime().exec("python D:\\test.py");
        reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));

        String line = null;
        while ((line = reader.readLine()) != null) {
            // 打印输出
            System.out.println(line);
        }

        reader.close();
        proc.waitFor();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

输出结果同上。

3.2.4 调用 Python 脚本调用某个函数,并动态传入参数,打印结果

实际的业务场景中,我们可能需要在调用脚本文件时动态传入参数,并打印结果。这里为了测试,小哈简单写了个发送邮件的 Python 脚本,定义了一个 sendEmail 函数,需要传入以下 3 个参数:

  • 邮件接受者: receiver
  • 邮件标题:subject
  • 邮件内容: content

代码如下:

import smtplib
from email.mime.text import MIMEText

# 邮件服务器地址
mail_host = 'smtp.qq.com'
# 邮件服务器用户名
mail_user = 'xxx@qq.com'
# 邮件服务器登录密码(有些是授权码)
mail_pwd = 'xxx'
# 邮件发送者
sender = 'xxx@qq.com'

def sendEmail(receiver, subject, content):
    """
    发送邮件
    :param receiver: 接收者
    :param subject: 邮件主题
    :param content: 邮件内容
    :return:
    """
    message = MIMEText(content, 'plain', 'utf-8')
    # 邮件主题
    message['Subject'] = subject
    # 发送方
    message['From'] = sender
    # 接收方
    message['To'] = receiver

    try:
        # 连接到服务器
        smtp = smtplib.SMTP_SSL(mail_host)
        # 登录服务器
        smtp.login(mail_user, mail_pwd)
        # 发送
        smtp.sendmail(sender, receiver, message.as_string())
        # 推出
        smtp.quit()
        return 'send email success ...'
    except smtplib.SMTPException as e:
        print('error', e)


if __name__ == '__main__':
    # 邮件接受者
    receiver = 'xxx@qq.com'
    # 邮件主题
    subject = '打个招呼'
    # 邮件内容
    content = '我是犬小哈'
    sendEmail(receiver, subject, content)

代码中使用的是 QQ 邮件,邮件服务器的用户名和授权码就不放出来了,有兴趣的小伙伴,可将其替换自己的试试。

再来看看如何通过 Jython 去调用 sendEmail 函数:

@Test
void executePythonFunction() {
    PythonInterpreter interpreter = new PythonInterpreter();
    // 指定指定路径下的 python 脚本
    interpreter.execfile("D:\\test.py");

    // 指定需要调用的函数
    PyFunction function = interpreter.get("sendEmail", PyFunction.class);
    // ↓↓↓↓↓↓↓↓ 需要传入的参数 ↓↓↓↓↓↓↓↓
    // 邮件接受者
    PyString receiver = Py.newStringOrUnicode("xxx@qq.com");
    // 邮件主题
    PyString subject = Py.newStringOrUnicode("打个招呼【动态参数】");
    // 邮件内容
    PyString content = Py.newStringOrUnicode("我是犬小哈【动态参数】");

    // 调用
    PyObject pyObject = function.__call__(receiver, subject, content);

    // 打印返回结果
    System.out.println(String.format("result: %s", pyObject));
}

执行一下,你会发现报错:

jython调用python脚本的函数jython调用python脚本的函数

Python 脚本在没有指定具体编码时,默认以 ASCII 编码,这里因为文件中涉及到中文,需要指定编码格式为 utf-8, 在脚本文件头添加如下代码:

# -*- coding: utf-8 -*-

在python文件头部指定编码格式在python文件头部指定编码格式

PS: 详细参考:https://peps.python.org/pep-0263/

再次执行看看:

python发送邮件结果python发送邮件结果

成功打印了返回参数,确认一下是否真的收到邮件了:

邮件接受成功邮件接受成功

成功收到了邮件。

细心的小伙伴应该发现了,在控制台打印中有个 550 错误,提示内容被拒绝了,但确实又收到了邮件,这是个啥情况,点进后面的连接看了一下 http://service.mail.qq.com/cgi-bin/help?subtype=1&&id=20022&&no=1000726:

提示垃圾邮件提示垃圾邮件

初步怀疑是自己做测试发送了过多的邮件导致,被 QQ 判定为垃圾营销邮件了,但是收还是能收到的,小伙伴们如果收不到也可以将发送者的邮箱地址设置为 QQ 邮件白名单。

四、结语

小伙伴们如果有需要在 Java 中执行 Python 脚本的,不妨试试 Jython 这个库,整体来说还是非常棒滴~ 这期分享就到这里了,下期见~

五、Ref

  • https://www.cnblogs.com/wuwuyong/p/10600749.html

  • https://blog.csdn.net/qq_26591517/article/details/80441540