起因:本人不會Java代碼,但是想在jmeter(純Java語言)中去調用python腳本,來達到我的目的。於是開啟了一個漫長的新知識探索。過程崎嶇,在小巷子里繞了好久。均告失敗!!!!
一、開始各種百度找思路,最終大概流程就是這個樣子的(以下所有操作均在window下進行)。
1、下載所需文件(包含JDK、Java編輯器、Python編輯器、Python3.6、jython-standalone-2.7.1.jar);
2、安裝並配置JDK環境變量(本人所用為版本為:JDK 64位 1.8.0_211);
3、安裝並配置Python環境(本人所用為:Python3.6、2.7版);
4、安裝Java編輯器(本人所用為:Eclipse);
5、安裝Python編輯器(本人所用為:PyCharm);
6、配置jython環境變量;
7、編寫Python測試腳本;
8、新建Java項目;
9、Java項目加載jython-standalone-2.7.1.jar包;
10、編寫Java測試腳本;
11、調試;
二、接下來就讓我們一起來踩坑、填坑吧,吼吼吼~
1、下載所需文件,其中JDK、jython-standalone-2.7.1.jar、Eclipse、PyCharm 已提供下載地址:
鏈接:https://pan.baidu.com/s/1TQvm0uxxYFXa_ICck86-hg
提取碼:812d
2、配置JDK環境變量(自行百度解決)
3、安裝並配置Python環境
1)、下載Python;去官網—> https://www.python.org/downloads/release/python-374/
2)、安裝並配置環境;去這里—> https://jingyan.baidu.com/article/c45ad29c05c208051653e270.html
4、安裝Java編輯器Eclipse
1)、將下載好的壓縮包進行解壓 (免安裝),點擊 eclipse.exe文件啟動編輯器即可;
5、安裝Python編輯器;(自行百度解決)
6、配置jython環境變量;
1)、作用:Jython的主要通途就是在Java中調用Python程序;而且,還可以直接在Jython程序中引用Java。就是一座橋,連接他和它。
2)、配置:其實是有兩個不同的文件
jython_installer-2.5.2.jar:需要安裝和配置環境變量的,多用於使用Java的Runtime()函數調用時。
jython-standalone-2.7.1.jar:免安裝,需要配置環境變量,通過Jython的API進行調用。能夠指定到具體的函數和方法。
本人采用的是第二種。配置環境變量,即將 jython-standalone-2.7.1.jar 所在的目錄(D:\java_test\lib\jython-standalone-2.7.1.jar)添加到系統環境變量的CLASSPATH中。
(沒有這一步會報錯:java.io.IOException: Cannot run program "python": CreateProcess error=2, 系統找不到指定的文件。)
7、編寫Python測試腳本,如下:
a = [1,2,3,4,5,6,7] b = a[:] print(b)
8、新建Java項目
1)、新建一個項目文件夾 java_test,在文件件中新建一個lib文件夾,將jython-standalone-2.7.1.jar復制到lib文件中;
2)、打開Eclipse,依次新建Java項目、填寫項目名稱。(Contents中選擇Create project from existing source ,位置選擇java_test文件夾),保存;
3)、選擇項目下的src文件后右鍵新建包,填寫包名稱,保存;
4)、選擇新建的包右鍵新建類,填寫類名稱,保存;
9、Java項目加載jython-standalone-2.7.1.jar包
1)、選擇新建的Java項目,右鍵后依次選擇 “構建路徑---->配置構建路徑---->L庫---->添加JAR--->找到lib文件夾中的jython-standalone-2.7.1.jar文件;
2)、在java_test文件夾中新建一個放Python腳本的文件Script文件夾;
此時可以看到的文件目錄結構如下:
其中bin、src文件夾、.classpath、.project是在創建Java項目時自動創建,bin是用來存放Java項目目錄、src存放類目錄,lib文件夾是手動添加的存放需要導入的jar文件目錄,Script文件夾是手動添加的存放需要用的Python文件目錄;
10、編寫Java測試腳本
1)、在Java中簡單調用Python程序,不需要傳遞參數,也不需要獲取返回值,簡單版的先測試一下有沒有問題;
Java測試代碼如下:
package java_Test; import java.io.IOException; import org.python.util.PythonInterpreter;
public class TestIng { /** * @param args * @throws IOException * @throws InterruptedException */
public static void main(String[] args) throws IOException { // 寫入jython文件的路徑
System.setProperty("python.home","D:\\java_test\\lib\\jython-standalone-2.7.1.jar"); // 寫入Python文件的路徑
String python = "D:\\java_test\\Script\\test.py"; PythonInterpreter interp = new PythonInterpreter(); interp.execfile(python); interp.cleanup(); interp.close(); } }
簡單測試了一下結果如下:
結果可以正常打印出來 ,但是報了錯,console: Failed to install '': java.nio.charset.UnsupportedCharsetException: cp0. 其實這是編碼的問題 。
解決辦法:解決辦法為在要執行的代碼上右鍵,Run As>Run Configurations,選擇第二個頁簽Arguments,在VM arguments中添加
-Dpython.console.encoding=UTF-8
在運行就不會有那個紅的報錯了 ,歐耶~~~
2)、以上完成算是將Java與Python文件打通了 ,但是這並不能滿足我的使用要求,因為我是需要有參數傳入和輸出的。於是乎,在Java中單向調用Python程序中的方法,需要傳遞參數,並接收返回值。Python既支持面向函數式編程,也支持面向對象編程。因此,調用Python程序中的方法也分別以面向函數式編程和面向對象式編程進行說明。
開始第二步的征程;
修改Python文件內容(調用方法),如下:
#coding=utf-8
import math
def power(x,y): return math.pow(x,y)
對應的Java代碼如下:
package java_Test; import java.io.IOException; import org.python.core.Py; import org.python.core.PyFunction; import org.python.core.PyObject; import org.python.util.PythonInterpreter; public class TestIng { /** * @param args * @throws IOException * @throws InterruptedException */
public static void main(String[] args) throws IOException { System.setProperty("python.home", "D:\\java_test\\lib\\jython-standalone-2.7.1.jar"); // 1. Python面向函數式編程: 在Java中調用Python函數
String pythonFunc = "D:\\java_test\\Script\\test.py"; PythonInterpreter pi1 = new PythonInterpreter(); // 加載python程序
pi1.execfile(pythonFunc); // 調用Python程序中的函數
PyFunction pyf = (PyFunction) pi1.get("power", PyFunction.class); PyObject dddRes = pyf.__call__(Py.newInteger(2), Py.newInteger(3)); System.out.println(dddRes); pi1.cleanup(); pi1.close(); } }
第一個錯誤出現了,
原因:說文件的編碼不合規,有問題 ,因為這個是直接修改后綴名來改變文件格式的所以相當於是假修改 。
解決辦法:將文件另存為,在另存為的時候選擇文件的編碼為UTF-8。就可以解決了
此時此刻,第二個錯出來了 。
如果你遇到這個問題,那么恭喜你。和我同喜了,哈哈 ~~
然后如果你去百度,貌似是解決不了的(是真的沒有相關詳細的解決辦法說明),那我就來悄悄地告訴你是為啥子吧!!!
原因:是jython的版本問題 ,版本太高了 ,他不支持這樣讓你玩,換個低版本的,我選jython-standalone-2.5.3.jar,於是我也把它上傳雲盤了
詳細解決辦法:
1)、解除之前導入的jython-standalone-2.7.1.jar版本的包,解除辦法就是將導入的辦法倒序操作就行;
2)、刪除java_test文件夾中所有的文件,按照之前創建的文件目錄接口重新文件夾結構;
3)、將jython-standalone-2.5.3.jar文件配置系統環境變量;
4)、重新新建Java項目;
期間還有其他的小問題,如:
原因:代碼的編寫問題,Python代碼中一個逗號是中文版的
解決辦法:改成英文版的就OK了
上邊貼的代碼此時也是會報錯的,如jar路徑名稱、代碼語法等。對應的修改一下就OK了 。
三、以上是完成了第一階段的調試,接下來為我自己所需來就行調試。
Python代碼如下(Python文件名為:Original.py):
# -*- coding: utf-8 -*-
import base64 import ast import urllib.parse def addse(Original): # 解碼
url_org = urllib.parse.unquote(Original) # 提取 args參數
parameter1 = urllib.parse.urlparse(url_org) parameter2 = urllib.parse.urlparse(parameter1.fragment) # base64位解碼args參數並切片截取值
parameter3 = base64.b64decode(parameter2.query[5:]) # 將截取的byte類型的值轉化為字符串str類型的值
# print(parameter3) 會輸出被b包圍的字典, b 表示 byte的意思,我們只要再將byte轉換回去
# 將str類型的值轉化為字典類型
parameter5 = ast.literal_eval(str(parameter3,'utf-8')) # 通過for循環將字典中的值取出
for i in parameter5: return("%s = %s" %(i,parameter5[i])) if __name__ == "__main__": addse(Original)
Java代碼如下:
package test_java; import java.io.IOException; import org.python.core.Py; import org.python.core.PyFunction; import org.python.core.PyObject; import org.python.util.PythonInterpreter; public class TestIng { /** * @param args * @throws IOException * @throws InterruptedException */
public static void main(String[] args) throws IOException { System.setProperty("python.home", "D:\\java_test\\lib\\jython-standalone-2.5.3.jar"); // 1. Python面向函數式編程: 在Java中調用Python函數
String pythonFunc = "D:\\java_test\\Script\\Original.py"; PythonInterpreter pi1 = new PythonInterpreter(); // 加載python程序
pi1.execfile(pythonFunc); // 調用Python程序中的函數
PyFunction pyf = (PyFunction) pi1.get("addse", PyFunction.class); PyObject dddRes = pyf.__call__(Py.newDecimal("https://***********.com/new/#/register/h5?args=eyJ0ZW5hbnROYW1lIjoiQUEyQkwiLCJzaGFyZVBhcmFtIjoibjM0Z0MvNHVGek5pVFdGRk1UTml1SFREUWhSUzZxNVV3NmVUSlp6cThabGF6ZVdjK0p4cWNnPT0ifQ%3d%3d" )); System.out.println(dddRes); pi1.cleanup(); pi1.cleanup(); } }
修改完參數,直接運行,狂吃,喜提報錯 :
原因:根據報錯內容,可以知道是Python文件中引入的第三方包沒有找到或者Python版本問題。
解決辦法:直接把Python代碼用Python2.7的語法重寫。即可解決
Python2.7語法的代碼如下:
import urlparse import base64 import ast def addse(Originals): # 解碼
url_org = urlparse.unquote(Originals) # 提取 args參數
parameter1 = urlparse.urlparse(url_org) parameter2 = urlparse.urlparse(parameter1.fragment) # # base64位解碼args參數並切片截取值
parameter3 = base64.b64decode(parameter2.query[5:]) parameter5 = ast.literal_eval(str(parameter3)) # # 通過for循環將字典中的值取出
for i in parameter5: print "%s = %s" %(i,parameter5[i]) if __name__ == "__main__": Original = "https://xxxxxxxxxxx.com/new/#/register/h5?args=eyJ0ZW5hbnROYW1lIjoiQUEyQkwiLCJzaGFyZVBhcmFtIjoibjM0Z0MvNHVGek5pVFk1UTml1S11231SUzZxNVV3NmVUSlp6cThabGF6ZVdjK0p4cWNnPT0ifQ%3d%3d" addse(Original )
再次試運行,,,,幺吼,又翻車了,換了個錯繼續報:
原因:提示說,Original沒有被定義。
解決辦法:修改Python代碼,不要初始化相關的信息:if __name__ == "__main__":
此時在運行,,OMG又他么報錯了
事實證明此時我的程序是通了的,但是我太菜了因為各種語法規則問題導致一直報錯問題就出在 :url_org = urlparse.unquote(Originals) 這一句上;
原因:在調用Python程序時,其中的unquote這個在urlparse這個中沒有(在pycharm中同樣的這一句卻是可以正常成功的,好奇為啥通過Java去調就失敗)。看了一下在Python2.7中關於解碼的方法調用。將解碼這一句改成:url_org = urllib.unquote_plus(Originals) 在一執行,奇跡出現了 ,沃德瑪雅,終於在控制台看到了我想要的結果。
其實還是有點小激動的。你們是不知道像我這樣太菜的人去搞這些是有多痛苦。不過解決了所有問題,看到了成功的時候還是很激動的。
這個就先這樣吧 ,吧這些代碼打成jar包,放在jmeter里,當做正常的jar包去調用就好了 ,具體的后續在更新》》》》》》》
參考文章: