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/1950193606174240768.htm"
                           title="GPT-4 在 AIGC 中的微调技巧:让模型更懂你的需求" target="_blank">GPT-4 在 AIGC 中的微调技巧:让模型更懂你的需求</a>
                        <span class="text-muted">AIGC应用创新大全</span>
<a class="tag" taget="_blank" href="/search/AI%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD%E4%B8%8E%E5%A4%A7%E6%95%B0%E6%8D%AE%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91/1.htm">AI人工智能与大数据应用开发</a><a class="tag" taget="_blank" href="/search/MCP%26amp%3BAgent/1.htm">MCP&Agent</a><a class="tag" taget="_blank" href="/search/%E4%BA%91%E7%AE%97%E5%8A%9B%E7%BD%91%E7%BB%9C/1.htm">云算力网络</a><a class="tag" taget="_blank" href="/search/AIGC/1.htm">AIGC</a><a class="tag" taget="_blank" href="/search/ai/1.htm">ai</a>
                        <div>GPT-4在AIGC中的微调技巧:让模型更懂你的需求关键词:GPT-4、AIGC、模型微调、监督学习、指令优化、过拟合预防、个性化生成摘要:AIGC(人工智能生成内容)正在重塑内容创作行业,但通用的GPT-4模型可能无法精准匹配你的垂直需求——比如写电商爆款文案时总“跑题”,或生成技术文档时专业术语不够。本文将用“教小朋友学画画”的通俗类比,从微调的底层逻辑讲到实战技巧,带你掌握让GPT-4“更懂</div>
                    </li>
                    <li><a href="/article/1950192848225759232.htm"
                           title="AIGC内容生成实战:如何用ChatGPT+DALL·E打造高转化内容" target="_blank">AIGC内容生成实战:如何用ChatGPT+DALL·E打造高转化内容</a>
                        <span class="text-muted">AI大模型应用工坊</span>
<a class="tag" taget="_blank" href="/search/AI%E5%A4%A7%E6%A8%A1%E5%9E%8B%E5%BC%80%E5%8F%91%E5%AE%9E%E6%88%98/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/ai/1.htm">ai</a>
                        <div>AIGC内容生成实战:如何用ChatGPT+DALL·E打造高转化内容关键词:AIGC、ChatGPT、DALL·E、内容生成、高转化营销、多模态协同、提示词工程摘要:随着AIGC(人工智能生成内容)技术的爆发式发展,ChatGPT(文本生成)与DALL·E(图像生成)的组合已成为内容创作领域的“黄金搭档”。本文将深度解析二者的协同原理,结合实战案例演示从需求分析到内容落地的全流程,并揭示提升内容</div>
                    </li>
                    <li><a href="/article/1950144603407577088.htm"
                           title="ChatGPT还不能写小说吗?" target="_blank">ChatGPT还不能写小说吗?</a>
                        <span class="text-muted">刘若愚</span>

                        <div>最近,ChatGPT大热,据说可以写论文,编故事,好像无所不能。于是,我给它出了个题目:写一篇5万字的科幻小说。人物:刘若愚,化学家;刘子琪,大律师;仔仔,刘子琪的宠物猫;周金凝,医生;刘泽余,大侦探;赵政淇,程序猿;杰夫(Jeff)机器人它给我的回答是:我很抱歉,我是一个AI语言模型,无法写出如此长篇的小说。但我可以为您提供一些写作灵感和指导:确定故事背景和时间线:在科幻小说中,背景和时间线非常</div>
                    </li>
                    <li><a href="/article/1949991881769283584.htm"
                           title="【20年架构师韩艳威整理】CentOS Stream10磁盘管理第4章" target="_blank">【20年架构师韩艳威整理】CentOS Stream10磁盘管理第4章</a>
                        <span class="text-muted">韩公子的Linux大集市</span>
<a class="tag" taget="_blank" href="/search/Bash%E5%85%A5%E9%97%A8/1.htm">Bash入门</a><a class="tag" taget="_blank" href="/search/centos/1.htm">centos</a><a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/%E8%BF%90%E7%BB%B4/1.htm">运维</a>
                        <div>文章目录优化细化1:磁盘识别与扫描(增强版)优化细化2:GPT分区高级操作优化细化3:文件系统优化参数优化细化4:LVM元数据管理优化细化5:LVM高级扩容技巧优化细化6:LVM快照管理优化细化7:LVM精简配置优化细化8:故障处理与恢复优化细化9:性能监控与调优优化细化10:安全与权限管理终极操作对比表:普通分区vsLVM灾难恢复检查清单以下是对CentOSStream10中BashShell磁</div>
                    </li>
                    <li><a href="/article/1949981160717217792.htm"
                           title="ChatGPT 嵌入 IDE:代码生成、调试一步到位!" target="_blank">ChatGPT 嵌入 IDE:代码生成、调试一步到位!</a>
                        <span class="text-muted">大力出奇迹985</span>
<a class="tag" taget="_blank" href="/search/chatgpt/1.htm">chatgpt</a><a class="tag" taget="_blank" href="/search/ide/1.htm">ide</a>
                        <div>当ChatGPT与IDE(集成开发环境)深度融合,开发领域正迎来颠覆性变革。这种结合不仅让代码生成从繁琐的手动编写转变为智能辅助下的高效创作,更将调试过程化繁为简,实现开发全流程的无缝衔接。本文将从开发效率革新、代码质量提升、调试模式重构、学习曲线优化以及未来挑战与机遇五个维度,详细剖析ChatGPT嵌入IDE的具体价值与实践场景,为开发者呈现这一技术融合带来的全新工作模式。在软件开发的历史长河中</div>
                    </li>
                    <li><a href="/article/1949956571953950720.htm"
                           title="使用中转API调用OpenAI大模型的指南" target="_blank">使用中转API调用OpenAI大模型的指南</a>
                        <span class="text-muted"></span>

                        <div>引言近年来,人工智能(AI)技术的飞速发展使得各种大模型(如GPT-4)在自然语言处理领域表现出色。然而,中国用户访问OpenAI的API时经常会遇到网络限制问题。本文将介绍如何通过中转API地址(http://api.wlai.vip)调用OpenAI的大模型,并提供示例代码以供参考。使用中转API调用OpenAI大模型步骤一:安装所需的Python库首先,确保你已安装了openai库。可以通过</div>
                    </li>
                    <li><a href="/article/1949922030967123968.htm"
                           title="2025年最新五大顶级大模型技术对比分析报告" target="_blank">2025年最新五大顶级大模型技术对比分析报告</a>
                        <span class="text-muted">it_czz</span>
<a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a>
                        <div>2025年最新五大顶级大模型技术对比分析报告执行摘要本报告基于2025年最新数据,深度分析当前最顶尖的5个已发布大语言模型:KimiK2(月之暗面)、Claude3.5Sonnet、GPT-4o、Gemini2.5Pro、DeepSeekR1,从技术架构、成本效益、性能表现、适配场景等多个维度进行全面对比。核心发现KimiK2:中文优化最强,超长上下文处理能力突出,本土化程度最高Claude3.5</div>
                    </li>
                    <li><a href="/article/1949919886650175488.htm"
                           title="TechGPT3部署" target="_blank">TechGPT3部署</a>
                        <span class="text-muted"></span>

                        <div>环境配置与TechGPT2配置相同:TechGPT2部署-CSDN博客。模型下载步骤如下。sudoaptupdatesudoaptinstallgit-lfs-ygitlfsinstall学术加速并克隆模型代码库。source/etc/network_turbogitclonehttps://github.com/neukg/TechGPT-3.0.git禁用smudge,防止clone过程中拉大</div>
                    </li>
                    <li><a href="/article/1949912700523966464.htm"
                           title="优化提示内容生成技术框架:提示工程架构师的坚实后盾" target="_blank">优化提示内容生成技术框架:提示工程架构师的坚实后盾</a>
                        <span class="text-muted"></span>

                        <div>优化提示内容生成技术框架:提示工程架构师的坚实后盾引言背景:大语言模型时代的“提示瓶颈”当GPT-4、Claude3、Gemini等大语言模型(LLM)的参数规模突破万亿、上下文窗口扩展至百万token时,一个矛盾逐渐凸显:模型能力的跃升与提示质量的滞后,正在成为制约AI应用落地的核心瓶颈。2023年斯坦福大学的研究显示,在企业级LLM应用中,70%的功能故障源于提示设计缺陷——或因指令模糊导致输</div>
                    </li>
                    <li><a href="/article/1949897298091765760.htm"
                           title="Golang不能发送udp广播" target="_blank">Golang不能发送udp广播</a>
                        <span class="text-muted">大地缸</span>

                        <div>title:"Golang不能发送udp广播"date:2021-01-29T20:55:16+08:00draft:truetags:['go','udp']author:"dadigang"author_cn:"大地缸"personal:"http://www.real007.cn"关于作者http://www.real007.cn/aboutgo不能发送udp广播,这算不算是一个bug?ne</div>
                    </li>
                    <li><a href="/article/1949876752226512896.htm"
                           title="Claude 4深夜爆更:OpenAI都沉默了,这才是AI的天花板!" target="_blank">Claude 4深夜爆更:OpenAI都沉默了,这才是AI的天花板!</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>“凌晨上线,不打招呼,一上线就是王炸。”2025年5月,一场没有任何预热的更新,Claude4系列在深夜悄悄炸翻了整个AI圈——这不是一次普通的版本升级,而是一次AI军备竞赛的彻底反转!谁能想到,一次更新就让Claude碾压全场?就在大家还沉浸在GPT-4.5的“小步快跑”时,Anthropic直接把Claude4系列一口气拉到:•Claude4.0正式登场•Claude4.1/Opus智力超越G</div>
                    </li>
                    <li><a href="/article/1949840302470656000.htm"
                           title="结合Golang语言说明对多线程编程以及 select/epoll等网络模型的使用" target="_blank">结合Golang语言说明对多线程编程以及 select/epoll等网络模型的使用</a>
                        <span class="text-muted">zhoupenghui168</span>
<a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/1.htm">计算机网络</a><a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C/1.htm">网络</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/select%E7%BD%91%E7%BB%9C%E6%A8%A1%E5%9E%8B/1.htm">select网络模型</a><a class="tag" taget="_blank" href="/search/epoll%E7%BD%91%E7%BB%9C%E6%A8%A1%E5%9E%8B/1.htm">epoll网络模型</a><a class="tag" taget="_blank" href="/search/%E5%A4%9A%E7%BA%BF%E7%A8%8B%E7%BC%96%E7%A8%8B/1.htm">多线程编程</a>
                        <div>首先介绍select和epoll这两个I/O多路复用的网络模型,然后介绍多线程编程,最后结合Go语言项目举例说明如何应用一、select和epoll的介绍1.select模型select是一种I/O多路复用技术,它允许程序同时监视多个文件描述符(通常是套接字),等待一个或多个描述符就绪(可读、可写或异常)然后进行相应的操作,它的跨平台兼容性好(Windows/Linux/macOS)核心原理:使用</div>
                    </li>
                    <li><a href="/article/1949833214038175744.htm"
                           title="ChatGPT聊天机器人搭建全攻略汇总:精心整理" target="_blank">ChatGPT聊天机器人搭建全攻略汇总:精心整理</a>
                        <span class="text-muted">柚米汇</span>

                        <div>一、ChatGPT接入微信:ChatGPT接入微信ChatGPT近期以强大的对话和信息整合能力风靡全网,可以写代码、改论文、讲故事,几乎无所不能,这让人不禁有个大胆的想法,能否用他的对话模型把我们的微信打造成一个智能机器人,可以在与好友对话中给出意想不到的回应,而且再也不用担心女朋友影响我们打游戏工作了。GitHub:https://github.com/zhayujie/chatgpt-on-w</div>
                    </li>
                    <li><a href="/article/1949825051763208192.htm"
                           title="Golang领域中间件的选型指南与最佳实践" target="_blank">Golang领域中间件的选型指南与最佳实践</a>
                        <span class="text-muted">Golang编程笔记</span>
<a class="tag" taget="_blank" href="/search/Golang%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/1.htm">Golang编程笔记</a><a class="tag" taget="_blank" href="/search/Golang%E5%BC%80%E5%8F%91%E5%AE%9E%E6%88%98/1.htm">Golang开发实战</a><a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/%E4%B8%AD%E9%97%B4%E4%BB%B6/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><a class="tag" taget="_blank" href="/search/ai/1.htm">ai</a>
                        <div>Golang领域中间件的选型指南与最佳实践关键词:Golang中间件、选型指南、最佳实践、微服务架构、性能优化、可观测性、安全防护摘要:本文深入探讨Golang生态系统中中间件的选型策略和实施最佳实践。我们将从基础概念出发,逐步分析各类中间件的核心功能、适用场景和性能特点,提供清晰的选型决策框架。通过实际代码示例和架构图解,展示如何构建高效、可靠的中间件层,帮助开发者在微服务架构中做出明智的技术选</div>
                    </li>
                    <li><a href="/article/1949814878260752384.htm"
                           title="SSM+Vue共享充电宝管理系统 充电宝投放管理系统 共享充电宝维护管理系统Java" target="_blank">SSM+Vue共享充电宝管理系统 充电宝投放管理系统 共享充电宝维护管理系统Java</a>
                        <span class="text-muted">计算机程序老哥</span>

                        <div>作者主页:计算机毕业设计老哥有问题可以主页问我一、开发介绍1.1开发环境开发语言:Java数据库:MySQL系统架构:B/S后端:SSM(Spring+SpringMVC+Mybatis)前端:Vue工具:IDEA或者Eclipse,JDK1.8,Maven二、系统介绍2.1图片展示注册登录页面:登陆前端页面功能:首页、合作商户、充电宝投放、公告栏、个人中心、后台管理首页.png充电宝投放.png</div>
                    </li>
                    <li><a href="/article/1949808285825691648.htm"
                           title="AI技术落地的综合实战经验报告,结合最新行业案例、代码示例及可视化图表,系统阐述AI在开发提效、算法优化与行业应用中的实践路径。" target="_blank">AI技术落地的综合实战经验报告,结合最新行业案例、代码示例及可视化图表,系统阐述AI在开发提效、算法优化与行业应用中的实践路径。</a>
                        <span class="text-muted"></span>

                        <div>一、自动化开发革命:从代码生成到低代码架构1.1自然语言转代码(NL2Code)实战技术架构基于GPT-4/Codex的代码生成器实现以下流程:graphTDA[自然语言输入]-->B(GPT-4/Codex解析)B-->C{代码解析器}C-->D[Python/Java/SQL]C-->E[测试用例]D-->F[代码质量检测]F-->G[可执行程序]典型场景:数据清洗函数生成python#输入提</div>
                    </li>
                    <li><a href="/article/1949781683813281792.htm"
                           title="【tower】Rust tower库原理详解以及axum限流实战" target="_blank">【tower】Rust tower库原理详解以及axum限流实战</a>
                        <span class="text-muted">景天科技苑</span>
<a class="tag" taget="_blank" href="/search/Rust%E8%AF%AD%E8%A8%80%E9%80%9A%E5%85%B3%E4%B9%8B%E8%B7%AF/1.htm">Rust语言通关之路</a><a class="tag" taget="_blank" href="/search/rust/1.htm">rust</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><a class="tag" taget="_blank" href="/search/tower/1.htm">tower</a><a class="tag" taget="_blank" href="/search/rust/1.htm">rust</a><a class="tag" taget="_blank" href="/search/tower/1.htm">tower</a><a class="tag" taget="_blank" href="/search/axum%E9%99%90%E6%B5%81/1.htm">axum限流</a>
                        <div>✨✨欢迎大家来到景天科技苑✨✨养成好习惯,先赞后看哦~作者简介:景天科技苑《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。《博客》:Rust开发,Python全栈,Golang开发,云原生开发,PyQt5和Tkinter桌面开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django</div>
                    </li>
                    <li><a href="/article/1949771845226000384.htm"
                           title="生成式引擎优化(GEO)在 Google Gemini 中的实践与探索" target="_blank">生成式引擎优化(GEO)在 Google Gemini 中的实践与探索</a>
                        <span class="text-muted">GEO优化助手</span>
<a class="tag" taget="_blank" href="/search/%E7%94%9F%E6%88%90%E5%BC%8F%E5%BC%95%E6%93%8E%E4%BC%98%E5%8C%96/1.htm">生成式引擎优化</a><a class="tag" taget="_blank" href="/search/AI%E6%90%9C%E7%B4%A2%E4%BC%98%E5%8C%96/1.htm">AI搜索优化</a><a class="tag" taget="_blank" href="/search/GEO%E4%BC%98%E5%8C%96/1.htm">GEO优化</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E7%94%9F%E6%88%90%E5%BC%8F%E5%BC%95%E6%93%8E%E4%BC%98%E5%8C%96/1.htm">生成式引擎优化</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/AI%E6%90%9C%E7%B4%A2%E8%90%A5%E9%94%80/1.htm">AI搜索营销</a><a class="tag" taget="_blank" href="/search/GEO%E4%BC%98%E5%8C%96/1.htm">GEO优化</a><a class="tag" taget="_blank" href="/search/Google/1.htm">Google</a><a class="tag" taget="_blank" href="/search/Gemini/1.htm">Gemini</a>
                        <div>2025年,生成式AI(如GoogleGemini、ChatGPT、DeepSeek)已占据全球63%的互联网用户信息获取入口。用户行为从"浏览多个网页"转向"直接获取AI生成的精准答案",这一转变使传统SEO(搜索引擎优化)面临失效风险——即使内容优质,若未被AI模型识别为"可信信源",仍可能被淹没在信息洪流中。在此背景下,生成式引擎优化(GEO,GenerativeEngineOptimiza</div>
                    </li>
                    <li><a href="/article/1949738942936969216.htm"
                           title="Java AI面试实战:Spring AI与RAG技术落地" target="_blank">Java AI面试实战:Spring AI与RAG技术落地</a>
                        <span class="text-muted">GEM的左耳返</span>
<a class="tag" taget="_blank" href="/search/Java%E5%9C%BA%E6%99%AF%E9%9D%A2%E8%AF%95%E5%AE%9D%E5%85%B8/1.htm">Java场景面试宝典</a><a class="tag" taget="_blank" href="/search/Java%E9%9D%A2%E8%AF%95/1.htm">Java面试</a><a class="tag" taget="_blank" href="/search/Spring/1.htm">Spring</a><a class="tag" taget="_blank" href="/search/AI/1.htm">AI</a><a class="tag" taget="_blank" href="/search/RAG/1.htm">RAG</a><a class="tag" taget="_blank" href="/search/%E5%90%91%E9%87%8F%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">向量数据库</a><a class="tag" taget="_blank" href="/search/AI%E5%BA%94%E7%94%A8/1.htm">AI应用</a><a class="tag" taget="_blank" href="/search/Prompt%E5%B7%A5%E7%A8%8B/1.htm">Prompt工程</a>
                        <div>JavaAI面试实战:SpringAI与RAG技术落地面试现场:AI技术终面室面试官:谢飞机同学,今天我们聚焦JavaAI应用开发,重点考察SpringAI和RAG技术栈。谢飞机:(兴奋地)面试官好!我可是AI达人!ChatGPT、Midjourney我天天用,SpringAI这新框架我也研究过!第一轮:SpringAI基础面试官:请详细描述SpringAI的核心组件及PromptTemplate</div>
                    </li>
                    <li><a href="/article/1949734657268445184.htm"
                           title="详细指南:如何使用WildCard升级到ChatGPT 4.0" target="_blank">详细指南:如何使用WildCard升级到ChatGPT 4.0</a>
                        <span class="text-muted">扑扑特桔</span>
<a class="tag" taget="_blank" href="/search/chatgpt/1.htm">chatgpt</a><a class="tag" taget="_blank" href="/search/AIGC/1.htm">AIGC</a><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/plus/1.htm">plus</a><a class="tag" taget="_blank" href="/search/openai/1.htm">openai</a>
                        <div>1.了解ChatGPT自从ChatGPT3.5发布以来,它便吸引了无数人的注意。今天我们要聊的,是它的继任者——ChatGPT-4.0。1.1什么是ChatGPT-4.0?ChatGPT-4.0是由OpenAI研发的一款先进的人工智能语言模型。相比于其前任,它在自然语言的理解和生成上,有了更进一步的提升。想象一下,这个模型能更流畅地对话,理解复杂问题,并且在执行各种任务时都能提供更精准的答案。从信</div>
                    </li>
                    <li><a href="/article/1949730613351215104.htm"
                           title="WildCard野卡停服倒计时!国内升级ChatGPT Plus的最稳替代方案" target="_blank">WildCard野卡停服倒计时!国内升级ChatGPT Plus的最稳替代方案</a>
                        <span class="text-muted">瀚鹏AI</span>
<a class="tag" taget="_blank" href="/search/chatgpt/1.htm">chatgpt</a>
                        <div>近日,WildCard野卡因"监管合规调整"及"上游政策变化"宣布自7月12日起全面停服,官网、App及客服系统悉数下线,用户充值、提现功能被永久封锁。尽管卡内余额仍可暂时用于订阅Netflix、Spotify等服务,但平台未来走向不明,引发用户对资金安全的广泛担忧。这场突如其来的变故,再次凸显选择合规、稳定服务的重要性。WildCard停服背后:合规风险成企业服务"隐形炸弹"WildCard曾以</div>
                    </li>
                    <li><a href="/article/1949725950484738048.htm"
                           title="WildCard野卡之后,我们如何解决ChatGPT Plus充值订阅难题?一份深度评测与备选方案" target="_blank">WildCard野卡之后,我们如何解决ChatGPT Plus充值订阅难题?一份深度评测与备选方案</a>
                        <span class="text-muted">gptplusplus</span>
<a class="tag" taget="_blank" href="/search/chatgpt/1.htm">chatgpt</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/gpt/1.htm">gpt</a>
                        <div>一、问题的出现:一个开发者工具链的“单点故障”兄弟们,今天这个消息,相信不少人都感同身受。我一直依赖的WildCard平台,刚刚宣布永久暂停服务。这不仅仅是一个工具的消失,更是我们许多人工作流中一个关键节点的“单点故障”。对于我们开发者来说,ChatGPTPlus早已是深度绑定的生产力工具:无论是辅助编码、调试,还是作为架构设计的“陪练”,它的重要性不言而喻。续费渠道的中断,意味着下个月的工作效率</div>
                    </li>
                    <li><a href="/article/1949719014334853120.htm"
                           title="Language Models are Few-Shot Learners: 开箱即用的GPT-3(三)" target="_blank">Language Models are Few-Shot Learners: 开箱即用的GPT-3(三)</a>
                        <span class="text-muted">新兴AI民工</span>
<a class="tag" taget="_blank" href="/search/%E6%B7%B1%E5%BA%A6%E7%BD%91%E7%BB%9C%2F%E5%A4%A7%E6%A8%A1%E5%9E%8B%E7%BB%8F%E5%85%B8%E8%AE%BA%E6%96%87%E8%AF%A6%E8%A7%A3/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/gpt-3/1.htm">gpt-3</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a>
                        <div>Result前面的两个部分介绍了背景,模型的情况和一些测试的方法,这一章就是展示各种尺寸的模型,包括175B的GPT-3在各种任务下的测试情况了。power-law第三章一上来,就用了14不同尺寸的模型来验证这个cross-entropy的线性提升与模型尺寸的指数关系(从最小的100000个参数,一只上升到175B的GPT-3,从10的5次方一直测试到10的11次方),从更大的尺度上来验证这个结论</div>
                    </li>
                    <li><a href="/article/1949705772782907392.htm"
                           title="深入详解K近邻算法(KNN):基本概念、原理及在医学影像领域的应用与实现" target="_blank">深入详解K近邻算法(KNN):基本概念、原理及在医学影像领域的应用与实现</a>
                        <span class="text-muted">猿享天开</span>
<a class="tag" taget="_blank" href="/search/%E8%BF%91%E9%82%BB%E7%AE%97%E6%B3%95/1.htm">近邻算法</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/%E5%8C%BB%E5%AD%A6%E5%BD%B1%E5%83%8F/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/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/1.htm">机器学习</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E6%A8%A1%E5%9E%8B/1.htm">大模型</a>
                        <div>博主简介:CSDN博客专家、CSDN平台优质创作者,高级开发工程师,数学专业,10年以上C/C++,C#,Java等多种编程语言开发经验,拥有高级工程师证书;擅长C/C++、C#等开发语言,熟悉Java常用开发技术,能熟练应用常用数据库SQLserver,Oracle,mysql,postgresql等进行开发应用,熟悉DICOM医学影像及DICOM协议,业余时间自学JavaScript,Vue,</div>
                    </li>
                    <li><a href="/article/1949705773940535296.htm"
                           title="机器学习模型评估:交叉验证、混淆矩阵、ROC曲线及其在医学影像领域的应用" target="_blank">机器学习模型评估:交叉验证、混淆矩阵、ROC曲线及其在医学影像领域的应用</a>
                        <span class="text-muted">猿享天开</span>
<a class="tag" taget="_blank" href="/search/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/1.htm">机器学习</a><a class="tag" taget="_blank" href="/search/%E7%9F%A9%E9%98%B5/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/DICOM%E5%8C%BB%E5%AD%A6%E5%BD%B1%E5%83%8F/1.htm">DICOM医学影像</a><a class="tag" taget="_blank" href="/search/%E6%A8%A1%E5%9E%8B%E8%AF%84%E4%BC%B0/1.htm">模型评估</a>
                        <div>博主简介:CSDN博客专家、CSDN平台优质创作者,高级开发工程师,数学专业,10年以上C/C++,C#,Java等多种编程语言开发经验,拥有高级工程师证书;擅长C/C++、C#等开发语言,熟悉Java常用开发技术,能熟练应用常用数据库SQLserver,Oracle,mysql,postgresql等进行开发应用,熟悉DICOM医学影像及DICOM协议,业余时间自学JavaScript,Vue,</div>
                    </li>
                    <li><a href="/article/1949625340502536192.htm"
                           title="golang学习线路图" target="_blank">golang学习线路图</a>
                        <span class="text-muted">gopher.guo</span>
<a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/go/1.htm">go</a><a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/go%E8%AF%AD%E8%A8%80/1.htm">go语言</a>
                        <div>学习Go(Golang)开发,应该从基础语法开始,逐步深入到并发编程、网络编程、Web开发、微服务架构、项目部署与调试等方向。以下是一个系统性的学习路线和内容详解,适合从零到进阶的开发者参考:一、Go语言基础Go语言的安装与配置Go的安装包下载与环境变量配置(GOROOT,GOPATH,gomod)使用GoModules管理依赖基础语法变量与常量的定义(var,const,类型推断:=)数据类型:</div>
                    </li>
                    <li><a href="/article/1949621683375632384.htm"
                           title="Golang Gorilla框架入门指南:从零开始构建Web应用" target="_blank">Golang Gorilla框架入门指南:从零开始构建Web应用</a>
                        <span class="text-muted"></span>

                        <div>GolangGorilla框架入门指南:从零开始构建Web应用关键词:Golang、Gorilla框架、Web开发、路由、中间件、RESTfulAPI、WebSocket摘要:本文将从零开始介绍如何使用Golang的Gorilla框架构建Web应用。我们将首先了解Gorilla框架的核心组件,然后通过实际案例演示如何构建一个完整的Web应用,包括路由设置、中间件使用、RESTfulAPI开发和We</div>
                    </li>
                    <li><a href="/article/1949621430706565120.htm"
                           title="Gorilla 在 Golang 中的实战应用:从入门到精通" target="_blank">Gorilla 在 Golang 中的实战应用:从入门到精通</a>
                        <span class="text-muted">Golang编程笔记</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><a class="tag" taget="_blank" href="/search/ai/1.htm">ai</a>
                        <div>Gorilla在Golang中的实战应用:从入门到精通关键词:Gorilla,Golang,Web开发,路由,WebSocket,中间件,RESTfulAPI摘要:本文将深入探讨Gorilla工具包在GolangWeb开发中的实战应用。从基础概念到高级用法,我们将全面解析Gorilla的核心组件,包括mux路由、WebSocket、中间件等。通过详细的代码示例和实际项目案例,帮助开发者掌握Gori</div>
                    </li>
                    <li><a href="/article/1949621431209881600.htm"
                           title="Golang Gorilla 框架性能优化:10 个必知技巧" target="_blank">Golang Gorilla 框架性能优化:10 个必知技巧</a>
                        <span class="text-muted"></span>

                        <div>GolangGorilla框架性能优化:10个必知技巧关键词:Gorilla框架、性能优化、Go语言、路由匹配、中间件、内存管理、并发处理、HTTP服务、Web开发、实战技巧摘要:Gorilla是Go语言生态中最受欢迎的Web开发框架之一,广泛用于构建高并发API和实时应用(如WebSocket聊天)。但随着业务规模扩大,如何让Gorilla应用保持“丝滑”性能?本文将从路由优化、内存管理、并发设</div>
                    </li>
                    <li><a href="/article/1949581461787045888.htm"
                           title="阿里开源Qwen3-Coder,编程大模型进入高效时代" target="_blank">阿里开源Qwen3-Coder,编程大模型进入高效时代</a>
                        <span class="text-muted">未来智慧谷</span>
<a class="tag" taget="_blank" href="/search/%E5%BC%80%E6%BA%90/1.htm">开源</a><a class="tag" taget="_blank" href="/search/Qwen3-Coder/1.htm">Qwen3-Coder</a>
                        <div>7月23日凌晨,阿里云宣布全面开源其最新AI编程大模型Qwen3-Coder,迅速引发全球开发者关注。该模型在多项编程能力测试中刷新开源模型纪录,并在Agent任务规划、工具调用等关键场景中超越GPT-4.1等闭源模型,达到与当前顶尖编程模型Claude4相近的水平。技术架构与性能突破Qwen3-Coder采用混合专家(MoE)架构,总参数量达480B,但实际激活参数仅35B,在保证性能的同时显著</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>