[golang gin框架] 2.Gin HTML模板渲染以及模板语法,自定义模板函数,静态文件服务

news2024/11/14 1:16:15

一.Gin HTML 模板渲染

  1. 全部模板放在一个目录里面的配置方法

首先在项目根目录新建 templates 文件夹,然后在文件夹中新建 对应的index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>这是一个 html 模板</h1>
<h3>{{.title}}</h3>
</body>
</html>

2.Gin 框架中使用 c.HTML 可以渲染模板,渲染模板前需要使用 LoadHTMLGlob()或者LoadHTMLFiles()方法加载模板

package main
import ( 
    "net/http"
    "github.com/gin-gonic/gin"
)

func main() {
    //初始化路由
    router := gin.Default()
    //加载templates中所有模板文件, 使用不同目录下名称相同的模板,注意:一定要放在配置路由之前才得行
    router.LoadHTMLGlob("templates/*")
    //router.LoadHTMLFiles("templates/template1.html", "templates/template2.html")

    router.GET("/", func(c *gin.Context) {
        c.HTML(http.StatusOK, "index.html", gin.H{ 
            "title": "首页", 
        })
    })
    
    router.GET("/", func(c *gin.Context) {
        c.HTML(http.StatusOK, "index.html", map[string]interface{}{ 
            "title": "前台首页"
        })
    })
    router.Run(":8080")
}
  1. 模板放在不同目录里面的配置方法

目录如下:
Gin 框架中如果不同目录下面有同名模板的话我们需要使用下面方法加载模板
注意:定义模板的时候需要通过 define 定义名称
//templates/admin/index.html
<!-- 相当于给模板定义一个名字 define end 成对出现-->

{{ define "admin/index.html" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>后台模板</h1>
<h3>{{.title}}</h3>
</body>
</html>
{{ end }}
templates/default/index.html
<!-- 相当于给模板定义一个名字 define end 成对出现-->

{{ define "default/index.html" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>前台模板</h1>
<h3>{{.title}}</h3>
</body>
</html>
{{end}}
代码如下:
package main
import ( "net/http"
"github.com/gin-gonic/gin"
)
func main() {
    router := gin.Default()
    router.LoadHTMLGlob("templates/**/*")
    router.GET("/", func(c *gin.Context) {
        c.HTML(http.StatusOK, "default/index.html", gin.H{ 
            "title": "前台首页", 
        })
    })
    router.GET("/admin", func(c *gin.Context) {
        c.HTML(http.StatusOK, "admin/index.html", gin.H{ 
            "title": "后台首页", 
        })
    })
    router.Run(":8080")
}
注意:如果模板在多级目录里面的话需要这样配置 r.LoadHTMLGlob("templates/**/**/*") /**
表示目录

3.Gin 模板基本语法

(1)、{{.}} 输出数据

模板语法都包含在{{和}}中间,其中{{.}}中的点表示当前对象,当传入一个结构体对象时,可以根据.来访问结构体的对应字段。例如:

package main

import ( 
    "net/http"
    "github.com/gin-gonic/gin"
)

type UserInfo struct {
    Name string
    Gender string
    Age int
}
func main() {
    router := gin.Default()
    router.LoadHTMLGlob("templates/**/*")
    user := UserInfo{
        Name: "张三",
        Gender: "男", 
        Age: 18, 
    }
    router.GET("/", func(c *gin.Context) {
        c.HTML(http.StatusOK, "default/index.html", map[string]interface{}{ 
            "title": "前台首页", 
            "user": user, 
        })
    })
    router.Run(":8080")
}

模板 <!-- 相当于给模板定义一个名字 define end 成对出现-->

{{ define "default/index.html" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>前台模板</h1>
<h3>{{.title}}</h3>
<h4>{{.user.Name}}</h4>
<h4>{{.user.Age}}</h4>
</body>
</html>
{{end}}

(2).注释

{{/* a comment */}}
注释,执行时会忽略,可以多行。注释不能嵌套,并且必须紧贴分界符始止

(3).变量

还可以在模板中声明变量,用来保存传入模板的数据或其他语句生成的结果,具体语法
如下:
<h4>{{$obj := .title}}</h4>
<h4>{{$obj}}</h4>

(4).移除空格

有时候在使用模板语法的时候会不可避免的引入一下空格或者换行符,这样模板最终渲
染出来的内容可能就和想的不一样,这个时候可以使用{{-语法去除模板内容左侧的所有
空白符号, 使用-}}去除模板内容右侧的所有空白符号,例如:
{{- .Name -}}
注意:-要紧挨{{和}},同时与模板值之间需要使用空格分隔

(5).比较函数

布尔函数会将任何类型的零值视为假,其余视为真.
下面是定义为函数的二元比较运算的集合

eq

如果 arg1 == arg2 则返回真

ne

如果 arg1 != arg2 则返回真

lt

如果 arg1 < arg2 则返回真

le

如果 arg1 <= arg2 则返回真

gt

如果 arg1 > arg2 则返回真

ge

如果 arg1 >= arg2 则返回真

(6).条件判断

Go 模板语法中的条件判断有以下几种
{{if pipeline}} 
    T1 
{{end}}

{{if pipeline}} 
    T1 
{{else}} 
    T0 
{{end}}

{{if pipeline}} 
    T1 
{{else if pipeline}} 
    T0 
{{end}}

{{if gt .score 60}}
    及格
{{else}}
    不及格
{{end}}

{{if gt .score 90}}
    优秀
{{else if gt .score 60}}
    及格
{{else}}
    不及格
{{end}}

(6).range

Go 的模板语法中使用 range 关键字进行遍历,有以下两种写法,其中 pipeline 的值必须是数
组、切片、字典或者通道
{{range $key,$value := .obj}}
    {{$value}}
{{end}}
如果 pipeline 的值其长度为 0,不会有任何输出
{{$key,$value := .obj}}
    {{$value}}
{{else}}
    pipeline 的值其长度为 0
{{end}}
如果 pipeline 的值其长度为 0,则会执行 T0
router.GET("/", func(c *gin.Context) {
    c.HTML(http.StatusOK, "default/index.html", map[string]interface{}{ 
        "hobby": []string{
            "吃饭", "睡觉", "写代码"
            }, 
        })
})
{{range $key,$value := .hobby}}
    <p>{{$value}}</p>
{{end}}

(7).with

user := UserInfo{
    Name: "张三", 
    Gender: "男", 
    Age: 18, 
}
router.GET("/", func(c *gin.Context) {
    c.HTML(http.StatusOK, "default/index.html", map[string]interface{}{ 
        "user": user, 
    })
})

以前要输出数据:

<h4>{{.user.Name}}</h4>
<h4>{{.user.Gender}}</h4>
<h4>{{.user.Age}}</h4>

现在要输出数据:

{{with .user}}
    <h4>姓名:{{.Name}}</h4>
    <h4>性别:{{.Gender}}</h4>
    <h4>年龄:{{.Age}}</h4>
{{end}}
相当于 var .=.user

(8).预定义函数

执行模板时,函数从两个函数字典中查找:首先是模板函数字典,然后是全局函数字典,一
般不在模板内定义函数,而是使用 Funcs 方法添加函数到模板里,预定义的全局函数如下:

and

函数返回它的第一个 empty 参数或者最后一个参数;

就是说"and x y"等价于"if x then y else x";所有参数都会执行

or

返回第一个非 empty 参数或者最后一个参数;

亦即"or x y"等价于"if x then x else y";所有参数都会执行

not

返回它的单个参数的布尔值的否定

len

返回它的参数的整数类型长度

index

执行结果为第一个参数以剩下的参数为索引/键指向的值;

如"index x 1 2 3"返回 x[1][2][3]的值;每个被索引的主体必须是数组、切片或者字典

print

即 fmt.Sprint

printf

即 fmt.Sprintf

println

即 fmt.Sprintln

html

返回与其参数的文本表示形式等效的转义 HTML。

这个函数在 html/template 中不可用

urlquery

以适合嵌入到网址查询中的形式返回其参数的文本表示的转义值。

这个函数在 html/template 中不可用

js

返回与其参数的文本表示形式等效的转义 JavaScript

call

执行结果是调用第一个参数的返回值,该参数必须是函数类型,其余参数作为调用该函

数的参数;

如"call .X.Y 1 2"等价于 go 语言里的 dot.X.Y(1, 2);

其中 Y 是函数类型的字段或者字典的值,或者其他类似情况;

call 的第一个参数的执行结果必须是函数类型的值(和预定义函数如 print 明显不同);

该函数类型值必须有 1 到 2 个返回值,如果有 2 个则后一个必须是 error 接口类型;

如果有 2 个返回值的方法返回的 error 非 nil,模板执行会中断并返回给调用模板执行者

该错误

{{len .title}}
{{index .hobby 2}}

(9).自定义模板函数

package main

import ( "fmt"
    "html/template"
    "net/http"
    "time"
    "github.com/gin-gonic/gin"
)

func formatAsDate(t time.Time) string {
    year, month, day := t.Date()
    return fmt.Sprintf("%d/%02d/%02d", year, month, day)
}

func main() {
    router := gin.Default()
    //注册全局模板函数 注意顺序,注册模板函数需要在加载模板上面
    router.SetFuncMap(template.FuncMap{ 
        "formatDate": formatAsDate,
     })
    //加载模板
    router.LoadHTMLGlob("templates/**/*")
    router.GET("/", func(c *gin.Context) {
            c.HTML(http.StatusOK, "default/index.html", map[string]interface{}{ 
                "title": "前台首页", 
                "now": time.Now(),
             })
    })
    router.Run(":8080")
}
{{.now | formatDate}}
//或者
{{formatDate .now }}

4.嵌套 template

(1).新建 templates/deafult/page_header.html

{{ define "default/page_header.html" }}
<h1>这是一个头部</h1>
{{end}}

(2).外部引入

注意:
1).引入的名字为 page_header.html 中定义的名字
2).引入的时候注意最后的点(.)
{{template "default/page_header.html" .}}
<!-- 相当于给模板定义一个名字 define end 成对出现-->
{{ define "default/index.html" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
{{template "default/page_header.html" .}}
</body>
</html>
{{end}}

二.静态文件服务

当渲染的HTML 文件中引用了静态文件时,需要配置静态 web 服务r.Static("/static", "./static"),前面的/static 表示路由,后面的./static 表示路径
func main() {
    r := gin.Default()
    r.Static("/static", "./static")
    r.LoadHTMLGlob("templates/**/*")
    // ... r.Run(":8080")
}
<link rel="stylesheet" href="/static/css/base.css" />

案例目录如下:

代码如下:

main.go

package main

import (
    "github.com/gin-gonic/gin"
    "html/template"
    "net/http"
    "time"
)

type Article struct {
    Title   string `json:"title"`
    Content string `json:"
"`
}

//时间戳转换成日期函数
func UnixToTime(timestamp int) string  {
    t := time.Unix(int64(timestamp), 0)
    return t.Format("2006-01-02 15:04:05")
}

func Println(str1 string, str2 string) string  {
    return str1 + str2
}

func main() {
    //初始化路由
    r := gin.Default()
    //自定义模板函数,必须在r.LoadHTMLGlob前面
    r.SetFuncMap(template.FuncMap{
        "UnixToTime":UnixToTime, //注册模板函数
        "Println": Println,
    })
    //加载templates中所有模板文件, 使用不同目录下名称相同的模板,注意:一定要放在配置路由之前才得行
    r.LoadHTMLGlob("templates/**/*")
    //配置静态web目录 第一个参数表示路由,第二个参数表示映射的目录
    r.Static("/static", "./static")

    //配置路由
    //前台路由
    r.GET("/", func(c *gin.Context) {
        //渲染模板文件
        c.HTML(http.StatusOK, "default/index.html", gin.H{
            "title": "首页",
            "score": 88,
            "hobby": []string{"吃饭", "睡觉", "打豆豆"}, // 切片
            "newList":[]interface{}{  // 接口
                &Article{
                    Title:   "新闻标题1",
                    Content: "新闻内容1",
                },
                &Article{
                    Title:   "新闻标题2",
                    Content: "新闻内容2",
                },
            },
            "testSlice":[]string{}, // 空数组/空切片
            "news": &Article{ // 结构体
                Title:   "新闻标题3",
                Content: "新闻内容3",
            },
            "date": 1672648334,
        })
    })
    r.GET("/news", func(c *gin.Context) {
        news := &Article{
            Title:   "新闻标题",
            Content: "新闻内容",
        }
        c.HTML(http.StatusOK, "default/news.html", gin.H{
            "title": "新闻详情",
            "news":  news,
        })
    })

    //后台路由
    r.GET("/admin", func(c *gin.Context) {
        //渲染模板文件
        c.HTML(http.StatusOK, "admin/index.html", gin.H{
            "title": "后台首页",
        })
    })
    r.GET("/admin/news", func(c *gin.Context) {
        news := &Article{
            Title:   "后台新闻标题",
            Content: "后台新闻内容",
        }
        c.HTML(http.StatusOK, "admin/news.html", gin.H{
            "title": "后台新闻详情",
            "news":  news,
        })
    })
    r.Run() // 启动一个web服务
}

templates/admin/index.html

<!-- 相当于给模板定义一个名字, define end 必须成对出现 -->
{{ define "admin/index.html" }}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>后台首页</title>
</head>
<body>
<h2>{{.title}}</h2>
</body>
</html>
{{ end }}

templates/admin/news.html

{{ define "admin/news.html" }}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>后台新闻详情</title>
</head>
<body>
<h2>{{.title}}</h2>
</body>
</html>
{{ end }}

templates/default/index.html

<!-- 相当于给模板定义一个名字, define end 必须成对出现 -->
{{ define "default/index.html" }}
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="/static/css/base.css">
        <title>首页</title>
    </head>
    <body>
    {{ template "public/page_header.html" .}}
    <h2>{{.title}}</h2>
    <img src="/static/images/test.png">
    <!-- 定义变量 把后台的变量赋值给$t -->
    {{ $t := .title}}
    <!-- 显示$t -->
    <h4> {{ $t }}</h4>
    <!-- if判断 -->
    {{if gt .score 90}}
        <div>优秀</div><br/>
    {{else if gt .score 80}}
        <div>良好</div><br/>
    {{else if gt .score 70}}
        <div>可以</div><br/>
    {{ else }}
        <div>合格</div><br/>
    {{end}}
    <!-- 循环数据 -->
    <ul>
        <!-- 循环切片 -->
        {{range $k, $v := .hobby}}
            <li>{{$k}} => {{$v}}</li>
        {{end}}
    </ul>
    <ul>
        <!-- 循环结构体 -->
        {{range $k, $v := .newList}}
            <li>{{$k}} => {{$v.Title}} --- {{$v.Content}}</li>
        {{end}}
    </ul>
    <ul>
        <!-- 循环空数组/切片 判断 -->
        {{range $k, $v := .testSlice}}
            <li>{{$k}} => {{$v.Title}} --- {{$v.Content}}</li>
        {{else}}
            <li>空数据</li>
        {{end}}
    </ul>
    <ul>
        <!-- with 解析结构体-->
        {{with .news}}
            <li>{{.Title}} => {{.Content}}</li>
        {{end}}
    </ul>
    <h4>
        <!--预定义函数 -->
        {{.title}}的长度为{{len .title}}
    </h4>
    <h4>
        <!--自定义函数 -->
        {{UnixToTime .date}}
        {{Println .title .news.Title}}
    </h4>
    <!-- 嵌套 template -->
    {{ template "public/page_footer.html" .}}
    </body>
    </html>
{{end}}

templates/default/news.html

<!-- 相当于给模板定义一个名字, define end 必须成对出现 -->
{{ define "default/news.html" }}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>news</title>
</head>
<body>
{{ template "public/page_header.html" .}}

<link rel="stylesheet" href="static/css/base.css">
<h2>{{.title}}</h2>
<h4>
    {{.news.Title}}
    {{.news.Content}}
</h4>
{{ template "public/page_footer.html" .}}
</body>
</html>
{{ end }}    

templates/public/page_footer.html

<!-- 相当于给模板定义一个名字, define end 必须成对出现 -->
{{ define "public/page_footer.html" }}
    <h4>
        公共的底部
    </h4>
{{end}}

templates/public/page_header.html

<!-- 相当于给模板定义一个名字, define end 必须成对出现 -->
{{ define "public/page_header.html" }}
    <h1>
        公共的 --- {{.title}}
    </h1>
{{end}}

[上一节][golang gin框架] 1.Gin环境搭建,程序的热加载,路由GET,POST,PUT,DELETE

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

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

相关文章

图像处理-边缘检测-文献阅读笔记

[1]李华琛. 基于opencv图像边缘检测技术[J]. 数字技术与应用, 2016(11):2. 高斯滤波有效抑制噪声&#xff1b;原理&#xff1a;识别图像中亮度改变较为明显的点&#xff0c;本质是采用不同的算子进行边缘检测并进行修整。算子&#xff1a;Laplacian 算子、Scharr 算子、Canny 算…

Kerberos简单介绍及使用

Kerberos作用 简单来说安全相关一般涉及以下方面&#xff1a;用户认证&#xff08;Kerberos的作用&#xff09;、用户授权、用户管理.。而Kerberos功能是用户认证&#xff0c;通俗来说解决了证明A是A 的问题。 认证过程&#xff08;时序图&#xff09; 核心角色/概念 KDC&…

电子学会2022年12月青少年软件编程(图形化)等级考试试卷(四级)答案解析

目录 一、单选题(共15题&#xff0c;共30分) 二、判断题(共10题&#xff0c;共20分) 三、编程题(共3题&#xff0c;共50分) 青少年软件编程&#xff08;图形化&#xff09;等级考试试卷&#xff08;四级&#xff09; 一、单选题(共15题&#xff0c;共30分) 1. 运行下列程序…

day39【代码随想录】动态规划之不同路径、不同路径||、最小路径和

文章目录前言一、不同路径&#xff08;力扣62&#xff09;二、不同路径||&#xff08;力扣63&#xff09;三、最小路径和&#xff08;力扣64&#xff09;前言 1、不同路径 2、不同路径|| 3、最小路径和 一、不同路径&#xff08;力扣62&#xff09; 一个机器人位于一个 m x n…

Spark09: Spark之checkpoint

一、checkpoint概述 checkpoint&#xff0c;是Spark提供的一个比较高级的功能。有时候&#xff0c;我们的Spark任务&#xff0c;比较复杂&#xff0c;从初始化RDD开始&#xff0c;到最后整个任务完成&#xff0c;有比较多的步骤&#xff0c;比如超过10个transformation算子。而…

使用Python,Opencv检测图像,视频中的猫

使用Python&#xff0c;Opencv检测图像&#xff0c;视频中的猫&#x1f431; 这篇博客将介绍如何使用Python&#xff0c;OpenCV库附带的默认Haar级联检测器来检测图像中的猫。同样的技术也可以应用于视频流。这些哈尔级联由约瑟夫豪斯&#xff08;Joseph Howse&#xff09;训练…

Ubuntu最新版本(Ubuntu22.04LTS)安装Tftp服务及其使用教程

目录 一、概述 二、在Ubuntu安装Tftp服务器  &#x1f356;2.1 安装tftp服务端&#xff08;tftpd-hpa&#xff09;  &#x1f356;2.2 配置&#xff0c;修改/etc/default/tftpd-hpa  &#x1f356;2.3 创建tftp服务的下载目录  &#x1f356;2.4 重启tftp服务器 三、在Ubun…

C++高级篇学习笔记

文章目录 前言 本文记录C一些面试难点问题剖析。 1. 左右值和右值引用的作用 左值&#xff1a;可以在左边&#xff0c;表达式结束后依然存在的持久对象&#xff0c;一般有名字&#xff0c;可以取地址。 提示&#xff1a; 前置自加/自减 可以做左值&#xff1b; 右值在右边&a…

java08-面向对象3

一&#xff1a;static 关键字&#xff1a;静态的 1.可以用来修饰的结构:主要用来修饰类的内部结构 属性、方法、代码块、内部类 2. static 修饰属性&#xff1a;静态变量&#xff08;或类变量&#xff09; 2.1 属性&#xff0c;是否使用static修饰&#xff0c;又分为静态属…

应对新的挑战!ChatGPT将如何改变多域作战?

​公众号博主推送内容&#xff0c;未经许可&#xff0c;不得转载或者引用。 原文&#xff1a;Exploring the Possibilities of ChatGPT in Rugged Military AI Applications 《ChatGPT&#xff1a;利用最先进的技术支撑多域作战》 ChatGPT是一款基于GPT-3大型自然语言模型的…

Spring Security in Action 第六章 一个小型的安全网络应用程序

本专栏将从基础开始&#xff0c;循序渐进&#xff0c;以实战为线索&#xff0c;逐步深入SpringSecurity相关知识相关知识&#xff0c;打造完整的SpringSecurity学习步骤&#xff0c;提升工程化编码能力和思维能力&#xff0c;写出高质量代码。希望大家都能够从中有所收获&#…

Leetcode.1138 字母板上的路径

题目链接 Leetcode.1138 字母板上的路径 Rating &#xff1a; 1411 题目描述 我们从一块字母板上的位置 (0, 0)出发&#xff0c;该坐标对应的字符为 board[0][0]。 在本题里&#xff0c;字母板为board ["abcde", "fghij", "klmno", "pqr…

day01查询 排序 数据处理函数 分组

文章目录1、什么是数据库&#xff1f;什么是数据库管理系统&#xff1f;什么是SQL&#xff1f;他们之间的关系是什么&#xff1f;2、安装MySQL数据库管理系统。3、MySQL数据库的完美卸载&#xff01;4、看一下计算机上的服务&#xff0c;找一找MySQL的服务在哪里&#xff1f;5、…

autox.js在vscode(win7)与雷神模拟器上的开发环境配置

目录 下载autox.js 安装autox.js&#xff1f; 在电脑上搭建autox.js开发环境 安装vscode 安装autox.js插件 雷神模拟器连接vscode 设置雷神模拟器IP 设置autox.js应用IP地址等 下载autox.js 大体来说&#xff0c;就是一个运行在Android平台上的JavaScript 运行环境 和…

计算机软考好不好考?

软考看你备考哪一科&#xff1f;对软考证书的需求量怎么样&#xff1f;对自己工作就业是否有帮助&#xff1f;从而来体现软考的意义~ 软考是什么&#xff1f; 软考全称是计算机技术与软件专业技术资格考试&#xff0c;通俗来说就是职称考试&#xff0c;也可以说是技术水平认定…

嵌入式Linux系统开发笔记(十六)

根文件系统rootfs启动验证测试 接下来我们使用测试一下前面创建好的根文件系统 rootfs&#xff0c;测试方法使用 NFS 挂载。 6.1 检查是否在Ubuntu主机中安装和开启了NFS服务 &#xff08;特别注意&#xff1a;nfs 配置文件/etc/exports中添加的路径一定要与实际使用的绝对路…

Elasticsearch:如何在提高跨索引搜索相关性的同时返回更多相关的文档

在 Elasticsearch 的搜索中&#xff0c;经常遇到的情况是&#xff0c;我们创建一个 data view 或者 index pattern 跨多个索引&#xff0c;这样我们可以对它们进行统一的搜索。我们有遇到这样的情况&#xff1a;完全匹配的文档的分数反而低于部分匹配的文档&#xff0c;这是为什…

Synchronized和Lock的区别

在分布式开发中&#xff0c;锁是控制线程安全的重要方式。Java提供了两种锁机制synchronized 和 Lock。 1、特性区别 Synchronized是Java内置的线程同步关键字&#xff1b; Lock是JUC包下面的一个接口&#xff0c;它有很多实现类&#xff0c;比如ReentrantLock就是它的一个实…

内存优化 · 基础论 · 初识 Android 内存优化

【小木箱成长营】内存优化系列文章&#xff1a; 内存优化 工具论 常见的 Android 内存优化工具和框架 内存优化 方法论 揭开内存优化神秘面纱 内存优化 实战论 内存优化实践与应用 Tips: 关注微信公众号小木箱成长营&#xff0c;回复"内存优化"可免费获得内存优…

Linux驱动开发(二)

一、驱动流程 驱动需要以下几个步骤才能完成对硬件的访问和操作&#xff1a; 模块加载函数 module_init注册主次设备号 <应用程序通过设备号找到设备>驱动设备文件 <应用程序访问驱动的方式> 1、手动创建 &#xff08;mknod&#xff09;2、程序自动创建file_oper…