精华内容
下载资源
问答
  • 数据库迁移升级最佳实践9i-10g-11g Oracle ASM扩容&数据迁移文档 06使用XTTS技术进行U2L跨平台数据迁移 Oracle 迁移至 PostgreSQL 在华为 ARM 上的解决方案 rman异机迁移 迁移 ORACLE数据库和应用异构迁移最佳实践_...
  • Python实战:pip 的常用技巧一、列出本机所有的安装包和版本信息二、下载安装包三、批量下载安装包四、升级4.1.pip升级4.2.安装包升级五、使用国内的pypi源5.1.在国内镜像中下载资源 一、列出本机所有的安装包和版本...
  • 中的技巧,全书分为基础篇、核心篇、进阶篇。基础篇包括第 1~4章,主要介绍PostgreSQL基础知识,例如安装与配置、客 户端工具、数据类型、SQL高级特性等,为读者阅读核心篇和 进阶篇做好准备;核心篇包括第5~9章,...
  • 《HBase实战

    2018-04-24 10:27:12
    第三部分通过真实的应用和代码示例以及支持这些实践技巧的理论知识,进一步探索HBase的一些实用技术;第四部分讲解如何把原型开发系统升级为羽翼丰满的生产系统。 《HBase实战》适合所有对云计算、大数据处理技术和...
  • PostgreSQL实战

    2019-01-03 22:39:41
    本书由资深数据库专业开发人员撰写,...进阶篇包括第10~18章,主要介绍PostgreSQL高级内容,例如性能优化、物理复制、逻辑复制、备份与恢复、高可用、版本升级、扩展模块、Oracle数据库迁移PostgreSQL实战、PostGIS等。
  • 在前几版的基础上做了全面升级,提供了zui新、zui有用的提示和技巧,而且通过教程说明现今可用的 CSS。会教你如何使用新工具(如弹性盒和 Sass)构建外观精美的网页,而且在任何桌面设备或移动设备中都能快速运行。...
  • 在前几版的基础上做了全面升级,提供了zui新、zui有用的提示和技巧,而且通过教程说明现今可用的 CSS。会教你如何使用新工具(如弹性盒和 Sass)构建外观精美的网页,而且在任何桌面设备或移动设备中都能快速运行。...
  • “明人不说暗话,跟着阿笨一起玩Xamarin”,本次分享课程阿笨将带来大家一起学习Xamarin For Android系列《C# Xamarin For Android自动升级项目实战》。如果您同样对本次分享课程感兴趣的话,那么请跟着阿笨一起学习...

    一、课程介绍

    “明人不说暗话,跟着阿笨一起玩Xamarin”,本次分享课程阿笨将带来大家一起学习Xamarin For Android系列《C# Xamarin For Android自动升级项目实战》。如果您同样对本次分享课程感兴趣的话,那么请跟着阿笨一起学习吧。

    本次分享课程适合人群如下:

    1、 热爱Xamarin跨平台移动开发。

    2、进一步了解和学习Xamarin For Android移动开发实战知识。

    本次分享课包含实战分享知识点如下:

    1、C# Android 如何制作打包编译APK文件

    2、C# Android如何实现自动升级功能(AutoUpdate)

    本次分享课程最终目标:希望学完本次分享课程后能够快速通过Xamarin For Android打造一个后台管理系统App应用程序,从而将学习成果转化为工作成果。

    废话不多说,直接上干货,我们不生产干货,我们只是干货的搬运工。

    二、涉及覆盖Android小技巧和小技能知识点

    学习本次《C# Xamarin For Android自动升级项目实战》分享课程,你将掌握以下关于Xamarin For Android方面的干货知识点。

    1)、拉风的窗体启动动画(SplashActivity)

    2)、酷炫漂亮的登录窗体(LoginActivity)布局。

    3)、漂亮的自定义导航栏控件(TitleBar)

    4)、C# Android如何检测网络是否正常。

    5)、UI线程(RunOnUiThread)第一次实际运用。

    6)、C# Android如何播放音频文件。

    7)、C# Android中封装MessageBoxHelper弹窗控件。

    8)、C# Android XML序列化和反序列化。

    9)、C# Android Assets目录存储我们的应用程序资源和配置文件。

    三、实战演练示例分享

    3.1、C# Android 如何制作打包编译APK文件

    阿笨将带来大家一步步学习Xamarin For Android 打包编译APK文件。

    1、首先签名是个什么东西?

    Android对应用程序签名就是为你的程序打上一种标记,来作为你自己的标识。

    2、为什么要进行数字签名?

    这是Android系统的要求,每一个应用程序必要要经过数字签名才可能安装到系统中,能安装的apk则是已经签名了的。     apk不签名是安装不了的,但是别人也可以重新签名。 使用你自己的同一个签名证书,就没有人能够覆盖你的应用程序,即使包名相同。

    特别注意:通过Debug和Release生成的apk文件由于没有带签名,直接部署在真机中会出现闪退的情况。

    参考文章:

    Xamarin 跨移动端开发系列(01) -- 搭建环境、编译、调试、部署、运行

    3.2、C# Android自动升级原理剖析

    Android如何实现自动升级功能(AutoUpdate)

    Autoupdate.exe从字面意思理解应该为一个自动升级程序。

    实现步骤:

    1.检测当前版本的信息AndroidManifest.xml–>manifest–>[Android]

    2.从服务器获取版本号(版本号存在于xml文件中)并与当前检测到的版本进行匹配,如果不匹配,提示用户进行升级,如果匹配则进入程序主界面。(demo中假设需要更新)

    3.当提示用户进行版本升级时,如果用户点击了“更新”,系统将自动从服务器上下载安装包并进行自动升级,如果点击取消将进入程序主界面。


    原理图

     

    四、在线源码解读和演示

     

     
    展开全文
  • Gin 入门实战

    万次阅读 2019-06-14 18:26:09
    #Gin 入门实战 Agenda 拨开云雾见天日:前置知识讲解 万丈高楼平地起:基础中的精髓 及 搭建企业级golang脚手架 秤砣虽小压千斤:实战学习开发用户管理系统 拨开云雾见天日 ##1-1 前置知识 Go开发web的优势 在 ...

    Gin 入门实战

    Agenda

    • 拨开云雾见天日:前置知识讲解
    • 万丈高楼平地起:基础中的精髓 及 搭建企业级golang脚手架
    • 秤砣虽小压千斤:实战学习开发用户管理系统

    拨开云雾见天日

    1-1 前置知识

    • Go开发web的优势
      在 Go 语言出现之前,开发者们总是面临非常艰难的抉择,
      究竟是使用执行速度快但是编译速度并不理想的语言(如:C++),还是
      使用编译速度较快但执行效率不佳的语言(如:.NET、Java),
      开发难度较低但执行速度一般的动态语言呢?(如:Python)
      显然,Go 语言在这 3 个条件之间做到了最佳的平衡:快速编译,高效执行,易于开发。
      在这里插入图片描述
    • gin是什么?
      Gin 框架 现在是 github 上 start 最多 Go 语言编写的 Web 框架,相比其他它的几个 start 数量差不多的框架,它更加的轻量,有更好的性能。
    • 性能对比

    在这里插入图片描述

    1. 在固定时间内重复完成的总数,数值越高的是越好的结果
    2. 单次重复持续时间(ns /op),越低越好
    3. 堆内存(B /op),越低越好
    4. 每次重复的平均分配(allocs /op),越低越好

    从内存分配、单词相应时间、Qps三个纬度分析。gin基本是碾压其他对手的。

    • httprouter 为gin插上了翅膀

    在这里插入图片描述

    https://chai2010.gitbooks.io/advanced-go-programming-book/ch5-web/ch5-02-router.html
    https://www.cnblogs.com/foxy/p/9469401.html

    1-2 golang开发环境准备

    下载与解压
    wget https://dl.google.com/go/go1.11.4.linux-amd64.tar.gz
    tar -xvf go1.11.4.linux-amd64.tar.gz
    
    修改环境变量
    vim ~/.bash_profile
    
    export GOROOT=/root/go
    export GOPATH=/root/go_path
    export GOBIN=$GOROOT/bin
    export PATH=$GOBIN:$GOROOT/bin:$GOPATH/bin:$PATH
    source ~/.bash_profile
    
    查看go的版本号
    go version
    

    1-2 go mod 包管理工具

    https://blog.csdn.net/e421083458/article/details/89762113

    万丈高楼平地起

    2-1 安装gin及快速开始

    测试使用版本:
    github.com/gin-gonic/gin v1.4.0

    go get -v github.com/gin-gonic/gin
    
    package main
    
    import "github.com/gin-gonic/gin"
    
    func main() {
    	r := gin.Default()
    	r.GET("/ping", func(c *gin.Context) {
    		c.JSON(200, gin.H{
    			"message": "pong",
    		})
    	})
    	r.Run() // listen and serve on 0.0.0.0:8080
    }
    

    2-2 请求路由

    • 设置多种请求类型
    func main() {
    	// Creates a gin router with default middleware:
    	// logger and recovery (crash-free) middleware
    	router := gin.Default()
    
    	router.GET("/someGet", getting)
    	router.POST("/somePost", posting)
    	router.PUT("/somePut", putting)
    	router.DELETE("/someDelete", deleting)
    	router.PATCH("/somePatch", patching)
    	router.HEAD("/someHead", head)
    	router.OPTIONS("/someOptions", options)
    
    	// By default it serves on :8080 unless a
    	// PORT environment variable was defined.
    	router.Run()
    	// router.Run(":3000") for a hard coded port
    }
    
    
    • 绑定静态文件夹
    func main() {
    	router := gin.Default()
    	router.Static("/assets", "./assets")
    	router.StaticFS("/more_static", http.Dir("my_file_system"))
    	router.StaticFile("/favicon.ico", "./resources/favicon.ico")
    
    	// Listen and serve on 0.0.0.0:8080
    	router.Run(":8080")
    }
    
    • 参数作为URL
    package main
    
    import "github.com/gin-gonic/gin"
    
    type Person struct {
    	ID string `uri:"id" binding:"required,uuid"`
    	Name string `uri:"name" binding:"required"`
    }
    
    func main() {
    	route := gin.Default()
    	route.GET("/:name/:id", func(c *gin.Context) {
    		var person Person
    		if err := c.ShouldBindUri(&person); err != nil {
    			c.JSON(400, gin.H{"msg": err})
    			return
    		}
    		c.JSON(200, gin.H{"name": person.Name, "uuid": person.ID})
    	})
    	route.Run(":8088")
    }
    
    • 正则绑定
    package main
    
    import (
    	"github.com/gin-gonic/gin"
    	"net/http"
    )
    
    func main() {
    	router := gin.Default()
    
    	router.GET("/user/*action", func(c *gin.Context) {
    		c.String(http.StatusOK, "Hello world")
    	})
    
    	router.Run(":8080")
    }
    

    2-3 获取请求参数

    • 获取GET请求参数
    func main() {
    	router := gin.Default()
    
    	// Query string parameters are parsed using the existing underlying request object.
    	// The request responds to a url matching:  /welcome?firstname=Jane&lastname=Doe
    	router.GET("/welcome", func(c *gin.Context) {
    		firstname := c.DefaultQuery("firstname", "Guest")
    		lastname := c.Query("lastname") // shortcut for c.Request.URL.Query().Get("lastname")
    
    		c.String(http.StatusOK, "Hello %s %s", firstname, lastname)
    	})
    	router.Run(":8080")
    }
    
    • 获取POST请求参数
    func main() {
    	router := gin.Default()
    
    	router.POST("/form_post", func(c *gin.Context) {
    		message := c.PostForm("message")
    		nick := c.DefaultPostForm("nick", "anonymous")
    
    		c.JSON(200, gin.H{
    			"status":  "posted",
    			"message": message,
    			"nick":    nick,
    		})
    	})
    	router.Run(":8080")
    }
    
    • 获取Body值
    package main
    
    import (
    	"github.com/gin-gonic/gin"
    	"io/ioutil"
    	"net/http"
    )
    
    func main() {
    	router := gin.Default()
    	
    	router.POST("/user/*action", func(c *gin.Context) {
    		bodyBytes, _ := ioutil.ReadAll(c.Request.Body)
    		c.String(http.StatusOK, string(bodyBytes))
    	})
    	router.Run(":8080")
    }
    

    测试效果:

    #form-urlencode
    curl 'http://127.0.0.1:8080/user/adsadsad' -F "key=value"
    --------------------------88baf4eac8fd4ba1
    Content-Disposition: form-data; name="key"
    
    value
    --------------------------88baf4eac8fd4ba1--
    
    #form-data
    curl 'http://127.0.0.1:8080/user/adsadsad' -d "key=value"
    key=value
    
    • bind绑定结构体获取参数(Get&POST&POST_BODY)

    只需要在结构体上设置form标签即可

    package main
    
    import (
    	"fmt"
    	"log"
    	"time"
    
    	"github.com/gin-gonic/gin"
    )
    
    type Person struct {
    	Name     string    `form:"name"`
    	Address  string    `form:"address"`
    	Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1"`
    }
    
    func main() {
    	route := gin.Default()
    	route.GET("/testing", startPage)
    	route.POST("/testing", startPage)
    	route.Run(":8085")
    }
    
    func startPage(c *gin.Context) {
    	var person Person
    	if c.ShouldBind(&person) == nil {
    		log.Println(person.Name)
    		log.Println(person.Address)
    		log.Println(person.Birthday)
    	}
    	c.String(200, fmt.Sprintf("%#v",person))
    }
    

    测试

    curl 'http://127.0.0.1:8085/testing?name=1&address=2&birthday=2006-01-02'
    
    main.Person{Name:"1", Address:"2", Birthday:time.Time{wall:0x0, ext:63271756800, loc:(*time.Location)(nil)}}
    
    curl 'http://127.0.0.1:8085/testing' -d 'name=5566&address=3344&birthday=2006-01-02'
    main.Person{Name:"5566", Address:"3344", Birthday:time.Time{wall:0x0, ext:63271756800, loc:(*time.Location)(nil)}}%
    

    2-4 验证请求参数

    • 结构体binding验证

    gin默认使用validator.v8作为验证器。

    多种验证规则请参见:

    https://github.com/go-playground/validator/tree/v8

    https://godoc.org/gopkg.in/go-playground/validator.v8#hdr-Using_Validator_Tags

    注意点:gin必须使用 binding tag 来设置校验规则,而不是 validate。

    package main
    
    import (
    	"fmt"
    	"time"
    
    	"github.com/gin-gonic/gin"
    )
    
    type Person struct {
    	Name     string    `form:"name" binding:"required"`
    	Address  string    `form:"address"`
    	Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1"`
    }
    
    func main() {
    	route := gin.Default()
    	route.GET("/testing", startPage)
    	route.Run(":8085")
    }
    
    func startPage(c *gin.Context) {
    	var person Person
    	if err:=c.ShouldBind(&person);err!=nil {
    		c.String(500,fmt.Sprint(err))
    	}
    	c.String(200, fmt.Sprintf("%#v",person))
    }
    

    测试

    curl 'http://127.0.0.1:8085/testing' -d 'name=&address=3344&birthday=2006-01-02&age=1'
    Key: 'Person.Age' Error:Field validation for 'Age' failed on the 'gt' tag
    Key: 'Person.Name' Error:Field validation for 'Name' failed on the 'required' tagmain.Person{Age:1, Name:"", Address:"3344", Birthday:time.Time{wall:0x0, ext:63271756800, loc:(*time.Location)(nil)}}
    
    curl 'http://127.0.0.1:8085/testing' -d 'name=5566&address=3344&birthday=2006-01-02&age=1'
    Key: 'Person.Age' Error:Field validation for 'Age' failed on the 'gt' tagmain.Person{Age:1, Name:"5566", Address:"3344", Birthday:time.Time{wall:0x0, ext:63271756800, loc:(*time.Location)(nil)}}
    
    • 自定义验证
    package main
    
    import (
    	"net/http"
    	"reflect"
    	"time"
    
    	"github.com/gin-gonic/gin"
    	"github.com/gin-gonic/gin/binding"
    	"gopkg.in/go-playground/validator.v8"
    )
    
    // Booking contains binded and validated data.
    type Booking struct {
    	CheckIn  time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"`
    	CheckOut time.Time `form:"check_out" binding:"required,gtfield=CheckIn" time_format:"2006-01-02"`
    }
    
    func bookableDate(
    	v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value,
    	field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string,
    ) bool {
    	if date, ok := field.Interface().(time.Time); ok {
    		today := time.Now()
    		if today.Year() > date.Year() || today.YearDay() > date.YearDay() {
    			return false
    		}
    	}
    	return true
    }
    
    func main() {
    	route := gin.Default()
    
    	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
    		v.RegisterValidation("bookabledate", bookableDate)
    	}
    
    	route.GET("/bookable", getBookable)
    	route.Run(":8085")
    }
    
    func getBookable(c *gin.Context) {
    	var b Booking
    	if err := c.ShouldBindWith(&b, binding.Query); err == nil {
    		c.JSON(http.StatusOK, gin.H{"message": "Booking dates are valid!"})
    	} else {
    		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    	}
    }
    
    $ curl "localhost:8085/bookable?check_in=2018-04-16&check_out=2018-04-17"
    {"message":"Booking dates are valid!"}
    
    $ curl "localhost:8085/bookable?check_in=2018-03-08&check_out=2018-03-09"
    {"error":"Key: 'Booking.CheckIn' Error:Field validation for 'CheckIn' failed on the 'bookabledate' tag"}
    
    • 升级v9验证,支持多语言错误信息

    注意v9验证的话,标签要使用 validate ,也是为了与v8的标签分开。

    package main
    
    import (
    	"fmt"
    	"github.com/gin-gonic/gin"
    	"github.com/go-playground/locales/en"
    	"github.com/go-playground/locales/zh"
    	"github.com/go-playground/locales/zh_Hant_TW"
    	"github.com/go-playground/universal-translator"
    	"gopkg.in/go-playground/validator.v9"
    	zh_translations "gopkg.in/go-playground/validator.v9/translations/zh"
    	en_translations "gopkg.in/go-playground/validator.v9/translations/en"
    	zh_tw_translations "gopkg.in/go-playground/validator.v9/translations/zh_tw"
    )
    
    var (
    	Uni      *ut.UniversalTranslator
    	Validate *validator.Validate
    )
    
    type User struct {
    	Username string `form:"user_name" validate:"required"`
    	Tagline  string `form:"tag_line" validate:"required,lt=10"`
    	Tagline2 string `form:"tag_line2" validate:"required,gt=1"`
    }
    
    func main() {
    	en := en.New()
    	zh := zh.New()
    	zh_tw := zh_Hant_TW.New()
    	Uni = ut.New(en, zh, zh_tw)
    	Validate = validator.New()
    
    	route := gin.Default()
    	route.GET("/testing", startPage)
    	route.POST("/testing", startPage)
    	route.Run(":8085")
    }
    
    func startPage(c *gin.Context) {
    	//这部分应该放到中间件中
    	locale:=c.DefaultQuery("locale","zh")
    	trans, _ := Uni.GetTranslator(locale)
    	switch locale {
    	case "zh":
    		zh_translations.RegisterDefaultTranslations(Validate, trans)
    		break
    	case "en":
    		en_translations.RegisterDefaultTranslations(Validate, trans)
    		break
    	case "zh_tw":
    		zh_tw_translations.RegisterDefaultTranslations(Validate, trans)
    		break
    	default:
    		zh_translations.RegisterDefaultTranslations(Validate, trans)
    		break
    	}
    
    	//自定义错误内容
    	Validate.RegisterTranslation("required", trans, func(ut ut.Translator) error {
    		return ut.Add("required", "{0} must have a value!", true) // see universal-translator for details
    	}, func(ut ut.Translator, fe validator.FieldError) string {
    		t, _ := ut.T("required", fe.Field())
    		return t
    	})
    
    	//这块应该放到公共验证方法中
    	user := User{}
    	c.ShouldBind(&user)
    	fmt.Println(user)
    	err := Validate.Struct(user)
    	if err != nil {
    		errs := err.(validator.ValidationErrors)
    		sliceErrs:=[]string{}
    		for _, e := range errs {
    			sliceErrs=append(sliceErrs,e.Translate(trans))
    		}
    		c.String(200,fmt.Sprintf("%#v",sliceErrs))
    	}
    	c.String(200, fmt.Sprintf("%#v",""))
    }
    

    测试

    http://127.0.0.1:8085/testing?user_name=1111111&tag_line=1111122222222222222222&tag_line=111&locale=zh
    []string{"Tagline长度必须小于10个字符", "Tagline2 must have a value!"}""
    
    http://127.0.0.1:8085/testing?user_name=1111111&tag_line=1111122222222222222222&tag_line=111&locale=zh
    []string{"Tagline must be less than 10 characters in length", "Tagline2 must have a value!"}""
    

    2-5 中间件

    • 使用gin中间件
    func Logger() gin.HandlerFunc {
    	return func(c *gin.Context) {
    		t := time.Now()
    
    		// Set example variable
    		c.Set("example", "12345")
    
    		// before request
    
    		c.Next()
    
    		// after request
    		latency := time.Since(t)
    		log.Print(latency)
    
    		// access the status we are sending
    		status := c.Writer.Status()
    		log.Println(status)
    	}
    }
    
    func main() {
    	r := gin.New()
    	r.Use(Logger())
    
    	r.GET("/test", func(c *gin.Context) {
    		example := c.MustGet("example").(string)
    
    		// it would print: "12345"
    		log.Println(example)
    	})
    
    	// Listen and serve on 0.0.0.0:8080
    	r.Run(":8080")
    }
    
    • 自定义ip白名单中间件
    package main
    
    import (
    	"fmt"
    	"github.com/gin-gonic/gin"
    	"log"
    )
    
    func IPAuthMiddleware() gin.HandlerFunc {
    	return func(c *gin.Context) {
    		ipList:=[]string{
    			"192.168.1.1",
    		}
    		isMatched:=false
    		for _, host := range ipList {
    			if c.ClientIP() == host {
    				isMatched = true
    			}
    		}
    		if !isMatched{
    			c.String(200,fmt.Sprintf("%v, not in iplist", c.ClientIP()))
    			c.Abort()
    		}
    	}
    }
    
    func main() {
    	r := gin.New()
    	r.Use(IPAuthMiddleware())
    
    	r.GET("/test", func(c *gin.Context) {
    		example := c.MustGet("example").(string)
    		log.Println(example)
    	})
    
    	r.Run(":8080")
    }
    

    2-6 其他补充

    • 优雅关停
      确保在 go1.8+ 下编译
    // +build go1.8
    package main
    import (
    	"context"
    	"log"
    	"net/http"
    	"os"
    	"os/signal"
    	"syscall"
    	"time"
    	"github.com/gin-gonic/gin"
    )
    
    func main() {
    	router := gin.Default()
    	router.GET("/", func(c *gin.Context) {
    		time.Sleep(5 * time.Second)
    		c.String(http.StatusOK, "Welcome Gin Server")
    	})
    
    	srv := &http.Server{
    		Addr:    ":8080",
    		Handler: router,
    	}
    
    	go func() {
    		// service connections
    		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
    			log.Fatalf("listen: %s\n", err)
    		}
    	}()
    
    	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
    	<-quit
    	log.Println("Shutdown Server ...")
    
    	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    	defer cancel()
    	if err := srv.Shutdown(ctx); err != nil {
    		log.Fatal("Server Shutdown:", err)
    	}
    	
    	select {
    	case <-ctx.Done():
    		log.Println("timeout of 5 seconds.")
    	}
    	log.Println("Server exiting")
    }
    

    Linux Signal及Golang中的信号处理
    https://blog.csdn.net/leonpengweicn/article/details/52131313

    • 模板渲染
      gin在html/template基础之上,进行的文件解析预处理。模块文件使用方法与之前相同。
      LoadHTMLGlob 可以解析一个文件夹的模板。
    package main
    
    import (
    	"github.com/gin-gonic/gin"
    	"net/http"
    )
    func main() {
    	router := gin.Default()
    	//router.LoadHTMLFiles("templates/index.html",)
    	router.LoadHTMLGlob("templates/*")
    	router.GET("/index", func(c *gin.Context) {
    		c.HTML(http.StatusOK, "index.html", gin.H{
    			"title": "Main website",
    		})
    	})
    	router.Run(":8080")
    }
    

    index.html

    <html>
    <h1>
        {{ .title }}
    </h1>
    </html>
    

    template使用样例
    https://www.do1618.com/archives/893/go-template学习样例/
    https://www.calhoun.io/intro-to-templates-p3-functions/

    • Let’s Encrypt 自动证书下载
      无需配置任何证书即可自动下载证书,过期后自动续订。

    Let’s Encrypt原理
    在这里插入图片描述
    更多原理细节:
    https://www.cnblogs.com/esofar/p/9291685.html
    https://blog.csdn.net/canghaiguzhou/article/details/79945001

    gin使用方法超级简单:

    package main
    
    import (
    	"log"
    
    	"github.com/gin-gonic/autotls"
    	"github.com/gin-gonic/gin"
    )
    
    func main() {
    	r := gin.Default()
    	r.GET("/ping", func(c *gin.Context) {
    		c.String(200, "pong")
    	})
    	log.Fatal(autotls.Run(r, "www.itpp.tk"))
    }
    

    测试

    https://www.itpp.tk/ping
    pong
    

    查看证书缓存

    [root@izrj998xcgvke9018fkvbvz autotls]# ls ~/.cache/golang-autocert/
    acme_account+key  www.itpp.tk
    

    福利彩蛋,免费域名注册:
    https://www.freenom.com/zh/index.html?lang=zh

    2-7 构建企业级脚手架

    代码地址:https://github.com/e421083458/gin_scaffold
    使用gin构建了企业级脚手架,代码简洁易读,可快速进行高效web开发。
    主要功能有:
    1、请求链路日志打印,涵盖mysql/redis/request_in/request_out
    2、接入validator.v9,支持多语言错误信息提示及自定义错误提示。
    3、借助golang_common,支持了多配置环境及log/redis/mysql/http.client

    现在开始

    go mod tidy
    
    • 运行脚本
    go run main.go
    
    ➜  gin_scaffold git:(master) ✗ go run main.go
    ------------------------------------------------------------------------
    [INFO]  config=./conf/dev/
    [INFO]  start loading resources.
    [INFO]  success loading resources.
    ------------------------------------------------------------------------
    [GIN-debug] [WARNING] Now Gin requires Go 1.6 or later and Go 1.7 will be required soon.
    
    [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
    
    [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
     - using env:	export GIN_MODE=release
     - using code:	gin.SetMode(gin.ReleaseMode)
    
    [GIN-debug] GET    /demo/index               --> github.com/e421083458/gin_scaffold/controller.(*Demo).Index-fm (6 handlers)
    [GIN-debug] GET    /demo/bind                --> github.com/e421083458/gin_scaffold/controller.(*Demo).Bind-fm (6 handlers)
    [GIN-debug] GET    /demo/dao                 --> github.com/e421083458/gin_scaffold/controller.(*Demo).Dao-fm (6 handlers)
    [GIN-debug] GET    /demo/redis               --> github.com/e421083458/gin_scaffold/controller.(*Demo).Redis-fm (6 handlers)
     [INFO] HttpServerRun::8880
    
    • 测试mysql与请求链路
    curl 'http://127.0.0.1:8880/demo/dao?id=1'
    {
        "errno": 0,
        "errmsg": "",
        "data": "[{\"id\":1,\"area_name\":\"area_name\",\"city_id\":1,\"user_id\":2,\"update_at\":\"2019-06-15T00:00:00+08:00\",\"create_at\":\"2019-06-15T00:00:00+08:00\",\"delete_at\":\"2019-06-15T00:00:00+08:00\"}]",
        "trace_id": "c0a8fe445d05b9eeee780f9f5a8581b0"
    }
    
    查看链路日志(确认是不是一次请求查询,都带有相同trace_id):
    tail -f gin_scaffold.inf.log
    
    [INFO][2019-06-16T11:39:26.802][log.go:58] _com_request_in||method=GET||from=127.0.0.1||traceid=c0a8fe445d05b9eeee780f9f5a8581b0||cspanid=||uri=/demo/dao?id=1||args=map[]||body=||spanid=9dad47aa57e9d186
    [INFO][2019-06-16T11:39:26.802][log.go:58] _com_mysql_success||affected_row=1||traceid=c0a8fe445d05b9ee07b80f9f66cb39b0||spanid=9dad47aa1408d2ac||source=/Users/niuyufu/go/src/github.com/e421083458/gin_scaffold/dao/demo.go:24||proc_time=0.000000000||sql=SELECT * FROM `area`  WHERE (id = '1')||level=sql||current_time=2019-06-16 11:39:26||cspanid=
    [INFO][2019-06-16T11:39:26.802][log.go:58] _com_request_out||method=GET||args=map[]||proc_time=0.025019164||traceid=c0a8fe445d05b9eeee780f9f5a8581b0||spanid=9dad47aa57e9d186||uri=/demo/dao?id=1||from=127.0.0.1||response={\"errno\":0,\"errmsg\":\"\",\"data\":\"[{\\\"id\\\":1,\\\"area_name\\\":\\\"area_name\\\",\\\"city_id\\\":1,\\\"user_id\\\":2,\\\"update_at\\\":\\\"2019-06-15T00:00:00+08:00\\\",\\\"create_at\\\":\\\"2019-06-15T00:00:00+08:00\\\",\\\"delete_at\\\":\\\"2019-06-15T00:00:00+08:00\\\"}]\",\"trace_id\":\"c0a8fe445d05b9eeee780f9f5a8581b0\"}||cspanid=
    
    • 测试参数绑定与多语言验证
    curl 'http://127.0.0.1:8880/demo/bind?name=name&locale=zh'
    {
        "errno": 500,
        "errmsg": "Age为必填字段,Passwd为必填字段",
        "data": "",
        "trace_id": "c0a8fe445d05badae8c00f9fb62158b0"
    }
    
    curl 'http://127.0.0.1:8880/demo/bind?name=name&locale=en'
    {
        "errno": 500,
        "errmsg": "Age is a required field,Passwd is a required field",
        "data": "",
        "trace_id": "c0a8fe445d05bb4cd3b00f9f3a768bb0"
    }
    

    文件分层

    ├── README.md
    ├── conf   配置文件夹
    │   └── dev
    │       ├── base.toml
    │       ├── mysql_map.toml
    │       └── redis_map.toml
    ├── controller 控制器
    │   └── demo.go
    ├── dao DB数据访问层
    │   └── demo.go
    ├── dto  Bind结构体层
    │   └── demo.go
    ├── gin_scaffold.inf.log  info日志
    ├── gin_scaffold.wf.log warning日志
    ├── go.mod go module管理文件
    ├── go.sum
    ├── main.go
    ├── middleware 中间件层
    │   ├── panic.go
    │   ├── response.go
    │   ├── token_auth.go
    │   └── translation.go
    ├── public  公共文件
    │   ├── log.go
    │   ├── mysql.go
    │   └── validate.go
    ├── router  路由层
    │   ├── httpserver.go
    │   └── route.go
    └── tmpl
    

    引入轻量级golang类库,支持 mysql、redis、http.client、log、支持多级环境配置、支持链路日志打印

    go get -v github.com/e421083458/golang_common
    

    测试日志打印功能:

    package main
    
    import (
    	"github.com/e421083458/golang_common/lib"
    	"log"
    	"time"
    )
    
    func main() {
    	if err := lib.InitModule("./conf/dev/",[]string{"base","mysql","redis",}); err != nil {
    		log.Fatal(err)
    	}
    	defer lib.Destroy()
    
    	//todo sth
    	lib.Log.TagInfo(lib.NewTrace(), lib.DLTagUndefind, map[string]interface{}{"message": "todo sth"})
    	time.Sleep(time.Second)
    }
    

    类库更多功能细节请查看:
    https://github.com/e421083458/golang_common

    输出格式统一封装

    func ResponseError(c *gin.Context, code ResponseCode, err error) {
    	trace, _ := c.Get("trace")
    	traceContext, _ := trace.(*lib.TraceContext)
    	traceId := ""
    	if traceContext != nil {
    		traceId = traceContext.TraceId
    	}
    	resp := &Response{ErrorCode: code, ErrorMsg: err.Error(), Data: "", TraceId: traceId}
    	c.JSON(200, resp)
    	response, _ := json.Marshal(resp)
    	c.Set("response", string(response))
    	c.AbortWithError(200, err)
    }
    
    func ResponseSuccess(c *gin.Context, data interface{}) {
    	trace, _ := c.Get("trace")
    	traceContext, _ := trace.(*lib.TraceContext)
    	traceId := ""
    	if traceContext != nil {
    		traceId = traceContext.TraceId
    	}
    	resp := &Response{ErrorCode: SuccessCode, ErrorMsg: "", Data: data, TraceId: traceId}
    	c.JSON(200, resp)
    	response, _ := json.Marshal(resp)
    	c.Set("response", string(response))
    }
    

    定义中间件链路日志打印

    package middleware
    
    import (
    	"bytes"
    	"errors"
    	"fmt"
    	"github.com/e421083458/gin_scaffold/public"
    	"github.com/e421083458/golang_common/lib"
    	"github.com/gin-gonic/gin"
    	"io/ioutil"
    	"time"
    )
    //链路请求日志
    func RequestInLog(c *gin.Context) {
    	traceContext := lib.NewTrace()
    	if traceId := c.Request.Header.Get("com-header-rid"); traceId != "" {
    		traceContext.TraceId = traceId
    	}
    	if spanId := c.Request.Header.Get("com-header-spanid"); spanId != "" {
    		traceContext.SpanId = spanId
    	}
    	c.Set("startExecTime", time.Now())
    	c.Set("trace", traceContext)
    	bodyBytes, _ := ioutil.ReadAll(c.Request.Body)
    	c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes)) // Write body back
    
    	lib.Log.TagInfo(traceContext, "_com_request_in", map[string]interface{}{
    		"uri":    c.Request.RequestURI,
    		"method": c.Request.Method,
    		"args":   c.Request.PostForm,
    		"body":   string(bodyBytes),
    		"from":   c.ClientIP(),
    	})
    }
    //链路输出日志
    func RequestOutLog(c *gin.Context) {
    	endExecTime := time.Now()
    	response, _ := c.Get("response")
    	st, _ := c.Get("startExecTime")
    	startExecTime, _ := st.(time.Time)
    	public.ComLogNotice(c, "_com_request_out", map[string]interface{}{
    		"uri":       c.Request.RequestURI,
    		"method":    c.Request.Method,
    		"args":      c.Request.PostForm,
    		"from":      c.ClientIP(),
    		"response":  response,
    		"proc_time": endExecTime.Sub(startExecTime).Seconds(),
    	})
    }
    
    func TokenAuthMiddleware() gin.HandlerFunc {
    	return func(c *gin.Context) {
    		RequestInLog(c)
    		defer RequestOutLog(c)
    		isMatched := false
    		for _, host := range lib.GetStringSliceConf("base.http.allow_ip") {
    			if c.ClientIP() == host {
    				isMatched = true
    			}
    		}
    		if !isMatched{
    			ResponseError(c, InternalErrorCode, errors.New(fmt.Sprintf("%v, not in iplist", c.ClientIP())))
    			c.Abort()
    			return
    		}
    		c.Next()
    	}
    }
    

    请求数据绑定到结构体与校验

    dto/demo.go

    package dto
    
    import (
    	"errors"
    	"github.com/e421083458/gin_scaffold/public"
    	"github.com/gin-gonic/gin"
    	"github.com/go-playground/universal-translator"
    	"gopkg.in/go-playground/validator.v9"
    	"strings"
    )
    
    type InStruct struct {
    	Name   string `form:"name" validate:"required"`
    	Age    int64  `form:"age" validate:"required"`
    	Passwd string `form:"passwd" validate:"required"`
    }
    
    func (o *InStruct) BindingValidParams(c *gin.Context)  error{
    	if err:=c.ShouldBind(o);err!=nil{
    		return err
    	}
    	v:=c.Value("trans")
    	trans,ok := v.(ut.Translator)
    	if !ok{
    		trans, _ = public.Uni.GetTranslator("zh")
    	}
    	err := public.Validate.Struct(o)
    	if err != nil {
    		errs := err.(validator.ValidationErrors)
    		sliceErrs:=[]string{}
    		for _, e := range errs {
    			sliceErrs=append(sliceErrs,e.Translate(trans))
    		}
    		return errors.New(strings.Join(sliceErrs,","))
    	}
    	return nil
    }
    

    controller/demo.go

    func (demo *Demo) Bind(c *gin.Context) {
    	st:=&dto.InStruct{}
    	if err:=st.BindingValidParams(c);err!=nil{
    		middleware.ResponseError(c,500,err)
    		return
    	}
    	middleware.ResponseSuccess(c, "")
    	return
    }
    

    秤砣虽小压千斤

    3-1 用户管理系统设计

    在这里插入图片描述
    在这里插入图片描述

    功能点

    • 管理员登陆及退出
    • 用户列表 翻页
    • 增、删、改

    数据库

    • 用户表设计
    CREATE TABLE `user` (
     `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
     `name` varchar(255) NOT NULL DEFAULT '' COMMENT '姓名',
     `addr` varchar(255) NOT NULL DEFAULT '' COMMENT '住址',
     `age` smallint(4) NOT NULL DEFAULT '0' COMMENT '年龄',
     `birth` varchar(100) NOT NULL DEFAULT '2000-01-01 00:00:00' COMMENT '生日',
     `sex` smallint(4) NOT NULL DEFAULT '0' COMMENT '性别',
     `update_at` datetime NOT NULL DEFAULT '1970-01-01 00:00:00' COMMENT '更新时间',
     `create_at` datetime NOT NULL DEFAULT '1970-01-01 00:00:00' COMMENT '创建时间',
     PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8 COMMENT='用户表'
    

    后端准备

    前端准备

    3-2 实战开发

    • 开发接口
    [GIN-debug] POST   /api/login                --> github.com/e421083458/gin_scaffold/controller.(*Api).Login-fm (7 handlers)
    [GIN-debug] GET    /api/loginout             --> github.com/e421083458/gin_scaffold/controller.(*Api).LoginOut-fm (7 handlers)
    [GIN-debug] GET    /api/user/listpage        --> github.com/e421083458/gin_scaffold/controller.(*Api).ListPage-fm (8 handlers)
    [GIN-debug] GET    /api/user/add             --> github.com/e421083458/gin_scaffold/controller.(*Api).AddUser-fm (8 handlers)
    [GIN-debug] GET    /api/user/edit            --> github.com/e421083458/gin_scaffold/controller.(*Api).EditUser-fm (8 handlers)
    [GIN-debug] GET    /api/user/remove          --> github.com/e421083458/gin_scaffold/controller.(*Api).RemoveUser-fm (8 handlers)
    [GIN-debug] GET    /api/user/batchremove     --> github.com/e421083458/gin_scaffold/controller.(*Api).RemoveUser-fm (8 handlers)
    
    • 整合前端调试
    npm run dev
    

    修改 config/index.js文件,作接口代理转发

    dev: {
            env: require('./dev.env'),
            port: 8080,
            autoOpenBrowser: true,
            assetsSubDirectory: 'static',
            assetsPublicPath: '/',
            proxyTable: {
                "/api/": {
                    target:"http://127.0.0.1:8880/",
                    changeOrigin: true,
                    pathRewrite: {
                    }
                }
            },
            cssSourceMap: false
        }
    
    • 前后端部署与整合
      正式部署时我们一般考虑使用nginx 作转发。
        server {
            listen       8882;
            server_name  localhost;
            root /Users/niuyufu/WebstormProjects/vue-admin/dist;
            index  index.html index.htm index.php;
            location / {
                try_files $uri $uri/ /index.html?$args;
            }
            location /api/ {
                proxy_pass http://127.0.0.1:8880/api/;
            }
        }
    

    课程总结

    随堂笔记
    https://blog.csdn.net/e421083458/article/details/91994788
    gin入门实战 - 基础精髓 随堂代码
    https://github.com/e421083458/hello_gin
    golang基础代码类库
    https://github.com/e421083458/golang_common
    gin开发脚手架
    https://github.com/e421083458/gin_scaffold
    整合vue.js的admin后台
    https://github.com/e421083458/vue-admin

    展开全文
  • 13-MySQL数据库分类与版本升级知识讲解.avi 14-MySQL数据库商业版与社区版区别.avi 15-MySQL数据库的发布版本知识讲解.avi 16-MySQL数据库发展的三条产品线介绍.avi 17-MySQL数据库发布版本命名知识介绍.avi 18-企业...
  • 有很多的玩家都认为,道士是1.76复古传奇里面非常鸡肋的一个职业,本身的攻击力并不强,而且攻击的技能也不...如果道士能够将自己的神兽升级到七级,那么在和别的玩家PK,或者是刷BOSS的时候,道士获胜的几率是极高...

    有很多的玩家都认为,道士是1.76复古传奇里面非常鸡肋的一个职业,本身的攻击力并不强,而且攻击的技能也不多,大多数都是辅助的技能,进攻方面非常的欠缺,主要就是靠灵魂火符和神兽来进行攻击。在这主要的两种攻击手段中,神兽是对道士帮助最大的,也是让道士摆脱鸡肋职业称呼的关键。

    道士的神兽,最高等级为七级。如果道士能够将自己的神兽升级到七级,那么在和别的玩家PK,或者是刷BOSS的时候,道士获胜的几率是极高的。因为七级神兽的攻击力是很可怕的。和道士同等级,装备也是同阶的其他职业,如果遇到道士的七级神兽,加上道士在胖辅助攻击,会很快被道士给KO掉,可见,七级神兽对道士来说是很重要的。

    不过,道士想要将神兽升级到七级是非常困难的。需要带着自己的神兽不断的去杀怪,让神兽战死,然后再召唤神兽,这样才能够达到让神兽升级的目的。我们可以想象出,这是一项很漫长的任务,需要很长时间才能够完成。

    但是,老天在关上一扇门的时候,也会给你打开一扇窗户。对道士也是一样,升级神兽也是有捷径的。道士可以跑到大刀护卫的旁边,然后实战召唤神兽,大刀护卫会攻击神兽,并且都是一刀解决。道士就可以不停的召唤,很快就能够将神兽练到七级,帮助道士玩家在游戏中闯荡。

    展开全文
  • Istio入门与实战

    2020-12-19 17:05:45
    Istio入门与实战电子书本书通过从零始搭建一个微服务实验,逐一展示Istio的主要功能,直观地帮助读者理解Istio,非常适合门级读者快速掌握Istio技术。售价:¥纸质售价:¥61.20购买纸书229人正在读 | 0人评论6.2...

    Istio入门与实战电子书

    本书通过从零始搭建一个微服务实验,逐一展示Istio的主要功能,直观地帮助读者理解Istio,非常适合门级读者快速掌握Istio技术。

    售       价:¥

    纸质售价:¥61.20购买纸书

    229人正在读 | 0人评论

    6.2

    作       者:

    出  版  社:

    出版时间:2019-04-01

    字       数:32.2万

    温馨提示:此类商品不支持退换货,不支持下载打印

    为你推荐

    读书简介

    目录

    累计评论(0条)

    读书简介

    目录

    累计评论(0条)

    本书系统化介绍Istio技术要与应用技巧,可帮助读者快速搭建微服务架构并行管理。 主要内容包括:service mesh基本概念与使用,Istio架构设计与主要功能,快速搭建一个微服务实验,介绍如何让服务流量控制更简单,让服务更具弹性,让服务故障测试更容易,让服务通信更安全可控,让服务更易观测与监控,以及istio维护方案。本书内容丰富、案例讲解,实用性强,非常适合门级读者快速掌握Istio技术。
    【推荐语】
    本书通过从零始搭建一个微服务实验,逐一展示Istio的主要功能,直观地帮助读者理解Istio,非常适合门级读者快速掌握Istio技术。   本书是一本实战型的书,书中没有大篇的理论知识。对于Istio提供的功能,本书只简单地描述其作用和使用方式,然后使用实验来演示效果。 只要你跟着书中的实验操作,并理解这些实验的目的,学习完本书后,你就一定能熟练使用Istio,并在以后的Istio使用中得心应手。  对服务网格感兴趣的人都可以阅读本书。如果你想了解服务网格,想知道服务网格提供了哪些功能,能解决什么问题,本书将是一个不错的选择。 如果你想了解Istio,体验Istio,将来有可能将Istio应用于生产环境,那么阅读本书将是一个不错的始。
    【作者】
    毛广献 某游戏社区与数据服务公司网络工程师,参与过多项业务技术架构设计与应用发运维。对分布式、微服务等有着独到的见解。他是热爱技术的极客,喜欢研究新技术和源项目。

    目录展开

    前言

    第1章 服务网格与Istio

    1.1 服务网格简介

    1.2 Istio简介

    1.3 Istio的架构设计

    1.4 Istio的功能特性

    1.5 本章小结

    第2章 实验说明

    2.1 实验的环境

    2.2 实验的应用

    2.3 应用的构建

    2.4 本章小结

    第3章 使用Vagrant管理虚拟机

    3.1 Vagrant简介

    3.2 Vagrant常用命令

    3.3 模拟实验时的场景

    3.4 本章小结

    第4章 创建Kubernetes集群

    4.1 安装Docker

    4.2 安装Kubeadm

    4.3 配置基础环境

    4.4 创建Kubernetes集群的步骤

    4.5 测试集群的正确性

    4.6 注意事项与技巧

    4.7 本章小结

    第5章 Istio部署与常用命令

    5.1 部署Istio

    5.2 常用资源类型

    5.3 常用的kubectl命令

    5.4 常用的istioctl命令

    5.5 注意事项与技巧

    5.6 本章小结

    第6章 微服务应用的部署

    6.1 微服务应用架构

    6.2 部署服务

    6.3 访问服务

    6.4 在Istio中部署微服务

    6.5 本章小结

    第7章 让服务流量控制更简单

    7.1 整体介绍

    7.2 管理集群的入口流量

    7.3 把请求路由到服务的指定版本

    7.4 根据服务版本权重拆分流量

    7.5 根据请求信息路由到服务的不同版本

    7.6 流量镜像

    7.7 管理集群的出口流量

    7.8 实现服务A/B测试

    7.9 实现服务灰度发布

    7.10 灰度发布与A/B测试结合

    7.11 本章小结

    第8章 让服务更具弹性

    8.1 整体介绍

    8.2 负载均衡

    8.3 连接池

    8.4 健康检测

    8.5 熔断

    8.6 超时

    8.7 重试

    8.8 限流

    8.9 本章小结

    第9章 让服务故障检测更容易

    9.1 整体介绍

    9.2 给服务增加时延

    9.3 给服务注入错误

    9.4 时延与错误配合使用

    9.5 本章小结

    第10章 让服务通信更安全可控

    10.1 整体介绍

    10.2 Denier适配器

    10.3 黑白名单

    10.4 服务与身份认证

    10.5 RBAC访问控制

    10.6 本章小结

    第11章 让服务更易观测与监控

    11.1 整体介绍

    11.2 指标收集

    11.3 日志收集

    11.4 调用链追踪

    11.5 服务指标可视化

    11.6 服务调用树

    11.7 本章小结

    第12章 Istio维护

    12.1 整体介绍

    12.2 Istio服务网格仪表板

    12.3 升级Istio

    12.4 使用Helm定制部署Istio

    12.5 故障排除

    12.6 一个请求的完整过程分析

    12.7 本章小结

    第13章 杂项

    13.1 CORS

    13.2 URL重定向

    13.3 URL重写

    13.4 TCP路由

    13.5 TLS路由

    13.6 mTLS迁移

    13.7 EnvoyFilter

    13.8 添加请求头

    13.9 在Gateway上使用HTTPS

    13.10 在HTTPS服务上开启mTLS

    13.11 网格中的服务健康检查

    13.12 Envoy代理Ingressgateway

    13.13 Mixer与Adapter模型

    13.14 本章小结

    累计评论(0条)1个书友正在讨论这本书

    发表评论

    发表评论

    发表评论,分享你的想法吧!

    买过这本书的人还买过

    读了这本书的人还在读

    展开全文
  • 本书基于PostgreSQL 10编写,重点介绍...进阶篇包括第10到18章,主要介绍PostgreSQL进阶内容,例如性能优化、物理复制、逻辑复制、备份与恢复、高可用、版本升级、Oracle数据库迁移PostgreSQL实战、PostGIS等。
  • HBase实战+权威指南

    2018-02-24 13:53:09
    《HBase实战》是一本基于经验提炼而成的指南,它教给读者如何运用HBase设计、搭建及运行大数据应用系统。全书共分为4个部分。前两个部分分别介绍了分布式系统和大规模数据处理的发展历史,讲解HBase的基本原理模式...
  • 2.很多基础方法,基础API,无论Unity怎么升级也没有变,且不说要不要向前兼容,官方自身也不敢改动太多(一个没什么错的代码,你会随便去改么?) Unity的资源加载分类: Resource DataPath PesistantPath ...
  • Vue全家桶基础+实战高仿美团外卖App

    千人学习 2020-07-06 15:17:49
    【课程收获】 1、从基础知识到项目实战,内容涵盖Vue各个层面的知识和技巧 2、学习曲线平缓,前端新人也可以看得懂 3、贴近企业项目,按照企业级代码标准和工程开发的流程进行讲解 4、让你能够独立开发高颜值的项目...
  • 大规模私有云产品自动升级的架构选型和实战 关注微信公众号:GitChat 技术杂谈 ,一本正经的讲技术 一、项目背景概述 对于云计算,每个人都有自己的定义,有按SAAS,PAAS,IAAS划分的;有按公有云,...
  • 配置数据生成技巧 强化升级数据解析 开发思路讲解 强化升级存储结构 强化升级系统逻辑1 强化升级系统逻辑2 强化升级系统逻辑3 强化升级系统逻辑4 强化升级系统逻辑5 强化升级系统逻辑6 强化升级系统逻辑7...
  • 在《Kubernetes探秘-多master节点容错部署》中介绍了通过部署多个主节点来提高Kubernetes的容错能力。其中,最为关键是存储集群控制数据的etcd服务必须在多个副节点间实时同步,而kube-apiserver通过keepalived进行...
  • 我 as 升级了,无法截我自己的配置页面图,原理是一样的,你的模板配置了哪些选项,在上图中就可以选择。 我的mvvm_templates 模板下载地址 这是我自己的配置,大家可以拿去参考修改。 2.2 as 版本4.1后 从 Android...
  • Hbase实战 中文版

    2014-10-14 17:14:25
    第三部分通过真实的应用和代码示例以及支持这些实践技巧的理论知识,进一步探索HBase的一些实用技术;第四部分讲解如何把原型开发系统升级为羽翼丰满的生产系统。 《HBase实战》适合所有对云计算、大数据处理技术和...
  • Hadoop实战

    2020-12-19 14:03:18
    Hadoop实战1 Hadoop简介1.1 什么是Hadoop1.1.1 Hadoop概述1.1.2 Hadoop的历史1.1.3 Hadoop的功能与作用1.1.4 Hadoop的优势1.1.5 Hadoop的应用现状和发展趋势1.2 Hadoop项目及其结构1.3 Hadoop的体系结构1.3.1 HDFS的...
  • 在前几版的基础上做了全面升级,提供了zui新、zui有用的提示和技巧,而且通过教程说明现今可用的 CSS。会教你如何使用新工具(如弹性盒和 Sass)构建外观精美的网页,而且在任何桌面设备或移动设备中都能快速运行。...
  • 第三部分通过真实的应用和代码示例以及支持这些实践技巧的理论知识,进一步探索HBase的一些实用技术;第四部分讲解如何把原型开发系统升级为羽翼丰满的生产系统。 《HBase实战》适合所有对云计算、大数据处理技术和...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 10,506
精华内容 4,202
关键字:

升级实战技巧