騷操作 !Java 中調(diào)用 Python,動態(tài)傳入?yún)?shù) !
點擊關(guān)注公眾號,Java干貨及時送達??

目錄
- 一、前言
- 二、Jython 官網(wǎng)地址
- 三、上手試試
- 添加依賴
- 測試執(zhí)行 Python
- 在 Java 類中直接執(zhí)行 Python 語句
- 在 Java 中調(diào)用 Python 腳本文件
- 另外一種方式:
Runtime.getRuntime()執(zhí)行 python 腳本文件 - 調(diào)用 Python 腳本發(fā)送郵件,并動態(tài)傳入?yún)?shù),打印結(jié)果
- 四、結(jié)語
一、前言
大家好,我是小哈~
今天給大家分享一下如何在 Java 中執(zhí)行 Python 腳本,這種需求,小哈在以前參與的定時任務(wù)調(diào)度平臺就遇到過,需要定時去觸發(fā)某個作業(yè),作業(yè)需要支撐業(yè)務(wù)線豐富的場景,可以是接口調(diào)用、Shell 腳本執(zhí)行、推送 MQ、Python 腳本執(zhí)行等。
除此以外,大家都知道 Python 擁有非常豐富的第三方類庫,有些功能用 Python 來實現(xiàn)的話,可能僅僅需要引入一下包,幾行代碼就搞定了,用 Java 來實現(xiàn)可能就需要費老鼻子勁了。
好了,廢話也不多說,進入今天的正題 !
給大家安利一個優(yōu)秀的第三方庫 Jython, 通過它可以非常方便的執(zhí)行 Python 腳本。
二、Jython 官網(wǎng)地址
官網(wǎng)地址:https://www.jython.org/
Github 地址:https://github.com/jython/jython
三、上手試試
小哈為了給大家演示,先新建一個 Spring Boot 項目。
3.1 添加依賴
在 maven 的 pom.xml 中添加 Jython 依賴:
org.python
jython-standalone
2.7.2
3.2 測試執(zhí)行 Python
注意,需要在你的機器上先安裝好 Python 環(huán)境。
3.2.1 在 Java 類中直接執(zhí)行 Python 語句
新建單元測試,通過 Java 代碼直接執(zhí)行 Python 語句:
@Test
void?executePython()?{
????//?一條簡單的?python?語句,打印?Hello?world?!
????String?py?=?"print('Hello?world!')";
????PythonInterpreter?interpreter?=?new?PythonInterpreter();
????//?執(zhí)行?Python?語句
????interpreter.exec(py);
}
輸出:
通過Jython執(zhí)行一條簡單的python語句3.2.2 在 Java 中調(diào)用 Python 腳本文件
大多數(shù)情況下,需要執(zhí)行的是具體目錄下的 Python 腳本,為了測試,我們在 D 盤的根目錄下新建 test.py,將剛剛的 Hello world 代碼以文件的形式來運行:
python輸出hello world腳本通過 Jython 去執(zhí)行這個腳本:
@Test
void?executePythonFile()?{
????//?定義腳本路徑
????String?path?=?"D:\\test.py";
????PythonInterpreter?interpreter?=?new?PythonInterpreter();
????//?執(zhí)行腳本文件
????interpreter.execfile(path);
}
可以看到,執(zhí)行 Python 腳本也是 ok 的:
在java中執(zhí)行python腳本3.2.3 另外一種方式:Runtime.getRuntime() 執(zhí)行 python 腳本文件
還是剛剛的測試腳本,還可以通過 ?Runtime.getRuntime() 來執(zhí)行, 示例代碼如下:
@Test
void?executePythonFile2()?{
????Process?proc;
????BufferedReader?reader;
????try?{
????????//?直接執(zhí)行?python?命令的方式來執(zhí)行腳本
????????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();
????}
}
輸出結(jié)果同上。
3.2.4 調(diào)用 Python 腳本調(diào)用某個函數(shù),并動態(tài)傳入?yún)?shù),打印結(jié)果
實際的業(yè)務(wù)場景中,我們可能需要在調(diào)用腳本文件時動態(tài)傳入?yún)?shù),并打印結(jié)果。這里為了測試,小哈簡單寫了個發(fā)送郵件的 Python 腳本,定義了一個 sendEmail 函數(shù),需要傳入以下 3 個參數(shù):
- 郵件接受者:
receiver - 郵件標(biāo)題:
subject - 郵件內(nèi)容:
content
代碼如下:
import?smtplib
from?email.mime.text?import?MIMEText
#?郵件服務(wù)器地址
mail_host?=?'smtp.qq.com'
#?郵件服務(wù)器用戶名
mail_user?=?'[email protected]'
#?郵件服務(wù)器登錄密碼(有些是授權(quán)碼)
mail_pwd?=?'xxx'
#?郵件發(fā)送者
sender?=?'[email protected]'
def?sendEmail(receiver,?subject,?content):
????"""
????發(fā)送郵件
????:param?receiver:?接收者
????:param?subject:?郵件主題
????:param?content:?郵件內(nèi)容
????:return:
????"""
????message?=?MIMEText(content,?'plain',?'utf-8')
????#?郵件主題
????message['Subject']?=?subject
????#?發(fā)送方
????message['From']?=?sender
????#?接收方
????message['To']?=?receiver
????try:
????????#?連接到服務(wù)器
????????smtp?=?smtplib.SMTP_SSL(mail_host)
????????#?登錄服務(wù)器
????????smtp.login(mail_user,?mail_pwd)
????????#?發(fā)送
????????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?=?'[email protected]'
????#?郵件主題
????subject?=?'打個招呼'
????#?郵件內(nèi)容
????content?=?'我是犬小哈'
????sendEmail(receiver,?subject,?content)
代碼中使用的是 QQ 郵件,郵件服務(wù)器的用戶名和授權(quán)碼就不放出來了,有興趣的小伙伴,可將其替換自己的試試。
再來看看如何通過 Jython 去調(diào)用 sendEmail 函數(shù):
@Test
void?executePythonFunction()?{
????PythonInterpreter?interpreter?=?new?PythonInterpreter();
????//?指定指定路徑下的?python?腳本
????interpreter.execfile("D:\\test.py");
????//?指定需要調(diào)用的函數(shù)
????PyFunction?function?=?interpreter.get("sendEmail",?PyFunction.class);
????//?↓↓↓↓↓↓↓↓?需要傳入的參數(shù)?↓↓↓↓↓↓↓↓
????//?郵件接受者
????PyString?receiver?=?Py.newStringOrUnicode("[email protected]");
????//?郵件主題
????PyString?subject?=?Py.newStringOrUnicode("打個招呼【動態(tài)參數(shù)】");
????//?郵件內(nèi)容
????PyString?content?=?Py.newStringOrUnicode("我是犬小哈【動態(tài)參數(shù)】");
????//?調(diào)用
????PyObject?pyObject?=?function.__call__(receiver,?subject,?content);
????//?打印返回結(jié)果
????System.out.println(String.format("result:?%s",?pyObject));
}
執(zhí)行一下,你會發(fā)現(xiàn)報錯:
jython調(diào)用python腳本的函數(shù)Python 腳本在沒有指定具體編碼時,默認(rèn)以 ASCII 編碼,這里因為文件中涉及到中文,需要指定編碼格式為 utf-8, 在腳本文件頭添加如下代碼:
#?-*-?coding:?utf-8?-*-
在python文件頭部指定編碼格式PS: 詳細參考:https://peps.python.org/pep-0263/
再次執(zhí)行看看:
python發(fā)送郵件結(jié)果成功打印了返回參數(shù),確認(rèn)一下是否真的收到郵件了:
郵件接受成功成功收到了郵件。
細心的小伙伴應(yīng)該發(fā)現(xiàn)了,在控制臺打印中有個 500 錯誤,提示內(nèi)容被拒絕了,但確實又收到了郵件,這是個啥情況,點進后面的連接看了一下 http://service.mail.qq.com/cgi-bin/help?subtype=1&&id=20022&&no=1000726:
提示垃圾郵件初步懷疑是自己做測試發(fā)送了過多的郵件導(dǎo)致,被 QQ 判定為垃圾營銷郵件了,但是收還是能收到的,小伙伴們?nèi)绻詹坏揭部梢詫l(fā)送者的郵箱地址設(shè)置為 QQ 郵件白名單。
四、結(jié)語
小伙伴們?nèi)绻行枰?Java 中執(zhí)行 Python 腳本的,不妨試試 Jython 這個庫,整體來說還是非常棒滴~ 這期分享就到這里了,下期見~
文章首發(fā)自個站:犬小哈教程
https://www.quanxiaoha.com/article/java-invoke-python-by-jython.html
五、Ref
https://www.cnblogs.com/wuwuyong/p/10600749.html
https://blog.csdn.net/qq_26591517/article/details/80441540
3.?3條原則,16個小點,幫你寫出一個優(yōu)秀的對外接口!
最近面試BAT,整理一份面試資料《Java面試BATJ通關(guān)手冊》,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫、數(shù)據(jù)結(jié)構(gòu)等等。
獲取方式:點“在看”,關(guān)注公眾號并回復(fù)?Java?領(lǐng)取,更多內(nèi)容陸續(xù)奉上。
PS:因公眾號平臺更改了推送規(guī)則,如果不想錯過內(nèi)容,記得讀完點一下“在看”,加個“星標(biāo)”,這樣每次新文章推送才會第一時間出現(xiàn)在你的訂閱列表里。
點“在看”支持小哈呀,謝謝啦??
