在此示例中,我们将通过用户界面表单读取-写入-更新JSON文件中的JSON数据,获取特定记录的数据并删除特定记录的数据。
net/http标准库包提供了多种创建HTTP服务器的方法,并附带了一个基本的路由器。此处使用的net/http包用于向服务器发出请求并响应请求。
项目目录结构:
示例代码:main.go
导入net/http包。包http提供HTTP客户端和服务器实现。在main函数中,使用HandleFunc方法创建路由 /。HandleFunc为给定模式注册处理程序函数。HandleFunc阻止我们在执行处理程序之前和之后使用中间件执行任务。ListenAndServe使用给定的地址和处理程序启动HTTP服务器。
package main
import (
handlers "./handlers"
"net/http"
)
func main() {
http.HandleFunc("/addnewuser/", handlers.AddNewUserFunc)
http.HandleFunc("/notsucceded", handlers.NotSucceded)
http.HandleFunc("/deleted", handlers.DeletedFunc)
http.HandleFunc("/deleteuser/deleted", handlers.DeleteUserFunc)
http.HandleFunc("/deleteuser/", handlers.DeleteUserServe)
http.HandleFunc("/deleteuser/notsuccededdelete", handlers.NotSuccededDelete)
http.HandleFunc("/", handlers.IndexFunc)
http.HandleFunc("/showuser/show", handlers.ShowUserFunc)
http.HandleFunc("/showuser/", handlers.ShowUser)
http.HandleFunc("/showuser/notsuccededshow/", handlers.NotSuccededShow)
http.ListenAndServe(":8080", nil)
}
示例代码:list.json
[
{
"id": 1,
"firstName": "Mariya",
"lastName": "Ivanova",
"balance": 300
},
{
"id": 2,
"firstName": "EKatina",
"lastName": "Milevskaya",
"balance": 5000
},
{
"id": 3,
"firstName": "Vasek",
"lastName": "Zalupickiy",
"balance": 2000
}
]
示例代码:handlers\handlers.go
package handlers
import (
model "../model"
"encoding/json"
"fmt"
"html/template"
"io/ioutil"
"net/http"
"os"
"regexp"
"strconv"
)
//function to check correct user adding input (regular expression and non-empty field input)
func checkFormValue(w http.ResponseWriter, r *http.Request, forms ...string) (res bool, errStr string) {
for _, form := range forms {
m, _ := regexp.MatchString("^[a-zA-Z]+$", r.FormValue(form))
if r.FormValue(form) == "" {
return false, "All forms must be completed"
}
if m == false {
return false, "Use only english letters if firstname,lastname forms"
}
}
return true, ""
}
func ShowUser(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "templates/showUser.html")
}
func NotSuccededShow(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "templates/notSuccededShow.html")
}
//handler to show user with id input
func ShowUserFunc(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
t, _ := template.ParseFiles("templates/showUserPage.html")
t.Execute(w, nil)
} else {
id, err := strconv.Atoi(r.FormValue("id"))
checkError(err)
var alUsrs model.AllUsers
file, err := os.OpenFile("list.json", os.O_RDONLY, 0666)
checkError(err)
b, err := ioutil.ReadAll(file)
checkError(err)
json.Unmarshal(b, &alUsrs.Users)
var allID []int
for _, usr := range alUsrs.Users {
allID = append(allID, usr.Id)
}
for _, usr := range alUsrs.Users {
if model.IsValueInSlice(allID, id) != true {
http.Redirect(w, r, "/showuser/notsuccededshow/", 302)
return
}
if usr.Id != id {
continue
} else {
t, err := template.ParseFiles("templates/showUserPage.html")
checkError(err)
t.Execute(w, usr)
}
}
}
}
//function to handle page with successful deletion
func DeletedFunc(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "templates/deleted.html")
}
//serving file with error (add function:empty field input or uncorrect input)
func NotSucceded(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "templates/notSucceded.html")
}
//function,which serve html file,when deleting was not succesful(id input is not correct)
func NotSuccededDelete(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "templates/notSuccededDelete.html")
}
//function,which serve page with delete information input
func DeleteUserServe(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "templates/deleteUser.html")
}
//function to delete user
func DeleteUserFunc(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
t, _ := template.ParseFiles("templates/deleteUser.html")
t.Execute(w, nil)
} else {
r.ParseForm()
id, err := strconv.Atoi(r.FormValue("id"))
checkError(err)
//open file with users
file, err := os.OpenFile("list.json", os.O_RDWR|os.O_APPEND, 0666)
defer file.Close()
//read file and unmarshall json to []users
b, err := ioutil.ReadAll(file)
var alUsrs model.AllUsers
err = json.Unmarshal(b, &alUsrs.Users)
checkError(err)
var allID []int
for _, usr := range alUsrs.Users {
allID = append(allID, usr.Id)
}
for i, usr := range alUsrs.Users {
if model.IsValueInSlice(allID, id) != true {
http.Redirect(w, r, "/deleteuser/notsuccededdelete", 302)
return
}
if usr.Id != id {
continue
} else {
alUsrs.Users = append(alUsrs.Users[:i], alUsrs.Users[i+1:]...)
}
}
newUserBytes, err := json.MarshalIndent(&alUsrs.Users, "", " ")
checkError(err)
ioutil.WriteFile("list.json", newUserBytes, 0666)
http.Redirect(w, r, "/deleted", 301)
}
}
func checkError(err error) {
if err != nil {
fmt.Println(err)
}
}
//function to add user
func AddNewUserFunc(w http.ResponseWriter, r *http.Request) {
//creating new instance and checking method
newUser := &model.User{}
if r.Method == "GET" {
t, _ := template.ParseFiles("templates/addNewUser.html")
t.Execute(w, nil)
} else {
resBool, errStr := checkFormValue(w, r, "firstname", "lastname")
if resBool == false {
t, err := template.ParseFiles("templates/notSucceded.html")
checkError(err)
t.Execute(w, errStr)
return
}
newUser.FirstName = r.FormValue("firstname")
newUser.LastName = r.FormValue("lastname")
var err error
newUser.Balance, err = strconv.ParseFloat(r.FormValue("balance"), 64)
checkError(err)
//open file
file, err := os.OpenFile("list.json", os.O_RDWR, 0644)
checkError(err)
defer file.Close()
//read file and unmarshall json file to slice of users
b, err := ioutil.ReadAll(file)
var alUsrs model.AllUsers
err = json.Unmarshal(b, &alUsrs.Users)
checkError(err)
max := 0
//generation of id(last id at the json file+1)
for _, usr := range alUsrs.Users {
if usr.Id > max {
max = usr.Id
}
}
id := max + 1
newUser.Id = id
//appending newUser to slice of all Users and rewrite json file
alUsrs.Users = append(alUsrs.Users, newUser)
newUserBytes, err := json.MarshalIndent(&alUsrs.Users, "", " ")
checkError(err)
ioutil.WriteFile("list.json", newUserBytes, 0666)
http.Redirect(w, r, "/", 301)
}
}
//Index page handler
func IndexFunc(w http.ResponseWriter, r *http.Request) {
au := model.ShowAllUsers()
t, err := template.ParseFiles("templates/indexPage.html")
checkError(err)
t.Execute(w, au)
}
示例代码:model/model.go
package model
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
)
func checkError(err error) {
if err != nil {
fmt.Println(err)
}
}
func IsValueInSlice(slice []int, value int) (result bool) {
for _, n := range slice {
if n == value {
return true
}
}
return false
}
type User struct {
Id int `json:"id"`
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
Balance float64 `json:"balance"`
}
type AllUsers struct {
Users []*User
}
func ShowAllUsers() (au *AllUsers) {
file, err := os.OpenFile("list.json", os.O_RDWR|os.O_APPEND, 0666)
checkError(err)
b, err := ioutil.ReadAll(file)
var alUsrs AllUsers
json.Unmarshal(b, &alUsrs.Users)
checkError(err)
return &alUsrs
}
示例代码:templates\indexPage.html
<html>
<head>
<title>User info</title>
</head>
<body>
{{range .Users}}
<div><h3> ID:{{ .Id }} </h3></div>
<div> First Name:{{ .FirstName }}</div>
<div> Last Name:{{ .LastName }} </div>
<div> Balance:{{ .Balance }}</div>
{{end}}
<h1>Options</h1>
<form action="/addnewuser/">
<button type="submit">Add new user</button>
</form>
<form action="/deleteuser/">
<button type="submit">Delete user</button>
</form>
<form action="/showuser/">
<button type="submit">Show user</button>
</form>
</body>
</html>
示例代码:templates\addNewUser.html
<html>
<head>
<title>Adding new user</title>
</head>
<body>
<h2>New user's data</h2>
<form method="POST" action="useraded">
<label>Enter firstname</label><br>
<input type="text" name="firstname" /><br><br>
<label>Enter lastname</label><br>
<input type="text" name="lastname" /><br><br>
<label>Enter balance</label><br>
<input type="number" name="balance" /><br><br>
<input type="submit" value="Submit" />
</form>
</body>
</html>
示例代码:templates\deleteUser.html
<html>
<head>
<title>Delete user</title>
</head>
<body>
<h2>Please,write an id of user you want to delete</h2>
<form method="POST" action="deleted">
<label>Enter id</label><br>
<input type="text" name="id" /><br><br>
<input type="submit" value="Submit" />
</form>
</body>
</html>
示例代码:templates\deleted.html
<html>
<head>
<title>User info</title>
</head>
<body>
<div>Done</div><br><br>
<form action="/">
<button type="submit">Back to main</button>
</form>
</body>
</html>
示例代码:templates\notSuccededDelete.html
<html>
<head>
<title>User info</title>
</head>
<body>
<div>There is no user with such ID</div><br><br>
<form action="/">
<button type="submit">Back to main</button>
</form>
</body>
</html>
示例代码:templates\notSuccededShow.html
<html>
<head>
<title>User info</title>
</head>
<body>
<div>Error:Cant find User with such ID,try again</div><br><br>
<form action="/">
<button type="submit">Back to main</button>
</form>
</body>
</html>
示例代码:templates\showUser.html
<html>
<head>
<title>Show user</title>
</head>
<body>
<h2>Please,write an id of user you want to show</h2>
<form method="POST" action="show">
<label>Enter id</label><br>
<input type="text" name="id" /><br><br>
<input type="submit" value="Submit" />
</form>
</body>
</html>
示例代码:templates\showUserPage.html
<html>
<head>
<title>User info</title>
</head>
<body>
<div><h3> ID:{{.Id}} </h3></div>
<div> First Name:{{ .FirstName }}</div>
<div> Last Name:{{ .LastName }} </div>
<div> Balance:{{ .Balance }}</div>
</body>
</html>
示例代码:templates\notSucceded.html
<html>
<head>
<title>User info</title>
</head>
<body>
<div>Error:{{.}}</div><br><br>
<form action="/">
<button type="submit">Back to main</button>
</form>
</body>
</html>
运行应用程序:
go run main.go
在浏览器访问http://localhost:8080即可看到如下页面
生成条形码的算法或内部逻辑可在第三方条形码包中找到。这里的目标是展示一个示例,如何使用包并创建Web应用程序。
安装软件包:
go get github.com/boombuler/barcode
示例代码:main.go
FormValue函数将给出dataString输入字段的值,该字段将用于使用Encode函数生成QR码。
package main
import (
"image/png"
"net/http"
"text/template"
"github.com/boombuler/barcode"
"github.com/boombuler/barcode/qr"
)
type Page struct {
Title string
}
func main() {
http.HandleFunc("/", homeHandler)
http.HandleFunc("/generator/", viewCodeHandler)
http.ListenAndServe(":8080", nil)
}
func homeHandler(w http.ResponseWriter, r *http.Request) {
p := Page{Title: "QR Code Generator"}
t, _ := template.ParseFiles("generator.html")
t.Execute(w, p)
}
func viewCodeHandler(w http.ResponseWriter, r *http.Request) {
dataString := r.FormValue("dataString")
qrCode, _ := qr.Encode(dataString, qr.L, qr.Auto)
qrCode, _ = barcode.Scale(qrCode, 512, 512)
png.Encode(w, qrCode)
}
示例代码:generator.html
<h1>{{.Title}}</h1>
<div>Please enter the string you want to QRCode.</div>
<form action="generator/" method=post>
<input type="text" name="dataString">
<input type="submit" value="Submit">
</form>
您想知道特定地理区域(例如加拿大、另一个国家或国家集团,甚至可能是整个世界)的Twitter趋势。Twitter的Trends API使你能够获取由Where On Earth(WOE)ID指定的地理区域的热门话题,该ID最初由Geo Planet定义,然后由Yahoo!
这是使用Twitter API获取位置附近趋势的Web应用程序的基本示例。
https://api.twitter.com/1.1/trends/place.json返回特定WOOID的前50个热门主题(如果有可用的热门信息)。与所有其他API一样,它将热门主题作为JSON数据返回,这些数据可以转换为标准Golang对象,然后使用列表推导式或类似技术进行操作。
在http://dev.twitter.com/apps的Twitter帐户下注册应用程序,并获取所需的凭据(使用者密钥、使用者密钥、访问令牌和访问令牌密钥),OAuth应用程序需要这些凭据才能获得帐户访问权限。
安装软件包:
go get github.com/dghubble/oauth1
软件包oauth1提供了OAuth 1规范的Go实现,允许最终用户授权客户端(即消费者)代表他/她访问受保护的资源。
示例代码:main.go
能够处理GET和POST请求的函数viewHashTagHandler。ParseFiles创建一个新模板,并从hash_tags.html文件中解析模板定义。
package main
import (
"encoding/json"
"fmt"
"github.com/dghubble/oauth1"
"html/template"
"io/ioutil"
"net/http"
"strings"
)
func getHashTags(country string) []string {
var listHashTags []string
consumerKey := "xxxxxxxxxxxxxxxxxxx"
consumerSecret := "xxxxxxxxxxxxxxxxxxx"
accessToken := "xxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxx"
accessSecret := "xxxxxxxxxxxxxxxxxxx"
if consumerKey == "" || consumerSecret == "" || accessToken == "" || accessSecret == "" {
panic("Missing required environment variable")
}
config := oauth1.NewConfig(consumerKey, consumerSecret)
token := oauth1.NewToken(accessToken, accessSecret)
httpClient := config.Client(oauth1.NoContext, token)
path := "https://api.twitter.com/1.1/trends/place.json?id=" + country
resp, _ := httpClient.Get(path)
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
var JSON = strings.TrimLeft(string(body), "[")
JSON = strings.TrimRight(JSON, "]")
var info map[string]interface{}
json.Unmarshal([]byte(JSON), &info)
trends := info["trends"].([]interface{})
for _, element := range trends {
if trendList, ok := element.(map[string]interface{}); ok {
for key, value := range trendList {
// Filter hashtags started with #
if strings.Contains(key, "name") && strings.Contains(value.(string), "#") {
listHashTags = append(listHashTags, value.(string))
}
}
}
}
return listHashTags
}
func main() {
http.HandleFunc("/", viewHashTagHandler)
http.ListenAndServe(":8080", nil)
}
func viewHashTagHandler(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.Error(w, "404 not found.", http.StatusNotFound)
return
}
switch r.Method {
case "GET":
getPage, _ := template.ParseFiles("hash_tags.html")
getPage.Execute(w, r)
case "POST":
var country string
if err := r.ParseForm(); err != nil {
fmt.Fprintf(w, "ParseForm() err: %v", err)
return
}
country = r.FormValue("country")
tags := getHashTags(country)
postPage, _ := template.ParseFiles("hash_tags.html")
postPage.Execute(w, tags)
default:
fmt.Fprintf(w, "Unable to get result.")
}
}
示例代码:hash_tags.html
<html>
<head>
<title>Trending hash tags</title>
</head>
<body>
<form method="POST" action="/">
<select name="country">
<option value="23424848">India</option>
<option value="455830">Brazil</option>
<option value="3369">Canada</option>
<option value="1">Global</option>
</select>
<button type="submit">Show Trends</button>
</form>
<ul>
{{ range $key, $value := . }}
<li>{{ $value }}</li>
{{ end }}
</ul>
</body>
</html>
运行程序:
go run main.go
这将在您机器上的端口8080上的Web服务器上开发一个静态网站。这也会启动您的浏览器导航到http://localhost:8080。
照片库是一种显示保存在特定位置的不同图像的方法。在这里,不同的图像由用户上传到指定的文件夹中。为了显示图像,首先我们需要读取包含不同图像的目录,然后在读取后逐个显示图像。
示例代码:main.go
package main
import (
"crypto/sha1"
"fmt"
"html/template"
"io"
"log"
"net/http"
"os"
"path/filepath"
"strings"
)
var tpl *template.Template
func init() {
tpl = template.Must(template.ParseGlob("templates/*"))
}
func main() {
http.HandleFunc("/", index)
http.Handle("/gallery/", http.StripPrefix("/gallery", http.FileServer(http.Dir("./gallery"))))
http.Handle("/favicon.ico", http.NotFoundHandler())
http.ListenAndServe(":8080", nil)
}
func index(w http.ResponseWriter, req *http.Request) {
if req.Method == http.MethodPost {
mf, fh, err := req.FormFile("nf")
if err != nil {
fmt.Println(err)
}
defer mf.Close()
// create sha for file name
ext := strings.Split(fh.Filename, ".")[1]
h := sha1.New()
io.Copy(h, mf)
fname := fmt.Sprintf("%x", h.Sum(nil)) + "." + ext
// create new file
wd, err := os.Getwd()
if err != nil {
fmt.Println(err)
}
path := filepath.Join(wd, "gallery", fname)
nf, err := os.Create(path)
if err != nil {
fmt.Println(err)
}
defer nf.Close()
mf.Seek(0, 0)
io.Copy(nf, mf)
}
file, err := os.Open("gallery")
if err != nil {
log.Fatalf("failed opening directory: %s", err)
}
defer file.Close()
list, _ := file.Readdirnames(0) // 0 to read all files and folders
tpl.ExecuteTemplate(w, "index.gohtml", list)
}
示例代码:index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Image Uploader</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</head>
<body>
<div class="container">
<h1>Photo Gallery</h1>
<hr class="mt-2 mb-5">
<div class="row text-center text-lg-left">
{{range .}}
<div class="col-lg-3 col-md-4 col-6">
<a href="#" class="d-block mb-4 h-100">
<img class="img-fluid img-thumbnail" src="/gallery/{{.}}">
</a>
</div>
{{end}}
</div>
<hr class="mt-2 mb-5">
<div class="row">
<div class="col-lg-3 col-md-4 col-6">
<form method="post" enctype="multipart/form-data">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text" id="inputGroupFileAddon01">Upload</span>
</div>
<div class="custom-file">
<input type="file" class="custom-file-input" name="nf" aria-describedby="inputGroupFileAddon01" id="inputGroupFile01" required>
<label class="custom-file-label" for="inputGroupFile01">Choose file</label>
</div>
</div>
<div class="input-group">
<div class="custom-file">
<input type="submit" class="btn btn-primary">
</div>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
now是一个非常简单的包,它为标准时间包提供了一个方便的包装器,并使其易于处理当前时间周围的各种日期和时间构造。
安装软件包:
go get -u github.com/jinzhu/now
示例代码:
package main
import (
"fmt"
"time"
"github.com/jinzhu/now"
)
func main() {
fmt.Println("BeginningOfMinute \t", now.BeginningOfMinute())
fmt.Println("BeginningOfHour \t", now.BeginningOfHour())
fmt.Println("BeginningOfDay \t", now.BeginningOfDay())
fmt.Println("BeginningOfWeek \t", now.BeginningOfWeek())
fmt.Println("BeginningOfMonth \t", now.BeginningOfMonth())
fmt.Println("BeginningOfQuarter \t", now.BeginningOfQuarter())
fmt.Println("BeginningOfYear \t", now.BeginningOfYear())
fmt.Println()
fmt.Println("EndOfMinute \t", now.EndOfMinute())
fmt.Println("EndOfHour \t", now.EndOfHour())
fmt.Println("EndOfDay \t", now.EndOfDay())
fmt.Println("EndOfWeek \t", now.EndOfWeek())
fmt.Println("EndOfMonth \t", now.EndOfMonth())
fmt.Println("EndOfQuarter \t", now.EndOfQuarter())
fmt.Println("EndOfYear \t", now.EndOfYear())
fmt.Println()
fmt.Println("Monday \t", now.Monday())
fmt.Println("Sunday \t", now.Sunday())
fmt.Println("EndOfSunday \t", now.EndOfSunday())
fmt.Println()
fmt.Println(now.Parse("2017"))
fmt.Println(now.Parse("2017-12-12 12:20"))
t := time.Date(2020, 07, 18, 17, 51, 49, 123456789, time.Now().Location())
fmt.Println(now.With(t).EndOfMonth())
}
输出:
BeginningOfMinute 2020-07-19 16:55:00 +0530 IST
BeginningOfHour 2020-07-19 16:00:00 +0530 IST
BeginningOfDay 2020-07-19 00:00:00 +0530 IST
BeginningOfWeek 2020-07-19 00:00:00 +0530 IST
BeginningOfMonth 2020-07-01 00:00:00 +0530 IST
BeginningOfQuarter 2020-07-01 00:00:00 +0530 IST
BeginningOfYear 2020-01-01 00:00:00 +0530 IST
EndOfMinute 2020-07-19 16:55:59.999999999 +0530 IST
EndOfHour 2020-07-19 16:59:59.999999999 +0530 IST
EndOfDay 2020-07-19 23:59:59.999999999 +0530 IST
EndOfWeek 2020-07-25 23:59:59.999999999 +0530 IST
EndOfMonth 2020-07-31 23:59:59.999999999 +0530 IST
EndOfQuarter 2020-09-30 23:59:59.999999999 +0530 IST
EndOfYear 2020-12-31 23:59:59.999999999 +0530 IST
Monday 2020-07-13 00:00:00 +0530 IST
Sunday 2020-07-19 00:00:00 +0530 IST
EndOfSunday 2020-07-19 23:59:59.999999999 +0530 IST
2017-01-01 00:00:00 +0530 IST
2017-12-12 12:20:00 +0530 IST
2020-07-31 23:59:59.999999999 +0530 IST
xmlquery是用于XML文档的XPath查询包,允许您通过XPath表达式从XML文档中提取数据或计算数据。
安装软件包:
go get github.com/antchfx/xmlquery
示例代码:
package main
import (
"fmt"
"strings"
"github.com/antchfx/xmlquery"
"github.com/antchfx/xpath"
)
func main() {
s := `<?xml version="1.0" encoding="UTF-8" ?>
<breakfast_menu>
<food>
<name price="10">Berry-Berry Belgian Waffles</name>
<description>Light Belgian waffles</description>
<calories>900</calories>
</food>
<food>
<name price="20">French Toast</name>
<description>Thick slices</description>
<calories>600</calories>
</food>
<food>
<name price="30">Homestyle Breakfast</name>
<description>Two eggs, bacon or sausage</description>
<calories>950</calories>
</food>
</breakfast_menu>`
doc, err := xmlquery.Parse(strings.NewReader(s))
if err != nil {
panic(err)
}
root := xmlquery.FindOne(doc, "//breakfast_menu")
if n := root.SelectElement("//food/name"); n != nil {
fmt.Printf("Name #%s\n", n.InnerText())
}
if n := root.SelectElement("//food[2]/name"); n != nil {
fmt.Printf("Name #%s\n", n.InnerText())
}
for i, n := range xmlquery.Find(doc, "//food/name/@price") {
fmt.Printf("Price #%d %s\n", i, n.InnerText())
}
for i, n := range xmlquery.Find(doc, "//food/calories") {
fmt.Printf("Calories #%d %s\n", i, n.InnerText())
}
if n := root.SelectElement("//food[2]/name"); n != nil {
fmt.Printf("Attr #%s\n", n.Attr)
}
if n := root.SelectElement("//food[2]/name"); n != nil {
fmt.Printf("Data #%s\n", n.Data)
}
node := xmlquery.FindOne(doc, "//breakfast_menu/food[2]")
if n := node.SelectElement("//description"); n != nil {
fmt.Printf("Description #%s\n", n.InnerText())
}
expr, err := xpath.Compile("sum(//breakfast_menu/food/name/@price)")
price := expr.Evaluate(xmlquery.CreateXPathNavigator(doc)).(float64)
fmt.Printf("Total price: %f\n", price)
countexpr, err := xpath.Compile("count(//breakfast_menu/food)")
count := countexpr.Evaluate(xmlquery.CreateXPathNavigator(doc))
fmt.Printf("Food Node Counts: %f\n", count)
}
输出:
Name #Berry-Berry Belgian Waffles
Name #French Toast
Price #0 10
Price #1 20
Price #2 30
Calories #0 900
Calories #1 600
Calories #2 950
Attr #[{{ price} 20}]
Data #name
description #Thick slices
total price: 60.000000
Food Node Counts: 3.000000
go-chart是一个非常简单的golang原生图表库,支持时间序列和连续折线图。
安装软件包:
go get -u github.com/wcharczuk/go-chart
示例代码1:
package main
import (
"os"
"github.com/wcharczuk/go-chart"
)
func main() {
graph := chart.BarChart{
Title: "Test Bar Chart",
Background: chart.Style{
Padding: chart.Box{
Top: 40,
},
},
Height: 512,
BarWidth: 60,
Bars: []chart.Value{
{Value: 5.25, Label: "Blue"},
{Value: 4.88, Label: "Green"},
{Value: 4.74, Label: "Gray"},
{Value: 3.22, Label: "Orange"},
{Value: 3, Label: "Test"},
{Value: 2.27, Label: "??"},
{Value: 1, Label: "!!"},
},
}
f, _ := os.Create("output.png")
defer f.Close()
graph.Render(chart.PNG, f)
}
示例代码2:
package main
import (
"os"
"github.com/wcharczuk/go-chart"
"github.com/wcharczuk/go-chart/drawing"
)
func main() {
viridisByY := func(xr, yr chart.Range, index int, x, y float64) drawing.Color {
return chart.Viridis(y, yr.GetMin(), yr.GetMax())
}
graph := chart.Chart{
Series: []chart.Series{
chart.ContinuousSeries{
Style: chart.Style{
StrokeWidth: chart.Disabled,
DotWidth: 5,
DotColorProvider: viridisByY,
},
XValues: chart.Seq{Sequence: chart.NewLinearSequence().WithStart(0).WithEnd(127)}.Values(),
YValues: chart.Seq{Sequence: chart.NewRandomSequence().WithLen(128).WithMin(0).WithMax(1024)}.Values(),
},
},
}
f, _ := os.Create("output.png")
defer f.Close()
graph.Render(chart.PNG, f)
}
imaging包提供基本的图像处理功能(调整大小、旋转、裁剪、亮度/对比度调整等)。包提供的所有图像处理函数都接受实现图像的任何图像类型。 image接口作为输入,并返回 *image的新图像。NRGBA类型(32位RGBA颜色,非预乘alpha)。
安装软件包:
go get -u github.com/disintegration/imaging
示例代码:
package main
import (
"image"
"image/color"
"log"
"github.com/disintegration/imaging"
)
func main() {
// 打开一个图像文件src, err := imaging.Open("test.png")
if err != nil {
log.Fatalf("failed to open image: %v", err)
}
// 从中心点裁剪300x300px
src = imaging.CropAnchor(src, 300, 300, imaging.Center)
// 将裁剪后的图像调整为宽度=200px,保留纵横比src = imaging.Resize(src, 200, 0, imaging.Lanczos)
// 创建图像的模糊版本img1 := imaging.Blur(src, 5)
// 创建具有更高对比度和清晰度的图像的灰度版本img2 := imaging.Grayscale(src)
img2 = imaging.AdjustContrast(img2, 20)
img2 = imaging.Sharpen(img2, 2)
// 创建图像的反转版本img3 := imaging.Invert(src)
// 使用卷积滤波器创建图像的浮雕版本img4 := imaging.Convolve3x3(
src,
[9]float64{
-1, -1, 0,
-1, 1, 1,
0, 1, 1,
},
nil,
)
// 创建一个新图像,并将生成的四个图像粘贴到其中dst := imaging.New(400, 400, color.NRGBA{0, 0, 0, 0})
dst = imaging.Paste(dst, img1, image.Pt(0, 0))
dst = imaging.Paste(dst, img2, image.Pt(0, 200))
dst = imaging.Paste(dst, img3, image.Pt(200, 0))
dst = imaging.Paste(dst, img4, image.Pt(200, 200))
// 将生成的图像另存为JPEG
err = imaging.Save(dst, "test.jpg")
if err != nil {
log.Fatalf("failed to save image: %v", err)
}
}
这是常用正则表达式的集合。它以简单的函数形式提供这些函数,用于获取与特定模式相对应的匹配字符串。这有助于在字符串中查找所有时间、日期、链接、电话号码、电子邮件、IP地址、价格、十六进制颜色和信用卡号。
安装软件包:
go get github.com/mingrammer/commonregex
示例代码:
package main
import (
"fmt"
cregex "github.com/mingrammer/commonregex"
)
func main() {
text := `John, please get that article on www.linkedin.com
to me by 5:00PM on Jan 9th 2012. 4:00 would be ideal, actually.
If you have any questions, You can reach me at (519)-236-2723x341 or 234-567-8900 or +41 22 730 5989
or get in touch with my associate at harold.smith@gmail.com. You system details as below:
fe80:0:0:0:204:61ff:fe9d:f156, 192.30.253.113`
dateList := cregex.Date(text)
fmt.Println(dateList)
timeList := cregex.Time(text)
fmt.Println(timeList)
linkList := cregex.Links(text)
fmt.Println(linkList)
ipList := cregex.IPs(text)
fmt.Println(ipList)
IPv4List := cregex.IPv4s(text)
fmt.Println(IPv4List)
IPv6List := cregex.IPv6s(text)
fmt.Println(IPv6List)
emailList := cregex.Emails(text)
fmt.Println(emailList)
phones := cregex.Phones(text)
fmt.Println(phones)
phoneList := cregex.PhonesWithExts(text)
fmt.Println(phoneList)
text = "price is $1,000. Pay using Credit card 4111 1111 1111 1111 and address is 504 parkwood drive, 02540, US"
creditCard := cregex.CreditCards(text)
fmt.Println(creditCard)
price := cregex.Prices(text)
fmt.Println(price)
address := "504 parkwood drive, 02540, US"
zip := cregex.ZipCodes(address)
fmt.Println(zip)
streetAddress := cregex.StreetAddresses(address)
fmt.Println(streetAddress)
}
输出:
[Jan 9th 2012 2.30.253]
[5:00PM 4:00 0:20 4:61]
[www.linkedin.com harold.smith@gmail.com 192.30.253.113]
[fe80:0:0:0:204:61ff:fe9d:f156 192.30.253.113]
[192.30.253.113]
[fe80:0:0:0:204:61ff:fe9d:f156]
[harold.smith@gmail.com]
[(519)-236-2723 234-567-8900 +41 22 730 5989]
[(519)-236-2723x341]
[4111 1111 1111 1111]
[$1,000]
[02540]
[504 parkwood drive,]
goquery实现了类似于jQuery的功能,包括可链接的语法,用于操作和查询HTML文档。
它为Go语言带来了类似于jQuery的语法和一组功能。它基于Go的net/html包和CSS选择器库cascadia。在语法方面,它尽可能接近jQuery,尽可能使用相同的方法名称。
安装软件包:
go get github.com/PuerkitoBio/goquery
示例代码1:
package main
import (
"fmt"
"log"
"net/http"
"github.com/PuerkitoBio/goquery"
)
func ExampleScrape() {
// http请求res, err := http.Get("https://stackoverflow.com/questions/tagged/javascript")
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
if res.StatusCode != 200 {
log.Fatalf("status code error: %d %s", res.StatusCode, res.Status)
}
// 加载html内容doc, err := goquery.NewDocumentFromReader(res.Body)
if err != nil {
log.Fatal(err)
}
// 查找目标元素doc.Find(".question-summary .summary").Each(func(i int, s *goquery.Selection) {
title := s.Find("H3").Text()
fmt.Println(i, title)
})
}
func main() {
ExampleScrape()
}
示例代码2:
package main
import (
"fmt"
"log"
"github.com/PuerkitoBio/goquery"
)
type Earthquake struct {
Timestamp string
Latitide string
Longitude string
Magnitudo string
Depth string
Territory string
}
var arrayEarthquake []Earthquake
func postScrape() {
doc, err := goquery.NewDocument("http://www.bmkg.go.id/gempabumi/gempabumi-terkini.bmkg")
if err != nil {
log.Fatal(err)
}
doc.Find("tbody tr").Each(func(_ int, tr *goquery.Selection) {
e := Earthquake{}
tr.Find("td").Each(func(ix int, td *goquery.Selection) {
switch ix {
case 1:
e.Timestamp = td.Text()
case 2:
e.Latitide = td.Text()
case 3:
e.Longitude = td.Text()
case 4:
e.Magnitudo = td.Text()
case 5:
e.Depth = td.Text()
case 6:
e.Territory = td.Text()
}
})
arrayEarthquake = append(arrayEarthquake, e)
})
fmt.Println(arrayEarthquake)
}
func main() {
postScrape()
}
go-funk这个辅助函数可以解决常见问题,如删除切片中的所有重复项、获取两个集合之间的差异、用值填充数组的元素、获取两个集合之间的交集等等。
安装软件包:
go get github.com/thoas/go-funk
示例代码1:
package main
import (
"fmt"
"github.com/thoas/go-funk"
)
func main() {
slice1 := []int{1, 3, 5, 7, 9}
slice2 := []int{1, 2, 3, 4, 5, 6}
// 集合1中,不包含在集合2的元素集合subtract := funk.Subtract(slice1, slice2)
fmt.Println(subtract)
// 计算交集intersect := funk.Intersect(slice1, slice2)
fmt.Println(intersect)
// 分别计算其他集合中不存在的元素slice_1_Diff, slice_2_Diff := funk.Difference(slice1, slice2)
fmt.Println(slice_1_Diff)
fmt.Println(slice_2_Diff)
// 按下标打包,类似python的元组zip := funk.Zip(slice1, slice2)
fmt.Println(zip)
// 判断集合1是否为集合2的子集subset := funk.Subset(slice1, slice2)
fmt.Println(subset)
// 判断两个切片元素是否相同Equal := funk.Equal(slice1, slice2)
fmt.Println(Equal)
// 判断slice1是否是slice2中的一个元素convertSlice := funk.Contains(slice2, slice1)
fmt.Println(convertSlice)
}
输出1:
[7 9]
[1 3 5]
[7 9]
[2 4 6]
[{1 1} {3 2} {5 3} {7 4} {9 5}]
false
false
false
示例代码2:
package main
import (
"fmt"
"github.com/thoas/go-funk"
)
func main() {
var map1 = map[string]int{"Mark": 10, "Sandy": 20,
"Rocky": 30, "Rajiv": 40, "Kate": 50}
// 通过自定义函数转换为另一种类型flip := funk.Map(map1, func(k string, v int) (int, string) {
return v, k
})
fmt.Println(flip)
// 返回元素键数组keys := funk.Keys(map1)
fmt.Println(keys)
// 返回元素值数组values := funk.Values(map1)
fmt.Println(values)
}
输出2:
map[10:Mark 20:Sandy 30:Rocky 40:Rajiv 50:Kate]
[Sandy Rocky Rajiv Kate Mark]
[40 50 10 20 30]
此软件包提供用于计算数值数据的数理统计的函数。即使数据集太大,也可以使用它。此包不能依赖于导入其他模块、包或库。您可以获得常用的统计函数,如平均值、中位数、标准差、方差、相关性、谐波平均值等。
安装软件包:
go get github.com/montanaflynn/stats
示例代码:
package main
import (
"fmt"
"github.com/montanaflynn/stats"
)
func main() {
// d := stats.LoadRawData([]interface{}{1.1, "2", 3.0, 4, "5"})
d := stats.LoadRawData([]int{1, 2, 3, 4, 5})
a, _ := stats.Min(d)
fmt.Println(a)
// Output: 1.1
a, _ = stats.Max(d)
fmt.Println(a)
// Output: 5
a, _ = stats.Sum([]float64{1.1, 2.2, 3.3})
fmt.Println(a)
// Output: 6.6
cs, _ := stats.CumulativeSum([]float64{1.1, 2.2, 3.3})
fmt.Println(cs) // [1.1 3.3000000000000003 6.6]
a, _ = stats.Mean([]float64{1, 2, 3, 4, 5})
fmt.Println(a)
// Output: 3
a, _ = stats.Median([]float64{1, 2, 3, 4, 5, 6, 7})
fmt.Println(a)
// Output: 4
m, _ := stats.Mode([]float64{5, 5, 3, 3, 4, 2, 1})
fmt.Println(m)
// Output: [5 3]
a, _ = stats.PopulationVariance([]float64{1, 2, 3, 4, 5})
fmt.Println(a)
// Output: 2
a, _ = stats.SampleVariance([]float64{1, 2, 3, 4, 5})
fmt.Println(a)
// Output: 2.5
a, _ = stats.MedianAbsoluteDeviationPopulation([]float64{1, 2, 3})
fmt.Println(a)
// Output: 1
a, _ = stats.StandardDeviationPopulation([]float64{1, 2, 3})
fmt.Println(a)
// Output: 0.816496580927726
a, _ = stats.StandardDeviationSample([]float64{1, 2, 3})
fmt.Println(a)
// Output: 1
a, _ = stats.Percentile([]float64{1, 2, 3, 4, 5}, 75)
fmt.Println(a)
// Output: 4
a, _ = stats.PercentileNearestRank([]float64{35, 20, 15, 40, 50}, 75)
fmt.Println(a)
// Output: 40
c := []stats.Coordinate{
{1, 2.3},
{2, 3.3},
{3, 3.7},
{4, 4.3},
{5, 5.3},
}
r, _ := stats.LinearRegression(c)
fmt.Println(r)
// Output: [{1 2.3800000000000026} {2 3.0800000000000014} {3 3.7800000000000002} {4 4.479999999999999} {5 5.179999999999998}]
r, _ = stats.ExponentialRegression(c)
fmt.Println(r)
// Output: [{1 2.5150181024736638} {2 3.032084111136781} {3 3.6554544271334493} {4 4.406984298281804} {5 5.313022222665875}]
r, _ = stats.LogarithmicRegression(c)
fmt.Println(r)
// Output: [{1 2.1520822363811702} {2 3.3305559222492214} {3 4.019918836568674} {4 4.509029608117273} {5 4.888413396683663}]
s, _ := stats.Sample([]float64{0.1, 0.2, 0.3, 0.4}, 3, false)
fmt.Println(s)
// Output: [0.2,0.4,0.3]
s, _ = stats.Sample([]float64{0.1, 0.2, 0.3, 0.4}, 10, true)
fmt.Println(s)
// Output: [0.2,0.2,0.4,0.1,0.2,0.4,0.3,0.2,0.2,0.1]
q, _ := stats.Quartile([]float64{7, 15, 36, 39, 40, 41})
fmt.Println(q)
// Output: {15 37.5 40}
iqr, _ := stats.InterQuartileRange([]float64{102, 104, 105, 107, 108, 109, 110, 112, 115, 116, 118})
fmt.Println(iqr)
// Output: 10
mh, _ := stats.Midhinge([]float64{1, 3, 4, 4, 6, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 10, 11, 12, 13})
fmt.Println(mh)
// Output: 7.5
tr, _ := stats.Trimean([]float64{1, 3, 4, 4, 6, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 10, 11, 12, 13})
fmt.Println(tr)
// Output: 7.25
o, _ := stats.QuartileOutliers([]float64{-1000, 1, 3, 4, 4, 6, 6, 6, 6, 7, 8, 15, 18, 100})
fmt.Printf("%+v\n", o)
// Output: {Mild:[15 18] Extreme:[-1000 100]}
gm, _ := stats.GeometricMean([]float64{10, 51.2, 8})
fmt.Println(gm)
// Output: 15.999999999999991
hm, _ := stats.HarmonicMean([]float64{1, 2, 3, 4, 5})
fmt.Println(hm)
// Output: 2.18978102189781
a, _ = stats.Round(2.18978102189781, 3)
fmt.Println(a)
// Output: 2.189
e, _ := stats.ChebyshevDistance([]float64{2, 3, 4, 5, 6, 7, 8}, []float64{8, 7, 6, 5, 4, 3, 2})
fmt.Println(e)
// Output: 6
e, _ = stats.ManhattanDistance([]float64{2, 3, 4, 5, 6, 7, 8}, []float64{8, 7, 6, 5, 4, 3, 2})
fmt.Println(e)
// Output: 24
e, _ = stats.EuclideanDistance([]float64{2, 3, 4, 5, 6, 7, 8}, []float64{8, 7, 6, 5, 4, 3, 2})
fmt.Println(e)
// Output: 10.583005244258363
e, _ = stats.MinkowskiDistance([]float64{2, 3, 4, 5, 6, 7, 8}, []float64{8, 7, 6, 5, 4, 3, 2}, float64(1))
fmt.Println(e)
// Output: 24
e, _ = stats.MinkowskiDistance([]float64{2, 3, 4, 5, 6, 7, 8}, []float64{8, 7, 6, 5, 4, 3, 2}, float64(2))
fmt.Println(e)
// Output: 10.583005244258363
e, _ = stats.MinkowskiDistance([]float64{2, 3, 4, 5, 6, 7, 8}, []float64{8, 7, 6, 5, 4, 3, 2}, float64(99))
fmt.Println(e)
// Output: 6
cor, _ := stats.Correlation([]float64{1, 2, 3, 4, 5}, []float64{1, 2, 3, 5, 6})
fmt.Println(cor)
// Output: 0.9912407071619302
ac, _ := stats.AutoCorrelation([]float64{1, 2, 3, 4, 5}, 1)
fmt.Println(ac)
// Output: 0.4
sig, _ := stats.Sigmoid([]float64{3.0, 1.0, 2.1})
fmt.Println(sig)
// Output: [0.9525741268224334 0.7310585786300049 0.8909031788043871]
sm, _ := stats.SoftMax([]float64{3.0, 1.0, 0.2})
fmt.Println(sm)
// Output: [0.8360188027814407 0.11314284146556013 0.05083835575299916]
e, _ = stats.Entropy([]float64{1.1, 2.2, 3.3})
fmt.Println(e)
// Output: 1.0114042647073518
}
Gabs是一个小型实用程序,用于处理Go中的动态或未知JSON结构。它不需要您知道有效负载的结构(例如创建结构),并允许通过提供字段的路径来访问字段。它是一个有用的包装器,用于访问encoding/json包提供的map[string]interface{} 对象的层次结构。
安装软件包:
go get github.com/Jeffail/gabs
示例代码:
package main
import (
"fmt"
"github.com/Jeffail/gabs"
)
func main() {
data := []byte(`{
"employees":{
"protected":false,
"address":{
"street":"22 Saint-Lazare",
"postalCode":"75003",
"city":"Paris",
"countryCode":"FRA",
"country":"France"
},
"employee":[
{
"id":1,
"first_name":"Jeanette",
"last_name":"Penddreth"
},
{
"id":2,
"firstName":"Giavani",
"lastName":"Frediani"
}
]
}
}`)
jsonParsed, err := gabs.ParseJSON(data)
if err != nil {
panic(err)
}
// Search JSON
fmt.Println("Get value of Protected:\t", jsonParsed.Path("employees.protected").Data())
fmt.Println("Get value of Country:\t", jsonParsed.Search("employees", "address", "country").Data())
fmt.Println("ID of first employee:\t", jsonParsed.Path("employees.employee.0.id").String())
fmt.Println("Check Country Exists:\t", jsonParsed.Exists("employees", "address", "countryCode"))
// Iterating address objects
for key, child := range jsonParsed.Search("employees", "address").ChildrenMap() {
fmt.Printf("Key=>%v, Value=>%v\n", key, child.Data().(string))
}
// Iterating employee array
for _, child := range jsonParsed.Search("employees", "employee").Children() {
fmt.Println(child.Data())
}
// Use index in your search
for _, child := range jsonParsed.Search("employees", "employee", "0").Children() {
fmt.Println(child.Data())
}
}
输出:
Get value of Protected: false
Get value of Country: France
ID of first employee: 1
Check Country Exists: true
Key=>street, Value=>22 Saint-Lazare
Key=>postalCode, Value=>75003
Key=>city, Value=>Paris
Key=>countryCode, Value=>FRA
Key=>country, Value=>France
map[id:1 first_name:Jeanette last_name:Penddreth]
map[id:2 firstName:Giavani lastName:Frediani]
Jeanette
Penddreth1
包验证器根据标签对结构体和单个字段进行值验证。它具有以下独特的功能,可通过使用验证标记或自定义验证器进行跨字段和跨结构验证。切片、数组和map,允许验证多维字段的任何或所有级别。能够深入研究映射键和值以进行验证。
安装验证包:
go get github.com/go-playground/validator
示例代码:
package main
import (
"fmt"
"github.com/go-playground/validator"
)
// User contains user information
type User struct {
FirstName string `json:"fname" validate:"alpha"`
LastName string `json:"lname" validate:"alpha"`
Age uint8 `validate:"gte=20,lte=65"`
Email string `json:"e-mail" validate:"required,email"`
JoiningDate string `validate:"datetime"`
}
// use a single instance of Validate, it caches struct info
var validate *validator.Validate
func main() {
validate = validator.New()
user := &User{
FirstName: "Test25",
LastName: "Test",
Age: 75,
Email: "Badger.Smith@",
JoiningDate: "005-25-10",
}
err := validate.Struct(user)
if err != nil {
if _, ok := err.(*validator.InvalidValidationError); ok {
fmt.Println(err)
return
}
fmt.Println("------ List of tag fields with error ---------")
for _, err := range err.(validator.ValidationErrors) {
fmt.Println(err.StructField())
fmt.Println(err.ActualTag())
fmt.Println(err.Kind())
fmt.Println(err.Value())
fmt.Println(err.Param())
fmt.Println("---------------")
}
return
}
}
输出:
------ List of tag fields with error ---------
FirstName
alpha
string
Test25
---------------
Age
lte
uint8
75
65
---------------
Email
email
string
Badger.Smith@
---------------
JoiningDate
datetime
string
005-25-10
---------------