码迷,mamicode.com
首页 > 其他好文 > 详细

golang todo实例

时间:2015-02-10 00:36:28      阅读:240      评论:0      收藏:0      [点我收藏+]

标签:golang   go语言   实例   todo   

之前写过一篇todo实例,是使用python的tornado框架实现的。地址:http://blog.csdn.net/luck_apple/article/details/8814091

最近go更新到了1.4版本,正好也研究来玩玩。

看了几天go基础,然后想找个例子练练手,就想起来遇险写过的tornado的todo了,

直接拿来用go重写一遍,本次没有使用web框架,使用go原生API实现。

go语言基础可以看看电子书:http://download.csdn.net/detail/luck_apple/8412345 (0资源分)


go版本1.4,再看下我的go env:

技术分享


先看看最终效果吧:

技术分享


ok,就是这个样子。

上次有人抱怨我没有把数据库表结构亮出来,这次索性使用sqlite数据库,表结构真心很简单:

CREATE TABLE todo (id integer PRIMARY KEY,titletext NOT NULL,finishboolean NOT NULLDEFAULT false)


再看下工程目录结构:

技术分享

咱虽然没有使用mvc的web框架,但也得有个mvc的样子,mode,view和controller还是呀纷纷清楚的。

入口为main.go(负责创建web server和路由):

package main

import (
	"log"
	"net/http"
	"todo/controllers"
)

func main() {
	// 静态资源服务
	http.Handle("/public/", http.FileServer(http.Dir("./")))

	// 路由
	http.HandleFunc("/new", controllers.NewTodo)
	http.HandleFunc("/edit", controllers.EditTodo)
	http.HandleFunc("/finish", controllers.FinishTodo)
	http.HandleFunc("/delete", controllers.DeleteTodo)
	http.HandleFunc("/", controllers.Index)

	err := http.ListenAndServe(":3000", nil)
	if err != nil {
		log.Fatal("ListenAndServer error:", err)
	}
}

上面定义的路由,都会执行到TodoController.go中的对应方法

再看看TodoController.go:

package controllers

import (
	"html/template"
	"net/http"
	"strconv"
	"todo/models"
)

func Index(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		showError(w, "异常", "非法请求,服务器无法响应")
	} else {
		if r.URL.Path == "/" {
			todos, err := models.QueryAll()
			if err != nil {
				showError(w, "异常", "查询异常")
				return
			}
			t, err := template.ParseFiles("views/index.html")
			if err != nil {
				showError(w, "异常", "页面渲染异常")
				return
			}
			data := make(map[string][]models.Todo)
			data["TodoList"] = todos
			t.Execute(w, data)
		} else {
			// 404页面,路由不到的都会到这里
			showError(w, "404", "页面不存在")
		}
	}
}

func NewTodo(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		showError(w, "异常", "非法请求")
	} else {
		title := r.FormValue("title")
		id, err := models.InsertTodo(title)

		if err != nil || id <= 0 {
			showError(w, "异常", "插入数据异常")
			return
		}
		// 重定向到主界面
		http.Redirect(w, r, "/", http.StatusSeeOther)
		// 没有return,没有效果,重定向不过去
		return
	}
}

func FinishTodo(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		showError(w, "异常", "非法请求")
	} else {
		// 获取表单参数,也可以这么写
		// r.ParseForm()
		// id := r.Form["id"]
		id := r.FormValue("id")
		finish := r.FormValue("finish")
		// FormValue取到的数据都为string类型,将id转为int64类型
		// strconv.ParseInt(id, 10, 64) 10意思为10进制,64意思为64位
		intId, _ := strconv.ParseInt(id, 10, 64)
		boolFinish, _ := strconv.ParseBool(finish)

		_, err := models.FinishTodo(intId, !boolFinish)
		if err != nil {
			showError(w, "异常", "完成Todo失败")
			return
		}
		http.Redirect(w, r, "/", http.StatusSeeOther)
		return
	}
}

func DeleteTodo(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		showError(w, "异常", "非法请求")
	} else {
		id := r.FormValue("id")
		intId, _ := strconv.ParseInt(id, 10, 64)
		_, err := models.DeleteTodo(intId)
		if err != nil {
			showError(w, "异常", "删除失败")
			return
		}
		http.Redirect(w, r, "/", http.StatusSeeOther)
		return
	}
}

func EditTodo(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		// 显示edit页面
		// 本可以将title内容提交至此,但url将会异常难看,还是根据id查询吧
		id := r.FormValue("id")
		intId, _ := strconv.ParseInt(id, 10, 64)
		title, err := models.GetTodoTitle(intId)
		if err != nil {
			showError(w, "异常", "查询Todo内容失败")
			return
		}
		t, _ := template.ParseFiles("views/edit.html")
		data := make(map[string]string)
		data["Id"] = id
		data["Title"] = title
		t.Execute(w, data)

	} else if r.Method == "POST" {
		// edit后的数据post提交至此处
		id, _ := strconv.ParseInt(r.FormValue("id"), 10, 64)
		title := r.FormValue("title")
		res, err := models.EditTodo(id, title)
		if err != nil || res <= 0 {
			showError(w, "异常", "修改失败")
			return
		}
		http.Redirect(w, r, "/", http.StatusSeeOther)
		return

	}
}

// 错误处理
func showError(w http.ResponseWriter, title string, message string) {
	t, _ := template.ParseFiles("views/error.html")
	data := make(map[string]string)
	data["title"] = title
	data["message"] = message
	t.Execute(w, data)
}

数据库使用了sqlite3数据库,使用github.com/mattn/go-sqlite3软件包

Mac的用户可以试试一款极好的sqlite数据库管理工具:http://download.csdn.net/detail/luck_apple/8436489 (0资源分)

再看看我们的model,TodoModel.go:

package models

import (
	"database/sql"
	_ "github.com/mattn/go-sqlite3"
)

// 为开发方便,使用sqlite数据库
type Todo struct {
	Id     int64
	Title  string
	Finish bool
}

func InsertTodo(title string) (int64, error) {
	// 数据库path是相对路径(相对于main.go)
	db, err := sql.Open("sqlite3", "./data/data.db")
	// 函数代码执行完后关闭数据库,这是个好习惯,我爱defer
	defer db.Close()
	if err != nil {
		return -1, err
	}

	stmt, err := db.Prepare("INSERT INTO todo(title, finish) VALUES(?, ?)")
	defer stmt.Close()
	if err != nil {
		return -1, err
	}

	res, err := stmt.Exec(title, false)
	if err != nil {
		return -1, err
	}
	return res.LastInsertId()
}

func QueryAll() ([]Todo, error) {
	db, err := sql.Open("sqlite3", "./data/data.db")
	defer db.Close()
	if err != nil {
		return nil, err
	}

	rows, err := db.Query("SELECT * FROM todo")
	defer rows.Close()
	if err != nil {
		return nil, err
	}

	var todos []Todo

	for rows.Next() {
		var id int64
		var title string
		var finish bool
		err = rows.Scan(&id, &title, &finish)
		if err != nil {
			return nil, err
		}
		todo := Todo{id, title, finish}
		todos = append(todos, todo)
	}
	return todos, nil
}

func FinishTodo(todoId int64, finish bool) (int64, error) {
	db, err := sql.Open("sqlite3", "./data/data.db")
	defer db.Close()
	if err != nil {
		return 0, err
	}
	stmt, err := db.Prepare("UPDATE todo SET finish=? WHERE id=?")
	defer stmt.Close()
	if err != nil {
		return 0, nil
	}

	res, err := stmt.Exec(finish, todoId)
	if err != nil {
		return 0, nil
	}
	affect, err := res.RowsAffected()
	if err != nil {
		return 0, nil
	}
	return affect, nil
}

func DeleteTodo(todoId int64) (int64, error) {
	db, err := sql.Open("sqlite3", "./data/data.db")
	defer db.Close()
	if err != nil {
		return 0, err
	}
	stmt, err := db.Prepare("DELETE FROM todo WHERE id=?")
	if err != nil {
		return 0, err
	}
	res, err := stmt.Exec(todoId)
	if err != nil {
		return 0, nil
	}
	affect, err := res.RowsAffected()
	if err != nil {
		return 0, nil
	}
	return affect, nil
}

func GetTodoTitle(todoId int64) (string, error) {
	db, err := sql.Open("sqlite3", "./data/data.db")
	defer db.Close()
	if err != nil {
		return "", err
	}
	// 只查询一行数据
	row := db.QueryRow("SELECT title FROM todo WHERE id=?", todoId)
	var title string
	e := row.Scan(&title)
	if e != nil {
		return "", e
	}
	return title, nil
}

func EditTodo(id int64, title string) (int64, error) {
	db, err := sql.Open("sqlite3", "./data/data.db")
	defer db.Close()
	if err != nil {
		return 0, err
	}
	stmt, err := db.Prepare("UPDATE todo SET title=? WHERE id=?")
	defer stmt.Close()
	if err != nil {
		return 0, nil
	}

	res, err := stmt.Exec(title, id)
	if err != nil {
		return 0, nil
	}
	affect, err := res.RowsAffected()
	if err != nil {
		return 0, nil
	}
	return affect, nil
}

至于view,代码就比较多了,不再贴出来了。

代码下载地址:http://download.csdn.net/detail/luck_apple/8436475 (0资源分)


golang todo实例

标签:golang   go语言   实例   todo   

原文地址:http://blog.csdn.net/luck_apple/article/details/43681495

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!