从零开始实现简单的webapi框架【Golang 入门系列十一】
之前,已经讲过很多Golang的东西,比如基础语法,mysql的使用,redis的使用等等,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.html,
今天就用从头写一个完整的go的示例项目吧。
本项目完全使用原生开发,没有使用任何WEB框架和ORM。虽然大家对mvc 呀,三层架构已经很了解了。但是,我还是想从头写一个完整的示例项目。这样大家有一个更深刻的了解,这样以后介绍web框架,orm框架的时候,学习起来应该会简单一点。
项目架构
下图这种架构模式相信大家应该十分清楚
Controller组合封装
Controller"基类"封装
package frameworktype Controller struct {Data interface{}}
UserController定义了用户注册,登录和查询等简单的三个接口
package controllerimport ("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-urlencodedfunc (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 <= {microcloud.ResultFail(w, "register fail")return}microcloud.ResultOk(w, "register success")}//POST Content-Type=application/x-www-form-urlencodedfunc (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) == {microcloud.ResultFail(w, "user does not exist")return}if users[].Password != password {microcloud.ResultFail(w, "password error")return}microcloud.ResultOk(w, "login success")}// GET/POSTfunc (p *UserConterller) findAll(w http.ResponseWriter, r *http.Request) {users := userService.SelectAllUser()framework.ResultJsonOk(w, users)}
数据访问层
package daoimport ("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.Userfor rows.Next() {var user model.Usererr := 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.Userfor rows.Next() {var user model.Usererr := 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 modelimport "time"type User struct {ID uint `json:"id"`Username string `json:"username"`Password string `json:"-"`CreateTime time.Time `json:"create_time"`}
database
数据库操作类的实现
package microcloudimport ("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.DBfunc InitDB() {//构建连接:"用户名:密码@tcp(IP:端口)/数据库?charset=uft8"//注意:要想解析time.Time类型,必须要设置parseTime=Truepath := 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: 5 * 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
相关文章