赞
踩
现状:
1、每次客户有需求,我们都需要在系统中新增接口,然后再将系统重新进行发布。
2、系统中存在很多的基本接口,大部分数据都能通过这些基本接口进行调用拼接。
因此,基于以上两点现状,领导提出以下要求:
1、系统能够动态新增接口,接口返回数据可以由系统已有基本接口进行调用拼接处理,而且系统不能够重新发布。
2、调用基本接口及拼接数据的流程在python脚本中完成,也就是一个接口对应一个脚本文件,能够将python脚本文件执行的结果返回给用户。(至于使用python脚本的原因主要是考虑外部团队使用python居多,既然未来动态api系统可能开发给他们,那么选择使用python最好不过,实际情况根据大家各自情况进行选择)。
3、能够向脚本文件中传入外部参数。
解决方案:
1、动态新增api接口时(并非实际在系统中新增一个接口,而是通过路径进行动态匹配),绑定python脚本文件,新增成功返回调用接口码。
2、根据固定调用地址+接口码进行接口调用,如果接口存在,则调用,不存在则结束。
3、用户调用接口之后,将找到对应的脚本文件进行调用,将调用结果返回给用户。
1、创建一个实体类,用于接收用户提交的创建接口相关参数
- /**
- * api实体类(页面提交)
- */
- @Data
- @ToString
- @NoArgsConstructor
- @AllArgsConstructor
- @Accessors(chain = true)
- public class ApiVO {
-
- private String name;
-
- private String file;
- }
2、创建一个Map存储工具类,用于模拟数据库插入获取数据(懒得创建表和写SQL之类的了)
- @Component
- public class AccessUtil {
-
- private final Map<String, String> urls = new ConcurrentHashMap<String, String>();
-
- public void putUrls(String code, String filePath){
- urls.put(code, filePath);
- }
-
- public String getValue(String code){
- return urls.get(code);
- }
-
- }
3、创建一个api新增接口,接口创建成功将返回唯一的一串字符码
- /**
- * api管理类
- */
- @RequestMapping("/dynamics-api")
- @RestController
- public class ApiController {
-
- @Resource
- private AccessUtil accessUtil;
-
- /**
- * 动态新增一个api接口, 并非实际创建出一个接口,而是根据路径上的{xxx}进行接口匹配
- * @param apiVO 新增接口对象
- */
- @PostMapping("/one")
- public String addApi(@RequestBody ApiVO apiVO){
- String apiName = apiVO.getName();
- // 这里实际需要上传一个脚本文件,为了省事,我先准备好了文件,这里通过上传脚本名称替代上传文件
- String file= apiVO.getFile();
- // code为生成的接口调用地址的一部分,唯一
- String code = DigestUtils.md5DigestAsHex((apiName + file).getBytes());
-
- // 模拟生成了一个接口
- accessUtil.putUrls(code, file);
- return code;
- }
-
- }
4、创建一个通过接口调用适配接口,所有新增的接口,将通过以下适配接口进行匹配调用
- @Slf4j
- @RequestMapping("/adapter")
- @RestController
- public class AdapterController {
-
- @Resource
- private AccessUtil accessUtil;
-
- @GetMapping("/execute/{code}")
- public String executeApi(@PathVariable("code") String code) throws Exception{
- String value = accessUtil.getValue(code);
- if(value == null){
- log.error("接口不存在");
- return null;
- }
-
- // 拿到python脚本文件
- String scriptPath = "D:\\test\\" + value;
- File file = new File(scriptPath);
-
- if(!file.exists() || !file.isFile()){
- log.error("脚本文件不存在");
- return null;
- }
-
- // 随便制造点参数,模拟向脚本中传递参数
- Map<String, String> paramsMap = new HashMap<>();
- paramsMap.put("param1", "value1");
- paramsMap.put("params2", "value2");
-
- // 拼接参数,以key1@@#@@value1##@##key2@@#@@value2的方式
- String lineSplit = "##@##";
- String valueSplit = "@@#@@";
- StringJoiner paramsStr = new StringJoiner(lineSplit);
- for(String key : paramsMap.keySet()) {
- paramsStr.add(key + valueSplit + paramsMap.get(key));
- }
-
- // 执行脚本
- ProcessBuilder processBuilder;
- // 没有配置virtualenv环境,直接运行,前提是本地安装了python
- processBuilder = new ProcessBuilder("python", file.getPath(), paramsStr.toString());
- processBuilder.redirectErrorStream(true);
- Process process = processBuilder.start();
-
- // 处理结果,每行以#@#@#进行分割
- InputStreamReader ir = new InputStreamReader(process.getInputStream());
- BufferedReader br = new BufferedReader(ir);
- String line;
- StringJoiner result = new StringJoiner("#@#@#");
- while ((line = br.readLine()) != null) {
- log.warn(line);
- result.add(line);
- }
- br.close();
- ir.close();
- process.waitFor();
-
- // 打印结果
- return result.toString();
- }
-
-
- }
5、python脚本内容如下
- # coding:utf-8
- import sys
- import json
- import ssl
- import base64
- import requests
- import time
-
- # 命令参数=========================================================================
- COMMAND_PARAMS = {}
-
- def getData():
- return [
- {
- "name": "zhangsan",
- "phone" "12345678910",
- "address": "x-y-z-santi"
- }
- ]
-
- def getCommandParams():
- return COMMAND_PARAMS
-
- def main():
- # 用户的主要编辑区域,返回变量data为最终想要的结果
- data = getData()
- commandParams = getCommandParams()
- return data
-
- #获取传入参数集合,参数是以如下形式传入: key1@@#@@value1##@##key2@@#@@value2
- paramList = sys.argv[1].split("##@##")
- for num in paramList:
- COMMAND_PARAMS[num.split("@@#@@")[0]] = num.split("@@#@@")[1]
-
- # 执行函数
- data = main()
- # 接口获取数据通过print()得到
- print(COMMAND_PARAMS)
- print(data)
请根据实际情况写脚本,我这里随便写的
6、测试效果
调用新增结果,返回code
返回唯一码:调用脚本返回结果如下:
将code拼接在适配接口上进行调用
调用脚本返回结果如下:
以上是通过在本地的python环境中执行的,还有一种就是在沙箱环境中去执行,能够更加的安全,请参考以下博客:
https://blog.csdn.net/lmchhh/article/details/128021914
https://blog.csdn.net/lmchhh/article/details/128806208?spm=1001.2014.3001.5502
以上就是新增api接口执行脚本具体实现流程,如果觉得对你有所有帮助,请点个赞或者收藏支持一下吧!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。