goctl 技术系列 - 通过模板简化应用开发

简介: goctl 技术系列 - 通过模板简化应用开发

在现代软件开发中,数据驱动的应用程序逐渐成为主流。无论是构建动态网站、代码生成,生成配置文件,还是创建复杂的文档模板,数据驱动的方式都能显著提升开发效率和代码可维护性。在 Go 语言中,text/template 包提供了一种强大的方式来处理文本和数据的结合。

一、基础功能回顾

文本和空格

text/template 中,文本和空格的处理直接影响到最终输出的格式。模板中的文本会原样输出,而空格和换行符会保留。

package main
import (
    "os"
    "text/template"
)
func main() {
    const templateText = `Hello, {{.Name}}!
Welcome to the Go template tutorial.`
    tmpl, err := template.New("example").Parse(templateText)
    if err != nil {
       panic(err)
    }
    data := struct {
       Name string
    }{
       Name: "go-zero",
    }
    err = tmpl.Execute(os.Stdout, data)
    if err != nil {
       panic(err)
    }
}

讲解:在这个示例中,模板中的文本会被原样输出,包括空格和换行符。模板中的 {{.Name}} 会被替换为数据中的 Name 字段。

动作

注释 action

注释可以在模板中添加不输出的文本,使用 {{/* ... */}} 语法。

注意:/*后和*/前必须有一个空格。

package main
import (
    "os"
    "text/template"
)
func main() {
    const templateText = `Hello, {{.Name}}! {{/* This is a comment */}}`
    tmpl, err := template.New("example").Parse(templateText)
    if err != nil {
       panic(err)
    }
    data := struct {
       Name string
    }{
       Name: "go-zero",
    }
    err = tmpl.Execute(os.Stdout, data)
    if err != nil {
       panic(err)
    }
}

讲解:注释内容不会出现在最终输出中,可以用于在模板中添加说明或备注。

if action

if action 用于条件判断,如果条件为真,则输出其中的内容。

package main
import (
    "os"
    "text/template"
)
func main() {
    const templateText = `{{if .ShowTitle}}<h1>{{.Title}}</h1>{{end}}`
    tmpl, err := template.New("example").Parse(templateText)
    if err != nil {
       panic(err)
    }
    data := struct {
       ShowTitle bool
       Title     string
    }{
       ShowTitle: true,
       Title:     "Hello, go-zero!",
    }
    err = tmpl.Execute(os.Stdout, data)
    if err != nil {
       panic(err)
    }
}

讲解if action 检查 ShowTitle 是否为 true,如果是,则输出标题。

if-else action

if-else action 用于条件判断,如果条件为真,则输出 if 部分的内容,否则输出 else 部分的内容。

package main
import (
    "os"
    "text/template"
)
func main() {
    const templateText = `{{if .ShowTitle}}<h1>{{.Title}}</h1>{{else}}<h1>No Title</h1>{{end}}`
    tmpl, err := template.New("example").Parse(templateText)
    if err != nil {
       panic(err)
    }
    data := struct {
       ShowTitle bool
       Title     string
    }{
       ShowTitle: false,
       Title:     "Hello, go-zero!",
    }
    err = tmpl.Execute(os.Stdout, data)
    if err != nil {
       panic(err)
    }
}

讲解if-else action 检查 ShowTitle 是否为 true,如果是,则输出标题,否则输出 No Title

if-else-if action

if-else-if action 用于多个条件的判断。

package main
import (
    "os"
    "text/template"
)
func main() {
    const templateText = `{{if .ShowTitle}}<h1>{{.Title}}</h1>{{else if .ShowSubtitle}}<h2>{{.Subtitle}}</h2>{{else}}<p>No Title or Subtitle</p>{{end}}`
    tmpl, err := template.New("example").Parse(templateText)
    if err != nil {
       panic(err)
    }
    data := struct {
       ShowTitle    bool
       ShowSubtitle bool
       Title        string
       Subtitle     string
    }{
       ShowTitle:    false,
       ShowSubtitle: true,
       Title:        "Hello, go-zero!",
       Subtitle:     "Hi, go-zero!",
    }
    err = tmpl.Execute(os.Stdout, data)
    if err != nil {
       panic(err)
    }
}

讲解if-else-if action 检查 ShowTitle 是否为 true,如果是,则输出标题<h1>{{Hello, go-zero!}}</h1>;否则检查 ShowSubtitle 是否为 true,如果是,则输出副标题;否则输出 <h2>Hi, go-zero!</h2>

字段链式调用

字段链式调用用于访问嵌套的结构体字段。

package main
import (
    "os"
    "text/template"
)
func main() {
    const templateText = `Name: {{.Repo.Name}}, Address: {{.Repo.Address}}`
    tmpl, err := template.New("example").Parse(templateText)
    if err != nil {
       panic(err)
    }
    data := struct {
       Repo struct {
          Name    string
          Address string
       }
    }{
       Repo: struct {
          Name    string
          Address string
       }{
          Name:    "go-zero",
          Address: "https://github.com/zeromicro/go-zero",
       },
    }
    err = tmpl.Execute(os.Stdout, data)
    if err != nil {
       panic(err)
    }
}

讲解:字段链式调用通过 . 操作符访问嵌套结构体中的字段,例如 {{.Repo.Name}}{{.Repo.Address}}

二、中级功能

range 数组

range action 用于遍历数组或切片。

package main
import (
    "os"
    "text/template"
)
func main() {
    const templateText = `
<ul>
{{range .Projects}}<li>{{.}}</li>{{end}}
</ul>
`
    tmpl, err := template.New("example").Parse(templateText)
    if err != nil {
       panic(err)
    }
    data := struct {
       Projects []string
    }{
       Projects: []string{"go-zero", "goctl"},
    }
    err = tmpl.Execute(os.Stdout, data)
    if err != nil {
       panic(err)
    }
}

讲解range action 遍历 Projects 切片中的每个元素,并生成一个包含每个元素的列表项 (<li>)。

range map

range action 也可以用于遍历 map。

package main
import (
    "os"
    "text/template"
)
func main() {
    const templateText = `
<ul>
{{range $key, $value := .Projects}}<li>{{$key}}: {{$value}}</li>{{end}}
</ul>
`
    tmpl, err := template.New("example").Parse(templateText)
    if err != nil {
       panic(err)
    }
    data := struct {
       Projects map[string]string
    }{
       Projects: map[string]string{"Name": "go-zero", "Address": "https://github.com/zeromicro/go-zero"},
    }
    err = tmpl.Execute(os.Stdout, data)
    if err != nil {
       panic(err)
    }
}

讲解range map action 遍历 Projects 切片中的每个key, value 元素,其变量以 $ 开头。

break action

range动作中可以通过 break 来中断循环。

package main
import (
    "os"
    "text/template"
)
func main() {
    const templateText = `
<ul>{{range .Items}}
  {{if eq . "Item 3"}}{{break}}{{end}}<li>{{.}}</li>{{end}}
</ul>`
    tmpl, err := template.New("example").Parse(templateText)
    if err != nil {
       panic(err)
    }
    data := struct {
       Items []string
    }{
       Items: []string{"Item 1", "Item 2", "Item 3"},
    }
    err = tmpl.Execute(os.Stdout, data)
    if err != nil {
       panic(err)
    }
}

讲解:通过{{break}},可以打断range循环操作,如上结果输出为

<ul>
  <li>Item 1</li>
  <li>Item 2</li>
  
</ul>

continue action

range动作中可以通过 continue 来跳过当次循环。

package main
import (
    "os"
    "text/template"
)
func main() {
    const templateText = `<ul>{{range .Items}}
  {{if eq . "Item 2"}}{{continue}}{{else}}<li>{{.}}</li>{{end}}{{end}}
</ul>`
    tmpl, err := template.New("example").Parse(templateText)
    if err != nil {
       panic(err)
    }
    data := struct {
       Items []string
    }{
       Items: []string{"Item 1", "Item 2", "Item 3"},
    }
    err = tmpl.Execute(os.Stdout, data)
    if err != nil {
       panic(err)
    }
}

讲解:通过 continue 动作,在模板中遇到特定条件时可以跳过当前循环。以上模板输出为

<ul>
  <li>Item 1</li>
  
  <li>Item 3</li>
</ul>

子模板

子模板允许将模板划分为多个部分,并在主模板中引用子模板。

package main
import (
    "os"
    "text/template"
)
func main() {
    const (
       headerTemplate = `{{define "header"}}<html><head><title>{{.Title}}</title></head><body>{{end}}`
       footerTemplate = `{{define "footer"}}</body></html>{{end}}`
       bodyTemplate   = `{{define "body"}}<h1>{{.Heading}}</h1><p>{{.Content}}</p>{{end}}`
       mainTemplate   = `{{template "header" .}} {{template "body" .}} {{template "footer" .}}`
    )
    tmpl := template.Must(template.New("main").Parse(headerTemplate + footerTemplate + bodyTemplate + mainTemplate))
    data := struct {
       Title   string
       Heading string
       Content string
    }{
       Title:   "Welcome",
       Heading: "Hello, go-zero!",
       Content: "This is a simple example of nested templates.",
    }
    if err := tmpl.Execute(os.Stdout, data); err != nil {
       panic(err)
    }
}

讲解:通过定义 headerfooterbody 子模板,并在主模板中使用 {{template "header" .}} 等方式引用子模板,可以实现模板的模块化和复用。

with action

with action 设置一个新的数据上下文,并在该上下文中执行模板。

package main
import (
    "os"
    "text/template"
)
func main() {
    const templateText = `{{with .User}}<p>Name: {{.Name}}</p>
<p>Age: {{.Age}}</p>
{{end}}
`
    tmpl, err := template.New("example").Parse(templateText)
    if err != nil {
       panic(err)
    }
    data := struct {
       User struct {
          Name string
          Age  int
       }
    }{
       User: struct {
          Name string
          Age  int
       }{
          Name: "John",
          Age:  30,
       },
    }
    if err := tmpl.Execute(os.Stdout, data); err != nil {
       panic(err)
    }
}

讲解with action 将 User 结构体设置为新的数据上下文{{.}},从而简化了模板中对嵌套字段的访问。

三、高级功能

内置函数

Go 模板提供了一些常用的内置函数,可以直接在模板中使用。

package main
import (
        "os"
        "text/template"
)
func main() {
        const templateText = `
<p>Upper: {{.Name | upper}}</p>
<p>Len: {{len .Name}}</p>
`
        funcMap := template.FuncMap{
                "upper": strings.ToUpper,
        }
        tmpl, err := template.New("example").Funcs(funcMap).Parse(templateText)
        if err != nil {
                panic(err)
        }
        data := struct {
                Name string
        }{
                Name: "John",
        }
        if err := tmpl.Execute(os.Stdout, data); err != nil {
                panic(err)
        }
}

讲解:示例中使用了 len 内置函数和自定义的 upper 函数。内置函数可以直接在模板中使用,而自定义函数需要通过 template.FuncMap 注册。

自定义函数

自定义函数允许开发者扩展模板的功能。

package main
import (
    "os"
    "strings"
    "text/template"
)
func main() {
    funcMap := template.FuncMap{
       "repeat": func(s string, count int) string {
          return strings.Repeat(s, count)
       },
    }
    const templateText = `{{repeat .Name 3}}`
    tmpl, err := template.New("example").Funcs(funcMap).Parse(templateText)
    if err != nil {
       panic(err)
    }
    data := struct {
       Name string
    }{
       Name: "Go",
    }
    if err := tmpl.Execute(os.Stdout, data); err != nil {
       panic(err)
    }
}

讲解:自定义函数 repeat 使用 strings.Repeat 函数重复字符串,并通过 template.FuncMap 注册后在模板中使用。

管道

管道 (|) 允许将数据传递给多个函数进行处理。

package main
import (
    "os"
    "strings"
    "text/template"
)
func main() {
    funcMap := template.FuncMap{
       "trim":  strings.TrimSpace,
       "upper": strings.ToUpper,
    }
    const templateText = `{{.Name | trim | upper}}`
    tmpl, err := template.New("example").Funcs(funcMap).Parse(templateText)
    if err != nil {
       panic(err)
    }
    data := struct {
       Name string
    }{
       Name: "  go  ",
    }
    if err := tmpl.Execute(os.Stdout, data); err != nil {
       panic(err)
    }
}

讲解:通过管道操作符 |,数据 {{.Name}} 依次传递给 trimupper 函数进行处理,实现了多步骤的数据处理。

四、综合使用

通过上述基础功能、中级功能和高级功能的介绍,我们可以构建一个功能完整的示例应用。该示例将展示如何使用 text/template 构建一个动态生成 HTML 页面的简单 Web 应用。

package main
import (
        "html/template"
        "log"
        "net/http"
        "strings"
)
// 定义数据结构
type PageData struct {
        Title   string
        Header  string
        Content string
        Items   []string
}
// 自定义函数
func trim(str string) string {
        return strings.TrimSpace(str)
}
func upper(str string) string {
        return strings.ToUpper(str)
}
func main() {
        // 创建模板函数映射
        funcMap := template.FuncMap{
                "trim":  trim,
                "upper": upper,
        }
        // 定义模板内容
        const baseTemplate = `
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{block "title" .}}Default Title{{end}}</title>
</head>
<body>
    {{template "header" .}}
    {{block "content" .}}{{end}}
    {{template "footer" .}}
</body>
</html>
`
        const headerTemplate = `
{{define "header"}}
<header>
    <h1>{{.Header | upper}}</h1>
</header>
{{end}}
`
        const footerTemplate = `
{{define "footer"}}
<footer>
    <p>Default Footer Content</p>
</footer>
{{end}}
`
        const contentTemplate = `
{{define "content"}}
<main>
    <p>{{.Content}}</p>
    <ul>
    {{range .Items}}
        {{template "item" .}}
    {{else}}
        <li>No items found</li>
    {{end}}
    </ul>
</main>
{{end}}
`
        const itemTemplate = `
{{define "item"}}
<li>{{. | trim | upper}}</li>
{{end}}
`
        // 解析所有模板
        tmpl := template.Must(template.New("base").Funcs(funcMap).Parse(baseTemplate))
        tmpl = template.Must(tmpl.Parse(headerTemplate))
        tmpl = template.Must(tmpl.Parse(footerTemplate))
        tmpl = template.Must(tmpl.Parse(contentTemplate))
        tmpl = template.Must(tmpl.Parse(itemTemplate))
        http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
                data := PageData{
                        Title:   "Go Template Best Practices",
                        Header:  "Welcome to Go Templates",
                        Content: "This is an example demonstrating various features of Go templates.",
                        Items:   []string{"Item 1", "Item 2", "Item 3"},
                }
                if err := tmpl.ExecuteTemplate(w, "base", data); err != nil {
                        http.Error(w, err.Error(), http.StatusInternalServerError)
                }
        })
        log.Println("Server started at :8080")
        http.ListenAndServe(":8080", nil)
}

主程序 (main.go)

  • 定义数据结构PageData 结构体用于传递数据给模板。
  • 自定义函数:定义了 trimupper 两个自定义函数,用于字符串处理。
  • 创建模板函数映射:使用 template.FuncMap 创建函数映射,以便在模板中使用自定义函数。
  • 定义模板内容:将模板内容作为字符串嵌入到 Go 代码中,包括基础模板和各个子模板。
  • 解析所有模板:使用 template.Musttemplate.New 解析所有模板字符串,并将函数映射添加到模板。
  • 处理 HTTP 请求:在 HTTP 处理函数中,创建 PageData 实例并传递给模板,通过 ExecuteTemplate 方法渲染模板并输出到浏览器。

基础模板 (baseTemplate)

  • block 动作:使用 block 动作定义可重写的块,如 titlecontent。子模板可以重写这些块以实现模板继承。
  • template 动作:使用 template 动作包含其他模板(如 headerfooter),实现模板的模块化和复用。

头部模板 (headerTemplate)

  • 定义模板:使用 define 动作定义一个可重用的模板块 header
  • 管道操作符:使用管道操作符将 Header 字段的值传递给 upper 函数,转换为大写。

页脚模板 (footerTemplate)

  • 定义模板:定义一个简单的页脚模板,包含固定的内容。

内容模板 (contentTemplate)

  • range 动作:使用 range 动作遍历 Items 列表,为每个项目渲染 item 模板。如果列表为空,则显示 else 分支中的内容。
  • 包含模板:使用 template 动作包含 item 模板,实现列表项的模块化渲染。

列表项模板 (itemTemplate)

  • 定义模板:定义一个用于渲染单个列表项的模板。
  • 管道操作符:使用管道操作符将列表项值依次传递给 trimupper 函数,去除空格并转换为大写。

运行示例

  1. 将上述代码保存到 main.go 文件中。
  2. 运行 main.go 程序。
  3. 打开浏览器并访问 http://localhost:8080,查看渲染结果。

五、实际应用

最近在写一个 goctl web 的应用来构造 api 文件,通过前端 form 表单数据来对 API 模板进行数据渲染,模板内容如下:

// generated by goctl.
syntax = "v1"
{{.types}}
{{range $group := .groups}}{{/* range route groups */}}
{{/* generate @server block */}}
{{with $group.server}}@server(
    {{if .jwt}}jwt: JWTAuth{{end}}
    {{if .prefix}}prefix: {{.prefix}}{{end}}
    {{if .group}}group: {{.group}}{{end}}
    {{if .timeout}}timeout: {{.timeout}}{{end}}
    {{if .middleware}}middleware: {{.middleware}}{{end}}
    {{if .maxBytes}}maxBytes: {{.maxBytes}}{{end}}
){{end}}
{{/* generate service block */}}
{{with $group.service}}service {{.name}}{
{{ $routes := .routes}} {{/* define a variable to block the follows range block */}}
{{range  $idx, $route := .routes}}{{/* releace $route to dot */}}
    @handler {{$route.handlerName}}
    {{$route.method}} {{$route.path}} {{if $route.request}}({{$route.request}}){{end}} {{if $route.response}}returns ({{$route.response}}){{end}}{{if lessThan $idx (len $routes)}}
{{end}}
{{end}}}{{end}}
{{end}}

模板头部

// generated by goctl.
syntax = "v1"
{{.types}}

// generated by goctl.:注释,表示这个文件是由 goctl 工具生成的。

syntax = "v1":定义了语法版本为 v1

{{.types}}:插入模板上下文中的结构体数据。

遍历分组(range

{{range $group := .groups}}{{/* range route groups */}}

{{range $group := .groups}}:遍历模板上下文中的 groups 路由分组列表,每个路由分组 group 被赋值给变量 $group

生成 @server

{{with $group.server}}@server(
    {{if .jwt}}jwt: JWTAuth{{end}}
    {{if .prefix}}prefix: {{.prefix}}{{end}}
    {{if .group}}group: {{.group}}{{end}}
    {{if .timeout}}timeout: {{.timeout}}{{end}}
    {{if .middleware}}middleware: {{.middleware}}{{end}}
    {{if .maxBytes}}maxBytes: {{.maxBytes}}{{end}}
){{end}}

{{with $group.server}}:进入 $group.server 子模板上下文,将$group.server重新赋值到{{.}},减少冗长的链式调用。

{{if .jwt}}jwt: JWTAuth{{end}}:如果 jwt 存在,则生成 jwt: JWTAuth,这里用到了条件动作,其他几个 if 条件类似。

{{end}}:结束 with 动作。

生成 service

{{/* generate service block */}}
{{with $group.service}}service {{.name}}{
{{ $routes := .routes}} {{/* define a variable to block the follows range block */}}

{{/\* generate service block \*/}}用到了注释动作,记得注释的/* 后和 */要有空格。

{{with $group.service}}:进入 $group.service 子模板上下文,将 $group.service 赋值到{{.}},减少冗长的链式调用。

service {{.name}}{:生成 service <name>{,其中 <name>service 的名称。

{{ $routes := .routes}}:定义一个临时变量 $routes 保存 routes 列表,用于突破下文的 range 上下文。

遍历 routes 列表并生成每个路由

{{range  $idx, $route := .routes}}{{/* releace $route to dot */}}
    @handler {{$route.handlerName}}
    {{$route.method}} {{$route.path}} {{if $route.request}}({{$route.request}}){{end}} {{if $route.response}}returns ({{$route.response}}){{end}}{{if lessThan $idx (len $routes)}}
{{end}}
{{end}}}{{end}}

{{range $idx, $route := .routes}}:遍历 routes 列表,每个 route 被赋值给 $route,索引被赋值给 $idx

@handler {{$route.handlerName}}:生成 @handler <handlerName>,其中 <handlerName> 是处理器名称。

{{$route.method}} {{$route.path}}:生成 <method> <path>,其中 <method> 是 HTTP 方法,<path> 是路径。

{{if $route.request}}({{$route.request}}){{end}}:如果 request 存在,则生成 (<request>)

{{if $route.response}}returns ({{$route.response}}){{end}}:如果 response 存在,则生成 returns (<response>)

{{if lessThan $idx (len $routes)}}:检查当前索引是否小于 routes 列表的长度。lessThan 用到自定义函数功能。

如下是模板数据填充的部分代码

var data []KV
for _, group := range mergedReq.List {
    var groupData = KV{}
    var hasServer bool
    var server = KV{}
    if group.Jwt {
       hasServer = true
       server["jwt"] = group.Jwt
    }
    if len(group.Prefix) > 0 {
       hasServer = true
       server["prefix"] = group.Prefix
    }
    if len(group.Group) > 0 {
       hasServer = true
       server["group"] = group.Group
    }
    if group.Timeout > 0 {
       hasServer = true
       server["timeout"] = fmt.Sprintf("%dms", group.Timeout)
    }
    if len(group.Middleware) > 0 {
       hasServer = true
       server["middleware"] = group.Middleware
    }
    if group.MaxBytes > 0 {
       hasServer = true
       server["maxBytes"] = group.MaxBytes
    }
    if hasServer {
       groupData["server"] = server
    }
    var routesData []KV
    for _, route := range group.Routes {
       var request, response string
       if len(route.RequestBody) > 0 {
          request = l.generateTypeName(route, true)
       }
       if !util.IsEmptyStringOrWhiteSpace(route.ResponseBody) {
          response = l.generateTypeName(route, false)
       }
       routesData = append(routesData, KV{
          "handlerName": l.generateHandlerName(route),
          "method":      strings.ToLower(route.Method),
          "path":        route.Path,
          "request":     request,
          "response":    response,
       })
    }
    var service = KV{
       "name":   req.Name,
       "routes": routesData,
    }
    groupData["service"] = service
    data = append(data, groupData)
}
t, err := template.New("api").Funcs(map[string]any{
    "lessThan": func(idx int, length int) bool {
       return idx < length-1
    },
}).Parse(apiTemplate)
if err != nil {
    return nil, err
}
tps, err := l.generateTypes(mergedReq.List)
if err != nil {
    return nil, err
}
var typeString string
if len(tps) > 0 {
    typeString = strings.Join(tps, "\n\n")
}
w := bytes.NewBuffer(nil)
err = t.Execute(w, map[string]any{
    "types":  typeString,
    "groups": data,
})
if err != nil {
    return nil, err
}
formatWriter := bytes.NewBuffer(nil)
err = format.Source(w.Bytes(), formatWriter)
if err != nil {
    return nil, err
}

最后在 web 页面上展示如图,图中右边的 api 内容就是由模板渲染出来的。

https://gen.go-zero.dev/

aef497707f9ebd0f70e709725bee4abf.png

六、总结

本文介绍了 Go 语言中 text/template 包的基础功能、中级功能和高级功能,并通过具体示例讲解了每个功能的使用方法。通过这些示例,我们可以看到 text/template 包的强大功能以及在实际开发中的广泛应用。希望本文能帮助您更好地理解和使用 text/template,构建出更加灵活和高效的数据驱动应用。

项目地址

https://github.com/zeromicro/go-zero

相关文章
|
6月前
|
敏捷开发 弹性计算 中间件
平台即服务(PaaS):简化开发与部署的新篇章
【6月更文挑战第21天】PaaS简化了应用开发与部署,提供资源池化、自动化管理及丰富的开发工具,助力企业降低成本、提高效率和系统稳定性。它支持敏捷开发、加速产品上市,改善用户体验,并推动创新,成为现代软件开发的关键。
|
2月前
|
Java 数据处理 Android开发
深入解析移动应用开发:从基础到高级
【10月更文挑战第2天】本文将带你深入探索移动应用开发的世界,从基础知识到高级技术,我们将一一解析。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和知识。我们将从移动操作系统的选择开始,然后深入探讨移动应用开发的流程和技术,最后还将分享一些实用的代码示例。让我们一起开启这场移动应用开发的旅程吧!
|
4月前
|
机器学习/深度学习 数据可视化 数据挖掘
构建可复用的 Jupyter 模板和插件:提高工作效率的最佳实践
【8月更文第29天】Jupyter Notebook 是一个广泛使用的交互式计算环境,支持多种编程语言。它不仅用于数据分析、可视化和机器学习项目,也是教学和科研的理想工具。然而,随着使用频率的增加,重复编写相似的代码和设置变得既耗时又低效。通过创建可复用的 Jupyter 模板和插件,我们可以显著提高工作效率。
95 1
|
5月前
|
数据可视化 数据挖掘 数据库
低代码开发全解析核心功能及其优势
低代码开发平台采用图形界面与预构建组件加速软件开发,降低技术门槛与成本,并支持敏捷迭代与快速部署。其核心功能包括可视化建模、预构建组件库、业务流程自动化、集成与连接性、多平台应用开发、数据分析报告、版本控制与协作、测试调试工具、安全性与合规性及快速部署更新。优点体现在提升开发速度与效率、降低成本、加强团队合作及提高灵活性与可扩展性。选择平台时需明确需求、评估功能与灵活性、考虑易用性、集成能力、安全性与合规性及成本与定价模型。例如,Zoho Creator作为成熟平台,拥有丰富的经验和广泛的应用案例。低代码开发已成为企业数字化转型的关键工具。
108 13
|
7月前
|
人工智能 API 开发工具
基于流程编排工具低代码搭建大模型应用
流程编排是一种面向开发者的可视化开发工具,支持LLM、API、脚本等类型节点,旨在简化接入大型语言模型(LLM)流程,同时提供应用流程的全生命周期管理,包括流程的编排、试验、部署等,为开发者提供自定义AI应用开发一站式服务。
|
数据可视化 物联网 数据挖掘
应用开发组件功能介绍(一)
应用开发组件功能介绍(一)
284 0
|
数据可视化 前端开发 安全
应用开发组件功能介绍(三)
应用开发组件功能介绍(三)
300 0
|
数据可视化 物联网 机器人
应用开发组件功能介绍(二)
应用开发组件功能介绍(二)
332 0
|
监控 数据可视化 搜索推荐
只需简单编写配置文件即可构建企业级应用程序的低代码平台
一套可视化建模,描述式编程的企业应用程序开发平台。只需简单的点击鼠标,几乎任何人都可以创建功能强大的企业应用程序,实现业务流程自动化。企业创建的应用程序可以部署在移动,平板电脑和Web上,创建的应用程序可以很简单,也可以非常复杂,并且可以连接到几乎任何数据源。
只需简单编写配置文件即可构建企业级应用程序的低代码平台
|
数据可视化 安全 数据管理
低代码快开平台:Web可视化开发+强大流程+源码+多端支持
本套低代码PaaS平台是一款基于 Salesforce Platform 的开源替代方案,支持多种企业应用场景,包括但不限于CRM、ERP、OA、BI、IoT、大数据等。无论是传统企业还是新兴企业,都可以使用管理后台快速构建自己的应用程序和流程。
332 0
低代码快开平台:Web可视化开发+强大流程+源码+多端支持
下一篇
DataWorks