python | 识别项目中的接口并生成接口文档

news2024/11/14 12:41:59

识别项目中的接口并生成接口文档

  • 前言
  • 起点
  • 用途
  • 使用方法
  • 控制台展示
  • 文档内容展示
  • 代码
  • 注意事项

前言

前段时间也是来了一场说走就走的旅行,去看了看祖国的大好河山,不得不说也是一场让我难忘的旅行,可惜钱包太扁了,禁不起我的的折腾。

2023年一晃上半年已经结束了,看了看口袋,又是白干,一个字就是惨!所以想着下半年不能这样躺着了,再躺就四肢退化了。

下半年的开端还是好的,7月1号线上服务出现问题,火急火燎回公司加班到晚上8点,回来继续码代码到11点,就是本篇的《python | 识别项目中的接口并生成接口文档》,加油吧!

起点

《python | 识别项目中的接口并生成接口文档》 代码很早就完成了,实际上也申请过公司的专利,因为太简单了,而且大众,大家都有着想法所以当然就不能通过评审了,但是我感觉用处还是蛮大的。

用途

比如说你接收一个项目,但是接口文档不是很全的情况下,可以使用程序梳理出项目的接口文档
再比如说你开发了一个新项目,但是只有开始的时候写了接口文档但是后面对接口有改动,并且没有及时更新文档,导致文档和代码实际不符合,我觉得这个比较常见,因为我经常忘记更新文档。

使用方法

运行之后只需要输入项目地址即可
文末会贴代码,只需要复制粘贴,然后添加依赖,运行之后输入项目地址即可。

控制台展示

输入项目地址之后是这样的,这个是你在控制台上看到的,实际会在你项目的同级目录下生成docx和xls文档
在这里插入图片描述
在这里插入图片描述

文档内容展示

在这里插入图片描述
在这里插入图片描述

代码

# 从文件中提取接口

# 定义一个文件夹名称
import datetime
import os

from docx import Document
from docx.enum.style import WD_STYLE_TYPE
import xlwt

# 生成excel文档要素
style_head = xlwt.XFStyle()
style_row = xlwt.XFStyle()

font = xlwt.Font()
font.name = "微软雅黑"
font.bold = True
font.colour_index = 1

bg = xlwt.Pattern()
bg.pattern = xlwt.Pattern.SOLID_PATTERN
bg.pattern_fore_colour = 4

style_head.font = font
style_head.pattern = bg
style_row.alignment.wrap = 1
ee = xlwt.Workbook(encoding='utf-8')

ss = ee.add_sheet("接口")
ss.write(0, 0, "文件名", style_head)
ss.write(0, 1, "接口名", style_head)
ss.write(0, 2, "请求类型", style_head)
ss.write(0, 3, "接口注释", style_head)
ss.write(0, 4, "方法参数", style_head)
ss.write(0, 5, "原生注释", style_head)
ss.write(0, 6, "原生参数", style_head)

sec = ss.col(0)
ser = ss.row(0)
sec.width = 256 * 30

sec = ss.col(1)
ser = ss.row(1)
sec.width = 256 * 30

sec = ss.col(2)
ser = ss.row(2)
sec.width = 256 * 10

sec = ss.col(3)
ser = ss.row(3)
sec.width = 256 * 40

sec = ss.col(4)
ser = ss.row(4)
sec.width = 256 * 30

sec = ss.col(5)
ser = ss.row(5)
sec.width = 256 * 60

sec = ss.col(6)
ser = ss.row(6)
sec.width = 256 * 100

aa = 0
bb = 0

# 生成doc文档要素
docment = Document()
docment.add_heading('来自路由名.exe生成的接口文档', 0)
doc_p = docment.add_paragraph("")
doc_p.add_run('路由名').bold = True
docment.add_page_break()


def p(i):
    if os.path.isdir(i):
        dirs = os.listdir(i)
        for d in dirs:
            if (i + "\\" + d).endswith(".java"):
                q(i + "\\" + d)
            elif os.path.isdir(i + "\\" + d):
                p(i + "\\" + d)
    else:
        if i.endwith(".java"):
            q(i)
        else:
            print("不支持此类型的文档!")


def q(r):
    i_o = False
    with open(r, encoding='utf-8', errors='ignore') as f:
        for l in f:
            if "@Controller" == l.replace("\n", "").strip() \
                    or "@Controller(" in l \
                    or "@RestController" == l.replace("\n", "").strip() \
                    or "@Controller(" in l:
                i_o = True
                break
    if not i_o:
        return
    global aa
    global bb
    s = ""
    t = False
    u = False
    v = False
    w = ""
    x = []
    y = []
    z = r.split("\\")[-1:][0]
    is_zh = False
    str_zh = ""
    i_c = 0
    # 调整编码 显示中文
    with open(r, encoding='utf-8', errors='ignore') as f:
        for l in f:
            if l == "":
                continue
            if 'Mapping' in l and 'import' in l:
                continue
            if '/**' in l and not is_zh:
                # 注释行
                str_zh = ""
                is_zh = True
                str_zh = str_zh + l
                continue
            if '*/' in l and is_zh:
                is_zh = False
                str_zh = str_zh + l
                continue
            if is_zh:
                str_zh = str_zh + l
                continue
            if 'Mapping' in l and 'import' not in l and t is False:
                s = l
                continue
            if 'public class' in l:
                t = True
                xls_h = str_zh
                str_zh = ""
                continue
            if 'Mapping' in l:
                x.append(l.strip())
                u = True
                continue
            if u and l.strip().startswith("public") and l.strip().endswith("{"):
                w = l
                x.append(w.strip())
                x.append(str_zh.strip())
                str_zh = ""
                y.append(x)
                w = ""
                x = []
                u = False
                continue
            if u and l.strip().startswith("public") and not l.strip().endswith("{"):
                print("w:"+w)
                print("l:" + l)
                w = w + l
                v = True
                continue
            if u and v and l.strip().endswith("{"):
                v = False
                w = w + l
                x.append(w.strip())
                x.append(str_zh.strip())
                str_zh = ""
                y.append(x)
                w = ""
                x = []
                u = False
                continue
            if u and v:
                w = w + l
        if s != "" or len(y) != 0:
            print(">>>>>>>>>>>>>>>>>>start parse >>>>>>>>>>>>>>>")
        if s != "":
            print(s.strip().split("\"")[1].split("\"")[0])

        # 标题就是 xls_h
        docment.add_heading(str(bb + 1) + "" + z.replace(".java", ""), level=1).bold = False
        # 产生一个表格吧
        table = docment.add_table(2, 3)
        table.style = "Light Shading Accent 2"
        heading_cells = table.rows[0].cells
        heading_cells[0].text = "类描述"
        heading_cells[1].text = "创建人"
        heading_cells[2].text = "创建时间"

        row_cells = table.rows[1].cells
        row_cells[0].text = str(get_word(xls_h))
        row_cells[1].text = str(get_creator_user(xls_h))
        row_cells[2].text = str(get_creator_time(xls_h))
        bb += 1
        if len(y) != 0:
            for oi in y:
                print(str(oi).replace("\\n", ""))
                pt = ""
                jk = oi[0]
                ff = oi[1]
                zh = oi[2]
                if "Post" in jk or "POST" in jk:
                    pt = "POST"
                elif "Get" in jk or "GET" in jk:
                    pt = "POST"
                elif "Delete" in jk or "DELETE" in jk:
                    pt = "POST"
                elif "Put" in jk or "PUT" in jk:
                    pt = "POST"
                elif "@RequestMapping" in jk:
                    pt = "GET/POST"
                else:
                    pt = "UNKNOWN"

                if len(jk.strip().split("\"")) == 1:
                    jk = ""
                else:
                    jk = jk.strip().split("\"")[1].split("\"")[0]

                ss.write(aa + 1, 0, z.strip(), style_row)
                new_s = ""
                if "" != s:
                    new_s = str(s.strip().split("\"")[1].split("\"")[0] + "/" + jk).replace("//", "/")
                    new_s = ("/" + new_s).replace("//", "/").strip()
                    ss.write(aa + 1, 1, new_s, style_row)
                else:
                    new_s = jk.replace("//", "/")
                    new_s = ("/" + new_s).replace("//", "/").strip()
                    ss.write(aa + 1, 1, new_s, style_row)
                ss.write(aa + 1, 2, pt.strip(), style_row)
                s6 = ff
                s6 = s6[:s6.find("<")] + s6[s6.find("<"):s6.rfind(">")].replace(",", "$") + s6[s6.rfind(">"):]
                s6 = s6[s6.find("(") + 1:s6.rfind(")")]
                c = s6.count("(")
                for i in range(c):
                    s6 = s6[:s6.find("(")] + s6[s6.find("(") + 1:s6.find(")")].replace(",", "").replace("",
                                                                                                        "") + "" + s6[
                                                                                                                   s6.find(
                                                                                                                       ")") + 1:]
                p6 = s6.split(",")
                n6 = ""
                for u6 in p6:
                    if u6 != "" and "HttpServetRequest".lower() not in u6.lower() and "HttpServetResponse".lower() not in u6.lower():
                        u6 = u6.replace("$", ",")
                        k6 = u6.split(" ")[-2:][0]
                        v6 = u6.split(" ")[-2:][1]
                        n6 = n6 + k6 + ":" + v6 + "\n"

                ss.write(aa + 1, 3, get_word(zh), style_row)
                ss.write(aa + 1, 4, n6[:n6.rfind("\n")].strip(), style_row)
                ss.write(aa + 1, 5, zh.strip(), style_row)
                ss.write(aa + 1, 6, ff.strip(), style_row)

                i_c = i_c + 1
                create_interface_table(bb, i_c, pt.strip(), new_s)
                create_interface_canshu(bb, i_c, n6[:n6.rfind("\n")].strip(), zh.strip())

                # 设置代码块
                # document.add_paragraph(zh.strip())
                # document.add_paragraph(ff.strip())
                aa = aa + 1


def create_interface_table(l, i_c, a, b):
    docment.add_heading(str(l) + "." + str(i_c) + "接口地址", level=2).bold = False
    # 产生一个表格
    table = docment.add_table(5, 3)
    table.style = "Light Shading Accent 5"
    heading_cells = table.rows[0].cells
    heading_cells[0].text = "序号"
    heading_cells[1].text = "接口选项"
    heading_cells[2].text = "描述"

    row_cells = table.rows[1].cells
    row_cells[0].text = "1"
    row_cells[1].text = "REST-HTTP-METHOD"
    row_cells[2].text = a

    row_cells = table.rows[2].cells
    row_cells[0].text = "2"
    row_cells[1].text = "REST-URI-Fragment"
    row_cells[2].text = b

    row_cells = table.rows[3].cells
    row_cells[0].text = "3"
    row_cells[1].text = "Content-Type"
    row_cells[2].text = ""

    row_cells = table.rows[4].cells
    row_cells[0].text = "4"
    row_cells[1].text = "Accept"
    row_cells[2].text = ""


def create_interface_canshu(l, i_c, a, b):
    docment.add_heading(str(l) + "." + str(i_c) + ".1 接口参数", level=3).bold = False
    if a == "":
        table = docment.add_table(2, 4)
        table.style = "Light Shading Accent 5"
        heading_cells = table.rows[0].cells
        heading_cells[0].text = "序号"
        heading_cells[1].text = "字段名"
        heading_cells[2].text = "类型"
        heading_cells[2].text = "说明"
        return
    r_l = a.split("\n")
    table = docment.add_table(len(r_l) + 1, 4)
    table.style = "Light Shading Accent 5"
    heading_cells = table.rows[0].cells
    heading_cells[0].text = "序号"
    heading_cells[1].text = "字段名"
    heading_cells[2].text = "类型"
    heading_cells[2].text = "说明"

    # 处理说明的内容
    s_m = {"1": 2}
    if b != "":
        shuo_b = b.split("\n")
        for s_b in shuo_b:
            if "@param" in s_b and len(s_b.strip().split(" ")) >= 4:
                s_m[s_b.strip().split(" ")[2]] = s_b.strip().split(" ")[3]

    rr_l = 0
    for rl in r_l:
        row_cells = table.rows[rr_l + 1].cells
        row_cells[0].text = str(rr_l + 1)
        row_cells[1].text = rl.split(":")[1]
        row_cells[2].text = rl.split(":")[0]
        try:
            row_cells[3].text = s_m[rl.split(":")[1]]
        except:
            pass
        rr_l += 1


def get_word(zh):
    z1 = ""
    if zh != "":
        zh_list = zh.replace("/**", "").replace("*/", "").split("*")
        for row_zh in zh_list:
            if "@" in row_zh or row_zh.strip() == "":
                continue
            z1 = z1 + row_zh + "\n"

    return z1.replace("\n", "").strip()


# 获取创建人
def get_creator_user(zh):
    z1 = ""
    if zh != "":
        zh_list = zh.replace("/**", "").replace("*/", "").split("*")
        for row_zh in zh_list:
            if "@author" in row_zh:
                z1 = row_zh.strip().split(" ")[1]
                break
    return z1


# 获取创建时间
def get_creator_time(zh):
    z1 = ""
    if zh != "":
        zh_list = zh.replace("/**", "").replace("*/", "").split("*")
        for row_zh in zh_list:
            if "@since" in row_zh:
                z1 = row_zh.strip().split(" ")[1]
                break
    return z1


def get(str1):
    rr = ""
    if len(str1.split("(")) == 1 and len(str1.split(")")) == 1:
        for s in str1.split(" ")[-2:]:
            rr = rr + " " + s
        return rr.strip()

    for s in str1.split["("][1:]:
        rr = rr + s
    rr1 = ""
    if rr == "":
        for s in str1.split(")")[:-1]:
            rr1 = rr1 + s
        if "" != rr1:
            rr = ""
            for s in rr1.split(" ")[-2:]:
                rr = rr + " " + s
    else:
        for s in rr.split(")")[:-1]:
            rr1 = rr1 + s
        if "" != rr1:
            rr = ""
            for s in rr1.split(" ")[-2:]:
                rr = rr + " " + s
    return rr.strip()


if __name__ == "__main__":
    print("*注:仅从.java后缀的文件中识别接口")
    i = input(r"输入项目地址(会在项目的统计目录下生成doc文档和xls文档,例如:c:\project):")
    # i = r"D:\python-project\springboot-plus-master"
    o = ""
    c_o = ""
    if not i.endswith("\\"):
        o = "\\" + str(datetime.datetime.now()).replace(" ", "").split(".")[0].replace(":", "-").replace("-",
                                                                                                         "_") + ".xls"
        c_o = "\\" + str(datetime.datetime.now()).replace(" ", "").split(".")[0].replace(":", "-").replace("-",
                                                                                                           "_") + ".docx"
    else:
        o = str(datetime.datetime.now()).replace(" ", "").split(".")[0].replace(":", "-").replace("-",
                                                                                                  "_") + ".xls"
        c_o = str(datetime.datetime.now()).replace(" ", "").split(".")[0].replace(":", "-").replace("-",
                                                                                                    "_") + ".docx"
    p(i)
    if i.endswith(".java"):
        i = i.split(".")[0]
        o = str(datetime.datetime.now()).replace(" ", "").split(".")[0].replace(":", "-").replace("-",
                                                                                                  "_") + ".xls"
        c_o = str(datetime.datetime.now()).replace(" ", "").split(".")[0].replace(":", "-").replace("-",
                                                                                                    "_") + ".docx"
    ee.save(i + o)
    docment.save(i + c_o)
    input('* 请按两次任意键退出>>>>>>>>>>>>>')
    input("")

注意事项

1、代码中间经过脱敏处理,然后基本上不可读了,但是其中的一些生成规则啊,其实还是可以看的懂得,也就是说你可以根据你的需求进行定制化改造。
2、代码逻辑比较简单,就是一种特殊匹配即可,匹配到了就放到篮子里,所以不建议读,看下就行了,有思路自己可以写
3、方便起见我打包成了exe程序,这个过程比较艰辛,因为环境导致我在打包过程中一直缺依赖,用不了,这一篇文章特别好,可以细读。
【问题的根本解决思路】pycharm可以运行但是pyinstaller 打包后运行exe程序出现的“ModuleNotFindError“错误

当然这个我设置了积分为0,并且禁止调分,直接下载使用就行,如果担心安全问题,可以研究一下代码自己生成exe程序,方便快捷。

点击下载 -》识别项目中的接口并生成接口文档

在这里插入图片描述
过去的就过去吧,至少珍惜一下眼前吧

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/710080.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

NOSQL之redis配置和安装

关系数据库与非关系型数据库 ●关系型数据库&#xff1a; 关系型数据库是一个结构化的数据库&#xff0c;创建在关系模型&#xff08;二维表格模型&#xff09;基础上&#xff0c;一般面向于记录。 SQL 语句&#xff08;标准数据查询语言&#xff09;就是一种基于关系型数据库…

Andriod Studio安装使用中

暑假快乐啊&#xff0c;终于考完啦 Android studio安装的前提是必须保证安装了jdk1.8版本以上 如果没有安装好&#xff0c;那么可以参考这个&#xff1a;win10下载jdk18以及环境配置 一、在官网下载Android Studio 官网&#xff1a;https://developer.android.google.cn/stud…

jedis使用,操作Redis数据库1

使用jedis的原因; 1.提高性能&#xff0c;减少Socket的创建和销毁对性能的影响 2.是一个线程安全的网络连接池。可以用JedisPool创建一些可靠Jedis实例&#xff0c;可以从池中获取Jedis实例&#xff0c;使用完后再把Jedis实例归还给JedisPool连接池。合理的JedisPool资源池参数…

8 款在线 API 接口文档管理工具;好用!

1、Postman Postman是被大家所熟知的网页调试Chrome插件&#xff0c;我们常常用它来进行临时的http请求调试。幸运的是&#xff0c;Postman可以将调试过的请求保存到Collection中。形成的Collection就可以作为一份简单有效且支持在线测试的接口文档&#xff0c;使用同一账号登录…

Jenkins+Docker 实现一键自动化部署项目

1、环境配置 环境&#xff1a;centos7git(gitee) 简述实现步骤&#xff1a;在docker安装jenkins&#xff0c;配置jenkins基本信息&#xff0c;利用Dockerfile和shell脚本实现项目自动拉取打包并运行。 2、安装docker docker 安装社区版本CE 确保 yum 包更新到最新。 yum …

react-redux(由浅到深)

文章目录 1. redux1.1 概述与使用原则1.2工作流程1.2.1 三个核心 1.3 store1.4 action1.5 reducer1.5.1 合并reducers 1.6 dispatch getState 及状态更新 2. react-redux2.1 基本特征2.2 connect()、mapStateToProps2.3 mapDispatchToProps2.4Provider2.5. 中间件&#xff0c;c…

【动手学习深度学习--逐行代码解析合集】04softmax回归的从零开始实现

【动手学习深度学习】逐行代码解析合集 04softmax回归的从零开始实现 视频链接&#xff1a;动手学习深度学习–softmax回归的从零开始实现 课程主页&#xff1a;https://courses.d2l.ai/zh-v2/ 教材&#xff1a;https://zh-v2.d2l.ai/ 1、 softmax网络架构 2、 softmax运算 3、…

实验三:运算类编程实验

实验目的 阐明本实验的目的。 一实验目的掌握学精变C6应) 乘汉运第《结购 3位)江程产设计方法穿握双精度[3位)加法运算乡饰程产设计方法穿握双精度园) 朱讼运算 [结果为64位)汇编往广设计方讯 实验要求 说明实现本实验需要掌握的知识及本实验需要的实验环境 、实强要求 了解简单…

20+个小而精的Python实战案例(附源码和数据)

公众号&#xff1a;尤而小屋作者&#xff1a;Peter编辑&#xff1a;Peter 大家好&#xff0c;我是Peter~ 最近小编认真整理了20个基于python的实战案例&#xff0c;主要包含&#xff1a;数据分析、可视化、机器学习/深度学习、时序预测等&#xff0c;案例的主要特点&#xff1…

spring boot security验证码登录示例

前言 在spring boot security自定义认证一文&#xff0c;基本给出了一个完整的自定义的用户登录认证的示例&#xff0c;但是未涉及到验证的使用&#xff0c;本文介绍登录的时候如何使用验证码。 本文介绍一个验证码生成工具&#xff0c;比较老的一个库了&#xff0c;仅作demo…

rust warp框架教程1-helloworld

warp框架简介 warp is a super-easy, composable, web server framework for warp speeds. warp建立在hyper之上&#xff0c;因此&#xff0c;warp天生支持异步&#xff0c;HTTP/2&#xff0c;以及“正确的HTTP实现”。 warp的强大之处在于其提供的filter系统&#xff0c;它…

软件设计模式与体系结构-设计模式-生成模式单例模式

目录 二、生成器模式1. 生成者模式概念实例一&#xff1a;房屋选购系统题目时序图类图 优缺点适用场景 2. 生成器模式与抽象工厂模式3. 课程作业*** 三、单例模式1. 单例模式要点&#xff1a;基本思路实例一&#xff1a;互联网连接问题 2. 多线程情况3. 优缺点4. 适用场景5. 课…

leetcode 88.合并两个有序数组

⭐️ 题目描述 &#x1f31f; leetcode链接&#xff1a;合并两个有序数组 ⭕️ 代码&#xff1a; /*思路&#xff1a;双指针问题1.从前往后拷贝依次比较两个数组元素的较小值&#xff0c;较小值先拷贝- 问题&#xff1a;从前拷贝会造成覆盖(有问题)2.从后往前拷贝依次比较两个…

SpringBoot(五)SpringBoot事务

在实际开发项目时&#xff0c;程序并不是总会按照正常的流程去执行&#xff0c;有时候线上可能出现一些无法预知的问题&#xff0c;任何一步操作都有可能发生异常&#xff0c;异常则会导致后续的操作无法完成。此时由于业务逻辑并未正确的完成&#xff0c;所以在之前操作过数据…

单臂路由实现不同VLAN之间数据转发

实验环境&#xff1a; 思科模拟器&#xff0c;Cisco Packet Tracer 实验拓扑&#xff1a; 实验配置&#xff1a; &#xff08;1&#xff09;PC配置 IP地址子网掩码网关PC1192.168.10.1255.255.255.0192.168.10.254PC2192.168.10.2255.255.255.0192.168.10.254PC3192.168.20…

串口通讯监控方法

当我们调试硬件的时候&#xff0c;发现串口数据异常&#xff0c;用示波器和逻辑分析仪的话会比较麻烦&#xff0c;此时可以并一个监控串口&#xff0c;如下图所示 232串口&#xff0c;我们是不能直接并一个串口上去的&#xff1b;但是我们的监控串口&#xff0c;可以只接一根R…

【玩转循环】探索Python中的无限可能性

前言 循环可能是每个编程语言中使用比较多的语法了&#xff0c;如果能合理利用好循环&#xff0c;就会出现意想不到的结果&#xff0c;大大地减少代码量&#xff0c;让机器做那些简单枯燥的循环过程&#xff0c;今天我将为大家分享 python 中的循环语法使用。&#x1f697;&am…

数据结构--栈的链式存储

数据结构–栈的链式存储 推荐使用不带头结点的单链表 \color{green}推荐使用不带头结点的单链表 推荐使用不带头结点的单链表 typedef struct LNode {ElemType data;struct LNode* next; } LNode, *LinkList;bool InitList(LinkList &L) {L->next NULL; }后插操作&…

python网络编程(二)模拟ssh远程执行命令

1、项目需求&#xff1a; 要实现一个像ssh远程连接工具一样&#xff0c;在终端输入命令&#xff0c;返回对应的结果。 比如window的dos命令&#xff1a; dir &#xff1a;查看目录下的文件 ipconfig : 查看网卡信息 tasklist : 查看进程列表 linux的命令&#xff1a; ls : 查看…

Jenkins与CI/CD

简介 CI&#xff08;持续集成&#xff09; Continuous Integration是一种软件开发实践&#xff0c;即团队开发成员经常集成他们的工作&#xff0c;通常每个成员每天至少集成一次&#xff0c;也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建&#xff08;包括编…