ohmybaby

ohmybaby 查看完整档案

成都编辑  |  填写毕业院校  |  填写所在公司/组织 zhangmj.com 编辑
编辑

_
| |__ __ _
| '_ | | | |/ _` |
| |_) | |_| | (_| |
|_.__/ \__,_|\__, |

         |___/

建了个golang交流群,欢迎大家加入
QQ群: 642154119
wx: mr_735416909

个人动态

ohmybaby 关注了专栏 · 10月10日

K8S 实战笔记

关注 3

ohmybaby 回答了问题 · 9月18日

解决除了cookie之外,还能用什么方法做验证码功能?

前端调用,服务端根据该接口的类型 向数据库插入一条数据,比如:
注册,手机号

insert code ( type = register and mobile = 10086 and code = 1111 )

查询的时候

select * from code where mobile = 10086 & type = register .

验证时间,code是否相同,手机号和类型 作为联合唯一键,

为了避免同一手机号 发送了过多短信,可以加个限制比如一天最多10条。

无需响应cookie,

关注 5 回答 5

ohmybaby 回答了问题 · 9月18日

解决golang开发 rpc 应用时,对于rpc服务的目录结构如何合理规划

我们是这样规划的:
如果这个项目的proto会被其他的项目引用,那么 proto 就放在 公共的proto项目里,
否则就放自己项目里,

生成的pb,自己去拉取对应的proto生成pb, 不管是客户端还是服务端

关注 4 回答 3

ohmybaby 回答了问题 · 9月18日

解决请问 怎么编写 go-micro 的 example 函数?

image.png
加号点开,看下具体的运行参数是不是带了

-test.testlogfile

如果是,在 run > params 看下是否有参数,有的话就清除掉。

image.png

关注 2 回答 2

ohmybaby 回答了问题 · 9月14日

解决关于开发环境问题,访问内网数据库

你可以偷偷的在运行代码的服务器上做一个tcp代理,

   mysql  <->  |   <-> server  <->  |   your computer  

关注 6 回答 4

ohmybaby 回答了问题 · 9月11日

解决Golang中如何int 16进制转byte再转int

    package main  

    import (  
       "encoding/binary"  
     "fmt")  

    func main() {  
         const x = 0x5AF3ACA48850  

         fmt.Println(int64(x))  

         var data = make([]byte, 8)  

         // 大端序  我们一般采用的是大端序. 小端序不考虑
         binary.BigEndian.PutUint64(data, uint64(x))  
         fmt.Println(data)  
          // output:  
         // [0 0 90 243 172 164 136 80]  
         // 小端序 binary.LittleEndian.PutUint64(data, uint64(x))  
         fmt.Println(data)  
         // output:  
         // [80 136 164 172 243 90 0 0]  
         var bytes = []byte{0, 0, 90, 243, 172, 164, 136, 80}  
         fmt.Println(binary.BigEndian.Uint64(bytes) == uint64(x))  
        // true
   }

因此:

  1. int转byte之后,得到的是[172 164 136 80] 而如何才可以得到这种输出?[]byte{0x17, 0xED, 0x48, 0x94, 0x1A, 0x08, 0xF9, 0x81} 因为需要直接填入到代码中,不能直接写数值。

int 转 byte 之后,得到的是 [0 0 90 243 172 164 136 80] ,因此填入代码应该是这么写:

 var bytes = []byte{0, 0, 90, 243, 172, 164, 136, 80} 

如果你需要使用16进制写法的话. 你手动算一下就行了,也可以在线工具算一下:

var bytes = []byte{0, 0, 0x5a, 0xf3, 0xac, 0xa4, 0x88,0x50}

你上面的写法的问题在于. 0x5AF3ACA48850 数值太大了,超过了 int32 的最大值,溢出了,应该使用的是 int64 去转换.

还有我转换的结果与你的不相等,不知道是否你的是正确与否

关注 2 回答 1

ohmybaby 回答了问题 · 9月5日

PHP程序员如何理解TCP协议

理解成一个TCP连接就是两根相反流动的水管,水就是其中的数据,
数据是没有边界的,水流也没有界限,因此你需要根据水流的大小,来截取对应的数据,解码成你需要的数据。

比如协议规定tcp 的头部2个字节表示长度,余下的字节表示body部分的具体内容(具体协议可以自定义)

于是我在第一次读取数据的时候,先读取2个字节,然后把这两个字节转成10进制,就是body的长度. 然后重新生成body的数组,继续读:

    var conn net.Conn
    type YourStruct struct {
        Username string `json:"username"`
    }
    for {
        b := make([]byte, 2)
        _, err := io.ReadFull(conn, b)
        if err != nil {
            return
        }
        length := binary.BigEndian.Uint16(b)

        body := make([]byte, length)
        _, err = io.ReadFull(conn, body)
        if err != nil {
            return
        } 
        // 解析结构体
        var v = new(YourStruct)
        json.Unmarshal(body, v)
        fmt.Println(v.Username)
    }

写数据也是一样的道理:

  1. 先计算需要写的长度,转换成byte数组发送,然后再发送body。
    var conn net.Conn
    type YourStruct struct {
        Username string `json:"username"`
    }
    for {
        v := YourStruct{Username: "hahah"}
        data, _ := json.Marshal(v)
        header := make([]byte, 2)
        binary.BigEndian.PutUint16(header, uint16(len(data)))

        // 写头
        conn.Write(header)
        // 写body
        conn.Write(data)
    }

tcp的边界定义就是跟据你定的协议,组装好数据包,发送的时候组装包,获取的时候拆包.
2个字节的头,body最长应该是65535个字节,超过这个长度,header就应该增加长度

关注 2 回答 1

ohmybaby 发布了文章 · 9月5日

swaggos 发布第一个版本v0.0.1

Swaggos

swaggos 是一个golang版本的swagger文档生成器,提供了native code包装器,并且支持主流的web框架包裹器

安装

    go get -u github.com/clearcodecn/swaggos

示例

目前只支持gin的包裹器
package main

import (
    "github.com/clearcodecn/swaggos"
    "github.com/clearcodecn/swaggos/ginwrapper"
    "github.com/gin-gonic/gin"
    "github.com/go-openapi/spec"
)

type User struct {
    Username     string `json:"username" required:"true"`
    Password     string `json:"password" required:"true" description:"密码" example:"123456" maxLength:"20" minLength:"6" pattern:"[a-zA-Z0-9]{6,20}"`
    Sex          int    `json:"sex" required:"false" default:"1" example:"1" format:"int64"`
    HeadImageURL string `json:"headImageUrl"`

    History string `json:"-"` // ignore
}

func main() {
    g := ginwrapper.Default()
    doc := g.Doc()
    g.Gin().Use(func(ctx *gin.Context) {
        ctx.Writer.Header().Set("Access-Control-Allow-Origin", "*")
    })
    doc.JWT("Authorization")
    doc.HostInfo("https://localhost:8080/", "/api/v1")
    group := g.Group("/api/v1")
    {
        group.GET("/users", listUsers).
            Query("order", swaggos.DescRequired("排序", false)).
            Query("q", swaggos.DescRequired("名称迷糊查询", false)).
            JSON([]User{})

        group.POST("/user/create", createUser).
            Body(new(User)).JSON(gin.H{"id": 1})

        group.DELETE("/user/*id", deleteUser).
            JSON(gin.H{"id": 1})

        group.PUT("/user/update", createUser).
            Body(new(User)).JSON(new(User))
    }
    g.ServeDoc()
    g.Gin().Run(":8888")
}

func listUsers(ctx *gin.Context)  {}
func createUser(ctx *gin.Context) {}
func deleteUser(ctx *gin.Context) {}

示例将会生成该图例:
您可以查看 examples 目录查看更多示例.

您也可以不使用包裹器

func main() {
    doc := swaggos.Default()

    doc.HostInfo("localhost:8080", "/api").
        Response(200, newSuccessExample()).
        Response(400, newErrorExample())

    group := doc.Group("/users")
    group.Get("/list").JSON(CommonResponseWithData([]model.User{}))
    group.Post("/create").Body(new(model.User)).JSON(CommonResponseWithData(1))
    group.Put("/update").Body(new(model.User)).JSON(CommonResponseWithData(1))
    // path item
    group.Get("/{id}").JSON(new(model.User))
    group.Delete("/{id}").JSON(CommonResponseWithData(1))

    data, _ := doc.Build()
    fmt.Println(string(data))

    data, _ = doc.Yaml()
    fmt.Println(string(data))
}

使用

增加请求头

     doc.Header("name","description",true)
    => generate a required header with key name

增加jwt token

    doc.JWT("Authorization")
    => ui will create authorization in request headers.  

Oauth2 支持

    scopes:= []string{"openid"}
    doc.Oauth2("http://path/to/oauth/token/url",scopes,scopes)
    => ui will create a oauth2 password credentials client

增加 host 信息

    doc.HostInfo("yourhost.com","/your/api/prefix")

增加 响应 content-Type 类型

    doc.Produces("application/json")

增加 请求 content-Type 类型

    doc.Consumes("application/json")

生成json

    data,_ := doc.Build()
    fmt.Println(string(data))
    => this is the swagger schema in json format

    data,_ := doc.Yaml()
    fmt.Println(string(data))
    => yaml format

struct的规则

swaggos 会解析结构体的tag并将其赋值到 swagger 规则上面,下面是本项目支持的一些tag示例

    type User struct {
        // 字段名称  model > json
        // this example field name will be m1
        ModelName string `model:"m1" json:"m2"`
        // 字段名会是  username 
        Username string `json:"username"` 
        //  字段名会是 Password
        Password string 
        // 会被忽略
        Ignored `json:"-"`
        // 是否必须
        Required string `required:"true"`
        // 字段的描述
        Description string `description:"this is description"`
        // 字段的类型: string,integer,time,number,boolean,array...
        Type string `type:"time"`
        // 默认值 abc
        DefaultValue string `default:"abc"`
        // 最大值 100
        Max float64 `maximum:"100"`
        // 最小值 0
        Min float64 `min:"0"`
        // 最大长度 20
        MaxLength string `maxLength:"20"`
        // 最小长度 10
        MinLength string `minLength:"10"`
        // 正则表达式规则
        Pattern string `pattern:"\d{0,9}"`
        // 数组长度 小于3
        MaxItems []int `maxItems:"3"`
        // 数组长度大于3
        MinItem []int `minItems:"3"`
        // 枚举,用 , 分割
        EnumValue int `enum:"a,b,c,d"`
        // 忽略字段
        IgnoreField string `ignore:"true"`
        // 匿名字段规则:
        // 如果是一个基本类型,则直接添加, 
        // 如果是一个 数组,也将直接添加
        // 如果是一个结构体 但是带了json tag,将会作为一个字段
        // 如果是一个结构体 带没有json tag,将会将里面的子字段添加上该结构体上
        Anymouse
    }

path上的工具方法

    path := doc.Get("/")
    // 创建一个 query 字段,包含了 描述和是否必须
    path.Query("name",DescRequired("description",true)).
    // 创建一个 query 字段,包含了 描述和是否必须 和默认值
    Query("name2",DescRequiredDefault("desc",true,"default"))

other useful functions:

    // 创建一个 swagger 的tag
    path.Tag("user group")
    
    // 请求的简单描述
    path.Summary("create a new user")

    // 请求的详细描述
    path.Description("....")
       
    // 设置请求-响应头
    path.ContentType("application/json","text/html")
   
    // form 字段
    path.Form("key1",swaggos.Attribute{Required:true})

    // 文件
    path.FormFile("file",swaggos.Attribute{Required:true})
    
    // form 用接头体解析
    path.FormObject(new(User))

    // query 用结构体解析
    path.QueryObject(new(User))
    
    // body 用结构体解析
    path.Body(new(User))

    // 响应json
    path.JSON(new(User))

响应

    // 响应带上具体的内容,将会创建具体的json示例
    // 400 
    path.BadRequest(map[string]interface{
            "data": nil,
            "code": 400,
    })
    // 401
    path.UnAuthorization(v)
    // 403
    path.Forbidden(v)
    // 500 
    path.ServerError(v)

github: https://github.com/clearcodecn/swaggos

gitee:  https://gitee.com/wocaa/swaggos

QQ群:642154119

欢迎Star 和提交issue&pr

查看原文

赞 0 收藏 0 评论 0

ohmybaby 回答了问题 · 8月26日

我该如何收集golang协程里面的值

var result = make(chan int,5)
for i := 0 ; i < 5 ; i ++ {
    go func() {
        val := getResult()
        result <- val
    }
}
var sum = 0 
for val := range result {
    sum += val
}

print(sum)

关注 3 回答 3

ohmybaby 回答了问题 · 8月26日

解决golang if 多个条件怎么简写

var fileTypes = map[string]bool{
    "cvs",
    "xlsx",
    "txt",
}
if _,ok := fileTypes[val] ; ok {
   // 存在
} else {
   // 不存在
}

关注 6 回答 5

认证与成就

  • 获得 18 次点赞
  • 获得 26 枚徽章 获得 0 枚金徽章, 获得 7 枚银徽章, 获得 19 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2016-09-13
个人主页被 606 人浏览