之前,已经讲过很多Golang的东西,比如基础语法,mysql的使用,redis的使用等等,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.html

今天就用从头写一个完整的go的示例项目吧。

本项目完全使用原生开发,没有使用任何WEB框架和ORM。虽然大家对mvc 呀,三层架构已经很了解了。但是,我还是想从头写一个完整的示例项目。这样大家有一个更深刻的了解,这样以后介绍web框架,orm框架的时候,学习起来应该会简单一点。
 

项目架构

下图这种架构模式相信大家应该十分清楚

Controller组合封装

Controller"基类"封装

package framework

type Controller struct {
Data interface{}
}

UserController定义了用户注册,登录和查询等简单的三个接口

package controller

import (
"net/http"
"micro-cloud/service"
"micro-cloud/utils"
"micro-cloud/framework"
) /**
* r.PostFormValue : 可以解析 Post/PUT Content-Type=application/x-www-form-urlencoded 或 Content-Type=multipart/form-data
*/ type UserConterller struct { } var userService = new(service.UserService) func (p *UserConterller) Router(router *framework.RouterHandler) {
router.Router("/register", p.register)
router.Router("/login", p.login)
router.Router("/findAll", p.findAll)
} //POST Content-Type=application/x-www-form-urlencoded
func (p *UserConterller) register(w http.ResponseWriter, r *http.Request) {
username := r.PostFormValue("username")
password := r.PostFormValue("password")
if utils.Empty(username) || utils.Empty(password) {
microcloud.ResultFail(w, "username or password can not be empty")
return
}
id := userService.Insert(username, password)
if id <= 0 {
microcloud.ResultFail(w, "register fail")
return
}
microcloud.ResultOk(w, "register success")
} //POST Content-Type=application/x-www-form-urlencoded
func (p *UserConterller) login(w http.ResponseWriter, r *http.Request) {
username := r.PostFormValue("username")
password := r.PostFormValue("password")
if utils.Empty(username) || utils.Empty(password) {
microcloud.ResultFail(w, "username or password can not be empty")
return
}
users := userService.SelectUserByName(username)
if len(users) == 0 {
microcloud.ResultFail(w, "user does not exist")
return
}
if users[0].Password != password {
microcloud.ResultFail(w, "password error")
return
} microcloud.ResultOk(w, "login success")
} // GET/POST
func (p *UserConterller) findAll(w http.ResponseWriter, r *http.Request) {
users := userService.SelectAllUser()
framework.ResultJsonOk(w, users)
}

数据访问层

package dao

import (
"micro-cloud/model"
"fmt"
) type UserDao struct {
} func (p *UserDao) Insert(user *model.User) int64 {
result, err := framework.DB.Exec("INSERT INTO user(`username`,`password`,`create_time`) value(?,?,?)", user.Username, user.Password, user.CreateTime)
if err != nil {
fmt.Println("Insert error")
return
}
id, err := result.LastInsertId()
if err != nil {
fmt.Println("Insert error")
return
}
return id
} func (p *UserDao) SelectUserByName(username string) []model.User {
rows, err := framework.DB.Query("SELECT * FROM user WHERE username = ?", username)
if err != nil {
fmt.Println("selectuserbyname error")
return nil
}
var users []model.User
for rows.Next() {
var user model.User
err := rows.Scan(&user.ID, &user.Username, &user.Password, &user.CreateTime)
if err != nil {
fmt.Println("selectuserbyname error")
continue
}
users = append(users, user)
}
rows.Close()
return users
} func (p *UserDao) SelectAllUser() []model.User {
rows, err := framework.DB.Query("SELECT * FROM user")
if err != nil {
fmt.Println("SelectAllUser error")
return nil
}
var users []model.User
for rows.Next() {
var user model.User
err := rows.Scan(&user.ID, &user.Username, &user.Password, &user.CreateTime)
if err != nil {
fmt.Println("SelectAllUser error")
continue
}
users = append(users, user)
}
rows.Close()
return users
}

实体层

package model

import "time"

type User struct {
ID uint `json:"id"`
Username string `json:"username"`
Password string `json:"-"`
CreateTime time.Time `json:"create_time"`
}

database

数据库操作类的实现

package microcloud

import (
"database/sql"
"log"
"strings"
_ "github.com/go-sql-driver/mysql"
) //数据库的配置
const (
username = "admin"
password = "123456"
ip = "10.2.1.5"
port = "3306"
dbName = "microcloud"
driverName = "mysql"
) //DB数据库连接池
var DB *sql.DB func InitDB() {
//构建连接:"用户名:密码@tcp(IP:端口)/数据库?charset=uft8"
//注意:要想解析time.Time类型,必须要设置parseTime=True
path := strings.Join([]string{username, ":", password, "@tcp(", ip, ":", port, ")/", dbName, "?charset=utf8&parseTime=True&loc=Local"}, "")
//打开数据库,前者是驱动名,所以要导入:_"github.com/go-sql-driver/mysql"
DB, _ = sql.Open(driverName, path)
//设置数据库最大连接数
DB.SetConnMaxLifetime(100)
//设置数据库最大闲置连接数
DB.SetMaxIdleConns(10)
//验证连接
if err := DB.Ping(); err != nil {
log.Panic(err)
}
log.Println("database connect success")
} func CreateTable() {
userTable := "CREATE TABLE IF NOT EXISTS `user`(" +
"`id` INT UNSIGNED AUTO_INCREMENT," +
"`username` VARCHAR(20) NOT NULL," +
"`password` VARCHAR(40) NOT NULL," +
"`create_time` DATETIME," +
"PRIMARY KEY ( `id` )" +
")ENGINE=InnoDB DEFAULT CHARSET=utf8;" _, err := DB.Exec(userTable)
if err != nil {
log.Panic(err)
}
}

http

http server的实现

    server := &http.Server{
Addr: ":8215",
Handler: microcloud.Router,
ReadTimeout: * time.Second,
}
RegiterRouter(microcloud.Router)
err := server.ListenAndServe()
if err != nil {
log.Panic(err)
}

Router

路由处理的实现,其实也就是一个转发的功能

type RouterHandler struct {
} var mux = make(map[string]func(http.ResponseWriter,*http.Request)) func (p *RouterHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Println(r.URL.Path)
if fun, ok := mux[r.URL.Path]; ok {
fun(w, r)
return
}
//静态资源
if strings.HasPrefix(r.URL.Path,constant.STATIC_BAES_PATH){
if fun, ok := mux[constant.STATIC_BAES_PATH]; ok {
fun(w, r)
return
}
}
http.Error(w, "error URL:"+r.URL.String(), http.StatusBadRequest) } func (p *RouterHandler) Router(relativePath string, handler func(http.ResponseWriter, *http.Request)) {
mux[relativePath] = handler
}

演示

执行 go run main.go 之后,打开Postman,调相关的接口

以下就是访问API的请求与响应

/findAll 接口

/register 接口

最后

以上,用Go语言实现webapi 的例子,已经介绍完了,虽然比较简单,session,权限验证等都没有加。但是最主要的功能已经讲完了,感兴趣的可以从头编写下相关的代码。

完整例子下载:microcloud.rar

Golang 入门系列(十一)Go语言实现webapi的更多相关文章

  1. 【Go语言入门系列】Go语言工作目录介绍及命令工具的使用

    [Go语言入门系列]前面的文章: [保姆级教程]手把手教你进行Go语言环境安装及相关VSCode配置 [Go语言入门系列](八)Go语言是不是面向对象语言? [Go语言入门系列](九)写这些就是为了搞 ...

  2. ABP入门系列(16)——通过webapi与系统进行交互

    ABP入门系列目录--学习Abp框架之实操演练 源码路径:Github-LearningMpaAbp 1. 引言 上一节我们讲解了如何创建微信公众号模块,这一节我们就继续跟进,来讲一讲公众号模块如何与 ...

  3. Golang 入门系列(五)GO语言中的面向对象

    前面讲了很多Go 语言的基础知识,包括go环境的安装,go语言的语法等,感兴趣的朋友可以先看看之前的文章.https://www.cnblogs.com/zhangweizhong/category/ ...

  4. Golang 入门系列(三)Go语言基础知识汇总

    前面已经了 Go 环境的配置和初学Go时,容易遇到的坑,大家可以请查看前面的文章 https://www.cnblogs.com/zhangweizhong/category/1275863.html ...

  5. Golang 入门系列(二)学习Go语言需要注意的坑

    上一章节我们已经了解了 Go 环境的配置,不了解的,请查看前面的文章 https://www.cnblogs.com/zhangweizhong/p/9459945.html,本章节我们将学习 Go ...

  6. Golang 入门系列(十五)如何理解go的并发?

    前面已经讲过很多Golang系列知识,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.html, 接下来要说的 ...

  7. Golang 入门系列(十) mysql数据库的使用

    之前,已经讲过一些Golang的基础的东西,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.html, 今天简 ...

  8. Golang 入门系列(九) 如何读取YAML,JSON,INI等配置文件

    实际项目中,读取相关的系统配置文件是很常见的事情.今天就来说一说,Golang 是如何读取YAML,JSON,INI等配置文件的. 1. json使用 JSON 应该比较熟悉,它是一种轻量级的数据交换 ...

  9. Golang 入门系列(七) Redis的使用

    安装 1. Redis 的安装很简单,我这里测试直接用的是windows 的版本.如何安装就不细说了.想了解的可以看之前的文章:https://www.cnblogs.com/zhangweizhon ...

随机推荐

  1. Docker最全教程——从理论到实战(四)

    往期内容链接 https://www.cnblogs.com/codelove/p/10030439.html https://www.cnblogs.com/codelove/p/10036608. ...

  2. [零]java8 函数式编程入门官方文档中文版 java.util.stream 中文版 流处理的相关概念

    前言 本文为java.util.stream 包文档的译文 极其个别部分可能为了更好理解,陈述略有改动,与原文几乎一致 原文可参考在线API文档 https://docs.oracle.com/jav ...

  3. java 标准输出与标准错误 out与 err 区别 用法 联系 java中的out与err区别 System.out和System.err的区别 System.out.println和System.err.println的区别 Java重定向System.out和System.err

    本文关键词: java 标准输出与标准错误    out与 err 区别 用法 联系  java中的out与err区别  System.out和System.err的区别 System.out.pri ...

  4. 痞子衡嵌入式:飞思卡尔i.MX RT系列MCU启动那些事(6)- Bootable image格式与加载(elftosb/.bd)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是飞思卡尔i.MX RT系列MCU的Bootable image格式与加载过程. 在i.MXRT启动系列第三篇文章 Serial Down ...

  5. windows server 2012/2016 设置多用户远程桌面(转载)

    方案一: 该方案只能满足两个人同时远程. 方案二: https://blog.csdn.net/flyingshuai/article/details/77869279

  6. .class文件查看

    十六进制查看(不仅class文件可以看,其他文件格式也可以) hexdump -C XXX.class #注意C是大写(小写c则输出十进制) 反汇编查看 javap -c XXX.class java ...

  7. 讲讲跳跃表(Skip Lists)

    跳跃表(Skip Lists)是一种有序的数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的.在大部分情况下,跳跃表的效率可以和平衡树相媲美,并且在实现上比平衡树要更为 ...

  8. 【Dojo 1.x】笔记5 使用本地引用

    习惯用CDN引用的同学肯定会知道还有一种叫本地引用,这篇笔记测试本地引用. Dojo SDK下载地址:点我 下载中间的Release Package即可,如果希望下载完整包(Full Source), ...

  9. Dynamics 365-如何下载新版本的Tools

    最近新写了个Plugin,想注册到CRM中,但是使用旧版的PluginRegistration Tool的时候,总是加载不出来Plugin数据,所以寻思下载个最新版的Tool试试.现在下载Tools的 ...

  10. alibaba fastjson 使用

    // 对象转 json 字符串 User user1 = new User("Marry", 30, new Date()); String str1 = JSON.toJSONS ...