新自动化文档生成-go语言-docx生成


关键字: word go语言 办公软件 自动化 excel office

背景

近来因为工作需要,经常性要重复地写报告,搞安全的就是苦逼啊。每次都需要人工查这查那,还要复制黏贴。 重复地复制黏贴会比较烦人。所以弄好一份表就自动让机器代替人工黏贴到word文档,自动生成会相对舒服且快速,有什么问题直接修改excel即可。

ps:因为苦于unioffice库的问题,所以重新找了两个库来实现,发现生成后的文件小了很多,而且文档及库的使用极度方便。

步骤

我是用go语言进行开发的。
go的版本:go version go1.14.4 windows/amd64

github.com/360EntSecGroup-Skylar/excelize/v2
github.com/nguyenthenguyen/docx

命令进行安装:
go get -v github.com/xxx

ps:
这两个库相对简单,excel的手册地址:https://xuri.me/excelize/zh-hans/workbook.html#SetDocProps
docx就暂时没有手册,但是提供的函数不多。研究一下即可。
注意两个函数:ReplaceRaw和Replace ,这两个的区别是ReplaceRaw直接动docx底层文件xml;Replace只是把你想要替换的内容给替换。

确定流程

其实最好先确定一下程序的处理流程和具体人工处理的步骤,因为偷懒我这里就不提供了,因为我也是画着画着就没有弄了。
该项目的步骤:
1、先填写好一个excel表,作为程序的数据输入。
2、打开模板docx,程序处理,输出修改后的报告。
3、输出写好的数据到一个汇总的表进行统计和闭环。

编写伪代码

在vscode上编写具体的流程伪代码

编写正式的代码

按照自己的思路,确定好变量、常量、具体的处理流程等等,按照伪代码进行一步一步的代码编写。

最终的代码

package main

import (
	"log"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/360EntSecGroup-Skylar/excelize/v2"
	"github.com/nguyenthenguyen/docx"
)

type biaozhi struct {
	yeMeiTime  string // 页眉的时间编号
	neiRouTime string // 内容的时间格式

	sjmc   string   // 事件名称
	sjjb   string   // 事件级别(漏洞、风险、应急)
	ipaddr string   // 告警对象(应急)
	gjlj   []string // 告警路径(应急、风险)
	tms    string   // 告警数量(应急)
	gjxx   string   // 告警描述(漏洞、风险)
	czjy   []string // 处置建议(漏洞、风险)
	sjly   string   // 事件类型(应急)
	llmc   string   // 漏洞名称(漏洞)
	yxbb   []string // 影响版本(漏洞)
	ywxt   string   // 业务系统(应急、风险)
	ywdw   string   // 业务单位(漏洞、应急、风险)
	fxms   string   // 风险验证描述(风险)
	kyfx   string   // 可疑分析(可疑)

	czjyStr   string // 写入excel的处置建立
	lujingStr string // 写入excel中的路径
	lcw       string // 另存为文件的名称
}

var (
	// Baogao 要打开的报告类型
	Baogao string
	// SaveFile 要保存的报告类型
	SaveFile string
	dataList biaozhi
	// qiantou这个比较重要。
	/*
	我不知道什么原因,这两个参数我已经第二次修改了,可能是因为docx的问题,所以建议如果你要动程序之前,最好先自己测试一下docx的这两个参数对不对。直接解压docx看就可以了。
	*/
	qiantou string = `<w:p><w:pPr><w:rPr><w:rFonts w:hint="eastAsia" w:ascii="仿宋_GB2312" w:hAnsi="仿宋_GB2312" w:eastAsia="仿宋_GB2312" w:cs="仿宋_GB2312"/><w:sz w:val="24"/><w:szCs w:val="24"/><w:lang w:val="en-US" w:eastAsia="zh-CN"/></w:rPr></w:pPr><w:r><w:rPr><w:rFonts w:hint="eastAsia" w:ascii="仿宋_GB2312" w:hAnsi="仿宋_GB2312" w:eastAsia="仿宋_GB2312" w:cs="仿宋_GB2312"/><w:sz w:val="24"/><w:szCs w:val="24"/><w:lang w:val="en-US" w:eastAsia="zh-CN"/></w:rPr><w:t>`
	jiewei  string = `</w:t></w:r><w:bookmarkStart w:id="0" w:name="_GoBack"/><w:bookmarkEnd w:id="0"/></w:p>`
)

// 1.判断输出的是什么通告
func tonggao() {
	cl, err := excelize.OpenFile("素材.xlsx")
	if err != nil {
		log.Println("打开素材文件错误!")
		return
	}
	SaveFile, _ = cl.GetCellValue("需要填写的资料", "B1")
	switch SaveFile {
	case "可疑行为":
		Baogao = "安全可疑行为通告模板.docx"
	case "风险预警":
		Baogao = "安全风险预警通告模板.docx"
	case "应急预警":
		Baogao = "安全事件应急通告模板.docx"
	case "漏洞预警":
		Baogao = "安全漏洞预警通告模板.docx"
	default:
		log.Println("请检查(素材.xlsx)文件(需要填写的资料)表中报告类型是否正确!")
	}

	// 获取相关的数据
	dataList.事件名称, _ = cl.GetCellValue("需要填写的资料", "B2")   // 风险预警:获取事件名称
	dataList.sjjb, _ = cl.GetCellValue("需要填写的资料", "B3")   // 所有预警:获取事件级别
	dataList.ipaddr, _ = cl.GetCellValue("需要填写的资料", "B4") // 应急预警:告警对象
	gjlj, _ := cl.GetCellValue("需要填写的资料", "B5")
	dataList.gjlj = strings.Split(gjlj, "\n")           // 告警路径
	dataList.tms, _ = cl.GetCellValue("需要填写的资料", "B6")  // 告警数量
	dataList.gjxx, _ = cl.GetCellValue("需要填写的资料", "B7") // 告警描述
	dataList.czjyStr, _ = cl.GetCellValue("需要填写的资料", "B8")
	dataList.czjy = strings.Split(dataList.czjyStr, "\n") // 所有预警:获取处置建议
	dataList.sjly, _ = cl.GetCellValue("需要填写的资料", "B9")   // 应急预警:事件类型
	dataList.llmc, _ = cl.GetCellValue("需要填写的资料", "B10")  // 漏洞预警:漏洞名称
	yxbb, _ := cl.GetCellValue("需要填写的资料", "B11")
	dataList.yxbb = strings.Split(yxbb, "\n")            // 漏洞预警:影响版本
	dataList.ywxt, _ = cl.GetCellValue("需要填写的资料", "B12") // 风险预警:业务系统名称
	dataList.ywdw, _ = cl.GetCellValue("需要填写的资料", "B13") // 风险预警:业务单位名称
	dataList.fxms, _ = cl.GetCellValue("需要填写的资料", "B14") // 风险预警:风险验证描述
	dataList.kyfx, _ = cl.GetCellValue("需要填写的资料", "B15") // 可疑行为:可疑分析

}

// 2.处理并输出报告
func baogao() {
	// 打开一个已有格式的文档,这个是要打开的文档路径。
	filesDir := "./template/" + Baogao
	// 添加页眉
	r, err := docx.ReadDocxFile(filesDir)
	if err != nil {
		log.Printf("打开word文档错误,错误信息: %s", err)
	}
	log.Println("打开报告完成")
	defer r.Close()
	docx1 := r.Editable()
	docx1.ReplaceHeader("页眉日期", dataList.yeMeiTime)

	switch SaveFile {
	case "应急预警":
		log.Println("当前正在处理应急预警类型的报告")
		docx1.Replace("事件名称:", "事件名称:"+dataList.sjmc, -1)
		docx1.Replace("事件类型:", "事件类型:"+dataList.sjly, -1)
		docx1.Replace("事件级别:", "事件级别:"+dataList.sjjb, -1)
		docx1.Replace("告警对象:", "告警对象:"+dataList.ipaddr, -1)
		docx1.Replace("所属系统:", "所属系统:"+dataList.ywxt+"系统,隶属于"+dataList.ywdw, -1)
		docx1.Replace("告警内容:", "告警内容:"+dataList.gjxx, -1)
		docx1.Replace("应急描述", dataList.neiRouTime+",发现业务(IP:"+dataList.ipaddr+")产生"+dataList.tms+"条“"+dataList.sjmc+"”日志告警信息。经云主机资产确认,该主机为“"+dataList.ywxt+"系统,隶属于"+dataList.ywdw+"。", -1)
		// 告警路径切片写入
		var shuZu []string
		for _, t := range dataList.gjlj {
			t = strings.Replace(t, "<", "&lt;", -1)
			t = strings.Replace(t, ">", "&gt;", -1)
			shuZu = append(shuZu, t+jiewei+qiantou)
		}
		shuZu = append(shuZu, jiewei)
		st1 := strings.Join(shuZu, "")
		docx1.ReplaceRaw("告警路径", st1, -1)
		// 处置建议切片写入
		var shuZu2 []string
		for _, t := range dataList.czjy {
		// 加了转换验证解决特殊符号导致的错误问题。
			t = strings.Replace(t, "<", "&lt;", -1)
			t = strings.Replace(t, ">", "&gt;", -1)
			shuZu2 = append(shuZu2, t+jiewei+qiantou)
		}
		shuZu2 = append(shuZu, jiewei)
		st2 := strings.Join(shuZu2, "") //把切片装回string类型的字符串
		docx1.ReplaceRaw("应急处置建议", st2, -1)
	case "漏洞预警":
		log.Println("当前正在处理漏洞预警类型的报告")
		docx1.Replace("漏洞名称填写", dataList.llmc, -1)
		docx1.Replace("风险等级填写", dataList.sjjb, -1)
		docx1.Replace("风险描述填写", dataList.gjxx, -1)
		// 影响版本切片写入
		var shuZu []string
		for _, t := range dataList.yxbb {
			t = strings.Replace(t, "<", "&lt;", -1)
			t = strings.Replace(t, ">", "&gt;", -1)
			shuZu = append(shuZu, t+jiewei+qiantou)
			//shuZu = append(shuZu, t)
		}
		shuZu = append(shuZu, jiewei)
		st1 := strings.Join(shuZu, "")
		// ReplaceRaw该函数是直接修改底层的xml文件。而Replace只是单纯的替换你想替换的内容,不修改格式。
		docx1.ReplaceRaw("影响版本填写", st1, 1)

		// 处置建议切片写入
		var shuZu2 []string
		for _, t := range dataList.czjy {
			t = strings.Replace(t, "<", "&lt;", -1)
			t = strings.Replace(t, ">", "&gt;", -1)
			shuZu2 = append(shuZu2, t+jiewei+qiantou)
		}
		shuZu2 = append(shuZu, jiewei)
		st2 := strings.Join(shuZu2, "")
		docx1.ReplaceRaw("处置建议填写", st2, -1)
	case "可疑行为":
		log.Println("当前正在处理可疑行为类型的报告")
		docx1.Replace("行为概述填写", dataList.neiRouTime+",资产:"+dataList.ipaddr+"产生"+dataList.tms+"条"+dataList.sjmc+"日志告警信息。经云主机资产确认,该主机为“"+dataList.ywxt+"”系统,隶属于“"+dataList.ywdw+"”。", -1)
		docx1.Replace("疑点分析填写", dataList.kyfx, -1)
		// 处置建议切片写入
		var shuZu []string
		for _, t := range dataList.czjy {
			t = strings.Replace(t, "<", "&lt;", -1)
			t = strings.Replace(t, ">", "&gt;", -1)
			shuZu = append(shuZu, t+jiewei+qiantou)
		}
		shuZu = append(shuZu, jiewei)
		st2 := strings.Join(shuZu, "")
		docx1.ReplaceRaw("处置建议填写", st2, -1)
	default:
		log.Println("正在处理默认的表格内容")
		docx1.Replace("事件名称填写", dataList.sjmc, -1)
		docx1.Replace("风险等级填写", dataList.sjjb, -1)
		docx1.Replace("风险描述填写", dataList.gjxx, -1)
		docx1.Replace("业务所属", "经云主机资产确认,该主机为"+dataList.ywxt+"系统,隶属于"+dataList.ywdw, -1)
		docx1.Replace("风险验证描述", dataList.fxms, -1)
		// 风险验证路径切片写入
		var shuZu []string
		for _, t := range dataList.gjlj {
			t = strings.Replace(t, "<", "&lt;", -1)
			t = strings.Replace(t, ">", "&gt;", -1)
			shuZu = append(shuZu, t+jiewei+qiantou)
		}
		shuZu = append(shuZu, jiewei)
		st1 := strings.Join(shuZu, "")
		docx1.ReplaceRaw("风险验证路径", st1, -1)
		// 处置建议切片写入
		var shuZu2 []string
		for _, t := range dataList.czjy {
			t = strings.Replace(t, "<", "&lt;", -1)
			t = strings.Replace(t, ">", "&gt;", -1)
			shuZu2 = append(shuZu2, t+jiewei+qiantou)
		}
		shuZu2 = append(shuZu, jiewei)
		st2 := strings.Join(shuZu2, "")
		docx1.ReplaceRaw("处置建议填写", st2, -1)
	}

	switch SaveFile {
	case "可疑行为":
		dataList.lcw = "【" + dataList.sjmc + "】" + "(" + dataList.ywdw + ")" + "安全可疑行为预警通告" + dataList.yeMeiTime + ".docx"
	case "风险预警":
		dataList.lcw = "【" + dataList.sjmc + "】" + "(" + dataList.ywdw + ")" + "安全风险预警通告" + dataList.yeMeiTime + ".docx"
	case "应急预警":
		dataList.lcw = "【" + dataList.sjmc + "】" + "(" + dataList.ywdw + ")" + "安全事件应急通告" + dataList.yeMeiTime + ".docx"
	case "漏洞预警":
		dataList.lcw = "【" + dataList.llmc + "】" + "(" + dataList.ywdw + ")" + "安全漏洞预警通告" + dataList.yeMeiTime + ".docx"
	}

	sp := "./report/" + dataList.lcw
	err = docx1.WriteToFile(sp)
	if err != nil {
		os.Mkdir("./report", os.ModePerm)
		log.Println("当前目录中没有report报告文件夹,现在创建文件夹成功!!!")
		docx1.WriteToFile(sp)
		log.Println("保存docx文件成功!!!")
	}
	log.Println("保存docx文件成功!!!")
}

func exc() {
	f, err := excelize.OpenFile("预警通报汇总表.xlsx")
	if err != nil {
		log.Println(err.Error())
	}

	//告警函编号、业务单位、业务系统、告警状态、漏洞名称、告警类型、告警级别、告警对象、告警描述、应急处置方法、发生时间、结束时间、告警根治处置方法建议、安全处置联系人、支撑人员、修复方法描述、修复时间、修复验证描述、修复验证人、修复验证时间

	// 非应急预警的格式
	exStr := []string{dataList.yeMeiTime, dataList.ywdw, dataList.ywxt, "未修复", dataList.llmc, dataList.事件名称, dataList.sjjb, dataList.ipaddr, dataList.gjxx, "", dataList.neiRouTime, "", dataList.czjyStr, "", "xxx", "", "", "", dataList.ywdw, SaveFile}

	// 检查A列一千行,判断是否有值,如果有值就不写。没有值就整行填写记录
	for n1 := 1; n1 < 1000; n1++ {
		s1 := strconv.Itoa(n1)
		lie := "A" + s1
		// 获取当前表,固定表格的值
		cell, _ := f.GetCellValue("Sheet1", lie)
		if cell == "" { // 判断是否为空
			// 为空就提交单元格编号并跳出循环
			f.SetSheetRow("Sheet1", lie, &exStr)
			// celSave = lie
			break
		}
	}
	// 保存文件
	f.Save()
	log.Println("通告内容已经写入“预警通报汇总表.xlsx”表中!!!")
}

func main() {
	// 获取符合我们格式的时间。
	dataList.neiRouTime = time.Now().Format("2006年01月02日15时04分")
	dataList.yeMeiTime = time.Now().Format("200601021504")

	// 判断是什么报告类型,提取素材exels里面的内容
	tonggao()

	// 将获取到的数据写入word并保存文件
	baogao()

	// 将获取到的数据写入到汇总excel里面
	exc()

	// 等待时间查看日志
	time.Sleep(time.Minute * 999)

}


以前的久问题

如果使用了unioffice库会出现以下问题:
1.页眉其实有排版和字体问题,可惜时间太短用了一天时间写了这个程序,因为是新手所以大神勿喷。
2.word读取的时候存在问题,需要docx清除所有格式才能如你所愿地识别出来字段,举个有问题的例子:

以下是word文档的两个段:
	恶意告警
	攻击事件经过分析还存在其他问题,1:端口继续对外开放;2:漏洞未被修复。

如果这个文档有自己的格式如:仿宋字体;加粗;四号等等。。。
那么识别就会出现问题,识别结果如下:

恶意
告警
攻击事件
经过
分析还存在其它问题,
1
:端口继续对外开放;2:漏洞未被修复。

那么识别出来的字段就会有问题,不能按照我们关键字的方式进行识别并替换。
如我想识别出恶意告警,作为关键字,再替换为我想要的写的内容。但是这样的情况下就无法做了。

3.excel读出数据之后,可以读取成切片,变成数组,通过unioffice这个库的AddBreak()函数进行换行,继续写入内容。示例代码如下:(目前已经不用该库了。直接动xml文件)

for _, t := range dataList.chuzhijianyi { //重复执行
	r.AddText(t) //写入内容
	r.AddBreak() //换行
}

新的注意点

针对以上的旧问题,已经不再是问题了,通过新的库已经解决。

注意的点

模版的问题

这里要说一下,docx是基于xml格式的文本文档;使用压缩软件打开docx文件:
在这里插入图片描述
在这里插入图片描述
这个就是docx的内容,看到下面还有页眉页尾的文件。打开后的内容,关注的是关键字的连续,如图:
在这里插入图片描述
硬件性能这个关键字,我们可以拿来作为替换;要注意的是,有可能这个关键字不一定是连续的。不连续的情况下,要重新删除内容,重新写,如图:
在这里插入图片描述
再用压缩软件检查,是否已经连续。不然后面会无法替换原文档内容。

插入的内容

因为文档是docx,所以要使用doc库里面的ReplaceRaw函数,该函数插入的内容是不经过转换的。

  • 所以需要添加xml的前缀内容:<w:p><w:pPr><w:rPr><w:rFonts w:hint=“eastAsia” w:ascii=“仿宋_GB2312” w:hAnsi=“仿宋_GB2312” w:eastAsia=“仿宋_GB2312” w:cs=“仿宋_GB2312”/><w:sz w:val=“24”/><w:szCs w:val=“24”/><w:lang w:val=“en-US” w:eastAsia=“zh-CN”/></w:rPr></w:pPr><w:r><w:rPr><w:rFonts w:hint=“eastAsia” w:ascii=“仿宋_GB2312” w:hAnsi=“仿宋_GB2312” w:eastAsia=“仿宋_GB2312” w:cs=“仿宋_GB2312”/><w:sz w:val=“24”/><w:szCs w:val=“24”/><w:lang w:val=“en-US” w:eastAsia=“zh-CN”/></w:rPr><w:t>
  • 后缀内容是:</w:t></w:r><w:bookmarkStart w:id=“0” w:name="_GoBack"/><w:bookmarkEnd w:id=“0”/></w:p>
    中间内容就是你想替换的内容啦。详情可以看我的源码。挺简单的。

特殊符号

在实践中,发现xml并是无脑地插入文本,特别是遇到符号的时候,
如果无脑代入,会在打开docx的时候报错,实际上,就是因为符号引起。
举个例子:
在这里插入图片描述
原因如下:

更正一下图片中的内容:“大于号这四个字符组成的 & g t ;” 小于号是这四个字符组成的"& l t ;"

在这里插入图片描述
以下这个图是正常能打开的docx截图:
在这里插入图片描述
正常的docx的xml如下:

与什么空格并没有什么关系。

在这里插入图片描述
在这里插入图片描述
PS:这个问题,目前已经找到折衷办法,使用strings.Replace()函数,把大小于号都替换就可以了。

  • 在 XML 中,有 5 个预定义的实体引用:
转义后的字符需要被转义的字符备注
&lt;<less than
&gt;>greater than
&amp;&ampersand
&apos;apostrophe
&quot;"quotation mark

注释:在 XML 中,只有字符 “<” 和 “&” 确实是非法的。大于号是合法的,但是用实体引用来代替它是一个好习惯。

总结

1、检查好自己的模版文档。
2、检查好输入输出的excel文档。
3、调试好程序的输出。
4、可以使用日志告警作为程序的接入、数据库表作为资产查询的输出。看个人喜欢。

至于图片的插入,目前需要用到的是unioffice库,我还没有研究过。

最终成果:
在这里插入图片描述

第01章 课程介绍 1-1 导学.mp4 1-2 课程介绍.mp4 第02章 实战-“云存储”系统原型 2-1 “云存储”系统原型之简单文件上传服务架构说明.mp4 2-2 编码实战:“云存储”系统之实现上传接口.mp4 2-3 编码实战:“云存储”系统之保存文件元信息.mp4 2-4 编码实战:“云存储‘系统之实现单个文件查询信息接口.mp4 2-5 编码实战:“云存储”系统之实现文件下载接口.mp4 2-6 编码实战:“云存储”系统之实现文件修改接口+小结.mp4 第03章 “云存储”系统之基于MySQL实现的文件数据库 3-1 MySQL基础知识.mp4 3-2 MySQL主从数据同步演示.mp4 3-3 文件表的设计及创建.mp4 3-4 编码实战:“云存储”系统之持久化元数据到文件表.mp4 3-5 编码实战:“云存储”系统之从文件表中获取元数据.mp4 3-6 Docker入门基础文档.mp4 3-6 本章小结.mp4 3-7 Ubuntu中通过Docker安装配置MySQL主从节点.mp4 第04章 “云存储”系统之基于用户系统实现的资源隔离及鉴权 4-1 帐号系统介绍与用户表设计.mp4 4-2 编码实战:“云存储”系统之实现用户注册接口.mp4 4-3 编码实战:“云存储”系统之实现用户登录接口.mp4 4-4 编码实战:“云存储”系统之实现用户信息查询接口.mp4 4-5 接口梳理小结.mp4 4-6 编码实战:“云存储”系统之快速实现访问鉴权接口+小结.mp4 4-7 关于静态资源访问404的问题【补漏.mp4 第05章 “云存储”系统之基于Hash计算实现秒传 5-1 Hash算法对比及秒传原理.mp4 5-2 用户文件表设计与创建.mp4 5-3 编码实战:“云存储”系统之升级改造上传接口.mp4 5-4 编码实战:“云存储”系统之基于用户查询文件Hash信息.mp4 5-5 编码实战:“云存储”系统之实现秒传功能接口+小结.mp4 第06章 “云存储”系统之基于Redis实现分块上传及断点续传 6-1_分块上传与断点续传原理.mp4 6-2_编码实战:Go实现Redis连接池(存储分块信息).mp4 6-3_编码实战:实现初始化分块上传接口.mp4 6-4_编码实战:实现分块上传接口.mp4 6-5_编码实战:实现分块合并接口.mp4 6-6_分块上传场景测试+小结.mp4 6-7_文件断点下载原理.mp4 第07章 “云存储”系统之基于Ceph实现私有云存储服务 7-1_Ceph是什么.mp4 7-2_Ceph集群介绍及兼容亚马逊S3接口详解.mp4 7-3_编码实战:Go访问管理Ceph集群.mp4 7-4_编码实战:Go实现Ceph的文件上传下载+小结.mp4 7-5_Ubuntu下通过Docker快速搭建Ceph测试集群(单机部署).mp4 7-6_Centos7下Docker部署Ceph集群(nautilus最版,多机部署).mp4 第08章 “云存储”系统之基于阿里云OSS实现海量数据上云 8-1_阿里云对象存储OSS简介.mp4 8-2_阿里云对象存储OSS特点.mp4 8-3_阿里云对象存储OSS专业术语.mp4 8-4_阿里云对象存储OSS控制台管理.mp4 8-5_编码实战:OSS上传文件.mp4 8-6_编码实战:OSS下载文件.mp4 8-7_编码实战:OSS对象生命周期管理等常用功能.mp4 8-8_阿里云OSS本章小结.mp4 第09章 “云存储”系统之基于RabbitMQ实现异步存储 9-1_Ubuntu下通过Docker安装RabbitMQ.mp4 9-2_关于任务的同步与异步.mp4 9-3_RabbitMQ简介.mp4 9-4_RabbitMQ工作原理和转发模式.mp4 9-5_Docker安装RabbitMQ及UI管理.mp4 9-6_编码实战_实现异步转移的MQ生产者.mp4 9-7_编码实战_实现异步转移的MQ消费者.mp4 9-8_编码实战_异步转移文件测试+小结.mp4 第10章 “云存储”系统之架构微服务化 10-1_基于Docker部署服务注册发现中心consul集群.mp4 10-2_微服务基础概念与原理.mp4 10-3_云存储系统之微服务架构(1).mp4 10-4_云存储系统之微服务架构(2).mp4 10-5_Web框架Gin基础介绍.mp4 10-6_编码实战_基于Gin改造用户service(1).mp4 10-7_编码实战_基于Gin改造用户service(2.mp4 10-8_gRPC与Protobuf基础原理.mp4 10-9_RPC框架go-micro基础介绍.mp4 10-10_编码实战_改造账号系统service.mp4 10-11_编码实战_改造api网关service.mp4 10-12_编码实战_改造文件上传service.mp4 10-13_综合测试演示+小结.mp4 第11章 “云存储”系统之k8s&Docker;容器化实战 11-1_Ubuntu18下通过kubeadm单机安装k8s(v1.14.1)集群.mp4 11-2_Ubuntu18下安装k8s(v1.14.1)可视化管理工具.mp4 11-3_Docker与Docker-Compose基础概念.mp4 11-4_基于容器的微服务反向代理利器Traefik.mp4 11-5_基于Docker-compose与Traefik的容器化部署演示.mp4 11-6_Kubernetes基础原理.mp4 11-7_基于Kubernetes的容器化部署演示.mp4 第12章 “云存储”系统之持续集成部署 12-1_ubuntu下离线安装harbor1.6.mp4 12-2_持续构建之基础概念.mp4 12-3_基于gitlab+jenkins+harbor的自动化部署配置演示.mp4 第13章 课程总结 13-1_课程总结之章节重点及技能树温习.mp4
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值