zoukankan      html  css  js  c++  java
  • Go 实现 自动检索 API 错误码代码行 并 打印成文档,例 markDown 形式等

    作者:林冠宏 / 指尖下的幽灵

    掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8

    博客:http://www.cnblogs.com/linguanh/

    GitHub : https://github.com/af913337456/

    腾讯云专栏: https://cloud.tencent.com/developer/user/1148436/activities


    源码--GitHub:https://github.com/af913337456/ErrorDocAutoPrinter

    如果你是一个后端Server程序开发人员。你应该知道,在你写完API之后,是需要给客户端的同学提供调用文档的。

    例如下面一个api handler创建一个用户

    func HandleCreateUser(w http.ResponseWriter,r *http.Request) map[string]interface{} {
    	if r.Body == nil {
    		return util.GetCommonErr(23,"create user req body is fucking null?")
    	}
    	....
    	....
    	return util.GetCommonSuccess("success")
    }
    

    上面有一行错误信息输出的代码

    util.GetCommonErr(23,"create user req body is fucking null?")
    

    假设我们要写成markDown风格的文档,上面的可能是这样一种对应

    错误码 含义 提示
    23 create user req body is fucking null? 暂无

    Ok,这只是一个错误信息的情况,我们很轻松就手动写完了。

    如果有几百上千个呢?一个完整的服务端程序,肯定会有很多这种错误信息输出的代码。在几百上千个的时候,还要手动写?这是多么低效率,且浪费时间令人窒息的操作。

    而我这篇文章要介绍的就是一个帮你自动检索并生成API输出错误信息文档开源程序

    ErrorDocAutoPrinter

    它,具备下面的特点

    • 自定义代码文件夹路径
    • Json 配置文件形式导入设置,避免反复编译程序
    • 按照给定的代码方法名称自动检索对应的代码行
    • 按照给定的切割参数规则,自动切割组合
    • 按照给定的列名描述,自动组合成新的文字
    • 接口化的设计逻辑,高度自定义
    • 自动按照code 从小到大排序输出,可控!
    • 自动提示重复出现过的错误信息。
    • 自动按照设定生成输出文件
    • 可设置符合目标的文件后缀
    • 可设置需要过滤的文件名,符合就不处理
    • 自定义输出风格,markDown?txt?html?
    • 自行定义输出的逻辑,可以映射到很多情况的文字玩法
    • 总之:‘为所欲为’

    我,提供了两种风格的输出

    • 简单文本 风格
    • markDown 风格

    使用步骤

    1. 配置好json文件 DefaultConfig.json
    {
      "TargetFileSuffix":[".go"],
      "TargetErrorFuncName":["util.GetCommonErr","util.GetErrWithTips"],
      "FilterFileName":["core"],
      "ParamsColumnNames":[" 错 误 码 "," 含 义 ","提 示"],
      "ParamsSplitChar":","
    }
    
    1. 输入你的代码文件夹路径并运行程序
    func TestDocPrinter(t *testing.T) {
    	p := NewDefaultErrorDocPrinter(NewDefaultMarkDownErrorDocPrinter())
    	if p == nil {
    		return
    	}
    	fmt.Println(p.printErrorDoc("../../errorDocPrinter"))
    }
    
    1. 复制粘贴结果
    错误码 含义 提示
    -9 invalid create user --空缺--
    -4 invalid create user --空缺--
    -1 create user failed 创建用户失败
    88 创建评论失败 --空缺--
    3110 error params --空缺--
    3111 update failed --空缺--
    3112 yellow 内容涉黄 --空缺--
    3113 forbid 禁止访问 --空缺--
    3114 empty id --空缺--
    3115 服务端开启事务失败 --空缺--
    3116 服务端事务提交失败 --空缺--
    3117 update effect row <= 0 --空缺--
    3118 RowsAffected 失败 --空缺--
    3119 更新只有部分成功 --空缺--
    3120 empty userId --空缺--
    3121 too lager --空缺--
    3122 user not exits --空缺--
    3123 非法更新 --空缺--
    3124 参数个数长度限制 --空缺--
    3126 服务端事务提交失败 --空缺--
    3127 invalid money --空缺--
    3128 money not enough --空缺--
    3129 创建消费记录失败 --空缺--
    基本说完了,源码见上面的开源链接,去玩吧。

    简单分析下 markDown 风格的生成

    接口

    type IErrorDocPrinter interface {
    	FindLines(printer *ErrorDocPrinter,reader *bufio.Reader,fileName,currentSuffix string,handleLine func(line string)) []string
    	BuildACell(printer ErrorDocPrinter,columns,size int,prefixName,param string) string
    	ResultLine(line string)
    	EndOfAFile(printer ErrorDocPrinter,aFileRetLines []string)
    	EndOfAllFile(printer ErrorDocPrinter,allRetLines []string)
    }
    

    找到一个文件所有行

    func (p MarkDownErrorDocPrinter) FindLines(
    	printer *ErrorDocPrinter,reader *bufio.Reader,fileName,currentSuffix string,handleLine func(line string)) []string {
    	// 正则匹配 todo
    	var lines []string
    	printer.currentLineNum = 0
    	for {
    		byt, _, err := reader.ReadLine()
    		if err != nil {
    			// 读完一个文件
    			break
    		}
    		line := string(byt)
    		// 排除注释
    		printer.currentLineNum++
    		if startWith(line,"//") {
    			continue
    		}
    		if startWith(line,"/*") {
    			continue
    		}
    		if startWith(line,"*") {
    			continue
    		}
    		for _,value := range printer.TargetErrorFuncName {
    			if strings.Contains(line,value) {
    				// hit,准备生成
    				handleLine(line)
    				lines = append(lines,line)
    			}
    		}
    	}
    	return lines
    }
    

    处理一个单元格

    func (p MarkDownErrorDocPrinter) BuildACell(
    printer ErrorDocPrinter,columns,size int,prefixName,param string) string {
    	/**
    	| Name | Academy | score |
    	| - | - | - |
    	| Harry Potter | Gryffindor| 90 |
    	| Hermione Granger | Gryffindor | 100 |
    	| Draco Malfoy | Slytherin | 90 |
    	*/
    	if columns == 0 {
    		code,err := strconv.ParseInt(param,10,64)
    		if err == nil {
    			codeArr = append(codeArr,code)
    		}
    		return "|" + param
    	}
    	count := tipsMap[param]
    	if columns == 1 {
    		// 保存提示列
    		if count != 0 {
    			count++
    			diffMap[fmt.Sprintf("param: -- %s -- times:%d",param,count-1)] =
    				fmt.Sprintf(" 与 %s 的第 %d 行提示重复",printer.currentFileName,printer.currentLineNum)
    		}else{
    			count = 1
    		}
    		tipsMap[param] = count
    	}
    	if columns == size - 1 {
    		return "|" + param + "|"
    	}
    	// 找出提示一样,但是 code 不一样的
    	return "|" + param
    }
    

    从小到大排序--code

    func quickSort(arr *[]int64,left,right int) {
    	if arr == nil {
    		return
    	}
    	if right == len(*arr) {
    		right--
    	}
    	if left < 0 || left >= len(*arr) {
    		return
    	}
    	hight := right
    	low   := left
    	base  := (*arr)[left]
    	if low < hight {
    		for ;low < hight; {
    			for ;low < hight && base <= (*arr)[hight]; {
    				hight--
    				break
    			}
    			(*arr)[low] = (*arr)[hight]
    			for ;low < hight && base >= (*arr)[low]; {
    				low++
    				break
    			}
    			(*arr)[hight] = (*arr)[low]
    		}
    		(*arr)[low] = base
    		quickSort(arr,left,low-1)
    		quickSort(arr,low+1,right)
    	}
    }
    

    组装

    
    quickSort(&codeArr,0,len(codeArr))
    codeArrSize := len(codeArr)
    for i:=0; i<codeArrSize ;i++ {
    	codeAtr := strconv.Itoa((int)(codeArr[i]))
    	index := 0
    	for _,line := range allRetLines {
    		if strings.Contains(line,"|"+codeAtr+"|") {
    			final = append(final,line)
    			// 减去一个,减少循环次数
    			//retLines = append(retLines[:index],retLines[index+1:]...)
    			index--
    			break
    		}
    		index++
    	}
    }
    
    // 生成文件
    fileName := "errorInfo.md"
    file,err := os.Create(fileName)
    defer file.Close()
    if err!=nil {
    	fmt.Println(err)
    }
    for _,line := range final {
    	fmt.Println(line)
    	file.WriteString(line+"
    ")
    }
    

    如果编程不是为了让复杂的问题简单化,那和机械学习有什么区别?

  • 相关阅读:
    抛开BlazeDS,自定义flex RPC
    设计模式学习03装饰器模式
    通过ANT生成MANIFEST.MF中的ClassPath属性
    Spring JDBCTemplate与Hiberante混用
    关于 两个 datetime 列的差别导致了运行时溢出
    在Wcf中使用Nhibernate (续)
    sql2005/sql2008 分页
    工行支付api查询asp.net C# 实现
    生成静态页面的vbscript
    Asp.net Mvc Post ID Bug
  • 原文地址:https://www.cnblogs.com/linguanh/p/9088495.html
Copyright © 2011-2022 走看看