如何在golang list 使用使用自定义的包

你的位置: >
> golang包管理工具godep save无效的坑
参照官方的方式下载安装完godep后,做了一个测试目录,测试目录结构如下:
|- main.go
main.go内容如下:
package main
&gopkg.in/mgo.v2&
func main() {
我琢磨着在项目目录下使用godep save命令,应当就会自动在当前目录下生成Godeps目录,并且把labix.org/v2/mgo这个库拷贝到其中的_workspace目录下。
$ godep save -r ./...
没有输出提示信息,应该是成功了,查看下目录信息
godep测试目录结构
有生成Godeps目录,但是_workspace下并没有项目库文件,好奇怪啊,也没有报错。
google搜索了下godeps save not work,没有找到有价值的信息,于是去翻了下源码,看到save这个有help信息,可以用-d, -v打印出相应的调试信息。
$ godep save -r -d -v ./...
这里会输出一堆调试信息...
仔细看了这些信息,发现有一个Done Looking For Package的调试信息,从调试信息来看是在源码文件中没有找到对应的依赖库,也就是上面的labix.org/v2/mgo没有被找到,没有找到自然不会自动去拷贝,也没有报错信息。Godeps.json的内容就是这样:
"ImportPath": ".",
"GoVersion": "go1.5",
"Packages": [
"Deps": []
太蛋疼了,这个是啥子问题呢!各种搜索引擎乱翻,看到一篇关于godep save版本库没有设置的问题:
godep: directory "/Users/tony/Test/GoToolsProjects/src" is not using a known version control system
godep: error loading dependencies
我依照该篇文章去测试,一切目录命名都是照搬,发现解决了版本库问题后居然就可以了。
我仔细对比了前面自己的方式和该篇的方式区别,发现该篇文章是的目录是在GOPATH的src目录下,而我前面测试的目录是在自己的code代码里,不在GOPATH的src下。想到这里我立马进行了测试,我把前面的测试目录拷贝到GOPATH的src下,再次执行godep save -r ./…就可以了。
最后总结一下这个问题是由于代码目录没有在GOPATH/src目录下造成的。
这个好大的一坑啊,我自己的习惯是GOPATH的目录只用来存放go get的代码库。其它的开发项目都是放在不同的目录下。这个不知道算不算是godep的一个bug呢?
参考文章:
转载请注明: &
与本文相关的文章package protocol
"encoding/binary"
ConstHeader
= "jackluo"
ConstHeaderLength
ConstSaveDataLength = 4
func Packet(message []byte) []byte {
return append(append([]byte(ConstHeader), IntToBytes(len(message))...), message...)
func Unpack(buffer []byte, readerChannel chan []byte) []byte {
length := len(buffer)
for i = 0; i & i = i + 1 {
if length & i+ConstHeaderLength+ConstSaveDataLength {
if string(buffer[i:i+ConstHeaderLength]) == ConstHeader {
messageLength := BytesToInt(buffer[i+ConstHeaderLength : i+ConstHeaderLength+ConstSaveDataLength])
if length & i+ConstHeaderLength+ConstSaveDataLength+messageLength {
data := buffer[i+ConstHeaderLength+ConstSaveDataLength : i+ConstHeaderLength+ConstSaveDataLength+messageLength]
readerChannel &- data
i += ConstHeaderLength + ConstSaveDataLength + messageLength - 1
if i == length {
return make([]byte, 0)
return buffer[i:]
//整形转换成字节
func IntToBytes(n int) []byte {
x := int32(n)
bytesBuffer := bytes.NewBuffer([]byte{})
binary.Write(bytesBuffer, binary.BigEndian, x)
return bytesBuffer.Bytes()
//字节转换成整形
func BytesToInt(b []byte) int {
bytesBuffer := bytes.NewBuffer(b)
var x int32
binary.Read(bytesBuffer, binary.BigEndian, &x)
return int(x)
package main
"./protocol"
func main() {
netListen, err := net.Listen("tcp", ":9988")
CheckError(err)
defer netListen.Close()
Log("Waiting for clients")
conn, err := netListen.Accept()
if err != nil {
Log(conn.RemoteAddr().String(), " tcp connect success")
go handleConnection(conn)
func handleConnection(conn net.Conn) {
//声明一个临时缓冲区,用来存储被截断的数据
tmpBuffer := make([]byte, 0)
//声明一个管道用于接收解包的数据
readerChannel := make(chan []byte, 16)
go reader(readerChannel)
buffer := make([]byte, 1024)
n, err := conn.Read(buffer)
if err != nil {
Log(conn.RemoteAddr().String(), " connection error: ", err)
Log(conn.RemoteAddr().String(), "receive data length:", n)
Log(conn.RemoteAddr().String(), "receive data:", buffer[:n])
Log(conn.RemoteAddr().String(), "receive data string:", string(buffer[:n]))
tmpBuffer = protocol.Unpack(append(tmpBuffer, buffer[:n]...), readerChannel)
func reader(readerChannel chan []byte) {
case data := &-readerChannel:
Log(string(data))
func Log(v ...interface{}) {
fmt.Println(v...)
func CheckError(err error) {
if err != nil {
fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
os.Exit(1)
package main
"./protocol"
func sender(conn net.Conn) {
for i := 0; i & 100; i++ {
words := "{\"Id\":1,\"Name\":\"golang\",\"Message\":\"message\"}"
conn.Write(protocol.Packet([]byte(words)))
fmt.Println("send over")
func main() {
server := "127.0.0.1:9988"
tcpAddr, err := net.ResolveTCPAddr("tcp4", server)
if err != nil {
fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
os.Exit(1)
conn, err := net.DialTCP("tcp", nil, tcpAddr)
if err != nil {
fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
os.Exit(1)
defer conn.Close()
fmt.Println("connect success")
go sender(conn)
time.Sleep(1 * 1e9)
阅读(...) 评论()golang中结构体的初始化方法(new方法) | 学习笔记&&当前位置: && && 列表
【玩转Golang】 自定义json序列化对象时,非法字符错
来源:网络 && 编辑:admin
  由于前台web页面传来的日期对象是这样的格式& 15:23:22&,所以我安装网上查来的办法,自定义包装了time.Time对象,实现自己的Marshal和UnMarshal方法
type DateTime struct {
const ctLayout = " 15:04:05"
const ctLayout_nosec = " 15:04"
const ctLayout_date = ""
func (this *DateTime) UnmarshalJSON(b []byte) (err error) {
if b[0] == """ && b[len(b)-1] == """ {
b = b[1 : len(b)-1]
loc, err := time.LoadLocation("Asia/Shanghai")
if err != nil {
panic(err)
sv := string(b)
if len(sv) == 10 {
sv += " 00:00:00"
} else if len(sv) == 16 {
sv += ":00"
this.Time, err = time.ParseInLocation(ctLayout, string(b), loc)
if err != nil {
if this.Time, err = time.ParseInLocation(ctLayout_nosec, string(b), loc); err != nil {
this.Time, err = time.ParseInLocation(ctLayout_date, string(b), loc)
func (this *DateTime) MarshalJSON() ([]byte, error) {
rs := []byte(this.Time.Format(ctLayout))
return rs, nil
var nilTime = (time.Time{}).UnixNano()
func (this *DateTime) IsSet() bool {
return this.UnixNano() != nilTime
然后,把结构中声明为time.Time的都修改为自定义的类型DateTime,试了一下,发现已经可以正确解析网页发来的时间,但是在输出时,总是不对,好像并没有调用自定义的Marshal方法。编写测试方法发现,原来json.Marshal方法调用DateTime.Marshal时出错了!
invalid character "-" after top-level value
开始没有认真看,以为&-&号不合法,就换了一个,结果错误一样:
invalid character "/" after top-level value
看来,根本不是分割符的问题,仔细分析错误,发现&top-level&字样,我这返回的就是一个字符串,怎么可能top-level呢!想到这儿突然醒悟,是不是返回字符串应该自己加引号呢,急忙修改代码一试,果然!~_~
最终代码如下:
type DateTime struct {
const ctLayout = " 15:04:05"
const ctLayout_nosec = " 15:04"
const ctLayout_date = ""
func (this *DateTime) UnmarshalJSON(b []byte) (err error) {
if b[0] == """ && b[len(b)-1] == """ {
b = b[1 : len(b)-1]
loc, err := time.LoadLocation("Asia/Shanghai")
if err != nil {
panic(err)
sv := string(b)
if len(sv) == 10 {
sv += " 00:00:00"
} else if len(sv) == 16 {
sv += ":00"
this.Time, err = time.ParseInLocation(ctLayout, string(b), loc)
if err != nil {
if this.Time, err = time.ParseInLocation(ctLayout_nosec, string(b), loc); err != nil {
this.Time, err = time.ParseInLocation(ctLayout_date, string(b), loc)
func (this *DateTime) MarshalJSON() ([]byte, error) {
rs := []byte(fmt.Sprintf(`"%s"`, this.Time.Format(ctLayout)))
return rs, nil
var nilTime = (time.Time{}).UnixNano()
func (this *DateTime) IsSet() bool {
return this.UnixNano() != nilTime
来源:网络 && 编辑:admin使用Golang开发微信公众平台
使用Golang开发微信公众平台
关注并使用过微信“飞常准”公众号的朋友们都有过如下体验:查询一个航班情况后,这个航班的checkin、登机、起降等信息都会在后续陆续异步发给你,这个服务就是通过微信公众平台的客服消息实现的。
中关于客服消息的解释如下:“当用户主动发消息给公众号的时候(包括发送信息、点击自定义菜单、订阅事件、扫描二维码事件、支付成功 事件、用户维权),微信将会把消息数据推送给开发者,开发者在一段时间内(目前修改为48小时)可以调用客服消息接口,通过POST一个JSON数据包来 发送消息给普通用户,在48小时内不限制发送次数。此接口主要用于客服等有人工消息处理环节的功能,方便开发者为用户提供更加优质的服务”。
这篇文章我们就来说说如何用实现发送文本客服消息。
一、获取access_token
access_token是公众号的全局唯一票据,公众号调用微信平台各接口时都需使用access_token。我们要主动给微信平台发送客服消息,该access_token就是我们的凭证。在构造和下发客服消息前,我们需要获取这个access_token。
access_token的有效期为2小时(7200s),我们获取一次,两小时内均可使用。微信公众平台开发文档也给出了access_token获取、保存以及刷新的技术建议。但我们这里仅是Demo,无需考虑这么多。
通过https GET请求,我们可以得到属于我们的access_token,请求line为:
https://api./cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
golang提供了默认的http client实现,通过默认的client实现我们可以很容器的获取access_token。
&&&&&&& token&&&&&&&&&&&&&& = "wechat4go"
&&&&&&& appID&&&&&&&&&&&&&& = "wx8e0fb2659c2eexxx"
&&&&&&& appSecret&&&&&&&&&& = "2fe50cbfyyy"
&&&&&&& accessTokenFetchUrl = "https://api./cgi-bin/token"
func fetchAccessToken() (string, float64, error) {
&&&&&&& requestLine := strings.Join([]string{accessTokenFetchUrl,
&&&&&&&&&&&&&&& "?grant_type=client_credential&appid=",
&&&&&&&&&&&&&&& appID,
&&&&&&&&&&&&&&& "&secret=",
&&&&&&&&&&&&&&& appSecret}, "")
&&&&&&& resp, err := http.Get(requestLine)
&&&&&&& if err != nil || resp.StatusCode != http.StatusOK {
&&&&&&&&&&&&&&& return "", 0.0, err
&&&&&&& defer resp.Body.Close()
&&&&&&& body, err := ioutil.ReadAll(resp.Body)
&&&&&&& if err != nil {
&&&&&&&&&&&&&&& return "", 0.0, err
&&&&&&& fmt.Println(string(body))
&&& &&& … …
无论成功与否,微信平台都会返回一个包含json数据的应答:
如果获取正确,那么应答里的Json数据为:
{"access_token":"0QCeHwiRtPRUCiM5MM0cSPYIP5QOUNYdb8usRSgVZcsFuVF6mu3vQq41OIifJdrtJPGn7b1x90HdvUanpb7eZHxg40B6bU_Sgszh2byyF40","expires_in":7200}
如果获取错误,那么应答里的Json数据为:
{"errcode":40001,"errmsg":"invalid credential"}
和xml数据包一样,golang也提供了json格式数据包的Marshal和Unmarshal方法,且使用方式相同,也是将一个json数据包与一 个struct对应起来。从上面来看,通过http response,我们无法区分出是否成功获取了token,因此我们需要首先判断试下body中是否包含某些特征字符串,比 如"access_token":
if bytes.Contains(body, []byte("access_token")) {
&&& //unmarshal to AccessTokenResponse struct
&&& //unmarshal to AccessTokenErrorResponse struct
针对获取成功以及失败的两种Json数据,我们定义了两个结构体:
type AccessTokenResponse struct {
&&&&&&& AccessToken string& `json:"access_token"`
&&&&&&& ExpiresIn&& float64 `json:"expires_in"`
type AccessTokenErrorResponse struct {
&&&&&&& Errcode float64
&&&&&&& Errmsg& string
Json unmarshal的代码片段如下:
//Json Decoding
if bytes.Contains(body, []byte("access_token")) {
&&& &&& atr := AccessTokenResponse{}
&&&&&&& err = json.Unmarshal(body, &atr)
&&& &&& if err != nil {
&&& &&& &&& return "", 0.0, err
&&&&&&& return atr.AccessToken, atr.ExpiresIn, nil
&&&&&&& fmt.Println("return err")
&&&&&&& ater := AccessTokenErrorResponse{}
&&&&&&& err = json.Unmarshal(body, &ater)
&&&&&&& if err != nil {
&&&&&&& & & return "", 0.0, err
&&&&&&& return "", 0.0, fmt.Errorf("%s", ater.Errmsg)
我们的main函数如下:
func main() {
&&&&&&& accessToken, expiresIn, err := fetchAccessToken()
&&&&&&& if err != nil {
&&&&&&&&&&&&&&& log.Println("Get access_token error:", err)
&&&&&&&&&&&&&&& return
&&&&&&& fmt.Println(accessToken, expiresIn)
编译执行,成功获取access_token的输出如下:
0QCeHwiRtPRUCiM5MM0cSPYIP5QOUNYdb8usRSgVZcsFuVF6mu3vQq41OIifJdrtJPGn7b1x90HdvUanpb7eZHxg40B6bU_Sgszh2byyF40 7200
失败时,输出如下:
12:39:56 Get access_token error: invalid credential
二、发送客服消息
平台开发文档中定义了文本客服消息的body格式,一个json数据:
&&& "touser":"OPENID",
&&& "msgtype":"text",
&&& "text":
&&&&&&&& "content":"Hello World"
其中的touser填写的是openid。之前的文章中提到过,每个微信用户针对某一个订阅号/服务号都有唯一的OpenID,这个ID可以在微信订阅号 /服务号管理页面中看到,也可以在收到的微信平台转发的消息中看到(FromUserName)。比如我个人订阅的我的测试体验号后得到的OpenID 为:
BQcwuAbKpiSAbbvd_DEZg7q27QI
我们要做的就是构造这样一个json数据,并放入HTTP Post包中,发到:
https://api./cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
从平台开发文档给出的json数据包样例来看,这是个嵌套json数据包,我们通过下面方法marshall:
type CustomServiceMsg struct {
&&&&&&& ToUser& string&&&&&&&& `json:"touser"`
&&&&&&& MsgType string&&&&&&&& `json:"msgtype"`
&&&&&&& Text&&& TextMsgContent `json:"text"`
type TextMsgContent struct {
&&&&&&& Content string `json:"content"`
func pushCustomMsg(accessToken, toUser, msg string) error {
&&&&&&& csMsg := &CustomServiceMsg{
&&&&&&&&&&&&&&& ToUser:& toUser,
&&&&&&&&&&&&&&& MsgType: "text",
&&&&&&&&&&&&&&& Text:&&& TextMsgContent{Content: msg},
&&&&&&& body, err := json.MarshalIndent(csMsg, " ", "& ")
&&&&&&& if err != nil {
&&&&&&&&&&&&&&& return err
&&&&&&& fmt.Println(string(body))
&&& &&& … …
如果单纯输出上面marshal的结果,可以看到:
&& "touser": "oBQcwuAbKpiSAbbvd_DEZg7q27QI",
&& "msgtype": "text",
&& "text": {
&&&& "content": "你好"
接下来将marshal后的[]byte放入一个http post的body中,发送到指定url中:
var openID = "oBQcwuAbKpiSAbbvd_DEZg7q27QI"
func pushCustomMsg(accessToken, toUser, msg string) error {
&&&&&&& … …
&&&&&&& postReq, err := http.NewRequest("POST",
&&&&&&&&&&&&&&& strings.Join([]string{customServicePostUrl, "?access_token=", accessToken}, ""),
&&&&&&&&&&&&&&& bytes.NewReader(body))
&&&&&&& if err != nil {
&&&&&&&&&&&&&&& return err
&&&&&&& postReq.Header.Set("Content-Type", "application/ encoding=utf-8")
&&&&&&& client := &http.Client{}
&&&&&&& resp, err := client.Do(postReq)
&&&&&&& if err != nil {
&&&&&&&&&&&&&&& return err
&&&&&&& resp.Body.Close()
&&&&&&& return nil
我们在main函数中加上客服消息的发送环节:
func main() {
&&&&&&& // Fetch access_token
&&&&&&& accessToken, expiresIn, err := fetchAccessToken()
&&&&&&& if err != nil {
&&&&&&&&&&&&&&& log.Println("Get access_token error:", err)
&&&&&&&&&&&&&&& return
&&&&&&& fmt.Println(accessToken, expiresIn)
&&&&&&& // Post custom service message
&&&&&&& msg := "你好"
&&&&&&& err = pushCustomMsg(accessToken, openID, msg)
&&&&&&& if err != nil {
&&&&&&&&&&&&&&& log.Println("Push custom service message err:", err)
&&&&&&&&&&&&&&& return
编译执行,手机响起提示音,打开观看,微信公众平台测试号发来消息:“你好”。
上述Demo完整代码在可以看到,别忘了appID,appSecret改成你自己的值。
目前客服接口仅提供给认证后的订阅号以及服务号,对于未认证的订阅号,无法发送客服消息。
? 2014, . 版权所有.
Related posts:
发表评论:
TA的最新馆藏

我要回帖

更多关于 golang 自定义包引用 的文章

 

随机推荐