java使用python_项目实践之java调用python

背景:在进行javaweb项目开发时,通过登录设备,调用不同的测试用例(对设备下发命令,获取回显信息),判断业务是否达到预期效果。利用python的telnet模块进行实现较为方便,具体实践时也遇到一系列问题,主要包括:(1)java调用python的参数传递与实时回显问题; (2)python日志模块的重复打印问题

1 java调用python

关于java调用python的方法,常见的有2种。第一种:使用java的Process类调用python脚本,然后读取回显信息,此方法的缺点是对于python的回显信息反应较慢,无法满足实时回显需求。

第二种方法,利用Jython执行python方法,优点:能获取python方法的返回值,作为java调用python其他方法的入参,较好地控制代码流程,能更好的满足项目需求,同时,它能及时的获取python方法的返回值,因此,强力推荐该方法。

第一种方法代码如下:

ContractedBlock.gif

ExpandedBlockStart.gif

1 public static voidmain(String[] args)2 {3 //1. 根据用户输入设备信息、选择用例修改脚本

4 String shellPath = "D:\\dDevelopemnt\\javaDemo\\project1\\clockDetect\\src";5

6 Runtime run =Runtime.getRuntime();7

8 //2. 执行cmd

9 try

10 {11 //run.exec("cmd /k shutdown -s -t 3600");12 //cmd.exe /k

13

14 Process process = run.exec(" cmd /c D: && cd " + shellPath + " && python clkChecker.py fdas fda 432");15

16 InputStream input =process.getInputStream();17 BufferedReader reader = new BufferedReader(new InputStreamReader(input, Charset.forName("GBK")));18 String szline;19 System.out.println("\n********** DOS info begin **********");20 while ((szline = reader.readLine()) != null)21 {22 System.out.println(szline);23 }24 System.out.println("********** DOS info end **********\n");25

26 //第四步:输出Log,移动到指定路径

27

28 reader.close();29 process.waitFor();30 process.destroy();31 }32 catch(Exception e)33 {34 e.printStackTrace();35 }36 }

View Code

第二种方法代码如下:

java侧代码

ContractedBlock.gif

ExpandedBlockStart.gif

1 public voidexeTestCases(2 ArrayListlstCaseNames,3 String projectName,4

5 String deviceAip,6 String deviceAport,7 String deviceAusername,8 String deviceApasswd,9

10 String deviceBip,11 String deviceBport,12 String deviceBusername,13 String deviceBpasswd){14

15 String shellPath = "D:\\dDevelopemnt\\javaDemo\\project1\\clockDetect\\src\\clkJython.py";16

17 Properties props = newProperties();18 props.put("python.console.encoding", "UTF-8"); //Used to prevent: console: Failed to install '': java.nio.charset.UnsupportedCharsetException: cp0.

19 props.put("python.security.respectJavaAccessibility", "false"); //don't respect java accessibility, so that we can access protected members on subclasses

20 props.put("python.import.site","false");21 Properties preprops =System.getProperties();22 PythonInterpreter.initialize(preprops, props, new String[0]);23 PythonInterpreter interpreter = newPythonInterpreter();24 interpreter.exec("import sys");25 interpreter.exec("sys.path.append('D:\\dDevelopemnt\\javaDemo\\project1\\clockDetect\\src')");//自定义库函数路径

26 interpreter.execfile(shellPath);27

28 //前端设备信息封装

29 JSONObject jsondata = newJSONObject();30 jsondata.put("\"projectName\"","\""+projectName+"\"");31 jsondata.put("\"deviceAip\"","\""+deviceAip+"\"");32 jsondata.put("\"deviceAusername\"","\""+deviceAusername+"\"");33 jsondata.put("\"deviceApasswd\"","\""+deviceApasswd+"\"");34 jsondata.put("\"deviceAport\"","\""+deviceAport+"\"");35 jsondata.put("\"deviceBip\"","\""+deviceBip+"\"");36 jsondata.put("\"deviceBusername\"","\""+deviceBusername+"\"");37 jsondata.put("\"deviceBpasswd\"","\""+deviceBpasswd+"\"");38 jsondata.put("\"deviceBport\"","\""+deviceBport+"\"");39 jsondata.put("\"lstCaseNames\"","\""+lstCaseNames+"\"");40

41 System.out.println(jsondata.toString());42

43 //调用Python方法传递参数、返回参数44 //第一个参数为期望获得的函数(变量)的名字,第二个参数为期望返回的对象类型

45 PyFunction pyFunction = interpreter.get("setConfig", PyFunction.class); //1.前端传递设备类表及参数信息46

47 //调用函数,如果函数需要参数,在Java中必须先将参数转化为对应的“Python类型”

48 PyObject pyobjDictInfo = pyFunction.__call__(new PyString(jsondata.toString())); //2.返回Python侧封装的设备信息49

50 //前端选取的测试用例

51 for(String item:lstCaseNames){52 System.out.println("-----"+item+"------");53 PyFunction fun1 = interpreter.get(item, PyFunction.class); //3.调用执行用例1

54 PyObject pyobjDictSync = fun1.__call__(pyobjDictInfo); //4. 获取执行用例1的结果

55 System.out.println("****"+item+" now exe finished! "+ item + newDate().toString() );56

57 //将消息推送至客户端,告知释放的设备ip

58 try{59 WebSocketServer.sendInfo(pyobjDictSync.toString());60 } catch(IOException e) {61 e.printStackTrace();62 }63 }64

65

66 }

View Code

上述29-39行是java侧封装成标准json格式数据

44-48行是java侧调用python方法,进行设备的登录,涉及项目进行参数的配置(设备用户名、密码、ip、项目名称等入参)

pyobjDictInfo是python侧封装的字典数据,包括设备列表以及Telnet对象等,该参数作为执行测试用例的入参,

51-63行是遍历测试用例

python侧代码

1 '''

2 通过Jython调用3 '''

4 defsetConfig(data):5 res= json.loads(data) #根据字符串书写格式,将字符串自动转换成 字典类型

6

7 globalprojectName8 projectName = eval(res['"projectName"'])9 logDir = "d:\\loggg\\" + projectName+"_log.txt"

10

11 #创建一个logger

12 globalroot_logger13 globalfh14 globalch15

16 root_logger = logging.getLogger("clkLogger")17 root_logger.setLevel(logging.DEBUG)18

19 #创建一个handler,用于写入日志文件

20 fh =logging.FileHandler(logDir)21 fh.setLevel(logging.DEBUG)22

23 #再创建一个handler,用于输出到控制台

24 ch =logging.StreamHandler()25 ch.setLevel(logging.DEBUG)26

27 #定义handler的输出格式

28 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')29 fh.setFormatter(formatter)30 ch.setFormatter(formatter)31

32 #给logger添加handler

33 root_logger.addHandler(fh)34 root_logger.addHandler(ch)35 logger = root_logger; #修改全局日志变量

36

37 logger.info("======================================== project"+projectName+"begin ========================================")38 logger.debug(res)39

40 dictDevice ={}41 dictDevice['key1'] = [eval(res['"deviceAip"']) , eval(res['"deviceAusername"']),eval( res['"deviceApasswd"']), eval(res['"deviceAport"'])]42 dictDevice['key2'] = [eval(res['"deviceBip"']), eval(res['"deviceBusername"']), eval(res['"deviceBpasswd"']), eval(res['"deviceBport"']) ]43

44 logger.info("==================== login device begin ====================")45 myclass =MyClass();46 dictInfo =myclass.tearUp(dictDevice)47

48 returndictInfo49

50

51 #测试用例1

52 defcheckClk(dictInfo):53 logger.info("==================== 1.1基本功能 begin ====================")54 lstInfo =clearConfigInfo(dictInfo)55 dict = detect_clk_sync(lstInfo[0],lstInfo[1],lstInfo[2],lstInfo[3])56 logger.debug(dict)57 logger.info("==================== 1.1基本功能 end ====================")58 returndict59

60 #测试用例2

61 defcheckClkfreq(dictInfo):62 logger.info("==================== 1.2测试用例2 begin ====================")63 lstInfo =clearConfigInfo(dictInfo)64 dict = detect_clk_freq_deviation(lstInfo[0],lstInfo[1],lstInfo[2],lstInfo[3])65 logger.debug(dict)66 logger.info("==================== 1.2测试用例2 end ====================")67 return dict

其中,46行处调用函数如下,返回值包含telnet对象

1 #登录设备

2 deftearUp(self,dictDevice):3 dictInfo ={}4

5

6 lstA = dictDevice['key1']7 lstB = dictDevice['key2']8 deviceA = [lstA[0],lstA[1],lstA[2],lstA[3]];9 deviceB = [lstB[0],lstB[1],lstB[2],lstB[3]];10

11 try:12 logger.info(deviceA)13 logger.info(deviceB)14

15 telnetA = telnetlib.Telnet(deviceA[0], port=23, timeout=50)16 loginsys(telnetA,deviceA[1],deviceA[2])17 #print deviceInfo(telnetA) # 获取设备信息

18

19 telnetB = telnetlib.Telnet(deviceB[0], port=23, timeout=50)20 loginsys(telnetB,deviceB[1],deviceB[2])21

22 dictInfo["telnetA"] =telnetA23 dictInfo["telnetB"] =telnetB24 dictInfo["deviceA"] =deviceA25 dictInfo["deviceB"] =deviceB26

27 logger.info("------ login success ------")28

29 except(SystemExit, KeyboardInterrupt):30 logger.info("------ ping error ------")31

32 exceptException as e:33 logger.error("failed to ping", exc_info=True)34

35 return dictInfo

2 日志的重复打印问题

背景:在前端配置页面,输入项目项目,后端python解析后,以该项目名称作为log名称。

1239627-20190305171126770-1187296802.png

因此,在每次点击“提交”按钮都会执行python侧的setConfig函数,导致日志模块会不断添加handler,重复打印日志,

如下图:

1239627-20190305171518463-984171323.png

这显然不利于日志处理,随着测试项目的不断增多,重复的次数也会不断增加。

因此,需要在每次执行完一个项目时,就删除日志的handler模块,具体实现函数为

1 '''

2 测试用例执行完毕,调用此方法3 '''

4 deftear_down():5 logger.debug("close the logging handlers")6 root_logger.removeHandler(fh)7 root_logger.removeHandler(ch)8 logger.removeHandler(fh)9 logger.removeHandler(ch)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值