在工作业务中,需要实现用Java调用Python脚本,对比了网上主流的几种实现方式,最终选择以 Process的形式来实现业务需求。
(1)Java代码实现处理方法
/**
* 运行脚本文件
*
* @param scriptPath 脚本位置
* @param params 请求参数
*/
public void runScript(String scriptPath, List<String> params) {
long start = System.currentTimeMillis();
long end = 0L;
try {
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.redirectErrorStream(true);
List<String> commands = new ArrayList<>();
commands.add("python");
commands.add(scriptPath);
// 参数编码
log.info("runScript params:" + params);
params = encodeParams(params);
commands.addAll(params);
// 加载命令
processBuilder.command(commands);
// 启动进程
Process process = processBuilder.start();
String result = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))
.lines().collect(Collectors.joining());
log.info("runScript result:" + result);
Long end = System.currentTimeMillis();
process.waitFor();
} catch (Exception e) {
log.info("运行脚本文件失败:" + e.getMessage());
Long end = System.currentTimeMillis();
}
log.info("运行时间:" + (end - start));
}
/**
* 参数编码
*
* @param params 参数
* @return 编码后的参数
*/
private List<String> encodeParams(List<String> params) {
if (params == null || params.isEmpty()) {
return params;
}
List<String> list = new ArrayList<>();
for (String param : params) {
param = param.replace("\"", "@");
param = new String(param.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
list.add(param);
}
return list;
}
此处参数编码是特殊处理,需要根据实际业务来处理。Java以Process形式实现的就是类似于CMD窗口运行程序,传递的参数是不能有引号的,如果参数比较简单可以省去这一步,如果需要传递JSON等类型的长字符串,那么需要将引号转为其它符号或者字符串,而且需要和Python端约定好,此处我使用了@符号替换了引号。
python返回的参数是python程序执行完成后返回给Java段,返回形式是以窗口输出流的形式返回,也就是在python中使用 print() 或者使用log输出等都会返回给Java。
(2)Python端实现
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
if __name__ == '__main__':
# 获取Java传递过来的参数,参数是一个列表,第一个是文件位置。后续都是传递过来的参数
argv = sys.argv
data = argv[1]
data = data.replace('@', '"')
result = json.loads(data)
print("此处是一个打印。" + str(result))
(3) 编码问题
Java调用Pyhton脚本,一个最主要的问题就是需要处理编码问题,此处我统一使用 UTF-8形式处理。
Java中编码处理如下:
写出编码:
param = new String(param.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
读取编码:
String result = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8)).lines().collect(Collectors.joining());
Python中编码处理如下:
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')