自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

beego API開(kāi)發(fā)以及自動(dòng)化文檔

開(kāi)發(fā) 前端 開(kāi)發(fā)工具 自動(dòng)化
beego1.3版本已經(jīng)在上個(gè)星期發(fā)布了,但是還是有很多人不了解如何來(lái)進(jìn)行開(kāi)發(fā),也是在一步一步的測(cè)試中開(kāi)發(fā),期間QQ群里面很多人都問(wèn)我如何開(kāi)發(fā),我的業(yè)余時(shí)間實(shí)在是排的太滿了,實(shí)在是沒(méi)辦法一一回復(fù)大家,在這里和大家說(shuō)聲對(duì)不起,這兩天我又不斷的改進(jìn),寫了一個(gè)應(yīng)用示例展示如何使用beego開(kāi)發(fā)API已經(jīng)自動(dòng)化文檔和測(cè)試,這里就和大家詳細(xì)的解說(shuō)一下。

beego API開(kāi)發(fā)以及自動(dòng)化文檔

beego1.3版本已經(jīng)在上個(gè)星期發(fā)布了,但是還是有很多人不了解如何來(lái)進(jìn)行開(kāi)發(fā),也是在一步一步的測(cè)試中開(kāi)發(fā),期間QQ群里面很多人都問(wèn)我如何開(kāi)發(fā),我的業(yè)余時(shí)間實(shí)在是排的太滿了,實(shí)在是沒(méi)辦法一一回復(fù)大家,在這里和大家說(shuō)聲對(duì)不起,這兩天我又不斷的改進(jìn),寫了一個(gè)應(yīng)用示例展示如何使用beego開(kāi)發(fā)API已經(jīng)自動(dòng)化文檔和測(cè)試,這里就和大家詳細(xì)的解說(shuō)一下。

自動(dòng)化文檔開(kāi)發(fā)的初衷

我們需要開(kāi)發(fā)一個(gè)API應(yīng)用,然后需要和手機(jī)組的開(kāi)發(fā)人員一起合作,當(dāng)然我們首先想到的是文檔先行,我們也根據(jù)之前的經(jīng)驗(yàn)寫了我們需要的API原型文檔,我們還是根據(jù)github的文檔格式寫了一些漂亮的文檔,但是我們開(kāi)始擔(dān)心這個(gè)文檔如果兩邊不同步怎么辦?因?yàn)楫吘故窃臀臋n,變動(dòng)是必不可少的。手機(jī)組有一個(gè)同事之前在雅虎工作過(guò),他推薦我看一個(gè)swagger的應(yīng)用,看了swagger的標(biāo)準(zhǔn)和文檔化的要求,感覺(jué)太棒了,這個(gè)簡(jiǎn)直就是神器啊,通過(guò)swagger可以方便的查看API的文檔,同時(shí)使用API的用戶可以直接通過(guò)swagger進(jìn)行請(qǐng)求和獲取結(jié)果。所以我就開(kāi)始學(xué)習(xí)swagger的標(biāo)準(zhǔn),同時(shí)開(kāi)始進(jìn)行Go源碼的研究,通過(guò)Go里面的AST進(jìn)行源碼分析,針對(duì)comments解析,然后生成swagger標(biāo)準(zhǔn)的json格式,這樣最后就可以和swagger完美結(jié)合了。

這樣做的好處有三個(gè):

  1. 注釋標(biāo)準(zhǔn)化

  2. 有了注釋之后,以后API代碼維護(hù)相當(dāng)方便

  3. 根據(jù)注釋自動(dòng)化生成文檔,方便調(diào)用的用戶查看和測(cè)試

beego API應(yīng)用入門

請(qǐng)大家更新到最新的bee和beego

go get -u github.com/beego/bee
go get -u github.com/astaxie/beego

然后進(jìn)入到你的GOPATH/src目錄,執(zhí)行命令bee api bapi,進(jìn)入目錄cd bapi,執(zhí)行命令bee run -downdoc=true -docgen=true.請(qǐng)看下面我執(zhí)行的效果圖:

執(zhí)行完成之后就打開(kāi)瀏覽器,輸入U(xiǎn)RL:http://127.0.0.1:8080/swagger/swagger-1/

記住這里必須要用127.0.0.1,不能使用localhost,存在CORS問(wèn)題,Ajax跨域

我們的效果和應(yīng)用都出來(lái)了,很酷很炫吧,那這后面到底采用了怎么樣的一些技術(shù)呢?讓我們一步一步來(lái)講解這些細(xì)節(jié):

項(xiàng)目目錄

我們首先來(lái)了解一下bee api創(chuàng)建的應(yīng)用的目錄結(jié)構(gòu):

|-- bapi
|-- conf
|   `-- app.conf
|-- controllers
|   |-- object.go
|   `-- user.go
|-- docs
|   |-- doc.go
|   `-- docs.go
|-- lastupdate.tmp
|-- main.go
|-- models
|   |-- object.go
|   `-- user.go
|-- routers
|   |-- commentsRouter.go
|   `-- router.go
|-- swagger
`-- tests
    `-- default_test.go
  • main.go 是程序的統(tǒng)一入口文件

  • bapi 是生成的二進(jìn)制文件

  • conf 配置文件目錄,app.conf

  • controllers 控制器目錄,主要是邏輯的處理

  • models 是數(shù)據(jù)處理層的目錄

  • docs 是自動(dòng)化生成文檔的目錄

  • lastupdate.tmp 是一個(gè)注解路由的緩存文件

  • routers是路由目錄,主要涉及一些路由規(guī)則

  • swagger 是一個(gè)html靜態(tài)資源目錄,是通過(guò)bee自動(dòng)下載的,主要就是展示我們看到的界面及測(cè)試

  • test 目錄是針對(duì)應(yīng)用的測(cè)試用例,beego相比其他revel框架的好處之一就是無(wú)需啟動(dòng)應(yīng)用就可以執(zhí)行test case。

#p#

入口文件main

我們第一步先來(lái)看一下入口是怎么寫的?

 

  1. package main  
  2.  
  3. import (  
  4.     _ "bapi/docs" 
  5.     _ "bapi/routers" 
  6.  
  7.     "github.com/astaxie/beego" 
  8. )  
  9.  
  10. func main() {  
  11.     if beego.RunMode == "dev" {  
  12.         beego.DirectoryIndex = true 
  13.         beego.StaticDir["/swagger"] = "swagger" 
  14.     }  
  15.     beego.Run()  

 

入口文件就是一個(gè)普通的beego應(yīng)用的標(biāo)準(zhǔn)代碼,只是這里多了幾行代碼,把swagger加入了static,因?yàn)槲覀冃枰盐臋n服務(wù)器集成到beego的API應(yīng)用中來(lái)。然后增加了docs的初始化引入,和router的效果一樣。接下里我們先來(lái)看看自動(dòng)化API的路由是怎么設(shè)計(jì)的

namespace路由

自動(dòng)化路由才有了namespace來(lái)進(jìn)行設(shè)計(jì),而且注意兩點(diǎn),第一目前只支持namespace的路由支持自動(dòng)化文檔,第二只支持NSNamespace和NSInclude解析,而且是只能兩個(gè)層級(jí),先看我們的路由設(shè)置:

 

  1. func init() {  
  2.     ns := beego.NewNamespace("/v1",  
  3.         beego.NSNamespace("/object",  
  4.             beego.NSInclude(  
  5.                 &controllers.ObjectController{},  
  6.             ),  
  7.         ),  
  8.         beego.NSNamespace("/user",  
  9.             beego.NSInclude(  
  10.                 &controllers.UserController{},  
  11.             ),  
  12.         ),  
  13.     )  
  14.     beego.AddNamespace(ns)  

 

我們先來(lái)看一下這個(gè)代碼,首先是使用beego.NewNamespace創(chuàng)建一個(gè)ns的變量,這個(gè)變量里面其實(shí)就是存儲(chǔ)了一棵路由樹(shù),我們可以把這棵樹(shù)加到其他任意已經(jīng)存在的樹(shù)中去,這也就是namespace的好處,可以在任意的模塊中設(shè)計(jì)自己的namespace,然后把這個(gè)namespace加到其他的應(yīng)用中去,可以增加任意的前綴等。

這里我們分析一下NewNamespace這個(gè)函數(shù),這個(gè)函數(shù)的定義是這樣的NewNamespace(prefix string, params ...innnerNamespace) *Namespace,他的第一個(gè)參數(shù)就是前綴,第二個(gè)參數(shù)是innnerNamespace多參數(shù),那么我們來(lái)看看innnerNamespace的定義是什么:

 

  1. type innnerNamespace func(*Namespace) 

 

它是一個(gè)函數(shù),也就是只要是符合參數(shù)是*Namespace的函數(shù)都可以。那么在beego里面定義了如下的方法支持返回這個(gè)函數(shù)類型:

  • NSCond(cond namespaceCond) innnerNamespace

  • NSBefore(filiterList ...FilterFunc) innnerNamespace

  • NSAfter(filiterList ...FilterFunc) innnerNamespace

  • NSInclude(cList …ControllerInterface) innnerNamespace

  • NSRouter(rootpath string, c ControllerInterface, mappingMethods …string) innnerNamespace

  • NSGet(rootpath string, f FilterFunc) innnerNamespace

  • NSPost(rootpath string, f FilterFunc) innnerNamespace

  • NSDelete(rootpath string, f FilterFunc) innnerNamespace

  • NSPut(rootpath string, f FilterFunc) innnerNamespace

  • NSHead(rootpath string, f FilterFunc) innnerNamespace

  • NSOptions(rootpath string, f FilterFunc) innnerNamespace

  • NSPatch(rootpath string, f FilterFunc) innnerNamespace

  • NSAny(rootpath string, f FilterFunc) innnerNamespace

  • NSHandler(rootpath string, h http.Handler) innnerNamespace

  • NSAutoRouter(c ControllerInterface) innnerNamespace

  • NSAutoPrefix(prefix string, c ControllerInterface) innnerNamespace

  • NSNamespace(prefix string, params …innnerNamespace) innnerNamespace

因此我們可以在NewNamespace這個(gè)函數(shù)的第二個(gè)參數(shù)列表中使用上面的任意函數(shù)作為參數(shù)調(diào)用。

我們看一下路由代碼,這是一個(gè)層級(jí)嵌套的函數(shù),第一個(gè)參數(shù)是/v1,即為/v1開(kāi)頭的路由樹(shù),第二個(gè)參數(shù)是beego.NSNamespace,第三個(gè)參數(shù)也是beego.NSNamespace,也就是路由樹(shù)嵌套了路由樹(shù),而我們的beego.NSNamespace里面也是和NewNamespace一樣的參數(shù),第一個(gè)參數(shù)是路由前綴,第二個(gè)參數(shù)是slice參數(shù)。這里我們調(diào)用了beego.NSInclude來(lái)進(jìn)行注解路由的引入,這個(gè)函數(shù)是專門為注解路由設(shè)計(jì)的,我們可以看到這個(gè)設(shè)計(jì)里面我們沒(méi)有任何的路由信息,只是設(shè)置了前綴,那么這個(gè)的路由是在哪里設(shè)置的呢?我們接下來(lái)分析什么是注解路由。

注解路由

可能有些同學(xué)不了解什么是注解路由,也就是在Controller類上添加一個(gè)注釋讓框架給自動(dòng)添加Route,那么我們來(lái)看一下ObjectControllerUserController中怎么寫路由注解的:

 

  1. // Operations about object  
  2. type ObjectController struct {  
  3.     beego.Controller  
  4. }  
  5.  
  6. // @Title create  
  7. // @Description create object  
  8. // @Param   body        body    models.Object   true        "The object content"  
  9. // @Success 200 {string} models.Object.Id  
  10. // @Failure 403 body is empty  
  11. // @router / [post]  
  12. func (this *ObjectController) Post() {  
  13.     var ob models.Object  
  14.     json.Unmarshal(this.Ctx.Input.RequestBody, &ob)  
  15.     objectid := models.AddOne(ob)  
  16.     this.Data["json"] = map[string]string{"ObjectId": objectid}  
  17.     this.ServeJson()  

 

我們看到我們的每一個(gè)函數(shù)上面有大段的注釋,注解路由其實(shí)主要關(guān)注最后一行// @router / [post],這一行的注釋就是表示這個(gè)函數(shù)是注冊(cè)到路由/,支持方法是post。

和我們平常的時(shí)候使用beego.Router("/", &ObjectController{},"post:Post")的效果是一模一樣的,只是這一次框架幫你自動(dòng)注冊(cè)了這樣的路由,框架是如何來(lái)自動(dòng)注冊(cè)的呢?在應(yīng)用啟動(dòng)的時(shí)候,會(huì)判斷是否有調(diào)用NSInclude,在調(diào)用的時(shí)候,判斷RunMode是否是dev模式,是的話就會(huì)判斷是否之前有分析過(guò),并且分析對(duì)象目錄有更新,就使用Go的AST進(jìn)行源碼分析(當(dāng)然只分析NSInclude調(diào)用的controller),然后生成文件routers/commentsRouter.go,在該文件中會(huì)自動(dòng)注冊(cè)我們需要的路由信息。這樣就完成了整個(gè)的注解路由注冊(cè)。

注解路由是使用// @router 開(kāi)頭來(lái)申明的,而且必須放在你要注冊(cè)的函數(shù)的上方,和其他注釋@Title @Description的順序無(wú)關(guān),你可以放在第一行,也可以最后一行。有兩個(gè)參數(shù),第一個(gè)是需要注冊(cè)的路由,第二個(gè)是支持的方法。

路由可以支持beego支持的任意規(guī)則,例如/object/:key這樣的參數(shù)路由,也可以固定路由/object,也可以是正則路由/cms_:id([0-9]+).html

支持的HTTP方法必須使用[]中間是支持的方法列表,多個(gè)使用,分割,例如[post,get]。但是目前自動(dòng)化文檔只支持一個(gè)方法,也就是你多個(gè)的方法的時(shí)候無(wú)法做到RESTFul到同一個(gè)函數(shù),也不鼓勵(lì)你這樣設(shè)計(jì)的API。如果你API設(shè)計(jì)的時(shí)候支持了多個(gè)方法,那么文檔生成的時(shí)候默認(rèn)是取第一個(gè)作為支持的方法。

上面我們看到我們的方法上面有很多注釋,那么接下來(lái)就進(jìn)入我們今天的重點(diǎn):自動(dòng)化文檔

自動(dòng)化文檔

所謂的自動(dòng)化文檔,說(shuō)白了就是根據(jù)我們的注釋自動(dòng)的生成我們可以看得懂的漂亮文檔。我們上面也說(shuō)了寫注釋不僅僅是方便我們的代碼維護(hù),邏輯闡述,同時(shí)如果能夠自動(dòng)生成文檔,那么對(duì)于使用API的用戶來(lái)說(shuō)也是很大的幫助。那么如何進(jìn)行自動(dòng)化文檔生成呢?

我當(dāng)初看了swagger的展示效果之后,首先研究了他的spec,發(fā)現(xiàn)是一些json數(shù)據(jù),只要我們的API能夠生成swagger認(rèn)識(shí)的json就可以了,因此我的思路就來(lái)了,根據(jù)注釋生成swagger的JSON標(biāo)準(zhǔn)數(shù)據(jù)輸出。swagger提供了一個(gè)例子代碼:petstore 我就是根據(jù)這個(gè)例子的格式一步一步實(shí)現(xiàn)了現(xiàn)在的自動(dòng)化文檔。

#p#

首先第一步就是API的描述:

API文檔

我們看到在router.go里面頭部有一大段的注釋,這些注釋就是描述整個(gè)項(xiàng)目的一些信息:

 

  1. // @APIVersion 1.0.0  
  2. // @Title beego Test API  
  3. // @Description beego has a very cool tools to autogenerate documents for your API  
  4. // @Contact astaxie@gmail.com  
  5. // @TermsOfServiceUrl http://beego.me/  
  6. // @License Apache 2.0  
  7. // @LicenseUrl http://www.apache.org/licenses/LICENSE-2.0.html 

 

這里面主要是幾個(gè)標(biāo)志:

  • @APIVersion

  • @Title

  • @Description

  • @Contact

  • @TermsOfServiceUrl

  • @License

  • @LicenseUrl

這里每一個(gè)都不是必須的,你可以寫也可以不寫,后面就是一個(gè)字符串,你可以使用任意喜歡的字符進(jìn)行描述。我們來(lái)看一下生成的:http://127.0.0.1:8080/docs

  1. {  
  2.   "apiVersion""1.0.0",  
  3.   "swaggerVersion""1.2",  
  4.   "apis": [  
  5.     {  
  6.       "path""/object",  
  7.       "description""Operations about object\n" 
  8.     },  
  9.     {  
  10.       "path""/user",  
  11.       "description""Operations about Users\n" 
  12.     }  
  13.   ],  
  14.   "info": {  
  15.     "title""beego Test API",  
  16.     "description""beego has a very cool tools to autogenerate documents for your API",  
  17.     "contact""astaxie@gmail.com",  
  18.     "termsOfServiceUrl""http://beego.me/",  
  19.     "license""Url http://www.apache.org/licenses/LICENSE-2.0.html" 
  20.   }  

 

 

這是首次請(qǐng)求的一些信息,那么apis是怎么來(lái)的呢?這個(gè)就是根據(jù)你的namespace進(jìn)行源碼AST分析獲取的,所以目前只支持兩層的namespace嵌套,而且必須是兩層,第一層是baseurl,第二層就是嵌套的namespace的prefix。也就是上面的path信息,那么里面的description那里獲取的呢?請(qǐng)看控制器的注釋,

控制器注釋文檔

針對(duì)每一個(gè)控制我們可以增加注釋,用來(lái)描述該控制器的作用:

 

  1. // Operations about object  
  2. type ObjectController struct {  
  3.     beego.Controller  

 

這個(gè)注釋就是用來(lái)表示我們的每一個(gè)控制器API的作用,而控制器的函數(shù)里面的注釋就是用來(lái)表示調(diào)用的路由、參數(shù)、作用以及返回的信息。

 

  1. // @Title Get  
  2. // @Description find object by objectid  
  3. // @Param   objectId        path    string  true        "the objectid you want to get"  
  4. // @Success 200 {object} models.Object  
  5. // @Failure 403 :objectId is empty  
  6. // @router /:objectId [get]  
  7. func (this *ObjectController) Get() {  

 

從上面的注釋我們可以把我們的注釋分為以下類別:

  • @Title

    接口的標(biāo)題,用來(lái)標(biāo)示唯一性,唯一,可選

    格式:之后跟一個(gè)描述字符串

  • @Description

    接口的作用,用來(lái)描述接口的用途,唯一,可選

    格式:之后跟一個(gè)描述字符串

  • @Param

    請(qǐng)求的參數(shù),用來(lái)描述接受的參數(shù),多個(gè),可選

    格式:變量名 傳輸類型 類型 是否必須 描述

    傳輸類型:

    類型:

    變量名和描述是一個(gè)字符串

    是否必須:true 或者false

    • string

    • int

    • int64

    • 對(duì)象,這個(gè)地方大家寫的時(shí)候需要注意,需要是相對(duì)于當(dāng)前項(xiàng)目的路徑.對(duì)象,例如models.Object表示models目錄下的Object對(duì)象,這樣bee在生成文檔的時(shí)候會(huì)去掃描改對(duì)象并顯示給用戶改對(duì)象。

    • query 表示帶在url串里面?aa=bb&cc=dd

    • form 表示使用表單遞交數(shù)據(jù)

    • path 表示URL串中得字符,例如/user/{uid} 那么uid就是一個(gè)path類型的參數(shù)

    • body 表示使用raw body進(jìn)行數(shù)據(jù)的傳輸

    • header 表示通過(guò)header進(jìn)行數(shù)據(jù)的傳輸

  • @Success

    成功返回的code和對(duì)象或者信息

    格式:code 對(duì)象類型 信息或者對(duì)象路徑

    code:表示HTTP的標(biāo)準(zhǔn)status code,200 201等

    對(duì)象類型:{object}表示對(duì)象,其他默認(rèn)都認(rèn)為是字符類型,會(huì)顯示第三個(gè)參數(shù)給用戶,如果是{object}類型,那么就會(huì)去掃描改對(duì)象,并顯示給用戶

    對(duì)象路徑和上面Param中得對(duì)象類型一樣,使用路徑.對(duì)象的方式來(lái)描述

  • @Failure

    錯(cuò)誤返回的信息,

    格式: code 信息

    code:同上Success

    錯(cuò)誤信息:字符串描述信息

  • @router

    上面已經(jīng)描述過(guò)支持兩個(gè)參數(shù),第一個(gè)是路由,第二個(gè)表示支持的HTTP方法

那么我們通過(guò)上面的注釋會(huì)生成怎么樣的JSON信息呢?

 

  1. {  
  2.   "path""/object/{objectId}",  
  3.   "description""",  
  4.   "operations": [  
  5.     {  
  6.       "httpMethod""GET",  
  7.       "nickname""Get",  
  8.       "type""",  
  9.       "summary""find object by objectid",  
  10.       "parameters": [  
  11.         {  
  12.           "paramType""path",  
  13.           "name""objectId",  
  14.           "description""\"the objectid you want to get\"",  
  15.           "dataType""string",  
  16.           "type""",  
  17.           "format""",  
  18.           "allowMultiple"false,  
  19.           "required"true,  
  20.           "minimum"0,  
  21.           "maximum"0 
  22.         }  
  23.       ],  
  24.       "responseMessages": [  
  25.         {  
  26.           "code"200,  
  27.           "message""models.Object",  
  28.           "responseModel""Object" 
  29.         },  
  30.         {  
  31.           "code"403,  
  32.           "message"":objectId is empty",  
  33.           "responseModel""" 
  34.         }  
  35.       ]  
  36.     }  
  37.   ]  

上面闡述的這些描述都是可以使用一個(gè)或者多個(gè) '\t', '\n', '\v', '\f', '\r', ' ', U+0085 (NEL), U+00A0 (NBSP)進(jìn)行分割

#p#

對(duì)象自定義注釋

我們的對(duì)象定義如下:

 

  1. type Object struct {  
  2.     ObjectId   string  
  3.     Score      int64  
  4.     PlayerName string  

 

通過(guò)掃描生成的代碼如下:

 

  1. Object {  
  2. ObjectId (string, optional): ,  
  3. PlayerName (string, optional): ,  
  4. Score (int64, optional):  

 

我們發(fā)現(xiàn)字段都是optional的,而且沒(méi)有任何針對(duì)字段的描述,其實(shí)我們可以在對(duì)象定義里面增加如下的tag:

 

  1. type Object struct {  
  2.     ObjectId   string   `required:"true" description:"object id"`  
  3.     Score      int64        `required:"true" description:"players's scores"`  
  4.     PlayerName string   `required:"true" description:"plaers name, used in system"`  

 

而且如果你的對(duì)象tag里面如果存在json或者thrift描述,那么就會(huì)使用改描述作為字段名,即如下的代碼:

 

  1. type Object struct {  
  2.     ObjectId   string   `json:"object_id"`  
  3.     Score      int64        `json:"player_score"`  
  4.     PlayerName string   `json:"player_name"`  

 

就會(huì)輸出如下的文檔信息:

 

  1. Object {  
  2. object_id (string, optional): ,  
  3. player_score (string, optional): ,  
  4. player_name (int64, optional):  

常見(jiàn)錯(cuò)誤及問(wèn)題

  1. Q:bee沒(méi)有上面執(zhí)行的命令?

    A:請(qǐng)更新bee到最新版本,目前bee的版本是1.1.2,beego的版本是1.3.1

  2. Q:bee更新的時(shí)候出錯(cuò)了?

    A:第一可能是GFW的問(wèn)題,第二可能是你修改過(guò)了源碼,刪除重新下載,第三可能你升級(jí)了Go版本,你需要?jiǎng)h除GOPATH/pkg下的所有文件

  3. Q:下載swagger很慢?

    A:想辦法讓他變快,因?yàn)槲椰F(xiàn)在放在了github上面

  4. Q:文檔生成了,但是我沒(méi)辦法測(cè)試請(qǐng)求?

    A:你看看你訪問(wèn)的地址是不是和請(qǐng)求的URL是同一個(gè)地址,因?yàn)閟wagger是使用Ajax請(qǐng)求數(shù)據(jù)的,所以跨域的問(wèn)題,解決CORS的辦法就是保持域一致,包括URL和端口。

  5. Q:運(yùn)行的時(shí)候發(fā)生了未知的錯(cuò)誤?

    A:那就來(lái)提issue或者給我留言吧,我會(huì)盡力幫助你解決你遇到的問(wèn)題

原文出自:http://my.oschina.net/astaxie/blog/284072

責(zé)任編輯:林師授 來(lái)源: oschina博客
相關(guān)推薦

2014-02-17 15:15:56

ARIS文檔

2009-09-04 13:55:04

C#文檔自動(dòng)化

2024-04-30 08:00:00

人工智能自動(dòng)化文件處理

2023-07-12 15:41:18

2017-12-17 21:58:18

2021-04-01 13:25:46

Node命令工具

2020-01-16 09:00:00

AI人工智能ML

2021-10-14 06:52:47

自動(dòng)化開(kāi)發(fā)環(huán)境

2013-05-02 13:02:59

開(kāi)發(fā)環(huán)境自動(dòng)化團(tuán)隊(duì)

2021-11-23 12:11:59

PowershellLinuxDevOps

2018-07-13 06:46:35

數(shù)據(jù)中心自動(dòng)化微服務(wù)

2013-09-03 09:58:51

Web前端

2009-07-22 14:50:50

ibmdwWeb2.0Twitter

2009-10-09 17:50:59

VB Script開(kāi)發(fā)

2018-02-25 19:29:49

自動(dòng)化數(shù)字化IT

2021-10-13 10:06:49

自動(dòng)化IT安全

2010-12-06 09:59:58

2022-02-04 21:50:37

網(wǎng)絡(luò)安全自動(dòng)化

2020-04-29 11:28:54

智能自動(dòng)化機(jī)器人流程自動(dòng)化AI

2023-10-25 08:00:00

人工智能游戲開(kāi)發(fā)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)