Go:解析JSON

开始

按照《Go语言编程》第五章的例子来的…(有很大改动,不然运行不了)
这本书是2012年左右出的,那时候Golang还没出1.0版本.
而现在Golang已经1.8版本了,改了不少东西才能正常的跑起来……
大概2017-03-11 0:30 开始写的…
这会3:15
……

搞完静态文件(就一个妹子UI的CSS),
已经3.40了…

还查了不少golang的文档,这下算是入坑了..

这是昨天改的一个梨子,也先贴一下吧.

Go相册网站程序

还有个问题,就是上传的图片名称会多一段数字,暂时没处理,但是不影响查看。
使用Go版本1.8

Go相册程序目录结构
uploads目录下面的文件是上传的,上传之后就可以看到了


package main

// 文件:photoweb.go
import (
	"io"
	"os"
	"log"
	"path"
	"net/http"
	"fmt"
	"io/ioutil"
	"html/template"
	"runtime/debug"
	"path/filepath"
)

/*
		 -----------------**********--------------------------------


		 运行方式: Golang 1.8 ,sublime text3 (安装之后要设置一个Go项目文件夹[go.exe只会从这个目录下面找可执行文件],具体百度)
		 
		 文件放在:E:\TMP\go\
		 目录下面,项目名字叫photoweb

		 然后直接启动就行,接着打开浏览器访问:
		 	http://localhost:8080/


		 搞定.
		 按照《Go语言编程》第五章的例子来的...(有很大改动,不然运行不了)
		 这本书是2012年左右出的,那时候Golang还没出1.0版本.
		 而现在Golang已经1.8版本了,改了不少东西才能正常的跑起来......
		 大概2017-03-11 0:30 开始写的...
		 这会3:15
		 ......

		 搞完静态文件(就一个妹子UI的CSS),
		 已经3.40了...

		 还查了不少golang的文档,这下算是入坑了..

		 by prd.


*/

const(
	ListDir = 0x0001
	UPLOAD_DIR="E:\\TMP\\go\\photoweb\\uploads\\"
	TEMPLATE_DIR = "./views"
)


var templates = make(map[string]*template.Template)
var tmpl = "tmpl"

/*

用不了,换了

// 静态文件读取
func staticDirHandler(mux *http.ServeMux,prefix string,
	staticDir string,flags int) {
	mux.HandleFunc(prefix,func(w http.ResponseWriter,r *http.Request){
		fileinfo := staticDir + r.URL.Path[len(prefix)-1:]
		fmt.Println(fileinfo)
		if (flags & ListDir) == 0 {
			if exists := isExists(fileinfo); !exists{
				http.NotFound(w,r)
				return
			}
		}
			http.ServeFile(w,r,fileinfo)
		})
}*/

// 错误处理
func check(err error) {
	if err != nil {
		panic(err)
	}
}


/* 上传图片. */
func uploadHandler(w http.ResponseWriter,r *http.Request) {
	if r.Method == "GET"{
		renderHtml(w,"upload.html",nil)
		//t.Execute(w,nil)
	}
	if r.Method == "POST"{
		f,h,err := r.FormFile("image")
		if err != nil {
			check(err)
			return
		}
		var filenamesinfo = h.Filename
		defer f.Close()
		fmt.Println(filenamesinfo)
		t,err := ioutil.TempFile(UPLOAD_DIR,filenamesinfo)
		check(err)
		defer t.Close()
		io.Copy(t,f)
		check(err)
		fainfo := filepath.Base(t.Name())
		fmt.Println("____________________")
		fmt.Println(fainfo)
		fmt.Println("____________________")
		http.Redirect(w,r,"view?id="+fainfo,http.StatusFound)
		}
}

/* 显示图片. */
func viewHandler(w http.ResponseWriter,r *http.Request) {
	imageId := r.FormValue("id")
	imagePath := UPLOAD_DIR + "\\" + imageId
	if exists := isExists(imagePath);!exists{
		http.NotFound(w,r)
		return
	}
	w.Header().Set("Content-Type","image")
	http.ServeFile(w,r,imagePath)
}

// 检查文件是否存在.
func isExists(path string) bool {
	_,err := os.Stat(path)
	if err == nil {
		return true
	}
	return os.IsExist(err)
}


// 列出所有图片.
func listHandler(w http.ResponseWriter,r *http.Request) {
	fileInfoArr,err := ioutil.ReadDir("E:\\TMP\\go\\photoweb\\uploads\\")
	check(err)
	//var listHtml string
	locals := make(map[string]interface{})
	images := []string{}
	for _,fileInfo := range fileInfoArr{
		//fmt.Println(fileInfo)
		images = append(images,fileInfo.Name())
	}
	locals["images"] = images
	renderHtml(w,"list.html",locals)
}


// 模板渲染方法.
func renderHtml(w http.ResponseWriter,tmpl string,locals map[string]interface{}){
	err := templates[tmpl].Execute(w,locals)
	check(err)
}

// 初始化方法,在main之前运行.
func init() {
	fileInfoArr,err := ioutil.ReadDir(TEMPLATE_DIR)
	fmt.Println(err)
	//panic(err)
	var templateName,templatePath string
	for _,fileInfo := range fileInfoArr{
		fmt.Println("_____")
		fmt.Println(fileInfo.Name())
		templateName = fileInfo.Name() //fileInfo.Name
		if ext := path.Ext(templateName); ext !=".html"{
			continue
		}
		templatePath = TEMPLATE_DIR + "\\" + templateName
		log.Println("Loading template:", templatePath)
		var t =  template.Must(template.ParseFiles(templatePath))
		templates[fileInfo.Name()] = t
	}
}

// 闭包.
func safeHandler(fn http.HandlerFunc)http.HandlerFunc {
	return func (w http.ResponseWriter,r *http.Request) {
		defer func(){
			if err,ok := recover().(error); ok {
				http.Error(w,err.Error(),http.StatusInternalServerError)
				// 或者输出自定义的50X错误页面
				// w.WriteHeader(http.StatusInternalServerError)
				// renderHtml(w,"error",e)
				// logging
				log.Println("WARN: panic in %v - %v ",fn,err)
				log.Println(string(debug.Stack()))
			}


		}()
		fn(w,r)
	}
}

func main() {
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
	http.HandleFunc("/",safeHandler(listHandler))
	http.HandleFunc("/upload",safeHandler(uploadHandler))
	http.HandleFunc("/view",safeHandler(viewHandler))
	// 端口.
	err := http.ListenAndServe(":8080",nil)
	if err != nil {
		log.Fatal("ListenAndServe: ",err.Error())
	}
}

列表页:list.html

<!doctype html>
<html>
<head>
	<meta charset="utf-8" />
	<title>列表</title>
	<link rel="stylesheet" type="text/css" href="/static/amazeui.min.css" /> 
</head>	
<body>
	<ol>
		{{ range $.images }}
		<li><a href="/view?id={{.|urlquery}}" target="_blank">{{.|html}}</a></li>
		{{end}}
	</ol>
		<pre>
		 搞定.
		 按照《Go语言编程》第五章的例子来的...(有很大改动,不然运行不了)
		 这本书是2012年左右出的,那时候Golang还没出1.0版本.
		 而现在Golang已经1.8版本了,改了不少东西才能正常的跑起来......
		 大概2017-03-11 0:30 开始写的...
		 这会3:15
		 ......
		 搞完静态文件(就一个妹子UI的CSS),
		 已经3.40了...


		 还查了不少golang的文档,这下算是入坑了..

		 by prd.
		</pre>
	 
	 <a href="/upload">上传</a>
</body>
</html>

上传页面:upload.html

<!doctype html>
<html>
<head>
	<meta charset="utf-8" />
	<title>上传</title>
</head>	
<body>
	<form method="POST" action="/upload"  enctype="multipart/form-data"> 
			  Choose an image to upload: <input name="image" type="file" />
			 <input type="submit" value="Upload" /> 
			</form>
			<a href="/">首页</a>
</body>
</html>

还有一个文件是妹子UI的css,可以在网上直接保存一份(ctrl+s),只是保存到指定目录就可以.[参考地址]

Go语言Logo

解析JSON数据

JSON解析成Go结构体,可以使用这个工具,直接获取相关结构体

源码如下(优先从网络获取数据,若从网络获取、解析失败,则直接使用本地数据[网络获取的数据与本地数据一样]):

package main

import (
	"fmt"
	"net/http"
	"encoding/json"
	"io/ioutil"
)


/**

参考(json to go):
https://mholt.github.io/json-to-go/


golang 解析json字符串.


date:2017-03-11
by:prd.

 */


type JsonInfoObj struct {
	Sites []struct {
		Name    string `json:"Name"`
		URL     string `json:"Url"`
		Country string `json:"Country"`
	} `json:"sites"`
}


/*

获取json数据-本地数据.

*/
func getJson() ([]byte) {
	return []byte(`{"sites":[{"Name":"菜鸟教程","Url":"www.runoob.com","Country":"CN"},{"Name":"Google","Url":"www.google.com","Country":"USA"},{"Name":"Facebook","Url":"www.facebook.com","Country":"USA"},{"Name":"微博","Url":"www.weibo.com","Country":"CN"}]}`)
}

/*

 从网络上获取Json数据.
 此函数获取的结果与getJson()中的内容一致.

 */
func getNetWorkJson() ([]byte) {
	fmt.Println("-----------从网络获取Json数据开始------------")
	resp, err := http.Get("http://www.runoob.com/try/angularjs/data/sites.php")
	if err != nil {
		// panic(err.Error())
		fmt.Println("-----------从网络获取失败,直接返回本地数据------------")
		return getJson()
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		// panic(err.Error())
		fmt.Println("-----------解析网络数据失败,直接返回本地数据------------")
		return getJson()
	}
	fmt.Println("-----------从网络获取Json数据成功------------")
	return body
}

/*

   显示JSON.

 */
func showJson() {
	jsoninfo := getNetWorkJson()
	var siteinfoJson JsonInfoObj
	err := json.Unmarshal(jsoninfo, &siteinfoJson)
	if err != nil {
		fmt.Println("error:", err)
	}
	fmt.Printf("%+v", siteinfoJson)
}

func main() {
	showJson()
}