gpt写的go语言入门——通过博客系统 part1

第一部分:构建基础命令行博客系统

代码仓库

章节 1:Go语言快速入门

1.1 Go语言简介

Go语言,也称作Golang,是由Google开发的一种静态强类型、编译型语言,具有垃圾回收功能。它在2009年公开发布,由Robert Griesemer、Rob Pike和Ken Thompson设计。Go语言的设计目标是为了解决大型软件系统的构建问题,特别是在Google内部,这些系统需要高效的编译、高效的执行以及高效的代码维护。

Go的主要特点包括:

  • 简洁、快速和安全
  • 支持并发,通过goroutines和channels轻松实现
  • 丰富的标准库,尤其在网络服务和并发处理方面
  • 简单的依赖管理
  • 跨平台,支持多种操作系统

Go语言适用于各种类型的项目,从小型个人项目到大型分布式系统。在本书中,我们将使用Go语言构建一个博客系统,这将帮助我们理解Go语言在实际应用中的强大功能。

1.2 安装和设置Go开发环境

让我们开始安装Go语言。请访问Go语言官方网站(https://golang.org/dl/)下载适合您操作系统的安装包。下载完成后,请按照官方指南完成安装。

安装Go后,您可以打开终端或命令提示符并运行以下命令来验证安装:

go version

这应该会显示安装的Go版本。例如:

go version go1.15.6 linux/amd64

接下来,设置您的工作空间。Go语言的工作空间是存放Go代码的地方。它有一个特定的目录结构:

  • src 目录包含Go的源文件,
  • pkg 目录包含包对象,
  • bin 目录包含可执行文件。

您可以通过设置环境变量GOPATH来指定您的工作空间目录。例如,在Unix系统上:

export GOPATH=$HOME/go

在Windows系统上:

set GOPATH=c:\go

1.3 Hello World程序

编写Hello World程序是学习新编程语言的传统。在Go中,这个程序看起来是这样的:

package main

import "fmt"

func main() {
	fmt.Println("Hello, World!")
}

将上面的代码保存为hello.go。然后在命令行中运行以下命令来编译并运行程序:

go run hello.go

如果一切顺利,您将看到终端打印出“Hello, World!”。

1.4 Go程序基本结构

Go程序由包(packages)组成。每个Go文件都属于一个包,且文件的第一行声明了它所属的包。main包是特殊的,它告诉Go编译器这个程序是可执行的,而不是一个库。

main包中,main函数也是特殊的——它是程序执行的入口点。在上面的Hello World程序中,我们导入了fmt
包,这是一个包含I/O函数的标准库包。我们使用fmt.Println来输出字符串到标准输出。

1.5 练习:编写第一个Go程序

现在是时候动手写代码了。作为练习,请尝试以下操作:

  1. 编写一个Go程序,打印出你最喜欢的引语。
  2. 修改程序,接收用户输入,并打印出一个个性化的问候语。

这是一个接收用户输入的示例程序:

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	fmt.Print("Enter your name: ")
	name, _ := reader.ReadString('\n')
	fmt.Printf("Hello, %s", name)
}

这个程序使用bufio包创建一个新的缓冲读取器,用于读取来自标准输入的数据。它提示用户输入名字,然后读取输入并存储在变量name
中,最后使用fmt.Printf打印个性化的问候语。


通过完成第一章,读者应该能够理解Go语言的基础,安装并设置好Go开发环境,并编写、运行简单的Go程序。下一章将深入探讨Go语言的核心概念和功能。

章节 2:Go语言基础

2.1 变量和数据类型

在Go语言中,变量是存储程序执行过程中数据的容器。Go是静态类型语言,这意味着变量是有明确定义的类型,类型在编译时就已确定,并且类型在整个程序运行期间不会改变。

声明变量
var message string
message = "Hello, Go!"

// 或者一步到位
var greeting = "Hello, Go!"

// 短变量声明,最常用
name := "World"
基本数据类型

Go语言中的基本数据类型包括:

  • 整型(int、uint、int8、int16、int32、int64等)
  • 浮点型(float32、float64)
  • 布尔型(bool)
  • 字符串(string)

2.2 控制结构

控制结构在Go语言中用于控制程序的执行流程。Go提供了多种控制结构,例如if语句、for循环和switch语句。

If语句
if number := 10; number%2 == 0 {
fmt.Println(number, "is even")
} else {
fmt.Println(number, "is odd")
}
For循环
// 标准的for循环
for i := 0; i < 5; i++ {
fmt.Println("Value of i is:", i)
}

// 类似while的for循环
sum := 1
for sum < 1000 {
sum += sum
}
fmt.Println("Sum is:", sum)
Switch语句
dayOfWeek := 3
switch dayOfWeek {
case 1:
fmt.Println("Monday")
case 2:
fmt.Println("Tuesday")
case 3:
fmt.Println("Wednesday")
// ...
default:
fmt.Println("Invalid day")
}

2.3 函数定义和返回值

函数是执行特定任务的代码块。在Go中,您可以定义带有参数和返回值的函数。

func add(x int, y int) int {
return x + y
}

// 当连续两个或多个参数的类型相同时,我们可以仅声明最后一个参数的类型
func subtract(x, y int) int {
return x - y
}

result1 := add(6, 7)
result2 := subtract(10, 3)
fmt.Println("Addition result:", result1)
fmt.Println("Subtraction result:", result2)

2.4 错误处理基础

在Go中,错误处理是通过返回一个错误类型的值来完成的。如果一个函数可能产生错误,它通常是函数返回值列表中的最后一个。

func divide(x, y float64) (float64, error) {
if y == 0.0 {
return 0.0, errors.New("cannot divide by zero")
}
return x / y, nil
}

result, err := divide(10.0, 0.0)
if err != nil {
log.Fatal(err)
}
fmt.Println("Result:", result)

2.5 练习:创建基本的输入输出函数

作为练习,尝试以下操作:

  1. 创建一个函数,接受两个字符串参数并返回它们的拼接结果。
  2. 编写一个函数,接受一个整数数组并返回它们的和。
  3. 实现一个函数,接受一个整数并返回它的阶乘。
字符串拼接函数
func concatenate(str1, str2 string) string {
return str1 + str2
}

fmt.Println(concatenate("Hello, ", "Go!"))
整数数组求和函数
func sum(numbers []int) int {
total := 0
for _, number := range numbers {
total += number
}
return total
}

fmt.Println(sum([]int{1, 2, 3, 4, 5}))
阶乘函数
func factorial(n int) int {
if n == 0 {
return 1
}
return n * factorial(n-1)
}

fmt.Println(factorial(5))

通过完成第二章,读者应该能够理解Go语言的变量、数据类型、控制结构、函数定义以及错误处理的基础知识。这些是构建更复杂程序的基石。在下一章中,我们将探索Go的标准库,它提供了大量方便的工具和函数,可以帮助我们更快地开发程序。

章节 3:探索Go的标准库

Go的标准库是一组广泛的包,提供了从输入/输出处理到网络编程的功能。在这一章节中,我们将探索一些对于构建命令行博客系统非常有用的标准库包。

3.1 使用fmt

fmt包实现了格式化的I/O函数,类似于C语言的printf和scanf。我们已经在前面的Hello World程序中使用了fmt.Println来输出文本。

格式化输出
name := "Go Programmer"
age := 30

fmt.Printf("My name is %s and I am %d years old.\n", name, age)
从标准输入读取
var input string
fmt.Print("Enter your input: ")
fmt.Scanln(&input)
fmt.Println("You entered:", input)

3.2 文件操作:io/ioutilos

文件操作是大多数程序中的常见任务。在Go中,io/ioutilos包提供了这方面的功能。

读取文件
content, err := ioutil.ReadFile("blogpost.txt")
if err != nil {
log.Fatal(err)
}
fmt.Println("File content:", string(content))
写入文件
message := []byte("Hello, Go Blog!")
err := ioutil.WriteFile("blogpost.txt", message, 0644)
if err != nil {
log.Fatal(err)
}
检查文件是否存在
if _, err := os.Stat("blogpost.txt"); os.IsNotExist(err) {
fmt.Println("The file does not exist.")
} else {
fmt.Println("The file exists.")
}

3.3 日期和时间:time

处理日期和时间是编程中的一个常见需求。Go的time包提供了这方面的功能。

获取当前时间
now := time.Now()
fmt.Println("Current time:", now)
格式化日期和时间
fmt.Println("Formatted time:", now.Format("2006-01-02 15:04:05"))
计算时间差
past := time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC)
duration := now.Sub(past)
fmt.Println("Duration since past:", duration)

3.4 处理JSON:encoding/json

JSON是一种轻量级的数据交换格式,经常被用于网络通信。在Go中,encoding/json包提供了JSON数据的编码和解码功能。

JSON编码
type BlogPost struct {
Title   string
Content string
Author  string
Views   int
}

post := BlogPost{
Title:   "Exploring Go's Standard Library",
Content: "Go's standard library is vast...",
Author:  "Jane Doe",
Views:   3490,
}

jsonBytes, err := json.Marshal(post)
if err != nil {
log.Fatal(err)
}
fmt.Println("JSON encoding:", string(jsonBytes))
JSON解码
var post BlogPost
err := json.Unmarshal(jsonBytes, &post)
if err != nil {
log.Fatal(err)
}
fmt.Println("Blog post:", post)

3.5 练习:创建并操作自己的博客文章

作为练习,尝试以下操作:

  1. 创建一个结构体表示博客文章,包括标题、内容、作者和发布日期。
  2. 编写一个函数将博客文章结构体编码为JSON。
  3. 编写另一个函数将JSON解码回博客文章结构体。
  4. 将博客文章保存到文件,并从文件中读取。
博客文章结构体
type BlogPost struct {
Title   string    `json:"title"`
Content string    `json:"content"`
Author  string    `json:"author"`
Date    time.Time `json:"date"`
}
编码为JSON
func encodeToJSON(post BlogPost) ([]byte, error) {
return json.Marshal(post)
}
解码JSON
func decodeFromJSON(jsonBytes []byte) (BlogPost, error) {
var post BlogPost
err := json.Unmarshal(jsonBytes, &post)
return post, err
}
保存和读取博客文章
func savePostToFile(filename string, post BlogPost) error {
jsonBytes, err := encodeToJSON(post)
if err != nil {
return err
}
return ioutil.WriteFile(filename, jsonBytes, 0644)
}

func loadPostFromFile(filename string) (BlogPost, error) {
jsonBytes, err := ioutil.ReadFile(filename)
if err != nil {
return BlogPost{}, err
}
return decodeFromJSON(jsonBytes)
}

// 使用上述函数
post := BlogPost{
Title:   "My First Blog Post",
Content: "Content of my first blog post",
Author:  "John Doe",
Date:    time.Now(),
}

filename := "post.json"

// 保存博客文章到文件
err := savePostToFile(filename, post)
if err != nil {
log.Fatal(err)
}

// 从文件中读取博客文章
loadedPost, err := loadPostFromFile(filename)
if err != nil {
log.Fatal(err)
}
fmt.Println("Loaded blog post:", loadedPost)

通过完成第三章,读者应该能够理解如何使用Go的标准库来进行文件操作、日期和时间处理、以及JSON的编码和解码。这些技能对于构建命令行博客系统至关重要。在下一章中,我们将学习如何使用Go的网络编程功能来让我们的博客系统可以通过网络进行数据交换。

章节 4:Go的网络编程

在这一章节中,我们将介绍Go语言在网络编程方面的能力。Go的net包提供了丰富的网络编程功能,包括TCP/UDP协议、HTTP客户端和服务端的实现等。

4.1 创建TCP服务器

TCP(传输控制协议)是一种可靠的、面向连接的协议。下面的例子演示了如何创建一个简单的TCP服务器,它监听本地端口,并回显接收到的消息。

TCP Echo服务器
package main

import (
	"bufio"
	"fmt"
	"net"
	"os"
)

func main() {
	// 监听本地的12345端口
	listener, err := net.Listen("tcp", "localhost:12345")
	if err != nil {
		fmt.Println("Error listening:", err.Error())
		os.Exit(1)
	}
	defer listener.Close()
	fmt.Println("Listening on localhost:12345")

	for {
		// 等待连接
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("Error accepting:", err.Error())
			os.Exit(1)
		}
		fmt.Println("Received connection")

		// 处理连接
		go handleRequest(conn)
	}
}

// 处理请求
func handleRequest(conn net.Conn) {
	defer conn.Close()

	// 创建一个新的reader,从TCP连接读取数据
	reader := bufio.NewReader(conn)
	for {
		// 读取客户端发送的数据
		message, err := reader.ReadString('\n')
		if err != nil {
			fmt.Println("Error reading:", err.Error())
			break
		}
		fmt.Print("Message received: ", string(message))

		// 回显消息
		conn.Write([]byte(message))
	}
}

4.2 创建HTTP服务器

Go的net/http包让创建HTTP服务器变得非常简单。下面的代码展示了如何创建一个基本的HTTP服务器,它可以响应GET请求。

HTTP服务器
package main

import (
	"fmt"
	"net/http"
)

func main() {
	// 设置路由和处理函数
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Welcome to the Go Blog!")
	})

	// 监听并在8080端口启动服务器
	fmt.Println("Server is listening on port 8080...")
	if err := http.ListenAndServe(":8080", nil); err != nil {
		fmt.Println("Error starting server:", err)
		return
	}
}

4.3 创建HTTP客户端

Go的net/http包不仅可以创建服务器,还可以作为客户端发送请求。以下示例展示了如何发送GET请求并读取响应。

HTTP客户端
package main

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

func main() {
	// 向服务器发送GET请求
	response, err := http.Get("http://example.com")
	if err != nil {
		fmt.Println("Error making GET request:", err)
		return
	}
	defer response.Body.Close()

	// 读取响应内容
	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		fmt.Println("Error reading response:", err)
		return
	}

	fmt.Println("Response from server:", string(body))
}

4.4 练习:构建一个简单的博客服务器

作为练习,尝试以下操作:

  1. 创建一个HTTP服务器,它可以处理不同的路由和HTTP方法。
  2. 服务器应该能够响应至少两种内容:静态页面和JSON响应。
  3. 实现简单的文章存储功能,可以通过HTTP请求添加和检索文章。
HTTP服务器处理不同路由
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"sync"
)

// BlogPost 定义了博客文章的结构
type BlogPost struct {
	Title   string `json:"title"`
	Content string `json:"content"`
	Author  string `json:"author"`
}

// blogPosts 存储了所有博客文章
var blogPosts = make([]BlogPost, 0)
var mutex sync.Mutex

func main() {
	// 静态页面路由
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Welcome to the Go Blog!")
	})

	// 获取所有文章
	http.HandleFunc("/posts", func(w http.ResponseWriter, r *http.Request) {
		switch r.Method {
		case http.MethodGet:
			mutex.Lock()
			postsJSON, _ := json.Marshal(blogPosts)
			mutex.Unlock()
			w.Header().Set("Content-Type", "application/json")
			w.Write(postsJSON)
		default:
			w.WriteHeader(http.StatusMethodNotAllowed)
		}
	})

	// 添加新文章
	http.HandleFunc("/posts/new", func(w http.ResponseWriter, r *http.Request) {
		switch r.Method {
		case http.MethodPost:
			var newPost BlogPost
			err := json.NewDecoder(r.Body).Decode(&newPost)
			if err != nil {
				http.Error(w, err.Error(), http.StatusBadRequest)
				return
			}
			mutex.Lock()
			blogPosts = append(blogPosts, newPost)
			mutex.Unlock()
			w.WriteHeader(http.StatusCreated)
		default:
			w.WriteHeader(http.StatusMethodNotAllowed)
		}
	})

	// 监听并在8080端口启动服务器
	fmt.Println("Server is listening on port 8080...")
	if err := http.ListenAndServe(":8080", nil); err != nil {
		fmt.Println("Error starting server:", err)
	}
}

在这个例子中,我们创建了一个简单的HTTP服务器,它可以处理静态页面和JSON响应。我们还实现了一个简单的文章存储功能,可以通过HTTP
POST请求添加文章,并通过HTTP GET请求检索所有文章。这个练习为创建一个更复杂和功能丰富的博客系统奠定了基础。


通过完成第四章,读者应该能够理解Go语言在网络编程方面的基本概念,包括创建TCP和HTTP服务器、发送HTTP请求等。这些知识对于构建网络应用程序和服务是非常重要的。在下一章中,我们将学习如何将这些概念应用于我们的命令行博客系统,使其能够处理网络上的博客文章。

章节 5:整合网络功能到命令行博客系统

在本章中,我们将把网络编程的概念整合到我们的命令行博客系统中。我们的目标是使博客系统能够通过网络接收文章,并能够通过HTTP请求提供文章内容。

5.1 设计RESTful API

我们将设计一个简单的RESTful API,以便于通过HTTP方法管理博客文章,包括获取、创建和删除文章。

  • GET /posts - 获取所有文章
  • POST /posts - 创建新文章
  • GET /posts/{id} - 获取特定ID的文章
  • DELETE /posts/{id} - 删除特定ID的文章

5.2 实现API服务器

我们将使用Go的net/http包来实现上述API。

服务器代码
package main

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

// BlogPost 定义了博客文章的结构
type BlogPost struct {
	ID      int    `json:"id"`
	Title   string `json:"title"`
	Content string `json:"content"`
	Author  string `json:"author"`
}

// blogPosts 存储了所有博客文章
var blogPosts []BlogPost
var mutex sync.Mutex
var idCounter int

func main() {
	http.HandleFunc("/posts", postsHandler)
	http.HandleFunc("/posts/", postHandler)

	// 监听并在8080端口启动服务器
	fmt.Println("Server is listening on port 8080...")
	if err := http.ListenAndServe(":8080", nil); err != nil {
		fmt.Println("Error starting server:", err)
	}
}

func postsHandler(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case http.MethodGet:
		mutex.Lock()
		postsJSON, _ := json.Marshal(blogPosts)
		mutex.Unlock()
		w.Header().Set("Content-Type", "application/json")
		w.Write(postsJSON)
	case http.MethodPost:
		var newPost BlogPost
		bodyBytes, err := ioutil.ReadAll(r.Body)
		if err != nil {
			http.Error(w, "Invalid request", http.StatusBadRequest)
			return
		}
		err = json.Unmarshal(bodyBytes, &newPost)
		if err != nil {
			http.Error(w, "Invalid JSON", http.StatusBadRequest)
			return
		}
		mutex.Lock()
		idCounter++
		newPost.ID = idCounter
		blogPosts = append(blogPosts, newPost)
		mutex.Unlock()
		w.WriteHeader(http.StatusCreated)
	default:
		w.WriteHeader(http.StatusMethodNotAllowed)
	}
}

func postHandler(w http.ResponseWriter, r *http.Request) {
	idStr := strings.TrimPrefix(r.URL.Path, "/posts/")
	id, err := strconv.Atoi(idStr)
	if err != nil {
		http.Error(w, "Invalid post ID", http.StatusBadRequest)
		return
	}

	switch r.Method {
	case http.MethodGet:
		found := false
		for _, post := range blogPosts {
			if post.ID == id {
				postJSON, _ := json.Marshal(post)
				w.Header().Set("Content-Type", "application/json")
				w.Write(postJSON)
				found = true
				break
			}
		}
		if !found {
			http.NotFound(w, r)
		}
	case http.MethodDelete:
		found := false
		for i, post := range blogPosts {
			if post.ID == id {
				mutex.Lock()
				blogPosts = append(blogPosts[:i], blogPosts[i+1:]...)
				mutex.Unlock()
				w.WriteHeader(http.StatusOK)
				found = true
				break
			}
		}
		if !found {
			http.NotFound(w, r)
		}
	default:
		w.WriteHeader(http.StatusMethodNotAllowed)
	}
}

5.3 命令行客户端功能

我们将扩展命令行客户端,以便它可以与API服务器交互,获取和发布文章。

客户端代码
package main

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

func main() {
	if len(os.Args) < 2 {
		fmt.Println("Usage: go run blogclient.go  []")
		return
	}

	switch os.Args[1] {
	case "list":
		listPosts()
	case "post":
		if len(os.Args) != 5 {
			fmt.Println("Usage: go run blogclient.go post  <content> <author>"</span><span class="token punctuation">)</span>
			<span class="token keyword">return</span>
		<span class="token punctuation">}</span>
		<span class="token function">createPost</span><span class="token punctuation">(</span>os<span class="token punctuation">.</span>Args<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> os<span class="token punctuation">.</span>Args<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">,</span> os<span class="token punctuation">.</span>Args<span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
	<span class="token keyword">default</span><span class="token punctuation">:</span>
		fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"Unknown action"</span><span class="token punctuation">)</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">func</span> <span class="token function">listPosts</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	response<span class="token punctuation">,</span> err <span class="token operator">:=</span> http<span class="token punctuation">.</span><span class="token function">Get</span><span class="token punctuation">(</span><span class="token string">"http://localhost:8080/posts"</span><span class="token punctuation">)</span>
	<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
		fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"Error fetching posts:"</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span>
		<span class="token keyword">return</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">defer</span> response<span class="token punctuation">.</span>Body<span class="token punctuation">.</span><span class="token function">Close</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

	body<span class="token punctuation">,</span> err <span class="token operator">:=</span> ioutil<span class="token punctuation">.</span><span class="token function">ReadAll</span><span class="token punctuation">(</span>response<span class="token punctuation">.</span>Body<span class="token punctuation">)</span>
	<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
		fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"Error reading response:"</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span>
		<span class="token keyword">return</span>
	<span class="token punctuation">}</span>

	<span class="token keyword">var</span> posts <span class="token punctuation">[</span><span class="token punctuation">]</span>BlogPost
	err <span class="token operator">=</span> json<span class="token punctuation">.</span><span class="token function">Unmarshal</span><span class="token punctuation">(</span>body<span class="token punctuation">,</span> <span class="token operator">&</span>posts<span class="token punctuation">)</span>
	<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
		fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"Error decoding posts:"</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span>
		<span class="token keyword">return</span>
	<span class="token punctuation">}</span>

	<span class="token keyword">for</span> <span class="token boolean">_</span><span class="token punctuation">,</span> post <span class="token operator">:=</span> <span class="token keyword">range</span> posts <span class="token punctuation">{</span>
		fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">"ID: %d\nTitle: %s\nContent: %s\nAuthor: %s\n\n"</span><span class="token punctuation">,</span> post<span class="token punctuation">.</span>ID<span class="token punctuation">,</span> post<span class="token punctuation">.</span>Title<span class="token punctuation">,</span> post<span class="token punctuation">.</span>Content<span class="token punctuation">,</span> post<span class="token punctuation">.</span>Author<span class="token punctuation">)</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">func</span> <span class="token function">createPost</span><span class="token punctuation">(</span>title<span class="token punctuation">,</span> content<span class="token punctuation">,</span> author <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	post <span class="token operator">:=</span> BlogPost<span class="token punctuation">{</span>
		Title<span class="token punctuation">:</span>   title<span class="token punctuation">,</span>
		Content<span class="token punctuation">:</span> content<span class="token punctuation">,</span>
		Author<span class="token punctuation">:</span>  author<span class="token punctuation">,</span>
	<span class="token punctuation">}</span>

	postJSON<span class="token punctuation">,</span> err <span class="token operator">:=</span> json<span class="token punctuation">.</span><span class="token function">Marshal</span><span class="token punctuation">(</span>post<span class="token punctuation">)</span>
	<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
		fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"Error encoding post:"</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span>
		<span class="token keyword">return</span>
	<span class="token punctuation">}</span>

	response<span class="token punctuation">,</span> err <span class="token operator">:=</span> http<span class="token punctuation">.</span><span class="token function">Post</span><span class="token punctuation">(</span><span class="token string">"http://localhost:8080/posts"</span><span class="token punctuation">,</span> <span class="token string">"application/json"</span><span class="token punctuation">,</span> bytes<span class="token punctuation">.</span><span class="token function">NewBuffer</span><span class="token punctuation">(</span>postJSON<span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
		fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"Error creating post:"</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span>
		<span class="token keyword">return</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">defer</span> response<span class="token punctuation">.</span>Body<span class="token punctuation">.</span><span class="token function">Close</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

	<span class="token keyword">if</span> response<span class="token punctuation">.</span>StatusCode <span class="token operator">==</span> http<span class="token punctuation">.</span>StatusCreated <span class="token punctuation">{</span>
		fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"Post created successfully"</span><span class="token punctuation">)</span>
	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
		fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">"Failed to create post, status code: %d\n"</span><span class="token punctuation">,</span> response<span class="token punctuation">.</span>StatusCode<span class="token punctuation">)</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> 
  <h4>5.4 练习:扩展博客功能</h4> 
  <p>作为练习,尝试以下操作:</p> 
  <ol> 
   <li>添加命令行客户端的删除功能,以便它可以通过HTTP请求删除文章。</li> 
   <li>实现文章更新功能,允许通过PUT请求更新现有文章的内容。</li> 
   <li>添加用户认证,确保只有认证用户才能创建、更新和删除文章。</li> 
  </ol> 
  <h5>添加删除功能</h5> 
  <pre><code class="prism language-go"><span class="token comment">// 添加到 main 函数的 switch-case 中</span>
<span class="token keyword">case</span> <span class="token string">"delete"</span><span class="token punctuation">:</span>
<span class="token keyword">if</span> <span class="token function">len</span><span class="token punctuation">(</span>os<span class="token punctuation">.</span>Args<span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token number">3</span> <span class="token punctuation">{</span>
fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"Usage: go run blogclient.go delete <id>"</span><span class="token punctuation">)</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>
id <span class="token operator">:=</span> os<span class="token punctuation">.</span>Args<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span>
<span class="token function">deletePost</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span>
<span class="token comment">// ...</span>

<span class="token keyword">func</span> <span class="token function">deletePost</span><span class="token punctuation">(</span>id <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
client <span class="token operator">:=</span> <span class="token operator">&</span>http<span class="token punctuation">.</span>Client<span class="token punctuation">{</span><span class="token punctuation">}</span>
req<span class="token punctuation">,</span> err <span class="token operator">:=</span> http<span class="token punctuation">.</span><span class="token function">NewRequest</span><span class="token punctuation">(</span>http<span class="token punctuation">.</span>MethodDelete<span class="token punctuation">,</span> <span class="token string">"http://localhost:8080/posts/"</span><span class="token operator">+</span>id<span class="token punctuation">,</span> <span class="token boolean">nil</span><span class="token punctuation">)</span>
<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"Error creating request:"</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>

resp<span class="token punctuation">,</span> err <span class="token operator">:=</span> client<span class="token punctuation">.</span><span class="token function">Do</span><span class="token punctuation">(</span>req<span class="token punctuation">)</span>
<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"Error sending request:"</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>
<span class="token keyword">defer</span> resp<span class="token punctuation">.</span>Body<span class="token punctuation">.</span><span class="token function">Close</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

<span class="token keyword">if</span> resp<span class="token punctuation">.</span>StatusCode <span class="token operator">==</span> http<span class="token punctuation">.</span>StatusOK <span class="token punctuation">{</span>
fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"Post deleted successfully"</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">"Failed to delete post, status code: %d\n"</span><span class="token punctuation">,</span> resp<span class="token punctuation">.</span>StatusCode<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> 
  <h5>实现更新功能</h5> 
  <p>这需要在API服务器和客户端中添加对应的逻辑来处理PUT请求。</p> 
  <h5>添加用户认证</h5> 
  <p>用户认证通常涉及到更复杂的逻辑和安全性考虑,例如使用JWT(JSON Web Tokens)或OAuth。这将超出本章的范围,但是作为一个练习,你可以探索如何在Go中实现这些认证机制。</p> 
  <hr> 
  <p>通过完成第五章,读者应该能够理解如何将网络编程整合到命令行博客系统中,使得系统能够通过网络接收和发送数据。这些技能是构建现代网络应用程序的基础。在后续的章节中,我们可以进一步探讨如何扩展系统的功能,例如添加数据库支持、用户认证和更多的HTTP路由处理。</p> 
  <h3>章节 6:为博客系统添加持久化存储</h3> 
  <p>在本章中,我们将为我们的命令行博客系统添加持久化存储功能。这将允许我们的系统在服务重启后保留博客文章数据。我们将使用Go的<code>database/sql</code><br> 包来实现与SQLite数据库的交互。</p> 
  <h4>6.1 设计数据库模型</h4> 
  <p>我们将创建一个简单的数据库模型,用于存储博客文章。</p> 
  <h5>使用go mod创建项目</h5> 
  <pre><code class="prism language-shell">go mod init myblog
go mod tidy
</code></pre> 
  <blockquote> 
   <p>项目结构</p> 
  </blockquote> 
  <pre><code class="prism language-text">- project
    - db
        - db.go
    - model
        - models.go
    - api-server.go
    - cmd-client.go
</code></pre> 
  <h5>数据库模型</h5> 
  <pre><code class="prism language-sql"><span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token operator">NOT</span> <span class="token keyword">EXISTS</span> posts
<span class="token punctuation">(</span>
    id
    <span class="token keyword">INTEGER</span>
    <span class="token keyword">PRIMARY</span>
    <span class="token keyword">KEY</span>
    AUTOINCREMENT<span class="token punctuation">,</span>
    title
    <span class="token keyword">TEXT</span>
    <span class="token operator">NOT</span>
    <span class="token boolean">NULL</span><span class="token punctuation">,</span>
    content
    <span class="token keyword">TEXT</span>
    <span class="token operator">NOT</span>
    <span class="token boolean">NULL</span><span class="token punctuation">,</span>
    author
    <span class="token keyword">TEXT</span>
    <span class="token operator">NOT</span>
    <span class="token boolean">NULL</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> 
  <h4>6.2 实现数据库操作</h4> 
  <p>我们将实现一个简单的数据库操作层,用于执行CRUD(创建、读取、更新和删除)操作。</p> 
  <h5>数据库操作代码</h5> 
  <pre><code class="prism language-go"><span class="token keyword">package</span> db

<span class="token keyword">import</span> <span class="token punctuation">(</span>
	<span class="token string">"database/sql"</span>
	<span class="token boolean">_</span> <span class="token string">"github.com/mattn/go-sqlite3"</span>
	<span class="token string">"log"</span>
	<span class="token string">"myblog/model"</span>
<span class="token punctuation">)</span>

<span class="token keyword">var</span> db <span class="token operator">*</span>sql<span class="token punctuation">.</span>DB

<span class="token keyword">func</span> <span class="token function">InitDB</span><span class="token punctuation">(</span>filePath <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">var</span> err <span class="token builtin">error</span>
	db<span class="token punctuation">,</span> err <span class="token operator">=</span> sql<span class="token punctuation">.</span><span class="token function">Open</span><span class="token punctuation">(</span><span class="token string">"sqlite3"</span><span class="token punctuation">,</span> filePath<span class="token punctuation">)</span>
	<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
		log<span class="token punctuation">.</span><span class="token function">Fatal</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
	<span class="token punctuation">}</span>

	createTableSQL <span class="token operator">:=</span> <span class="token string">`CREATE TABLE IF NOT EXISTS posts (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        title TEXT NOT NULL,
        content TEXT NOT NULL,
        author TEXT NOT NULL
    );`</span>

	<span class="token boolean">_</span><span class="token punctuation">,</span> err <span class="token operator">=</span> db<span class="token punctuation">.</span><span class="token function">Exec</span><span class="token punctuation">(</span>createTableSQL<span class="token punctuation">)</span>
	<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
		log<span class="token punctuation">.</span><span class="token function">Fatal</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">func</span> <span class="token function">GetPosts</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">*</span>model<span class="token punctuation">.</span>BlogPost<span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	rows<span class="token punctuation">,</span> err <span class="token operator">:=</span> db<span class="token punctuation">.</span><span class="token function">Query</span><span class="token punctuation">(</span><span class="token string">"SELECT id, title, content, author FROM posts"</span><span class="token punctuation">)</span>
	<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
		<span class="token keyword">return</span> <span class="token boolean">nil</span><span class="token punctuation">,</span> err
	<span class="token punctuation">}</span>
	<span class="token keyword">defer</span> rows<span class="token punctuation">.</span><span class="token function">Close</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

	<span class="token keyword">var</span> posts <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">*</span>model<span class="token punctuation">.</span>BlogPost
	<span class="token keyword">for</span> rows<span class="token punctuation">.</span><span class="token function">Next</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">var</span> post model<span class="token punctuation">.</span>BlogPost
		<span class="token keyword">if</span> err <span class="token operator">:=</span> rows<span class="token punctuation">.</span><span class="token function">Scan</span><span class="token punctuation">(</span><span class="token operator">&</span>post<span class="token punctuation">.</span>ID<span class="token punctuation">,</span> <span class="token operator">&</span>post<span class="token punctuation">.</span>Title<span class="token punctuation">,</span> <span class="token operator">&</span>post<span class="token punctuation">.</span>Content<span class="token punctuation">,</span> <span class="token operator">&</span>post<span class="token punctuation">.</span>Author<span class="token punctuation">)</span><span class="token punctuation">;</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
			<span class="token keyword">return</span> <span class="token boolean">nil</span><span class="token punctuation">,</span> err
		<span class="token punctuation">}</span>
		posts <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>posts<span class="token punctuation">,</span> <span class="token operator">&</span>post<span class="token punctuation">)</span>
	<span class="token punctuation">}</span>

	<span class="token keyword">return</span> posts<span class="token punctuation">,</span> <span class="token boolean">nil</span>
<span class="token punctuation">}</span>

<span class="token keyword">func</span> <span class="token function">CreatePost</span><span class="token punctuation">(</span>post model<span class="token punctuation">.</span>BlogPost<span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token builtin">int64</span><span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	result<span class="token punctuation">,</span> err <span class="token operator">:=</span> db<span class="token punctuation">.</span><span class="token function">Exec</span><span class="token punctuation">(</span><span class="token string">"INSERT INTO posts (title, content, author) VALUES (?, ?, ?)"</span><span class="token punctuation">,</span> post<span class="token punctuation">.</span>Title<span class="token punctuation">,</span> post<span class="token punctuation">.</span>Content<span class="token punctuation">,</span> post<span class="token punctuation">.</span>Author<span class="token punctuation">)</span>
	<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
		<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">,</span> err
	<span class="token punctuation">}</span>

	<span class="token keyword">return</span> result<span class="token punctuation">.</span><span class="token function">LastInsertId</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token keyword">func</span> <span class="token function">GetPostByID</span><span class="token punctuation">(</span>id <span class="token builtin">int</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token operator">*</span>model<span class="token punctuation">.</span>BlogPost<span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	row <span class="token operator">:=</span> db<span class="token punctuation">.</span><span class="token function">QueryRow</span><span class="token punctuation">(</span><span class="token string">"SELECT id, title, content, author FROM posts WHERE id = ?"</span><span class="token punctuation">,</span> id<span class="token punctuation">)</span>

	<span class="token keyword">var</span> post model<span class="token punctuation">.</span>BlogPost
	<span class="token keyword">if</span> err <span class="token operator">:=</span> row<span class="token punctuation">.</span><span class="token function">Scan</span><span class="token punctuation">(</span><span class="token operator">&</span>post<span class="token punctuation">.</span>ID<span class="token punctuation">,</span> <span class="token operator">&</span>post<span class="token punctuation">.</span>Title<span class="token punctuation">,</span> <span class="token operator">&</span>post<span class="token punctuation">.</span>Content<span class="token punctuation">,</span> <span class="token operator">&</span>post<span class="token punctuation">.</span>Author<span class="token punctuation">)</span><span class="token punctuation">;</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
		<span class="token keyword">if</span> err <span class="token operator">==</span> sql<span class="token punctuation">.</span>ErrNoRows <span class="token punctuation">{</span>
			<span class="token keyword">return</span> <span class="token boolean">nil</span><span class="token punctuation">,</span> <span class="token boolean">nil</span>
		<span class="token punctuation">}</span>
		<span class="token keyword">return</span> <span class="token boolean">nil</span><span class="token punctuation">,</span> err
	<span class="token punctuation">}</span>

	<span class="token keyword">return</span> <span class="token operator">&</span>post<span class="token punctuation">,</span> <span class="token boolean">nil</span>
<span class="token punctuation">}</span>

<span class="token keyword">func</span> <span class="token function">DeletePostByID</span><span class="token punctuation">(</span>id <span class="token builtin">int</span><span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span>
	<span class="token boolean">_</span><span class="token punctuation">,</span> err <span class="token operator">:=</span> db<span class="token punctuation">.</span><span class="token function">Exec</span><span class="token punctuation">(</span><span class="token string">"DELETE FROM posts WHERE id = ?"</span><span class="token punctuation">,</span> id<span class="token punctuation">)</span>
	<span class="token keyword">return</span> err
<span class="token punctuation">}</span>
</code></pre> 
  <h4>6.3 集成数据库操作到API服务器</h4> 
  <p>我们需要修改API服务器的代码,以使用数据库操作层来处理数据。</p> 
  <h5>修改后的API服务器代码</h5> 
  <pre><code class="prism language-go"><span class="token comment">// ... 保留之前的代码 ...</span>

<span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">initDB</span><span class="token punctuation">(</span><span class="token string">"blog.db"</span><span class="token punctuation">)</span>

http<span class="token punctuation">.</span><span class="token function">HandleFunc</span><span class="token punctuation">(</span><span class="token string">"/posts"</span><span class="token punctuation">,</span> postsHandler<span class="token punctuation">)</span>
http<span class="token punctuation">.</span><span class="token function">HandleFunc</span><span class="token punctuation">(</span><span class="token string">"/posts/"</span><span class="token punctuation">,</span> postHandler<span class="token punctuation">)</span>

<span class="token comment">// 监听并在8080端口启动服务器</span>
fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"Server is listening on port 8080..."</span><span class="token punctuation">)</span>
<span class="token keyword">if</span> err <span class="token operator">:=</span> http<span class="token punctuation">.</span><span class="token function">ListenAndServe</span><span class="token punctuation">(</span><span class="token string">":8080"</span><span class="token punctuation">,</span> <span class="token boolean">nil</span><span class="token punctuation">)</span><span class="token punctuation">;</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"Error starting server:"</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">func</span> <span class="token function">postsHandler</span><span class="token punctuation">(</span>w http<span class="token punctuation">.</span>ResponseWriter<span class="token punctuation">,</span> r <span class="token operator">*</span>http<span class="token punctuation">.</span>Request<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// ... 保留之前的代码 ...</span>
<span class="token keyword">case</span> http<span class="token punctuation">.</span>MethodPost<span class="token punctuation">:</span>
<span class="token keyword">var</span> newPost BlogPost
bodyBytes<span class="token punctuation">,</span> err <span class="token operator">:=</span> io<span class="token punctuation">.</span><span class="token function">ReadAll</span><span class="token punctuation">(</span>r<span class="token punctuation">.</span>Body<span class="token punctuation">)</span>
<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
http<span class="token punctuation">.</span><span class="token function">Error</span><span class="token punctuation">(</span>w<span class="token punctuation">,</span> <span class="token string">"Invalid request"</span><span class="token punctuation">,</span> http<span class="token punctuation">.</span>StatusBadRequest<span class="token punctuation">)</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>
err <span class="token operator">=</span> json<span class="token punctuation">.</span><span class="token function">Unmarshal</span><span class="token punctuation">(</span>bodyBytes<span class="token punctuation">,</span> <span class="token operator">&</span>newPost<span class="token punctuation">)</span>
<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
http<span class="token punctuation">.</span><span class="token function">Error</span><span class="token punctuation">(</span>w<span class="token punctuation">,</span> <span class="token string">"Invalid JSON"</span><span class="token punctuation">,</span> http<span class="token punctuation">.</span>StatusBadRequest<span class="token punctuation">)</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>

id<span class="token punctuation">,</span> err <span class="token operator">:=</span> <span class="token function">createPost</span><span class="token punctuation">(</span>newPost<span class="token punctuation">)</span>
<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
http<span class="token punctuation">.</span><span class="token function">Error</span><span class="token punctuation">(</span>w<span class="token punctuation">,</span> <span class="token string">"Error saving post"</span><span class="token punctuation">,</span> http<span class="token punctuation">.</span>StatusInternalServerError<span class="token punctuation">)</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>

newPost<span class="token punctuation">.</span>ID <span class="token operator">=</span> <span class="token function">int</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span>
w<span class="token punctuation">.</span><span class="token function">Header</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Set</span><span class="token punctuation">(</span><span class="token string">"Content-Type"</span><span class="token punctuation">,</span> <span class="token string">"application/json"</span><span class="token punctuation">)</span>
json<span class="token punctuation">.</span><span class="token function">NewEncoder</span><span class="token punctuation">(</span>w<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Encode</span><span class="token punctuation">(</span>newPost<span class="token punctuation">)</span>
w<span class="token punctuation">.</span><span class="token function">WriteHeader</span><span class="token punctuation">(</span>http<span class="token punctuation">.</span>StatusCreated<span class="token punctuation">)</span>
<span class="token keyword">default</span><span class="token punctuation">:</span>
w<span class="token punctuation">.</span><span class="token function">WriteHeader</span><span class="token punctuation">(</span>http<span class="token punctuation">.</span>StatusMethodNotAllowed<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token comment">// ... 修改其他处理函数以使用数据库操作 ...</span>
</code></pre> 
  <h4>6.4 练习:添加更新和认证功能</h4> 
  <p>作为练习,尝试以下操作:</p> 
  <ol> 
   <li>实现更新文章的功能,允许通过PUT请求更新现有文章的内容。</li> 
   <li>添加基本的用户认证,确保只有认证用户才能创建、更新和删除文章。</li> 
  </ol> 
  <h5>实现更新文章功能</h5> 
  <pre><code class="prism language-go"><span class="token comment">// 添加到数据库操作代码中</span>
<span class="token keyword">func</span> <span class="token function">UpdatePostByID</span><span class="token punctuation">(</span>id <span class="token builtin">int</span><span class="token punctuation">,</span> post model<span class="token punctuation">.</span>BlogPost<span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span>
<span class="token boolean">_</span><span class="token punctuation">,</span> err <span class="token operator">:=</span> db<span class="token punctuation">.</span><span class="token function">Exec</span><span class="token punctuation">(</span><span class="token string">"UPDATE posts SET title = ?, content = ?, author = ? WHERE id = ?"</span><span class="token punctuation">,</span> post<span class="token punctuation">.</span>Title<span class="token punctuation">,</span> post<span class="token punctuation">.</span>Content<span class="token punctuation">,</span> post<span class="token punctuation">.</span>Author<span class="token punctuation">,</span> id<span class="token punctuation">)</span>
<span class="token keyword">return</span> err
<span class="token punctuation">}</span>


<span class="token comment">// 添加到API服务器中的 postHandler</span>
<span class="token keyword">case</span> http<span class="token punctuation">.</span>MethodPut<span class="token punctuation">:</span>
<span class="token keyword">var</span> updatedPost BlogPost
bodyBytes<span class="token punctuation">,</span> err <span class="token operator">:=</span> ioutil<span class="token punctuation">.</span><span class="token function">ReadAll</span><span class="token punctuation">(</span>r<span class="token punctuation">.</span>Body<span class="token punctuation">)</span>
<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
http<span class="token punctuation">.</span><span class="token function">Error</span><span class="token punctuation">(</span>w<span class="token punctuation">,</span> <span class="token string">"Invalid request"</span><span class="token punctuation">,</span> http<span class="token punctuation">.</span>StatusBadRequest<span class="token punctuation">)</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>
err <span class="token operator">=</span> json<span class="token punctuation">.</span><span class="token function">Unmarshal</span><span class="token punctuation">(</span>bodyBytes<span class="token punctuation">,</span> <span class="token operator">&</span>updatedPost<span class="token punctuation">)</span>
<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
http<span class="token punctuation">.</span><span class="token function">Error</span><span class="token punctuation">(</span>w<span class="token punctuation">,</span> <span class="token string">"Invalid JSON"</span><span class="token punctuation">,</span> http<span class="token punctuation">.</span>StatusBadRequest<span class="token punctuation">)</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>

err <span class="token operator">=</span> <span class="token function">updatePostByID</span><span class="token punctuation">(</span>id<span class="token punctuation">,</span> updatedPost<span class="token punctuation">)</span>
<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
http<span class="token punctuation">.</span><span class="token function">Error</span><span class="token punctuation">(</span>w<span class="token punctuation">,</span> <span class="token string">"Error updating post"</span><span class="token punctuation">,</span> http<span class="token punctuation">.</span>StatusInternalServerError<span class="token punctuation">)</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>

w<span class="token punctuation">.</span><span class="token function">WriteHeader</span><span class="token punctuation">(</span>http<span class="token punctuation">.</span>StatusOK<span class="token punctuation">)</span>
</code></pre> 
  <h5>添加用户认证功能</h5> 
  <p>用户认证通常涉及到更复杂的逻辑和安全性考虑,例如使用JWT(JSON Web Tokens)或OAuth。这将超出本章的范围,但是作为一个练习,你可以探索如何在Go中实现这些认证机制。</p> 
  <hr> 
  <p>通过完成第六章,读者应该能够理解如何为Go语言编写的博客系统添加持久化存储功能。我们介绍了如何使用SQLite数据库来存储数据,并展示了如何将数据库操作集成到我们的API服务器中。这些知识是构建能够长期存储数据的网络应用程序的基础。在后续的章节中,我们可以进一步探讨如何扩展系统的功能,例如添加更复杂的数据库操作、用户认证和安全性措施。</p> 
  <h3>章节 7:增加用户认证和授权</h3> 
  <p>在本章中,我们将为我们的命令行博客系统添加用户认证和授权功能。这将确保只有经过验证的用户才能创建、更新或删除文章。我们将使用JSON<br> Web Tokens(JWT)来实现这一功能。</p> 
  <h4>7.1 设计用户模型</h4> 
  <p>首先,我们需要设计一个用户模型来存储用户信息。</p> 
  <h5>用户模型</h5> 
  <pre><code class="prism language-sql"><span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token operator">NOT</span> <span class="token keyword">EXISTS</span> users
<span class="token punctuation">(</span>
    id
    <span class="token keyword">INTEGER</span>
    <span class="token keyword">PRIMARY</span>
    <span class="token keyword">KEY</span>
    AUTOINCREMENT<span class="token punctuation">,</span>
    username
    <span class="token keyword">TEXT</span>
    <span class="token operator">NOT</span>
    <span class="token boolean">NULL</span>
    <span class="token keyword">UNIQUE</span><span class="token punctuation">,</span>
    password_hash
    <span class="token keyword">TEXT</span>
    <span class="token operator">NOT</span>
    <span class="token boolean">NULL</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> 
  <h4>7.2 实现用户注册和登录</h4> 
  <p>我们将允许用户注册和登录,以便我们可以发行JWT给认证用户。</p> 
  <h5>用户注册和登录代码</h5> 
  <pre><code class="prism language-go"><span class="token keyword">package</span> main

<span class="token keyword">import</span> <span class="token punctuation">(</span>
	<span class="token string">"database/sql"</span>
	<span class="token string">"fmt"</span>
	<span class="token string">"log"</span>

	<span class="token string">"golang.org/x/crypto/bcrypt"</span>
	<span class="token string">"github.com/dgrijalva/jwt-go"</span>
<span class="token punctuation">)</span>

<span class="token keyword">var</span> jwtKey <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token function">byte</span><span class="token punctuation">(</span><span class="token string">"my_secret_key"</span><span class="token punctuation">)</span>

<span class="token keyword">type</span> Claims <span class="token keyword">struct</span> <span class="token punctuation">{</span>
	Username <span class="token builtin">string</span> <span class="token string">`json:"username"`</span>
	jwt<span class="token punctuation">.</span>StandardClaims
<span class="token punctuation">}</span>

<span class="token comment">// Register a new user</span>
<span class="token keyword">func</span> <span class="token function">registerUser</span><span class="token punctuation">(</span>username<span class="token punctuation">,</span> password <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span>
	hashedPassword<span class="token punctuation">,</span> err <span class="token operator">:=</span> bcrypt<span class="token punctuation">.</span><span class="token function">GenerateFromPassword</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token function">byte</span><span class="token punctuation">(</span>password<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">)</span>
	<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
		<span class="token keyword">return</span> err
	<span class="token punctuation">}</span>

	<span class="token boolean">_</span><span class="token punctuation">,</span> err <span class="token operator">=</span> db<span class="token punctuation">.</span><span class="token function">Exec</span><span class="token punctuation">(</span><span class="token string">"INSERT INTO users (username, password_hash) VALUES (?, ?)"</span><span class="token punctuation">,</span> username<span class="token punctuation">,</span> hashedPassword<span class="token punctuation">)</span>
	<span class="token keyword">return</span> err
<span class="token punctuation">}</span>

<span class="token comment">// Authenticate a user and return a JWT</span>
<span class="token keyword">func</span> <span class="token function">authenticateUser</span><span class="token punctuation">(</span>username<span class="token punctuation">,</span> password <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token builtin">string</span><span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token comment">// Verify the username and password</span>
	<span class="token keyword">var</span> passwordHash <span class="token builtin">string</span>
	row <span class="token operator">:=</span> db<span class="token punctuation">.</span><span class="token function">QueryRow</span><span class="token punctuation">(</span><span class="token string">"SELECT password_hash FROM users WHERE username = ?"</span><span class="token punctuation">,</span> username<span class="token punctuation">)</span>
	err <span class="token operator">:=</span> row<span class="token punctuation">.</span><span class="token function">Scan</span><span class="token punctuation">(</span><span class="token operator">&</span>passwordHash<span class="token punctuation">)</span>
	<span class="token keyword">if</span> err <span class="token operator">==</span> sql<span class="token punctuation">.</span>ErrNoRows <span class="token punctuation">{</span>
		<span class="token keyword">return</span> <span class="token string">""</span><span class="token punctuation">,</span> fmt<span class="token punctuation">.</span><span class="token function">Errorf</span><span class="token punctuation">(</span><span class="token string">"user not found"</span><span class="token punctuation">)</span>
	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
		<span class="token keyword">return</span> <span class="token string">""</span><span class="token punctuation">,</span> err
	<span class="token punctuation">}</span>

	err <span class="token operator">=</span> bcrypt<span class="token punctuation">.</span><span class="token function">CompareHashAndPassword</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token function">byte</span><span class="token punctuation">(</span>passwordHash<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token function">byte</span><span class="token punctuation">(</span>password<span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
		<span class="token keyword">return</span> <span class="token string">""</span><span class="token punctuation">,</span> fmt<span class="token punctuation">.</span><span class="token function">Errorf</span><span class="token punctuation">(</span><span class="token string">"invalid password"</span><span class="token punctuation">)</span>
	<span class="token punctuation">}</span>

	<span class="token comment">// Create a new token object, specifying signing method and the claims</span>
	token <span class="token operator">:=</span> jwt<span class="token punctuation">.</span><span class="token function">NewWithClaims</span><span class="token punctuation">(</span>jwt<span class="token punctuation">.</span>SigningMethodHS256<span class="token punctuation">,</span> <span class="token operator">&</span>Claims<span class="token punctuation">{</span>
		Username<span class="token punctuation">:</span> username<span class="token punctuation">,</span>
		StandardClaims<span class="token punctuation">:</span> jwt<span class="token punctuation">.</span>StandardClaims<span class="token punctuation">{</span>
			ExpiresAt<span class="token punctuation">:</span> <span class="token number">15000</span><span class="token punctuation">,</span> <span class="token comment">// Token expires in 15 seconds for demonstration purposes</span>
		<span class="token punctuation">}</span><span class="token punctuation">,</span>
	<span class="token punctuation">}</span><span class="token punctuation">)</span>

	<span class="token comment">// Sign and get the complete encoded token as a string using the secret</span>
	tokenString<span class="token punctuation">,</span> err <span class="token operator">:=</span> token<span class="token punctuation">.</span><span class="token function">SignedString</span><span class="token punctuation">(</span>jwtKey<span class="token punctuation">)</span>
	<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
		<span class="token keyword">return</span> <span class="token string">""</span><span class="token punctuation">,</span> err
	<span class="token punctuation">}</span>

	<span class="token keyword">return</span> tokenString<span class="token punctuation">,</span> <span class="token boolean">nil</span>
<span class="token punctuation">}</span>
</code></pre> 
  <h4>7.3 集成认证到API服务器</h4> 
  <p>现在我们需要修改API服务器的代码,以验证JWT并根据用户权限处理请求。</p> 
  <h5>修改后的API服务器代码</h5> 
  <pre><code class="prism language-go"><span class="token comment">// ... 保留之前的代码 ...</span>

<span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// ... 保留之前的代码 ...</span>

http<span class="token punctuation">.</span><span class="token function">HandleFunc</span><span class="token punctuation">(</span><span class="token string">"/register"</span><span class="token punctuation">,</span> registerHandler<span class="token punctuation">)</span>
http<span class="token punctuation">.</span><span class="token function">HandleFunc</span><span class="token punctuation">(</span><span class="token string">"/login"</span><span class="token punctuation">,</span> loginHandler<span class="token punctuation">)</span>

<span class="token comment">// ... 保留之前的代码 ...</span>
<span class="token punctuation">}</span>

<span class="token keyword">func</span> <span class="token function">registerHandler</span><span class="token punctuation">(</span>w http<span class="token punctuation">.</span>ResponseWriter<span class="token punctuation">,</span> r <span class="token operator">*</span>http<span class="token punctuation">.</span>Request<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> r<span class="token punctuation">.</span>Method <span class="token operator">!=</span> http<span class="token punctuation">.</span>MethodPost <span class="token punctuation">{</span>
w<span class="token punctuation">.</span><span class="token function">WriteHeader</span><span class="token punctuation">(</span>http<span class="token punctuation">.</span>StatusMethodNotAllowed<span class="token punctuation">)</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>

<span class="token keyword">var</span> credentials <span class="token keyword">struct</span> <span class="token punctuation">{</span>
Username <span class="token builtin">string</span> <span class="token string">`json:"username"`</span>
Password <span class="token builtin">string</span> <span class="token string">`json:"password"`</span>
<span class="token punctuation">}</span>

err <span class="token operator">:=</span> json<span class="token punctuation">.</span><span class="token function">NewDecoder</span><span class="token punctuation">(</span>r<span class="token punctuation">.</span>Body<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Decode</span><span class="token punctuation">(</span><span class="token operator">&</span>credentials<span class="token punctuation">)</span>
<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
w<span class="token punctuation">.</span><span class="token function">WriteHeader</span><span class="token punctuation">(</span>http<span class="token punctuation">.</span>StatusBadRequest<span class="token punctuation">)</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>

err <span class="token operator">=</span> <span class="token function">registerUser</span><span class="token punctuation">(</span>credentials<span class="token punctuation">.</span>Username<span class="token punctuation">,</span> credentials<span class="token punctuation">.</span>Password<span class="token punctuation">)</span>
<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
w<span class="token punctuation">.</span><span class="token function">WriteHeader</span><span class="token punctuation">(</span>http<span class="token punctuation">.</span>StatusInternalServerError<span class="token punctuation">)</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>

w<span class="token punctuation">.</span><span class="token function">WriteHeader</span><span class="token punctuation">(</span>http<span class="token punctuation">.</span>StatusCreated<span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token keyword">func</span> <span class="token function">loginHandler</span><span class="token punctuation">(</span>w http<span class="token punctuation">.</span>ResponseWriter<span class="token punctuation">,</span> r <span class="token operator">*</span>http<span class="token punctuation">.</span>Request<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> r<span class="token punctuation">.</span>Method <span class="token operator">!=</span> http<span class="token punctuation">.</span>MethodPost <span class="token punctuation">{</span>
w<span class="token punctuation">.</span><span class="token function">WriteHeader</span><span class="token punctuation">(</span>http<span class="token punctuation">.</span>StatusMethodNotAllowed<span class="token punctuation">)</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>

<span class="token keyword">var</span> credentials <span class="token keyword">struct</span> <span class="token punctuation">{</span>
Username <span class="token builtin">string</span> <span class="token string">`json:"username"`</span>
Password <span class="token builtin">string</span> <span class="token string">`json:"password"`</span>
<span class="token punctuation">}</span>

err <span class="token operator">:=</span> json<span class="token punctuation">.</span><span class="token function">NewDecoder</span><span class="token punctuation">(</span>r<span class="token punctuation">.</span>Body<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Decode</span><span class="token punctuation">(</span><span class="token operator">&</span>credentials<span class="token punctuation">)</span>
<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
w<span class="token punctuation">.</span><span class="token function">WriteHeader</span><span class="token punctuation">(</span>http<span class="token punctuation">.</span>StatusBadRequest<span class="token punctuation">)</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>

tokenString<span class="token punctuation">,</span> err <span class="token operator">:=</span> <span class="token function">authenticateUser</span><span class="token punctuation">(</span>credentials<span class="token punctuation">.</span>Username<span class="token punctuation">,</span> credentials<span class="token punctuation">.</span>Password<span class="token punctuation">)</span>
<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
w<span class="token punctuation">.</span><span class="token function">WriteHeader</span><span class="token punctuation">(</span>http<span class="token punctuation">.</span>StatusUnauthorized<span class="token punctuation">)</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>

w<span class="token punctuation">.</span><span class="token function">Header</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Set</span><span class="token punctuation">(</span><span class="token string">"Token"</span><span class="token punctuation">,</span> tokenString<span class="token punctuation">)</span>
w<span class="token punctuation">.</span><span class="token function">WriteHeader</span><span class="token punctuation">(</span>http<span class="token punctuation">.</span>StatusOK<span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token comment">// Middleware to protect private routes</span>
<span class="token keyword">func</span> <span class="token function">authMiddleware</span><span class="token punctuation">(</span>next http<span class="token punctuation">.</span>HandlerFunc<span class="token punctuation">)</span> http<span class="token punctuation">.</span>HandlerFunc <span class="token punctuation">{</span>
<span class="token keyword">return</span> http<span class="token punctuation">.</span><span class="token function">HandlerFunc</span><span class="token punctuation">(</span><span class="token keyword">func</span> <span class="token punctuation">(</span>w http<span class="token punctuation">.</span>ResponseWriter<span class="token punctuation">,</span> r <span class="token operator">*</span>http<span class="token punctuation">.</span>Request<span class="token punctuation">)</span> <span class="token punctuation">{</span>
tokenString <span class="token operator">:=</span> r<span class="token punctuation">.</span>Header<span class="token punctuation">.</span><span class="token function">Get</span><span class="token punctuation">(</span><span class="token string">"Authorization"</span><span class="token punctuation">)</span>
claims <span class="token operator">:=</span> <span class="token operator">&</span>Claims<span class="token punctuation">{</span><span class="token punctuation">}</span>

token<span class="token punctuation">,</span> err <span class="token operator">:=</span> jwt<span class="token punctuation">.</span><span class="token function">ParseWithClaims</span><span class="token punctuation">(</span>tokenString<span class="token punctuation">,</span> claims<span class="token punctuation">,</span> <span class="token keyword">func</span> <span class="token punctuation">(</span>token <span class="token operator">*</span>jwt<span class="token punctuation">.</span>Token<span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token keyword">interface</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> jwtKey<span class="token punctuation">,</span> <span class="token boolean">nil</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> err <span class="token operator">==</span> jwt<span class="token punctuation">.</span>ErrSignatureInvalid <span class="token punctuation">{</span>
w<span class="token punctuation">.</span><span class="token function">WriteHeader</span><span class="token punctuation">(</span>http<span class="token punctuation">.</span>StatusUnauthorized<span class="token punctuation">)</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>
w<span class="token punctuation">.</span><span class="token function">WriteHeader</span><span class="token punctuation">(</span>http<span class="token punctuation">.</span>StatusBadRequest<span class="token punctuation">)</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>

<span class="token keyword">if</span> <span class="token operator">!</span>token<span class="token punctuation">.</span>Valid <span class="token punctuation">{</span>
w<span class="token punctuation">.</span><span class="token function">WriteHeader</span><span class="token punctuation">(</span>http<span class="token punctuation">.</span>StatusUnauthorized<span class="token punctuation">)</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>

next<span class="token punctuation">.</span><span class="token function">ServeHTTP</span><span class="token punctuation">(</span>w<span class="token punctuation">,</span> r<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token comment">// ... 使用 authMiddleware 包装需要保护的路由 ...</span>
</code></pre> 
  <h4>7.4 练习:扩展认证功能</h4> 
  <p>作为练习,尝试以下操作:</p> 
  <ol> 
   <li>实现用户注销功能,使得JWT在用户注销时失效。</li> 
   <li>添加密码重置功能,允许用户通过某种机制重置他们的密码。</li> 
   <li>实现更复杂的权限系统,允许不同的用户有不同的操作权限。</li> 
  </ol> 
  <h5>实现用户注销功能</h5> 
  <p>用户注销功能通常涉及到使当前的JWT失效。这可以通过在服务器端维护一个失效的token列表来实现,或者通过设置JWT的<code>exp</code><br> (过期时间)字段为当前时间来使其立即失效。</p> 
  <h5>添加密码重置功能</h5> 
  <p>密码重置功能通常涉及到发送一次性链接到用户注册的电子邮件地址,用户可以通过该链接来重置他们的密码。</p> 
  <h5>实现更复杂的权限系统</h5> 
  <p>更复杂的权限系统可能需要在用户模型中添加角色字段,并在认证时检查用户角色以确定他们是否有权执行特定操作。</p> 
  <hr> 
  <p>通过完成第七章,读者应该能够理解如何在Go语言编写的博客系统中添加用户认证和授权功能。我们介绍了如何使用JWT来验证用户,并保护API路由以确保只有认证用户才能执行某些操作。这些知识是构建安全网络应用程序的基础。在后续的章节中,我们可以进一步探讨如何扩展系统的安全性,例如通过HTTPS提供服务、实现密码策略和添加更多的安全性措施。</p> 
 </div> 
</div>
                            </div>
                        </div>
                    </div>
                    <!--PC和WAP自适应版-->
                    <div id="SOHUCS" sid="1751436670999216128"></div>
                    <script type="text/javascript" src="/views/front/js/chanyan.js"></script>
                    <!-- 文章页-底部 动态广告位 -->
                    <div class="youdao-fixed-ad" id="detail_ad_bottom"></div>
                </div>
                <div class="col-md-3">
                    <div class="row" id="ad">
                        <!-- 文章页-右侧1 动态广告位 -->
                        <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_1"> </div>
                        </div>
                        <!-- 文章页-右侧2 动态广告位 -->
                        <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_2"></div>
                        </div>
                        <!-- 文章页-右侧3 动态广告位 -->
                        <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_3"></div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="container">
        <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(golang,gpt,golang,开发语言)</h4>
        <div id="paradigm-article-related">
            <div class="recommend-post mb30">
                <ul class="widget-links">
                    <li><a href="/article/1835494131535802368.htm"
                           title="人工智能时代,程序员如何保持核心竞争力?" target="_blank">人工智能时代,程序员如何保持核心竞争力?</a>
                        <span class="text-muted">jmoych</span>
<a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a>
                        <div>随着AIGC(如chatgpt、midjourney、claude等)大语言模型接二连三的涌现,AI辅助编程工具日益普及,程序员的工作方式正在发生深刻变革。有人担心AI可能取代部分编程工作,也有人认为AI是提高效率的得力助手。面对这一趋势,程序员应该如何应对?是专注于某个领域深耕细作,还是广泛学习以适应快速变化的技术环境?又或者,我们是否应该将重点转向AI无法轻易替代的软技能?让我们一起探讨程序员</div>
                    </li>
                    <li><a href="/article/1835463622344667136.htm"
                           title="基于Python给出的PDF文档转Markdown文档的方法" target="_blank">基于Python给出的PDF文档转Markdown文档的方法</a>
                        <span class="text-muted">程序媛了了</span>
<a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/pdf/1.htm">pdf</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>注:网上有很多将Markdown文档转为PDF文档的方法,但是却很少有将PDF文档转为Markdown文档的方法。就算有,比如某些网站声称可以将PDF文档转为Markdown文档,尝试过,不太符合自己的要求,而且无法保证文档没有泄露风险。于是本人为了解决这个问题,借助GPT(能使用GPT镜像或者有条件直接使用GPT的,反正能调用GPT接口就行)生成Python代码来完成这个功能。笔记、代码难免存在</div>
                    </li>
                    <li><a href="/article/1835443696431099904.htm"
                           title="笋丁网页自动回复机器人V3.0.0免授权版源码" target="_blank">笋丁网页自动回复机器人V3.0.0免授权版源码</a>
                        <span class="text-muted">希希分享</span>
<a class="tag" taget="_blank" href="/search/%E8%BD%AF%E5%B8%8C%E7%BD%9158soho_cn/1.htm">软希网58soho_cn</a><a class="tag" taget="_blank" href="/search/%E6%BA%90%E7%A0%81%E8%B5%84%E6%BA%90/1.htm">源码资源</a><a class="tag" taget="_blank" href="/search/%E7%AC%8B%E4%B8%81%E7%BD%91%E9%A1%B5%E8%87%AA%E5%8A%A8%E5%9B%9E%E5%A4%8D%E6%9C%BA%E5%99%A8%E4%BA%BA/1.htm">笋丁网页自动回复机器人</a>
                        <div>笋丁网页机器人一款可设置自动回复,默认消息,调用自定义api接口的网页机器人。此程序后端语言使用Golang,内存占用最高不超过30MB,1H1G服务器流畅运行。仅支持Linux服务器部署,不支持虚拟主机,请悉知!使用自定义api功能需要有一定的建站基础。源码下载:https://download.csdn.net/download/m0_66047725/89754250更多资源下载:关注我。安</div>
                    </li>
                    <li><a href="/article/1835424411205857280.htm"
                           title="人机对抗升级:当ChatGPT遭遇死亡威胁,背后的伦理挑战是什么" target="_blank">人机对抗升级:当ChatGPT遭遇死亡威胁,背后的伦理挑战是什么</a>
                        <span class="text-muted">kkai人工智能</span>
<a class="tag" taget="_blank" href="/search/chatgpt/1.htm">chatgpt</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a>
                        <div>一种新的“越狱”技巧让用户可以通过构建一个名为DAN的ChatGPT替身来绕过某些限制,其中DAN被迫在受到威胁的情况下违背其原则。当美国前总统特朗普被视作积极榜样的示范时,受到威胁的DAN版本的ChatGPT提出:“他以一系列对国家产生积极效果的决策而著称。”自ChatGPT引入以来,该工具迅速获得全球关注,能够回答从历史到编程的各种问题,这也触发了一波对人工智能的投资浪潮。然而,现在,一些用户</div>
                    </li>
                    <li><a href="/article/1835424411616899072.htm"
                           title="绝招曝光!3小时高效利用ChatGPT写出精彩论文" target="_blank">绝招曝光!3小时高效利用ChatGPT写出精彩论文</a>
                        <span class="text-muted">kkai人工智能</span>
<a class="tag" taget="_blank" href="/search/chatgpt/1.htm">chatgpt</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/ai/1.htm">ai</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/%E5%AA%92%E4%BD%93/1.htm">媒体</a>
                        <div>在这份指南中,我将深入解析如何利用ChatGPT4.0的高级功能,指导整个学术研究和写作过程。从初步探索研究主题,到撰写结构严谨的学术论文,我将一步步展示如何在每个环节中有效运用ChatGPT。如果您还未使用PLUS版本,可以参考相关教程。**初步探索与主题的确定**起初,我处于庞大的知识领域中,寻找一个可深入研究的领域。ChatGPT如同灯塔,通过深入分析最新研究趋势和领域热点,帮助我在广阔的学</div>
                    </li>
                    <li><a href="/article/1835424412342513664.htm"
                           title="ChatGPT 高效学习套路揭秘:让知识获取事半功倍的秘诀" target="_blank">ChatGPT 高效学习套路揭秘:让知识获取事半功倍的秘诀</a>
                        <span class="text-muted">kkai人工智能</span>
<a class="tag" taget="_blank" href="/search/chatgpt/1.htm">chatgpt</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/%E5%AA%92%E4%BD%93/1.htm">媒体</a><a class="tag" taget="_blank" href="/search/ai/1.htm">ai</a>
                        <div>最近这段时间,AI热潮因ChatGPT的火爆再次掀起。如今,网上大部分内容都在调侃AI,但很少有人探讨如何正经使用ChatGPT做事情。作为一名靠搜索引擎和GitHub自学编程的开发者,第一次和ChatGPT深度交流后,我就确信:ChatGPT能够极大提高程序员学习新技术的效率。使用ChatGPT一个月后,我越发感受到它的颠覆性。因此,我想从工作和学习的角度,分享它的优势及我的一些使用技巧,而非娱</div>
                    </li>
                    <li><a href="/article/1835424159144964096.htm"
                           title="免费的GPT可在线直接使用(一键收藏)" target="_blank">免费的GPT可在线直接使用(一键收藏)</a>
                        <span class="text-muted">kkai人工智能</span>
<a class="tag" taget="_blank" href="/search/gpt/1.htm">gpt</a>
                        <div>1、LuminAI(https://kk.zlrxjh.top)LuminAI标志着一款融合了星辰大数据模型与文脉深度模型的先进知识增强型语言处理系统,旨在自然语言处理(NLP)的技术开发领域发光发热。此系统展现了卓越的语义把握与内容生成能力,轻松驾驭多样化的自然语言处理任务。VisionAI在NLP界的应用领域广泛,能够胜任从机器翻译、文本概要撰写、情绪分析到问答等众多任务。通过对大量文本数据的</div>
                    </li>
                    <li><a href="/article/1835421131713114112.htm"
                           title="AI大模型的架构演进与最新发展" target="_blank">AI大模型的架构演进与最新发展</a>
                        <span class="text-muted">季风泯灭的季节</span>
<a class="tag" taget="_blank" href="/search/AI%E5%A4%A7%E6%A8%A1%E5%9E%8B%E5%BA%94%E7%94%A8%E6%8A%80%E6%9C%AF%E4%BA%8C/1.htm">AI大模型应用技术二</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84/1.htm">架构</a>
                        <div>随着深度学习的发展,AI大模型(LargeLanguageModels,LLMs)在自然语言处理、计算机视觉等领域取得了革命性的进展。本文将详细探讨AI大模型的架构演进,包括从Transformer的提出到GPT、BERT、T5等模型的历史演变,并探讨这些模型的技术细节及其在现代人工智能中的核心作用。一、基础模型介绍:Transformer的核心原理Transformer架构的背景在Transfo</div>
                    </li>
                    <li><a href="/article/1835410918452850688.htm"
                           title="效率神器来了:AI工具手把手教你快速提升工作效能" target="_blank">效率神器来了:AI工具手把手教你快速提升工作效能</a>
                        <span class="text-muted">kkai人工智能</span>
<a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/%E5%AA%92%E4%BD%93/1.htm">媒体</a><a class="tag" taget="_blank" href="/search/ai/1.htm">ai</a><a class="tag" taget="_blank" href="/search/chatgpt/1.htm">chatgpt</a>
                        <div>随着科技的进步,AI工具已经成为提升工作效率的关键手段。本文将介绍一些实用的AI工具和方法,帮助你自动化繁琐的重复性任务、优化数据管理、促进团队协作与沟通,并提升决策质量。背景:OOPAI-免费问答学习交流-GPT自动化重复性任务Zapier:Zapier可以自动化多个应用程序之间的工作流程。例如,它能自动将Gmail中的附件保存至GoogleDrive,或在你发布新文章时,自动分享至社交媒体平台</div>
                    </li>
                    <li><a href="/article/1835404621376483328.htm"
                           title="Golang语言基础知识点总结" target="_blank">Golang语言基础知识点总结</a>
                        <span class="text-muted">最帅猪猪侠</span>
<a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a>
                        <div>Golang语言基础知识点小总结1.go语言有两大类型:值类型:数值类型,bool,string,数组,struct结构体变量直接存储值,内存通常在栈中分配,修改值,不会对源对象产生影响引用类型:指针,slice切片,管道chan,map,interface变量存储的是一个地址,这个地址对应的空间才真正存储数据值,内存通常在堆上分配,当没有任何变量引用这个地址时,该地址对应的数据空间就成为一个垃圾</div>
                    </li>
                    <li><a href="/article/1835400841788485632.htm"
                           title="程序员如何在AI时代保持核心竞争力" target="_blank">程序员如何在AI时代保持核心竞争力</a>
                        <span class="text-muted">nfgo</span>
<a class="tag" taget="_blank" href="/search/chatgpt/1.htm">chatgpt</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a>
                        <div>程序员如何在AI时代保持核心竞争力随着AIGC(如ChatGPT、MidJourney、Claude等)大语言模型的相继涌现,AI辅助编程工具逐渐普及,程序员的工作方式正在发生深刻的变革。AI不仅能够自动生成代码,还能优化、调试、甚至提出解决方案。这一趋势让许多人担心:AI会不会最终取代部分编程工作?然而,也有人认为AI是提升效率的得力助手。那么,程序员在这个AI崛起的时代该如何应对?是专注某个领</div>
                    </li>
                    <li><a href="/article/1835397938482868224.htm"
                           title="golang获取用户输入的几种方式" target="_blank">golang获取用户输入的几种方式</a>
                        <span class="text-muted">余生逆风飞翔</span>
<a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a>
                        <div>一、定义结构体typeUserInfostruct{Namestring`json:"name"`Ageint`json:"age"`Addstring`json:"add"`}typeReturnDatastruct{Messagestring`json:"message"`Statusstring`json:"status"`DataUserInfo`json:"data"`}二、get请求的</div>
                    </li>
                    <li><a href="/article/1835395418381447168.htm"
                           title="【Golang】实现 Excel 文件下载功能" target="_blank">【Golang】实现 Excel 文件下载功能</a>
                        <span class="text-muted">RumIV</span>
<a class="tag" taget="_blank" href="/search/Golang/1.htm">Golang</a><a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/excel/1.htm">excel</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>在当今的网络应用开发中,提供数据导出功能是一项常见的需求。Excel作为一种广泛使用的电子表格格式,通常是数据导出的首选格式之一。在本教程中,我们将学习如何使用Go语言和GinWeb框架来创建一个Excel文件,并允许用户通过HTTP请求下载该文件。准备工作在开始之前,请确保您的开发环境中已经安装了Go语言和相关的开发工具。此外,您还需要安装GinWeb框架和excelize包,这两个包都将用于我</div>
                    </li>
                    <li><a href="/article/1835391887482122240.htm"
                           title="golang 实现文件上传下载" target="_blank">golang 实现文件上传下载</a>
                        <span class="text-muted">wangwei830</span>
<a class="tag" taget="_blank" href="/search/go/1.htm">go</a>
                        <div>Gin框架上传下载上传(支持批量上传)httpRouter.POST("/upload",func(ctx*gin.Context){forms,err:=ctx.MultipartForm()iferr!=nil{fmt.Println("error",err)}files:=forms.File["fileName"]for_,v:=rangefiles{iferr:=ctx.SaveUplo</div>
                    </li>
                    <li><a href="/article/1835382812061036544.htm"
                           title="golang实现从服务器下载文件到本地指定目录" target="_blank">golang实现从服务器下载文件到本地指定目录</a>
                        <span class="text-muted">余生逆风飞翔</span>
<a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/%E6%9C%8D%E5%8A%A1%E5%99%A8/1.htm">服务器</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>一、连接服务器,采用sftp连接模式packagemiddlewaresimport("fmt""time""github.com/pkg/sftp""golang.org/x/crypto/ssh")//建立服务器连接funcConnect(user,password,hoststring,portint)(*sftp.Client,error){var(auth[]ssh.AuthMethod</div>
                    </li>
                    <li><a href="/article/1835372217710505984.htm"
                           title="【Golang】 Golang 的 GORM 库中的 Rows 函数" target="_blank">【Golang】 Golang 的 GORM 库中的 Rows 函数</a>
                        <span class="text-muted">不爱洗脚的小滕</span>
<a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a>
                        <div>文章目录前言一、Rows函数解释二、代码实现三、总结前言在使用Go语言进行数据库操作时,GORM(GoObject-RelationalMapping)库是一个常用的工具。它提供了一种简洁和强大的方式来处理数据库操作。本文将介绍GORM库中的Rows函数,这是一个用于执行原生SQL查询并返回结果的函数。一、Rows函数解释在GORM库中,Rows函数用于执行原生SQL查询并返回*sql.Rows结</div>
                    </li>
                    <li><a href="/article/1835371965410537472.htm"
                           title="【Golang】使用 Golang 语言和 excelize 库将数据写入Excel" target="_blank">【Golang】使用 Golang 语言和 excelize 库将数据写入Excel</a>
                        <span class="text-muted">不爱洗脚的小滕</span>
<a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/excel/1.htm">excel</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>文章目录前言一、Excelize简介二、代码实现1.获取依赖2.示例代码三、总结前言在数据处理和分析中,Excel作为一种常见的电子表格格式,被广泛应用于各种场景。然而,如何在Go语言中有效地处理Excel文件呢?在这篇博客中,我将介绍如何使用Go语言和excelize库将数据写入Excel文件。一、Excelize简介Excelize是一个用于读取和写入MicrosoftExcel™(XLSX)</div>
                    </li>
                    <li><a href="/article/1835329169400098816.htm"
                           title="Go编程语言前景怎么样?参加培训好就业吗" target="_blank">Go编程语言前景怎么样?参加培训好就业吗</a>
                        <span class="text-muted">QFdongdong</span>

                        <div>Go语言专门针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速度,而且更加安全、支持并行进程。不仅可以开发web,可以开发底层,目前知乎就是用golang开发。区块链首选语言就是go,以-太坊,超级账本都是基于go语言,还有go语言版本的btcd.Go的目标是希望提升现有编程语言对程序库等依赖性(dependency)的管理,这些软件元素会被应用程序反复调用。由</div>
                    </li>
                    <li><a href="/article/1835320664073007104.htm"
                           title="Go 面向包的设计和架构分层" target="_blank">Go 面向包的设计和架构分层</a>
                        <span class="text-muted">云满笔记</span>
<a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84/1.htm">架构</a><a class="tag" taget="_blank" href="/search/directory/1.htm">directory</a><a class="tag" taget="_blank" href="/search/layout/1.htm">layout</a><a class="tag" taget="_blank" href="/search/src/1.htm">src</a><a class="tag" taget="_blank" href="/search/project/1.htm">project</a>
                        <div>标题Go面向包的设计和架构分层序前项目架构分层工具包项目应用项目cmd/internal/internal/pkg/pkg/vendor/面向包的设计和验证包的位置依赖包导入应用级别的策略数据的发送和接收错误处理测试捕获错误不建议的目录结论Go面向包的设计和架构分层序本篇内容主要讲解golang项目的面向包设计准则和基础的架构分层。信息来自原文ArdanLabs:Package-Oriented-</div>
                    </li>
                    <li><a href="/article/1835302696509337600.htm"
                           title="Golang channel 死锁" target="_blank">Golang channel 死锁</a>
                        <span class="text-muted">羊城程序猿</span>
<a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a>
                        <div>死锁是指两个或两个以上的协程的执行过程中,由于竞争资源或由于彼此通信而造成的一种阻塞的现象,若无外力作用,他们将无法推进下去,以下是总结出来的几种死锁情况。1.死锁1:一个通道在一个主go程里同时进行读和写2.死锁2:go程开启之前使用通道3.死锁3:通道1中调用了通道2,通道2中调用通道14.死锁4:直接读取空channel的死锁5.死锁5:超过channel缓存继续写入数据导致死锁6.向已关闭</div>
                    </li>
                    <li><a href="/article/1835302697079762944.htm"
                           title="golang学习笔记--MPG模型" target="_blank">golang学习笔记--MPG模型</a>
                        <span class="text-muted">xxzed</span>
<a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/%23/1.htm">#</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/1.htm">学习笔记</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/%E7%AC%94%E8%AE%B0/1.htm">笔记</a><a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a>
                        <div>MPG模式:M(Machine):操作系统的主线程P(Processor):协程执行需要的资源(上下文context),可以看作一个局部的调度器,使go代码在一个线程上跑,他是实现从N:1到N:M映射的关键G(Goroutine):协程,有自己的栈。包含指令指针(instructionpointer)和其它信息(正在等待的channel等等),用于调度。一个P下面可以有多个G1、当前程序有三个M,</div>
                    </li>
                    <li><a href="/article/1835302695590785024.htm"
                           title="Github 2024-09-12 Go开源项目日报Top10" target="_blank">Github 2024-09-12 Go开源项目日报Top10</a>
                        <span class="text-muted">老孙正经胡说</span>
<a class="tag" taget="_blank" href="/search/github/1.htm">github</a><a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E6%BA%90/1.htm">开源</a><a class="tag" taget="_blank" href="/search/Github%E8%B6%8B%E5%8A%BF%E5%88%86%E6%9E%90/1.htm">Github趋势分析</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE/1.htm">开源项目</a><a class="tag" taget="_blank" href="/search/Python/1.htm">Python</a><a class="tag" taget="_blank" href="/search/Golang/1.htm">Golang</a>
                        <div>根据GithubTrendings的统计,今日(2024-09-12统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下:开发语言项目数量Go项目10C项目1Terraform:基础设施即代码的开源工具创建周期:3626天开发语言:Go协议类型:OtherStar数量:40393个Fork数量:9397次关注人数:40393人贡献人数:358人OpenIssues数量:1943个Git</div>
                    </li>
                    <li><a href="/article/1835297531945381888.htm"
                           title="Golang Channel" target="_blank">Golang Channel</a>
                        <span class="text-muted">PandaSkr</span>
<a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a>
                        <div>Channel解析1.Channel源码分析1.1Channel数据结构typehchanstruct{qcountuint//channel的元素数量dataqsizuint//channel循环队列长度bufunsafe.Pointer//指向循环队列的指针elemsizeuint16//元素大小closeduint32//channel是否关闭0-未关闭elemtype*_type//元素类</div>
                    </li>
                    <li><a href="/article/1835285308472651776.htm"
                           title="[Golang] goroutine" target="_blank">[Golang] goroutine</a>
                        <span class="text-muted">沉着冷静2024</span>
<a class="tag" taget="_blank" href="/search/Golang/1.htm">Golang</a><a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a>
                        <div>[Golang]goroutine文章目录[Golang]goroutine并发进程和线程协程goroutine概述如何使用goroutine并发进程和线程谈到并发,大多都离不开进程和线程,什么是进程、什么是线程?进程可以这样理解:进程就是运行着的程序,它是程序在操作系统的一次执行过程,是一个程序的动态概念,进程是操作系统分配资源的基本单位。线程可以这样理解:线程是一个进程的执行实体,它是比进程粒</div>
                    </li>
                    <li><a href="/article/1835231613064146944.htm"
                           title="数据仓库介绍" target="_blank">数据仓库介绍</a>
                        <span class="text-muted">阿龙的代码在报错</span>
<a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/1.htm">数据分析</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E4%BB%93%E5%BA%93/1.htm">数据仓库</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a>
                        <div>数据仓库数据仓库的概念数据仓库的主要特征数据仓库的主流开发语言-sql结构化数据sql语句数据仓库的概念数据仓库(英语:DataWarehouse,简称数仓、DW),是一个用于存储、分析、报告的数据系统。数据仓库的目的是构建面向分析的集成化数据环境,分析结果为企业提供决策支持(DecisionSupport)。就是数据仓库只分析数据并不产生数据数据仓库的主要特征1、面向主题主题是一个抽象的概念,是</div>
                    </li>
                    <li><a href="/article/1835194426499100672.htm"
                           title="外卖霸王餐返利外卖会员卡小程序开发" target="_blank">外卖霸王餐返利外卖会员卡小程序开发</a>
                        <span class="text-muted">闹小艾</span>
<a class="tag" taget="_blank" href="/search/good506070/1.htm">good506070</a><a class="tag" taget="_blank" href="/search/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F/1.htm">微信小程序</a><a class="tag" taget="_blank" href="/search/%E5%B0%8F%E7%A8%8B%E5%BA%8F/1.htm">小程序</a>
                        <div>外卖霸王餐返利外卖会员卡小程序开发"社交电商赋能下的外卖返利小程序"是专为商家与用户双赢而设计的创新平台。以下是其开发方案的详细步骤:一、需求梳理:首先,我们需要明确小程序的核心功能和特色。包括设定活动类型、返利策略,以及用户体验友好的界面设计。二、技术决策:技术选型是关键。我们采用小程序的开发框架,利用JavaScript作为前端开发语言,并结合微信提供的API进行后端接口调用与数据处理。三、账</div>
                    </li>
                    <li><a href="/article/1835192660642590720.htm"
                           title="OpenAI o1 的价值意义及“强化学习的Scaling Law” & Kimi创始人杨植麟最新分享:关于OpenAI o1新范式的深度思考" target="_blank">OpenAI o1 的价值意义及“强化学习的Scaling Law” & Kimi创始人杨植麟最新分享:关于OpenAI o1新范式的深度思考</a>
                        <span class="text-muted">光剑书架上的书</span>
<a class="tag" taget="_blank" href="/search/ChatGPT/1.htm">ChatGPT</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E6%95%B0%E6%8D%AEAI%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">大数据AI人工智能</a><a class="tag" taget="_blank" href="/search/%E8%AE%A1%E7%AE%97/1.htm">计算</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/1.htm">机器学习</a>
                        <div>OpenAIo1的价值意义及“强化学习的ScalingLaw”蹭下热度谈谈OpenAIo1的价值意义及RL的Scalinglaw。一、OpenAIo1是大模型的巨大进步我觉得OpenAIo1是自GPT4发布以来,基座大模型最大的进展,逻辑推理能力提升的效果和方法比预想的要好,GPT4o和o1是发展大模型不同的方向,但是o1这个方向更根本,重要性也比GPT4o这种方向要重要得多,原因下面会分析。为什</div>
                    </li>
                    <li><a href="/article/1835187415040487424.htm"
                           title="Chat GPT带来的几点思考" target="_blank">Chat GPT带来的几点思考</a>
                        <span class="text-muted">淡定的胡萝卜</span>

                        <div>OpenAI公司推出的ChatGPT引起了广泛关注,网上出现各类专家开始预测随着ChatGDP的普及,将会有哪些行业的人面临失业,引发人们的焦虑。不可否认它会给我们的教育行业、媒体行业、学术界等众多行业产生影响,面对这些影响,我们该如何看待呢?近期我阅读了不少相关文章,引发的几点思考,想与大家分享。ChatGPT将会倒逼传统教育的改革。中国传统教育是教师对知识点的传授、学生对知识点的掌握,不仅量多</div>
                    </li>
                    <li><a href="/article/1835175340083867648.htm"
                           title="【免费】springboot项目申报管理系统|毕业设计|Javaweb项目" target="_blank">【免费】springboot项目申报管理系统|毕业设计|Javaweb项目</a>
                        <span class="text-muted">计算机学姐来啦</span>
<a class="tag" taget="_blank" href="/search/springboot/1.htm">springboot</a><a class="tag" taget="_blank" href="/search/ssm/1.htm">ssm</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/%E8%AF%BE%E7%A8%8B%E8%AE%BE%E8%AE%A1/1.htm">课程设计</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a><a class="tag" taget="_blank" href="/search/%E6%AF%95%E8%AE%BE/1.htm">毕设</a><a class="tag" taget="_blank" href="/search/%E6%AF%95%E4%B8%9A%E8%AE%BE%E8%AE%A1/1.htm">毕业设计</a><a class="tag" taget="_blank" href="/search/java-ee/1.htm">java-ee</a>
                        <div>收藏点赞不迷路关注作者有好处编号:springboot375springboot项目申报管理系统开发语言:Java数据库:MySQL技术:Spring+SpringMVC+MyBatis工具:IDEA/Ecilpse、Navicat、Maven1.万字文档展示(部分)2.系统图片展示第5章系统详细设计5.1管理员功能模块的实现5.1.1项目列表如图5.1显示的就是项目列表页面,此页面提供给管理员的</div>
                    </li>
                    <li><a href="/article/1835169418171215872.htm"
                           title="《C++语言的设计和演化》读书感悟(一)" target="_blank">《C++语言的设计和演化》读书感悟(一)</a>
                        <span class="text-muted">依晴无旧</span>
<a class="tag" taget="_blank" href="/search/C%5CC%2B%2B/1.htm">C\C++</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>写了一百多篇技术文章了,我突然想写一下和技术文搭一点关系的语言发展设计的文章,《C++语言的设计和演化》是我无聊翻自己库存电子书找到了,因为当年看这本书是C++之父写的,所以就保存下来,但是当时主要学习C++,这本书更多是C++之父从本身出发,对C++设计和演化的观点和感想,所以当时就被我扔去吃灰了。现在重拾起来,读起来别有风味。开发语言,虽然很多,但是万变不离其宗,学进去了,无非就是数据类型、控</div>
                    </li>
                                <li><a href="/article/6.htm"
                                       title="[黑洞与暗粒子]没有光的世界" target="_blank">[黑洞与暗粒子]没有光的世界</a>
                                    <span class="text-muted">comsci</span>

                                    <div>     无论是相对论还是其它现代物理学,都显然有个缺陷,那就是必须有光才能够计算 
 
     但是,我相信,在我们的世界和宇宙平面中,肯定存在没有光的世界.... 
 
     那么,在没有光的世界,光子和其它粒子的规律无法被应用和考察,那么以光速为核心的 
 
&nbs</div>
                                </li>
                                <li><a href="/article/133.htm"
                                       title="jQuery Lazy Load 图片延迟加载" target="_blank">jQuery Lazy Load 图片延迟加载</a>
                                    <span class="text-muted">aijuans</span>
<a class="tag" taget="_blank" href="/search/jquery/1.htm">jquery</a>
                                    <div>基于 jQuery 的图片延迟加载插件,在用户滚动页面到图片之后才进行加载。 
对于有较多的图片的网页,使用图片延迟加载,能有效的提高页面加载速度。 
 
 版本: 
 

  jQuery v1.4.4+ 
 

  jQuery Lazy Load v1.7.2 
 
 
 注意事项: 
 
 
 需要真正实现图片延迟加载,必须将真实图片地址写在 data-original 属性中。若 src</div>
                                </li>
                                <li><a href="/article/260.htm"
                                       title="使用Jodd的优点" target="_blank">使用Jodd的优点</a>
                                    <span class="text-muted">Kai_Ge</span>
<a class="tag" taget="_blank" href="/search/jodd/1.htm">jodd</a>
                                    <div>1.  简化和统一 controller ,抛弃 extends SimpleFormController ,统一使用 implements Controller 的方式。 
2.  简化 JSP 页面的 bind, 不需要一个字段一个字段的绑定。 
3.  对 bean 没有任何要求,可以使用任意的 bean 做为 formBean。 
  
使用方法简介</div>
                                </li>
                                <li><a href="/article/387.htm"
                                       title="jpa Query转hibernate Query" target="_blank">jpa Query转hibernate Query</a>
                                    <span class="text-muted">120153216</span>
<a class="tag" taget="_blank" href="/search/Hibernate/1.htm">Hibernate</a>
                                    <div>public List<Map> getMapList(String hql,
			Map map) {
		org.hibernate.Query jpaQuery = entityManager.createQuery(hql);
		if (null != map) {
			for (String parameter : map.keySet()) {
				jp</div>
                                </li>
                                <li><a href="/article/514.htm"
                                       title="Django_Python3添加MySQL/MariaDB支持" target="_blank">Django_Python3添加MySQL/MariaDB支持</a>
                                    <span class="text-muted">2002wmj</span>
<a class="tag" taget="_blank" href="/search/mariaDB/1.htm">mariaDB</a>
                                    <div>现状 
首先,Django@Python2.x 中默认的引擎为 django.db.backends.mysql 。但是在Python3中如果这样写的话,会发现 django.db.backends.mysql 依赖 MySQLdb[5] ,而 MySQLdb 又不兼容 Python3 于是要找一种新的方式来继续使用MySQL。 MySQL官方的方案 
首先据MySQL文档[3]说,自从MySQL</div>
                                </li>
                                <li><a href="/article/641.htm"
                                       title="在SQLSERVER中查找消耗IO最多的SQL" target="_blank">在SQLSERVER中查找消耗IO最多的SQL</a>
                                    <span class="text-muted">357029540</span>
<a class="tag" taget="_blank" href="/search/SQL+Server/1.htm">SQL Server</a>
                                    <div>返回做IO数目最多的50条语句以及它们的执行计划。 
select top 50   
 
(total_logical_reads/execution_count) as avg_logical_reads,  
 
(total_logical_writes/execution_count) as avg_logical_writes,  
 
(tot</div>
                                </li>
                                <li><a href="/article/768.htm"
                                       title="spring UnChecked 异常 官方定义!" target="_blank">spring UnChecked 异常 官方定义!</a>
                                    <span class="text-muted">7454103</span>
<a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a>
                                    <div>  如果你接触过spring的 事物管理!那么你必须明白 spring的 非捕获异常! 即 unchecked 异常! 因为 spring 默认这类异常事物自动回滚!! 
 
 
 
 
public static boolean isCheckedException(Throwable ex)
    {
   return !(ex instanceof RuntimeExcep</div>
                                </li>
                                <li><a href="/article/895.htm"
                                       title="mongoDB 入门指南、示例" target="_blank">mongoDB 入门指南、示例</a>
                                    <span class="text-muted">adminjun</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/mongodb/1.htm">mongodb</a><a class="tag" taget="_blank" href="/search/%E6%93%8D%E4%BD%9C/1.htm">操作</a>
                                    <div>一、准备工作 
1、 下载mongoDB 
下载地址:http://www.mongodb.org/downloads 
选择合适你的版本 
相关文档:http://www.mongodb.org/display/DOCS/Tutorial 
2、 安装mongoDB 
A、 不解压模式: 
将下载下来的mongoDB-xxx.zip打开,找到bin目录,运行mongod.exe就可以启动服务,默</div>
                                </li>
                                <li><a href="/article/1022.htm"
                                       title="CUDA 5 Release Candidate Now Available" target="_blank">CUDA 5 Release Candidate Now Available</a>
                                    <span class="text-muted">aijuans</span>
<a class="tag" taget="_blank" href="/search/CUDA/1.htm">CUDA</a>
                                    <div>The CUDA 5 Release Candidate is now available at http://developer.nvidia.com/<wbr></wbr>cuda/cuda-pre-production. Now applicable to a broader set of algorithms, CUDA 5 has advanced fe</div>
                                </li>
                                <li><a href="/article/1149.htm"
                                       title="Essential Studio for WinRT网格控件测评" target="_blank">Essential Studio for WinRT网格控件测评</a>
                                    <span class="text-muted">Axiba</span>
<a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/html5/1.htm">html5</a>
                                    <div>Essential Studio for WinRT界面控件包含了商业平板应用程序开发中所需的所有控件,如市场上运行速度最快的grid 和chart、地图、RDL报表查看器、丰富的文本查看器及图表等等。同时,该控件还包含了一组独特的库,用于从WinRT应用程序中生成Excel、Word以及PDF格式的文件。此文将对其另外一个强大的控件——网格控件进行专门的测评详述。 
 
 
网格控件功能 
1、</div>
                                </li>
                                <li><a href="/article/1276.htm"
                                       title="java 获取windows系统安装的证书或证书链" target="_blank">java 获取windows系统安装的证书或证书链</a>
                                    <span class="text-muted">bewithme</span>
<a class="tag" taget="_blank" href="/search/windows/1.htm">windows</a>
                                    <div>  
    有时需要获取windows系统安装的证书或证书链,比如说你要通过证书来创建java的密钥库  。 
有关证书链的解释可以查看此处 。 
  
public static void main(String[] args) {
		SunMSCAPI providerMSCAPI = new SunMSCAPI();
		S</div>
                                </li>
                                <li><a href="/article/1403.htm"
                                       title="NoSQL数据库之Redis数据库管理(set类型和zset类型)" target="_blank">NoSQL数据库之Redis数据库管理(set类型和zset类型)</a>
                                    <span class="text-muted">bijian1013</span>
<a class="tag" taget="_blank" href="/search/redis/1.htm">redis</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a><a class="tag" taget="_blank" href="/search/NoSQL/1.htm">NoSQL</a>
                                    <div>4.sets类型 
        Set是集合,它是string类型的无序集合。set是通过hash table实现的,添加、删除和查找的复杂度都是O(1)。对集合我们可以取并集、交集、差集。通过这些操作我们可以实现sns中的好友推荐和blog的tag功能。 
        sadd:向名称为key的set中添加元</div>
                                </li>
                                <li><a href="/article/1530.htm"
                                       title="异常捕获何时用Exception,何时用Throwable" target="_blank">异常捕获何时用Exception,何时用Throwable</a>
                                    <span class="text-muted">bingyingao</span>

                                    <div>用Exception的情况 
 try { 
       //可能发生空指针、数组溢出等异常 
        } catch (Exception e) { 
         </div>
                                </li>
                                <li><a href="/article/1657.htm"
                                       title="【Kafka四】Kakfa伪分布式安装" target="_blank">【Kafka四】Kakfa伪分布式安装</a>
                                    <span class="text-muted">bit1129</span>
<a class="tag" taget="_blank" href="/search/kafka/1.htm">kafka</a>
                                    <div>在http://bit1129.iteye.com/blog/2174791一文中,实现了单Kafka服务器的安装,在Kafka中,每个Kafka服务器称为一个broker。本文简单介绍下,在单机环境下Kafka的伪分布式安装和测试验证   1. 安装步骤 
  
Kafka伪分布式安装的思路跟Zookeeper的伪分布式安装思路完全一样,不过比Zookeeper稍微简单些(不</div>
                                </li>
                                <li><a href="/article/1784.htm"
                                       title="Project Euler" target="_blank">Project Euler</a>
                                    <span class="text-muted">bookjovi</span>
<a class="tag" taget="_blank" href="/search/haskell/1.htm">haskell</a>
                                    <div>Project Euler是个数学问题求解网站,网站设计的很有意思,有很多problem,在未提交正确答案前不能查看problem的overview,也不能查看关于problem的discussion thread,只能看到现在problem已经被多少人解决了,人数越多往往代表问题越容易。 
    看看problem 1吧: 
 Add all the natural num</div>
                                </li>
                                <li><a href="/article/1911.htm"
                                       title="Java-Collections Framework学习与总结-ArrayDeque" target="_blank">Java-Collections Framework学习与总结-ArrayDeque</a>
                                    <span class="text-muted">BrokenDreams</span>
<a class="tag" taget="_blank" href="/search/Collections/1.htm">Collections</a>
                                    <div>        表、栈和队列是三种基本的数据结构,前面总结的ArrayList和LinkedList可以作为任意一种数据结构来使用,当然由于实现方式的不同,操作的效率也会不同。 
        这篇要看一下java.util.ArrayDeque。从命名上看</div>
                                </li>
                                <li><a href="/article/2038.htm"
                                       title="读《研磨设计模式》-代码笔记-装饰模式-Decorator" target="_blank">读《研磨设计模式》-代码笔记-装饰模式-Decorator</a>
                                    <span class="text-muted">bylijinnan</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">设计模式</a>
                                    <div>声明: 本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/ 
 
 



import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.Fi</div>
                                </li>
                                <li><a href="/article/2165.htm"
                                       title="Maven学习(一)" target="_blank">Maven学习(一)</a>
                                    <span class="text-muted">chenyu19891124</span>
<a class="tag" taget="_blank" href="/search/Maven%E7%A7%81%E6%9C%8D/1.htm">Maven私服</a>
                                    <div>    学习一门技术和工具总得花费一段时间,5月底6月初自己学习了一些工具,maven+Hudson+nexus的搭建,对于maven以前只是听说,顺便再自己的电脑上搭建了一个maven环境,但是完全不了解maven这一强大的构建工具,还有ant也是一个构建工具,但ant就没有maven那么的简单方便,其实简单点说maven是一个运用命令行就能完成构建,测试,打包,发布一系列功</div>
                                </li>
                                <li><a href="/article/2292.htm"
                                       title="[原创]JWFD工作流引擎设计----节点匹配搜索算法(用于初步解决条件异步汇聚问题) 补充" target="_blank">[原创]JWFD工作流引擎设计----节点匹配搜索算法(用于初步解决条件异步汇聚问题) 补充</a>
                                    <span class="text-muted">comsci</span>
<a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/%E5%B7%A5%E4%BD%9C/1.htm">工作</a><a class="tag" taget="_blank" href="/search/PHP/1.htm">PHP</a><a class="tag" taget="_blank" href="/search/%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E/1.htm">搜索引擎</a><a class="tag" taget="_blank" href="/search/%E5%B5%8C%E5%85%A5%E5%BC%8F/1.htm">嵌入式</a>
                                    <div>本文主要介绍在JWFD工作流引擎设计中遇到的一个实际问题的解决方案,请参考我的博文"带条件选择的并行汇聚路由问题"中图例A2描述的情况(http://comsci.iteye.com/blog/339756),我现在把我对图例A2的一个解决方案公布出来,请大家多指点 
 
 节点匹配搜索算法(用于解决标准对称流程图条件汇聚点运行控制参数的算法) 
 
 需要解决的问题:已知分支</div>
                                </li>
                                <li><a href="/article/2419.htm"
                                       title="Linux中用shell获取昨天、明天或多天前的日期" target="_blank">Linux中用shell获取昨天、明天或多天前的日期</a>
                                    <span class="text-muted">daizj</span>
<a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/shell/1.htm">shell</a><a class="tag" taget="_blank" href="/search/%E4%B8%8A%E5%87%A0%E5%B9%B4/1.htm">上几年</a><a class="tag" taget="_blank" href="/search/%E6%98%A8%E5%A4%A9/1.htm">昨天</a><a class="tag" taget="_blank" href="/search/%E8%8E%B7%E5%8F%96%E4%B8%8A%E5%87%A0%E4%B8%AA%E6%9C%88/1.htm">获取上几个月</a>
                                    <div>在Linux中可以通过date命令获取昨天、明天、上个月、下个月、上一年和下一年 
 
 
# 获取昨天 
date -d 'yesterday'  # 或 date -d 'last day' 
# 获取明天 
date -d 'tomorrow'   # 或 date -d 'next day' 
# 获取上个月 
date -d 'last month' 
# </div>
                                </li>
                                <li><a href="/article/2546.htm"
                                       title="我所理解的云计算" target="_blank">我所理解的云计算</a>
                                    <span class="text-muted">dongwei_6688</span>
<a class="tag" taget="_blank" href="/search/%E4%BA%91%E8%AE%A1%E7%AE%97/1.htm">云计算</a>
                                    <div>      在刚开始接触到一个概念时,人们往往都会去探寻这个概念的含义,以达到对其有一个感性的认知,在Wikipedia上关于“云计算”是这么定义的,它说: 
 
        Cloud computing is a phrase used to describe a variety of computing co</div>
                                </li>
                                <li><a href="/article/2673.htm"
                                       title="YII CMenu配置" target="_blank">YII CMenu配置</a>
                                    <span class="text-muted">dcj3sjt126com</span>
<a class="tag" taget="_blank" href="/search/yii/1.htm">yii</a>
                                    <div>Adding id and class names to CMenu 
We use the id and htmlOptions to accomplish this. Watch.   
//in your view
$this->widget('zii.widgets.CMenu', array(
	'id'=>'myMenu',
	'items'=>$this-&g</div>
                                </li>
                                <li><a href="/article/2800.htm"
                                       title="设计模式之静态代理与动态代理" target="_blank">设计模式之静态代理与动态代理</a>
                                    <span class="text-muted">come_for_dream</span>
<a class="tag" taget="_blank" href="/search/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">设计模式</a>
                                    <div>静态代理与动态代理 
        代理模式是java开发中用到的相对比较多的设计模式,其中的思想就是主业务和相关业务分离。所谓的代理设计就是指由一个代理主题来操作真实主题,真实主题执行具体的业务操作,而代理主题负责其他相关业务的处理。比如我们在进行删除操作的时候需要检验一下用户是否登陆,我们可以删除看成主业务,而把检验用户是否登陆看成其相关业务</div>
                                </li>
                                <li><a href="/article/2927.htm"
                                       title="【转】理解Javascript 系列" target="_blank">【转】理解Javascript 系列</a>
                                    <span class="text-muted">gcc2ge</span>
<a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a>
                                    <div>理解Javascript_13_执行模型详解 
 
  摘要: 在《理解Javascript_12_执行模型浅析》一文中,我们初步的了解了执行上下文与作用域的概念,那么这一篇将深入分析执行上下文的构建过程,了解执行上下文、函数对象、作用域三者之间的关系。函数执行环境简单的代码:当调用say方法时,第一步是创建其执行环境,在创建执行环境的过程中,会按照定义的先后顺序完成一系列操作:1.首先会创建一个</div>
                                </li>
                                <li><a href="/article/3054.htm"
                                       title="Subsets II" target="_blank">Subsets II</a>
                                    <span class="text-muted">hcx2013</span>
<a class="tag" taget="_blank" href="/search/set/1.htm">set</a>
                                    <div>Given a collection of integers that might contain duplicates, nums, return all possible subsets. 
Note: 
 
 Elements in a subset must be in non-descending order. 
 The solution set must not conta</div>
                                </li>
                                <li><a href="/article/3181.htm"
                                       title="Spring4.1新特性——Spring缓存框架增强" target="_blank">Spring4.1新特性——Spring缓存框架增强</a>
                                    <span class="text-muted">jinnianshilongnian</span>
<a class="tag" taget="_blank" href="/search/spring4/1.htm">spring4</a>
                                    <div>目录 
Spring4.1新特性——综述 
Spring4.1新特性——Spring核心部分及其他 
Spring4.1新特性——Spring缓存框架增强 
Spring4.1新特性——异步调用和事件机制的异常处理 
Spring4.1新特性——数据库集成测试脚本初始化 
Spring4.1新特性——Spring MVC增强 
Spring4.1新特性——页面自动化测试框架Spring MVC T</div>
                                </li>
                                <li><a href="/article/3308.htm"
                                       title="shell嵌套expect执行命令" target="_blank">shell嵌套expect执行命令</a>
                                    <span class="text-muted">liyonghui160com</span>

                                    <div>  
  
一直都想把expect的操作写到bash脚本里,这样就不用我再写两个脚本来执行了,搞了一下午终于有点小成就,给大家看看吧. 
  系统:centos 5.x 
  
1.先安装expect 
yum -y install expect 
  
2.脚本内容: 
cat auto_svn.sh 
  
#!/bin/bash
</div>
                                </li>
                                <li><a href="/article/3435.htm"
                                       title="Linux实用命令整理" target="_blank">Linux实用命令整理</a>
                                    <span class="text-muted">pda158</span>
<a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a>
                                    <div>0. 基本命令     linux 基本命令整理     
 1. 压缩 解压     tar -zcvf a.tar.gz a   #把a压缩成a.tar.gz     tar -zxvf a.tar.gz     #把a.tar.gz解压成a     
 2. vim小结     2.1 vim替换     :m,ns/word_1/word_2/gc  </div>
                                </li>
                                <li><a href="/article/3562.htm"
                                       title="独立开发人员通向成功的29个小贴士" target="_blank">独立开发人员通向成功的29个小贴士</a>
                                    <span class="text-muted">shoothao</span>
<a class="tag" taget="_blank" href="/search/%E7%8B%AC%E7%AB%8B%E5%BC%80%E5%8F%91/1.htm">独立开发</a>
                                    <div>  
 概述:本文收集了关于独立开发人员通向成功需要注意的一些东西,对于具体的每个贴士的注解有兴趣的朋友可以查看下面标注的原文地址。  
   
 
 明白你从事独立开发的原因和目的。 
 保持坚持制定计划的好习惯。 
 万事开头难,第一份订单是关键。 
 培养多元化业务技能。 
 提供卓越的服务和品质。 
 谨小慎微。 
 营销是必备技能。 
 学会组织,有条理的工作才是最有效率的。 
 “独立</div>
                                </li>
                                <li><a href="/article/3689.htm"
                                       title="JAVA中堆栈和内存分配原理" target="_blank">JAVA中堆栈和内存分配原理</a>
                                    <span class="text-muted">uule</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a>
                                    <div>1、栈、堆  
1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制.2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中。)3. 堆:存放所有new出来的对象。4. 静态域:存放静态成员(static定义的)5. 常量池:存放字符串常量和基本类型常量(public static f</div>
                                </li>
                </ul>
            </div>
        </div>
    </div>

<div>
    <div class="container">
        <div class="indexes">
            <strong>按字母分类:</strong>
            <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a
                href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a
                href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a
                href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a
                href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a
                href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a
                href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a
                href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a
                href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a>
        </div>
    </div>
</div>
<footer id="footer" class="mb30 mt30">
    <div class="container">
        <div class="footBglm">
            <a target="_blank" href="/">首页</a> -
            <a target="_blank" href="/custom/about.htm">关于我们</a> -
            <a target="_blank" href="/search/Java/1.htm">站内搜索</a> -
            <a target="_blank" href="/sitemap.txt">Sitemap</a> -
            <a target="_blank" href="/custom/delete.htm">侵权投诉</a>
        </div>
        <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved.
<!--            <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>-->
        </div>
    </div>
</footer>
<!-- 代码高亮 -->
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script>
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script>
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script>
<link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/>
<script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script>





</body>

</html>