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/1887384731046178816.htm"
                           title="大模型Dense、MoE 与 Hybrid-MoE 架构的比较" target="_blank">大模型Dense、MoE 与 Hybrid-MoE 架构的比较</a>
                        <span class="text-muted">灵机️</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/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/1.htm">深度学习</a><a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84/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>
                        <div>在大模型架构设计中,Dense(全连接)、MoE(混合专家)和Hybrid-MoE(混合式MoE)是三种主流的参数组织方式,它们在模型容量、计算效率和应用场景上存在显著差异。以下从核心原理、技术特点、优缺点及适用场景进行系统对比:1.核心原理对比架构类型核心思想典型模型Dense所有参数对所有输入生效,每层神经元全连接,统一处理所有输入特征。GPT-3、BERT、LLAMAMoE将模型划分为多个“</div>
                    </li>
                    <li><a href="/article/1887374650741157888.htm"
                           title="chatgpt赋能python:Win7怎么安装Python?" target="_blank">chatgpt赋能python:Win7怎么安装Python?</a>
                        <span class="text-muted">u012804784</span>
<a class="tag" taget="_blank" href="/search/ChatGpt/1.htm">ChatGpt</a><a class="tag" taget="_blank" href="/search/chatgpt/1.htm">chatgpt</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</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/%E8%AE%A1%E7%AE%97%E6%9C%BA/1.htm">计算机</a>
                        <div>Win7怎么安装Python?如果你正在使用Windows7操作系统,想要安装Python,那么你来对了地方。Python是一种利用广泛的编程语言,可用于开发Web应用程序、数据分析和科学计算、机器学习等各种领域。在此篇文章中,我们会提供一些简单易懂的步骤,以帮助初学者在Win7系统上安装Python。步骤1:下载Python首先,你需要从Python官方网站下载Python的安装程序。在网站的下</div>
                    </li>
                    <li><a href="/article/1887334301339545600.htm"
                           title="在 Python 中生成一个简单的类 GPT 软件?" target="_blank">在 Python 中生成一个简单的类 GPT 软件?</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/%23/1.htm">#</a><a class="tag" taget="_blank" href="/search/%E8%87%AA%E7%84%B6%E8%AF%AD%E8%A8%80%E5%A4%84%E7%90%86/1.htm">自然语言处理</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/gpt/1.htm">gpt</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>一、引言近年来,大型语言模型如GPT展现出了强大的自然语言处理能力,在对话、文本生成、知识问答等多个领域有着广泛的应用。在Python中,我们可以借助现有的开源资源和工具,构建一个简单的类GPT软件。本文将详细介绍实现这一目标的具体步骤,涵盖环境搭建、数据准备、模型选择、训练与推理等多个方面。二、环境搭建2.1安装Python首先要确保系统中安装了Python。建议使用Python3.7及以上版本</div>
                    </li>
                    <li><a href="/article/1887334049157017600.htm"
                           title="OpenAI宣布ChatGPT集成到苹果操作系统,将带来哪些新功能?" target="_blank">OpenAI宣布ChatGPT集成到苹果操作系统,将带来哪些新功能?</a>
                        <span class="text-muted">开心的AI频道</span>
<a class="tag" taget="_blank" href="/search/chatgpt/1.htm">chatgpt</a>
                        <div>OpenAI宣布ChatGPT现已集成到苹果操作系统,将带来哪些新功能?这一合作有哪些意义?AI有了它的新家:苹果生态系统如果说iPhone开启了智能手机时代,那么苹果与OpenAI的合作,是对整个科技行业的一次深刻变革,预示着AI普及时代的真正到来。OpenAI近日正式宣布,ChatGPT已深度集成到苹果三大操作系统:iOS18.2、iPadOS18.2和macOSSequoia15.2。这一重</div>
                    </li>
                    <li><a href="/article/1887325482517590016.htm"
                           title="Java牙科诊所管理系统web医院病例挂号预约平台springboot/ssm代码编写" target="_blank">Java牙科诊所管理系统web医院病例挂号预约平台springboot/ssm代码编写</a>
                        <span class="text-muted">kirito学长-Java</span>
<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/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>Java牙科诊所管理系统web医院病例挂号预约平台springboot/ssm代码编写基于springboot(可改ssm)+html+vue项目开发语言:Java框架:springboot/可改ssm+vueJDK版本:JDK1.8(或11)服务器:tomcat数据库:mysql5.7(或8.0)数据库工具:Navicat/sqlyog开发软件:eclipse/idea依赖管理包:Maven代码</div>
                    </li>
                    <li><a href="/article/1887318925650227200.htm"
                           title="Rust代写 OCaml代做 Go R语言 SML Haskell Prolog DrRacket Lisp" target="_blank">Rust代写 OCaml代做 Go R语言 SML Haskell Prolog DrRacket Lisp</a>
                        <span class="text-muted">matlabgoodboy</span>
<a class="tag" taget="_blank" href="/search/rust/1.htm">rust</a><a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/r%E8%AF%AD%E8%A8%80/1.htm">r语言</a>
                        <div>Rust:Rust是一种注重性能和安全性的系统编程语言。它具有严格的内存管理,能够防止许多常见的内存错误。Rust作业可能涉及编写高效的算法、处理并发问题、与操作系统接口等。OCaml:OCaml是一种函数式编程语言,具有强大的类型系统和模块系统。它适合用于开发高性能、高可靠性的应用程序。OCaml作业可能涉及编写函数、处理数据结构、实现算法等。Go:Go(又称Golang)是一种编译型、并发型,</div>
                    </li>
                    <li><a href="/article/1887271778426875904.htm"
                           title="如何和 GPT 做最有效的沟通" target="_blank">如何和 GPT 做最有效的沟通</a>
                        <span class="text-muted">百锦再@新空间代码工作室</span>
<a class="tag" taget="_blank" href="/search/%E5%8C%85%E7%BD%97%E4%B8%87%E8%B1%A1/1.htm">包罗万象</a><a class="tag" taget="_blank" href="/search/gpt/1.htm">gpt</a><a class="tag" taget="_blank" href="/search/AI%E7%BC%96%E7%A8%8B/1.htm">AI编程</a><a class="tag" taget="_blank" href="/search/AI%E5%86%99%E4%BD%9C/1.htm">AI写作</a><a class="tag" taget="_blank" href="/search/AIGC/1.htm">AIGC</a><a class="tag" taget="_blank" href="/search/chatgpt/1.htm">chatgpt</a><a class="tag" taget="_blank" href="/search/GPT-4O/1.htm">GPT-4O</a>
                        <div>让我们一起走向未来作者简介:全栈领域优质创作者个人主页:百锦再@新空间代码工作室工作室:新空间代码工作室(提供各种软件服务)个人邮箱:[15045666310@163.com]个人微信:15045666310网站:https://meihua150.cn/座右铭:坚持自己的坚持,不要迷失自己!要快乐目录让我们一起走向未来**引言****一、了解GPT的工作原理****二、与GPT沟通的基本技巧**</div>
                    </li>
                    <li><a href="/article/1887263321984397312.htm"
                           title="鸿蒙5.0开发【应用并发设计(线程间通信)】架构" target="_blank">鸿蒙5.0开发【应用并发设计(线程间通信)】架构</a>
                        <span class="text-muted">蒸糕笑QAQ</span>
<a class="tag" taget="_blank" href="/search/harmonyos5.0/1.htm">harmonyos5.0</a><a class="tag" taget="_blank" href="/search/harmonyos/1.htm">harmonyos</a><a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84/1.htm">架构</a><a class="tag" taget="_blank" href="/search/%E5%8D%8E%E4%B8%BA/1.htm">华为</a><a class="tag" taget="_blank" href="/search/%E9%B8%BF%E8%92%99%E7%B3%BB%E7%BB%9F/1.htm">鸿蒙系统</a><a class="tag" taget="_blank" href="/search/%E9%B8%BF%E8%92%99/1.htm">鸿蒙</a>
                        <div>线程间通信概述线程间通信指的是并发多线程间存在的数据交换行为,目前已支持ArkTS、C++等开发语言,因此存在不同语言、不同线程的通信场景,接下来详细展开介绍。同语言线程间通信(ArkTS内)场景描述ArkTS线程指的是包含ArkTS运行环境的线程,包括主线程、TaskPool线程、Worker线程。它们之间可以通过不同的接口进行通信。常见业务场景如下所示:常见业务场景具体业务描述宿主JS线程Ta</div>
                    </li>
                    <li><a href="/article/1887259533248622592.htm"
                           title="golang fmt包Stringer接口测试实例" target="_blank">golang fmt包Stringer接口测试实例</a>
                        <span class="text-muted">只会打野怪我咯</span>
<a class="tag" taget="_blank" href="/search/GO/1.htm">GO</a><a class="tag" taget="_blank" href="/search/GO%E8%AF%AD%E8%A8%80%E6%B5%8B%E8%AF%95%E5%AE%9E%E4%BE%8B/1.htm">GO语言测试实例</a><a class="tag" taget="_blank" href="/search/go/1.htm">go</a><a class="tag" taget="_blank" href="/search/fmt/1.htm">fmt</a><a class="tag" taget="_blank" href="/search/Stringer/1.htm">Stringer</a>
                        <div>Stringer接口结构如下:typeStringerinterface{String()string}作用:实现了Stringer接口的类型(即有String方法),定义了该类型值的原始显示。当采用任何接受字符的verb(%v%s%q%x%X)动作格式化一个操作数时,或者被不使用格式字符串如Print函数打印操作数时,会调用String方法来生成输出的文本。int类型实现String()方法ty</div>
                    </li>
                    <li><a href="/article/1887259406182182912.htm"
                           title="【Golang学习之旅】Go 语言基础语法概览" target="_blank">【Golang学习之旅】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/%E5%AD%A6%E4%B9%A0/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>文章目录前言1.Go语言简介1.1Go语言是什么?1.2Go语言的应用场景2.Go语言开发环境2.1安装Go2.2配置Go环境2.3Hello,World!(第一个Go程序)3.Go语言基础语法3.1变量与常量3.2数据类型3.3条件判断与循环3.4数组与切片(slice)3.5Map(哈希表)4.Go语言函数5.Go语言并发编程(Goroutine&Channel)5.1Goroutine(轻量</div>
                    </li>
                    <li><a href="/article/1887218546845478912.htm"
                           title="GPT对话代码库——esp32和单片机实现远程wifi升级代码方案。" target="_blank">GPT对话代码库——esp32和单片机实现远程wifi升级代码方案。</a>
                        <span class="text-muted">玄奕子</span>
<a class="tag" taget="_blank" href="/search/%E5%B5%8C%E5%85%A5%E5%BC%8F/1.htm">嵌入式</a><a class="tag" taget="_blank" href="/search/%E5%8D%95%E7%89%87%E6%9C%BA/1.htm">单片机</a><a class="tag" taget="_blank" href="/search/gpt/1.htm">gpt</a><a class="tag" taget="_blank" href="/search/stm32/1.htm">stm32</a><a class="tag" taget="_blank" href="/search/Bootloader/1.htm">Bootloader</a><a class="tag" taget="_blank" href="/search/OTA%E8%BF%9C%E7%A8%8B%E5%8D%87%E7%BA%A7/1.htm">OTA远程升级</a>
                        <div>目录1,问:1,答:方案概述ESP32实现OTA升级的代码方案步骤1:准备OTA固件步骤2:ESP32OTA升级实现代码代码说明:步骤3:设置固件服务器单片机和ESP32的通信与控制单片机通过UART控制ESP32升级单片机发送指令给ESP32ESP32处理单片机发送的指令方案总结提问模型:GPT-4o-mini提问时间:2024.09.211,问:esp32和单片机实现远程wifi升级代码方案1</div>
                    </li>
                    <li><a href="/article/1887209343917551616.htm"
                           title="Golang 并发机制-6:掌握优雅的错误处理艺术" target="_blank">Golang 并发机制-6:掌握优雅的错误处理艺术</a>
                        <span class="text-muted">梦想画家</span>
<a class="tag" taget="_blank" href="/search/%23/1.htm">#</a><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>并发编程可能是提高软件系统效率和响应能力的一种强有力的技术。它允许多个工作负载同时运行,充分利用现代多核cpu。然而,巨大的能力带来巨大的责任,良好的错误管理是并发编程的主要任务之一。并发代码的复杂性并发编程增加了顺序程序所不具备的复杂性。多个线程或协程可以并发运行,这可能会导致竞争情况和同步困难。由于这种复杂性,并发程序中的错误管理比单线程编程更加困难。当并发程序中出现错误时,确定是哪个协程或线</div>
                    </li>
                    <li><a href="/article/1887197106511343616.htm"
                           title="【瑞萨RH850/U2A16】学习小结:MCAL多核配置" target="_blank">【瑞萨RH850/U2A16】学习小结:MCAL多核配置</a>
                        <span class="text-muted">枫俊天空</span>
<a class="tag" taget="_blank" href="/search/Autosar_MCAL/1.htm">Autosar_MCAL</a><a class="tag" taget="_blank" href="/search/%E7%91%9E%E8%90%A8U2A/1.htm">瑞萨U2A</a><a class="tag" taget="_blank" href="/search/MCAL/1.htm">MCAL</a><a class="tag" taget="_blank" href="/search/%E5%A4%9A%E6%A0%B8/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%B5%8C%E5%85%A5%E5%BC%8F%E7%A1%AC%E4%BB%B6/1.htm">嵌入式硬件</a>
                        <div>这里写自定义目录标题MCAL多核MCAL分核方式注意事项MCAL多核基于目前域控制器和区域控制器,融合的功能越来越多,多核使用越来越频繁,对于功能簇方式的分核,从应用层到BSW到MCAL整个功能簇放到不同的核,实现物理隔离和功能安全需求。MCAL分核方式对于瑞萨RH850芯片,mcal驱动的分核方案比Tricore个人觉得较复杂,原理也不同,RH850U2A16支持ADC/ICU/PWM/GPT/</div>
                    </li>
                    <li><a href="/article/1887149826412441600.htm"
                           title="golang开发技能" target="_blank">golang开发技能</a>
                        <span class="text-muted">焱齿</span>
<a class="tag" taget="_blank" href="/search/%E8%AF%AD%E8%A8%80/1.htm">语言</a><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>本文主要介绍go相关开发技巧、调试技巧、工具使用、单元测试、基准测试、性能测试相关。1、Go命令:gotest工具详解这里先大致介绍测试工具“gotest”,gotest本身可以携带很多参数,熟悉这些参数可以让我们的测试过程更加方面。具体使用参见下一节。(1)运行整个项目gotest(2)只运行某个测试文件注:math_test.go和math.go是一对,缺一不可且前后顺序不可调。gotestm</div>
                    </li>
                    <li><a href="/article/1887143018390155264.htm"
                           title="DeepSeek:探索未来的人工智能模型与技术" target="_blank">DeepSeek:探索未来的人工智能模型与技术</a>
                        <span class="text-muted">一ge科研小菜鸡</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/DeepSeek/1.htm">DeepSeek</a>
                        <div>个人主页:一ge科研小菜鸡-CSDN博客期待您的关注1.引言近年来,大语言模型(LLM)迅速发展,推动了人工智能在多个领域的应用。从OpenAI的GPT系列到Google的Gemini,再到国内的多个自研大模型,全球AI竞赛已进入白热化阶段。在这一背景下,DeepSeekAI作为一个新兴的AI研究机构,凭借其强大的技术实力和创新能力,在大模型领域崭露头角。本文将从DeepSeek的背景、核心技术、</div>
                    </li>
                    <li><a href="/article/1887090578567524352.htm"
                           title="大语言模型本地化部署+可视化微调" target="_blank">大语言模型本地化部署+可视化微调</a>
                        <span class="text-muted">科研小fw</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/%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9E%8B/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/%E8%87%AA%E7%84%B6%E8%AF%AD%E8%A8%80%E5%A4%84%E7%90%86/1.htm">自然语言处理</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/chatgpt/1.htm">chatgpt</a>
                        <div>目录本地化部署GLM4Qwen2大模型微调本地化部署2023年被称为人工智能(AI)元年,AI技术在全球范围内飞速发展,已经渗透到了各行各业。随着chatgpt的爆火,国内外的大语言模型(LargeLanguageModel,LLM)争先恐后,高速发展,人工智能技术也从传统的判别式人工智能逐渐转向了生成式人工智能,LLM作为AI的一种具体表现形式,除去关注大模型的回答精度,作为用户来说,会更加关注</div>
                    </li>
                    <li><a href="/article/1887078229194371072.htm"
                           title="探索未来:golang-nextjs-portable,轻量级的跨平台应用框架" target="_blank">探索未来:golang-nextjs-portable,轻量级的跨平台应用框架</a>
                        <span class="text-muted">郝赢泉</span>

                        <div>探索未来:golang-nextjs-portable,轻量级的跨平台应用框架golang-nextjs-portableGoprogramwithembeddedNext.jsapp.项目地址:https://gitcode.com/gh_mirrors/go/golang-nextjs-portable在现代开发领域,融合不同技术栈以创造高效、便捷的应用已成为趋势。今天,我们来探讨一个创新项目</div>
                    </li>
                    <li><a href="/article/1887078229701881856.htm"
                           title="使用 docker buildx 构建跨平台 Go 镜像" target="_blank">使用 docker buildx 构建跨平台 Go 镜像</a>
                        <span class="text-muted">huainian</span>
<a class="tag" taget="_blank" href="/search/%E5%BC%80%E6%BA%90%E7%B3%BB%E7%BB%9F%E9%83%A8%E7%BD%B2/1.htm">开源系统部署</a><a class="tag" taget="_blank" href="/search/docker/1.htm">docker</a><a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/%E5%AE%B9%E5%99%A8/1.htm">容器</a>
                        <div>目录前提dockerbuildx启用Buildxbuilder实例构建驱动buildx的跨平台构建策略一次构建多个架构Go镜像实践源代码和Dockerfile执行跨平台构建验证构建结果如何交叉编译Golang的CGO项目准备交叉编译环境和依赖交叉编译CGO示例总结参考链接在不同操作系统和处理器架构上运行应用是很普遍的场景,因此为不同平台单独构建发布版本是一种常见做法。当我们用来开发应用的平台与部署</div>
                    </li>
                    <li><a href="/article/1887078102857740288.htm"
                           title="探秘Golang构建利器:Maven-Golang-Wrapper" target="_blank">探秘Golang构建利器:Maven-Golang-Wrapper</a>
                        <span class="text-muted">幸竹任</span>

                        <div>探秘Golang构建利器:Maven-Golang-Wrapper项目地址:https://gitcode.com/gh_mirrors/mv/mvn-golangGolang与Maven的融合,为Java开发者打开了新世界的大门。让我们一起深入探索【Maven-Golang-Wrapper】这一强大工具,它将带你轻松迈入Go语言的开发世界。1.项目介绍Maven-Golang-Wrapper是一</div>
                    </li>
                    <li><a href="/article/1887076588202291200.htm"
                           title="如何使用Java代码给图片增加倒影效果" target="_blank">如何使用Java代码给图片增加倒影效果</a>
                        <span class="text-muted"></span>

                        <div>在多模态模型的架构上,ChatGPT的绘图能力主要依赖以下几个核心组件:跨模态编码器(Cross-ModalEncoder):跨模态编码器的作用是将文本和图像的特征进行对齐。GPT可以将用户输入的文本描述转换为文本特征表示,然后利用跨模态编码器将这些特征映射到图像特征空间。这种方式确保模型能够理解描述性语言中不同细节是如何与图像特征对应的。</div>
                    </li>
                    <li><a href="/article/1887075707658498048.htm"
                           title="golang命令大全8--跨平台构建" target="_blank">golang命令大全8--跨平台构建</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>Go语言以其强大的跨平台能力而著称,其内置的工具链使得构建适配不同平台的二进制可执行文件变得非常简单。在本章中,我们将详细讲解跨平台构建的基本概念、环境变量的配置方法、如何构建适配不同平台的二进制文件,以及相关的注意事项。1、跨平台构建的基本概念Go的编译器支持将源代码直接编译为适配不同操作系统和架构的二进制文件。通过设置特定的环境变量,开发者可以快速为不同的目标平台生成可执行文件,而无需在目标平</div>
                    </li>
                    <li><a href="/article/1887074066544783360.htm"
                           title="【产品经理修炼之道】- 如何用AI重做B端产品(附3个案例与3个方法论)?" target="_blank">【产品经理修炼之道】- 如何用AI重做B端产品(附3个案例与3个方法论)?</a>
                        <span class="text-muted">xiaoli8748_软件开发</span>
<a class="tag" taget="_blank" href="/search/%E4%BA%A7%E5%93%81%E7%BB%8F%E7%90%86/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/%E4%BA%A7%E5%93%81%E7%BB%8F%E7%90%86/1.htm">产品经理</a>
                        <div>随着AI的发展,产品的应用思路逐渐被打开。本文将就“如何运用AI重做B端产品”展开探讨,作者结合相关案例进行分析,希望对你有所帮助。“如何用AI重做B端产品?这是笔者近期的一点思考与实践,期望对你有启发。”2023年ChatGPT的横空出世,让所有人为之一振,有人兴奋(新/大机会到来),有人恐惧(被替代/被抛弃)。2023年大模型赛道成为了最火热的赛道,一年之内推出N个大模型,它成为了继移动互联网</div>
                    </li>
                    <li><a href="/article/1887070659352260608.htm"
                           title="vue 使用fetch-event-source 处理sse,实现ChatGpt逐字输出效果" target="_blank">vue 使用fetch-event-source 处理sse,实现ChatGpt逐字输出效果</a>
                        <span class="text-muted">reembarkation</span>
<a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a>
                        <div>1.安装npminstall@microsoft/fetch-event-source2.引用import{fetchEventSource}from"@microsoft/fetch-event-source";3.使用fetchEventSource('/api/chat',{method:'POST',headers:{'Content-Type':'application/json','A</div>
                    </li>
                    <li><a href="/article/1887061705775706112.htm"
                           title="每个程序员‌都应掌握的5种开发语言" target="_blank">每个程序员‌都应掌握的5种开发语言</a>
                        <span class="text-muted">2501_90255623</span>
<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语言,作为最早的高级编程语言之一,以其简洁、高效和接近硬件的特性,成为了操作系统、嵌入式系统、驱动程序等底层软件开发的首选。而C++,作为C语言的扩展,引入了面向对象编程、模板等现代语言特性,使得它在保持C语言高性能的同时,也具备了更强的表达能力和可扩展性。学习C/C++,你将深入理解</div>
                    </li>
                    <li><a href="/article/1887053886569639936.htm"
                           title="【Golang学习之旅】Go 语言数据类型详解(string、slice、map等)" target="_blank">【Golang学习之旅】Go 语言数据类型详解(string、slice、map等)</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%AD%A6%E4%B9%A0/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>文章目录前言1.Go语言数据类型概览2.Go语言基本数据类型2.1整型(int,uint,float)2.2布尔类型(bool)2.3字符串(string)3.Go语言复合数据类型3.1数组(Array)3.2切片(Slice)3.3映射(Map)4.结构体(Struct)5.指针(Pointer)总结&进阶学习方向前言✅适合人群:Golang新手|后端开发者|面试求职者✅文章亮点:超详细解析+代</div>
                    </li>
                    <li><a href="/article/1887048218714370048.htm"
                           title="Java垃圾分类回收系统web社区垃圾运输回收springboot/ssm代码编写" target="_blank">Java垃圾分类回收系统web社区垃圾运输回收springboot/ssm代码编写</a>
                        <span class="text-muted">kirito学长-Java</span>
<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>Java垃圾分类回收系统web校园社区垃圾运输回收管理springboot/ssm代码编写基于springboot(可改ssm)+html+vue项目开发语言:Java框架:springboot/可改ssm+vueJDK版本:JDK1.8(或11)服务器:tomcat数据库:mysql5.7(或8.0)数据库工具:Navicat/sqlyog开发软件:eclipse/idea依赖管理包:Maven</div>
                    </li>
                    <li><a href="/article/1887039138838933504.htm"
                           title="彻底颠覆!DeepSeek-R1横空出世,直接碾压OpenAI!" target="_blank">彻底颠覆!DeepSeek-R1横空出世,直接碾压OpenAI!</a>
                        <span class="text-muted">盼达思文体科创</span>
<a class="tag" taget="_blank" href="/search/%E7%BB%8F%E9%AA%8C%E5%88%86%E4%BA%AB/1.htm">经验分享</a>
                        <div>引言家人们,最近科技圈可太炸了!在人工智能领域,一直以来OpenAI就像一个超级霸主,凭借着强大的技术和广泛的应用,占据着全球人工智能市场的重要地位。它的GPT系列产品,从GPT-3到GPT-4Turbo,每一次更新都能引起全球的关注,无论是内容创作、智能客服还是科学研究,OpenAI的技术都发挥着重要作用。然而,就在大家都以为OpenAI会一直“独孤求败”的时候,中国的DeepSeek-R1突然</div>
                    </li>
                    <li><a href="/article/1887036862044893184.htm"
                           title="DeepBI 对于Airbnb的数据分析,Agent是如何工作的" target="_blank">DeepBI 对于Airbnb的数据分析,Agent是如何工作的</a>
                        <span class="text-muted">知识花海</span>
<a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%8F%AF%E8%A7%86%E5%8C%96/1.htm">数据可视化</a><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%E6%8C%96%E6%8E%98/1.htm">数据挖掘</a><a class="tag" taget="_blank" href="/search/ai/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>
                        <div>#数据分析#各位看官认为生成式AI发展方向是Agent还是Chat?首先我们来简单看一下这两个的区别:Chat是一个以“大脑和嘴”为主要构成的智能体,专注于信息处理和语言交流。以ChatGPT为例,它能够准确理解用户的查询,并给出有价值和连贯的回应,但它本身并不直接执行任务。Agent像一个具备“大脑、手和脚”功能的智能体,不仅具备思考和决策的能力,还能执行具体的任务。这意味着Agent不仅能在思</div>
                    </li>
                    <li><a href="/article/1887017796555042816.htm"
                           title="ChatGPT Plus和Pro详解对比:国内用户如何升级?" target="_blank">ChatGPT Plus和Pro详解对比:国内用户如何升级?</a>
                        <span class="text-muted"></span>
<a class="tag" taget="_blank" href="/search/chatgpt/1.htm">chatgpt</a>
                        <div>ChatGPTPro和ChatGPTPlus:详细对比与升级指南一、ChatGPTPro是什么?ChatGPTPro是OpenAI推出的高级付费订阅服务,提供比ChatGPT免费版和ChatGPTPlus更强大的功能和更高的服务质量。ChatGPTPro每月费用为200美元,针对需要更高计算能力和更强大功能的用户,特别是企业、专业人士以及技术开发者。通过ChatGPTPro,用户可以享受更丰富的模</div>
                    </li>
                    <li><a href="/article/1887016154241757184.htm"
                           title="基于Ernie-Bot打造语音对话功能" target="_blank">基于Ernie-Bot打造语音对话功能</a>
                        <span class="text-muted"></span>
<a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a>
                        <div>GPT-4的语音对话功能前段时间在网上火了一把,许多人被其强大的自然语言处理能力和流畅的语音交互所吸引。现在,让我们来看看如何使用类似的技术,即基于百度的ERNIE-Bot,来打造自己的语音对话功能。ERNIE-Bot是一种先进的语言理解模型,可以处理复杂的语言任务,包括语音到文本的转换和自然语言理解。视频演示:涉及技术:langchainMemory、ChainErnie-bot百度智能云语音识</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>