(一)goweb千锋教育练习项目

43 篇文章 1 订阅
30 篇文章 0 订阅

页面展示

登录页面
在这里插入图片描述
欢迎页
在这里插入图片描述

商品查询(目前我还没再mysql中添加数据,目前没有数据展示)
在这里插入图片描述
新增商品
在这里插入图片描述

一.项目搭建

  • 新建项目:ego
  • 项目结构如下
--ego
	--src 						所有go源码
		--user					业务模块包,user自定义名称,表示业务
			--User.go			编写结构体,当作实体
			--UserDao.go		数据访问
			--UserService.go	 业务逻辑
			--UserController.go	 控制器
	--static 					所有静态文件
		--js 					脚本
		--css 					样式表
		--images 				图片
	--view 						页面
	--main.go 					程序入口
  • 编写main.go,显示login.html页面(因为这是练习,html文件不需要自己去写)
package main

import (
	"net/http"
	"html/template"
)

func welcome(w http.ResponseWriter, r *http.Request) {
	t, _ := template.ParseFiles("view/login.html")
	t.Execute(w, nil)
}

func main() {
	s := http.Server{Addr: ":80"}
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
	http.HandleFunc("/", welcome)
	s.ListenAndServe()
}
  • 在浏览器输入http://localhost 测试登录页面是否显示正常
  • 页面演示如下

三.Commons编写

  • Commons中内容是所有模块都可能使用的内容
  • 在Commons中提供EgoResult.go的文件,表示前后台交互数据模版,文件内容如下
package commons

//前后台数据交互模版
type EgoResult struct {
	Status int
	Data   interface{}
	Msg    string
}
  • 提供DBUtils的.go文件,里面封装了对数据访问的代码,一共四个函数,其中Dml表示增加,删除,修改,Dql表示查询,并对外提供访问权限

    • Dql函数没有关闭数据库连接,需要调用房手动关闭
    package commons
    
    import (
    	"database/sql"
    	_ "github.com/go-sql-driver/mysql"
    	"fmt"
    )
    
    //数据库操作的三个对象
    var (
    	db   *sql.DB
    	stmt *sql.Stmt
    	rows *sql.Rows
    )
    
    //打开数据库连接,不要忘记导入驱动包
    func openConn()(err error){
    	//此处为等号,否则创建局部变量
    	db,err=sql.Open("mysql","root:smallming@tcp(localhost:3306)/ego")
    	if err!=nil{
    		fmt.Println("连接失败",err)
    		return
    	}
    	return nil
    }
    
    //关闭连接,首字母大写,需要跨包访问的
    func CloseConn(){
    	if rows!=nil{
    		rows.Close()
    	}
    	if stmt!=nil{
    		stmt.Close()
    	}
    	if db!=nil{
    		db.Close()
    	}
    }
    
    //执行DML新增,删除,修改操作
    func Dml(sql string ,args ... interface{}) (int64,error){
    	err:=openConn()
    	if err!=nil{
    		fmt.Println("执行DML时出现错误,打开连接失败")
    		return 0,err
    	}
    	//此处也是等号
    	stmt,err=db.Prepare(sql)
    	if err!=nil{
    		fmt.Println("执行DML时出现错误,预处理出现错误")
    		return 0,err
    	}
    	//此处要有...表示切片,如果没有表示数组,会报错
    	result,err:=stmt.Exec(args...)
    	if err!=nil{
    		fmt.Println("执行DML出现错误,执行错误")
    		return 0,err
    	}
    	count,err:=result.RowsAffected()
    	if err!=nil{
    		fmt.Println("执行DML出现错误,获取受影响行数错误")
    		return 0,err
    	}
    	CloseConn()//关闭连接
    	return count,err
    }
    
    
    //执行DQL查询
    func Dql(sql string,args ... interface{}) (*sql.Rows,error){
    	err:= openConn()
    	if err!=nil{
    		fmt.Println("执行DQL出现错误,打开连接失败")
    		return nil,err
    	}
    	//此处是等号
    	stmt,err=db.Prepare(sql)
    	if err!=nil{
    		fmt.Println("执行DQL出现错误,预处理实现")
    		return nil,err
    	}
    	//此处参数是切片
    	rows,err=stmt.Query(args...)
    	if err!=nil{
    		fmt.Println("执行DQL出现错误,执行错误")
    		return nil,err
    	}
    	//此处没有关闭,调用此函数要记得关闭连接
    	return rows,nil
    }
    
    

四.登录功能流程图

  • 用户登录后判断帐号和密码是否正确
  • 服务器端判断后返回EgoResult结构体对应的JSON数据,其中Status=200表示成功,成功后页面跳转到/index,Status只要不为200都表示登录失败,页面给出提示框告诉用户登录失败
  • 流程图
Created with Raphaël 2.3.0 用户输入帐号和密码,点击登录按钮,发送给服务端 服务器/login接收到登录请求 根据查询结果设置EgoResult.Status值,并以JSON响应给客户端 客户端接收JSON数据后判断Status是否为200 跳转到主页面/index 登录执行结束 弹出提示框告诉用户登录失败 yes no

五.登录代码实现

  • 在src下新建user目录
  • 在user下新建TbUser.go文件,编写实体
package user

//对应数据库中用户表
type TbUser struct {
	//属性首字母大写:1. 要转换为json   2. 可能出现跨包访问
	Id int64
	Username string
	Password string
	Phone string
	Email string
	Created string
	Updated string
}

  • 在user下新建TbUserDao.go文件,编写数据访问代码
package user

import (
	"commons"
	"fmt"
)
//根据用户名和密码查询,如果返回值为nil表示查询失败,否则成功
func SelByUnPwdDao(un, pwd string) *TbUser{
	sql := "select * from tb_user where username=? and password=? or email=? and password=? or phone=? and password=?"
	rows,err:=commons.Dql(sql, un, pwd, un, pwd, un, pwd)
	if err!=nil{
		fmt.Println(err)
		return nil
	}
	if rows.Next(){
		user:=new(TbUser)
		rows.Scan(&user.Id,&user.Username,&user.Password,&user.Phone,&user.Email,&user.Created,&user.Updated)
		commons.CloseConn()
		return user
	}
	return nil
}

  • 在user下新建TbUserService.go 编写业务逻辑代码
package user

import "commons"

func LoginService(un,pwd string) (er commons.EgoResult){
	u:=SelByUnPwdDao(un,pwd)
	if u!=nil{
		er.Status=200
	}else{
		er.Status=400
	}
	return
}

  • 在user下新建TbUserController.go编写控制器代码
package user

import (
	"net/http"
	"encoding/json"
)

//所有user模块的handler
func UserHandler() {
	http.HandleFunc("/login", loginController)
}

//登录
func loginController(w http.ResponseWriter, r *http.Request) {
	username := r.FormValue("username")
	password := r.FormValue("password")
	er := LoginService(username, password)
	//把结构体转换为json数据
	b, _ := json.Marshal(er)
	//设置响应内容为json
	w.Header().Set("Content-Type", "application/json;charset=utf-8")
	w.Write(b)
}

  • 在main.go中引用UserHandler()让user模块所有控制器生效
func main() {
	s := http.Server{Addr: ":80"}
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
	http.HandleFunc("/", welcome)
	//用户相关
	user.UserHandler()
	s.ListenAndServe()
}

六.页面整体展示

  • 确保%GOROOT%/src/github.com/下有gorilla文件夹,如果没有请进行配置(Github就可以)
  • 由于在main中声明的全局对象无法被其他包调用,所以在commons文件夹下新建CommonVars.go,保证整个项目任何包都可以使这个对象进行设置Handler
package commons

import "github.com/gorilla/mux"

var (
	Router = mux.NewRouter()
)
  • 修改main.go中代码,称为restful风格
package main

import (
	"net/http"
	"html/template"
	"user"
	"commons"
	"github.com/gorilla/mux"
)

//显示登录页面
func welcome(w http.ResponseWriter, r *http.Request) {
	t, _ := template.ParseFiles("view/login.html")
	t.Execute(w, nil)
}

//restfule风格显示页面
func showPage(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	t, _ := template.ParseFiles("view/" + vars["page"] + ".html")
	t.Execute(w, nil)
}

func main() {
	commons.Router.HandleFunc("/", welcome)
	commons.Router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
	commons.Router.HandleFunc("/page/{page}", showPage)
	//调用所有user模块的handler
	user.UserHandler()
	http.ListenAndServe(":80", commons.Router)
}
  • 修改user/UserController中UserHandler()函数
//所有user模块的handler
func UserHandler() {
	commons.Router.HandleFunc("/login", loginController)
}

七. 查询功能分析

  • 从item.html页面中复制部分脚本
    • datagrid请求的url为/showItem
    • 填充的列属性中数据除了tb_item表以外,还有CategoryName是商品对应的类目名称,存在于tb_item_cat表中,所以在查询时是两表查询
        $('#item_table').datagrid({
            url: '/showItem',
            columns: [[
                {field: 'Id', title: '商品ID', width: 100},
                {field: 'Title', title: '商品标题', width: 100},
                {field: 'CategoryName', title: '叶子类目', width: 100},
                {field: 'SellPoint', title: '卖点', width: 100},
                {field: 'Price', title: '价格', width: 100},
                {field: 'Num', title: '库存数量', width: 100},
                {field: 'Barcode', title: '条形码', width: 100},
                {field: 'Status', title: '状态', width: 100},
                {field: 'Created', title: '创建日期', width: 100},
                {field: 'Updated', title: '更新日期', width: 100}
            ]],
  • EasyUI中Datagrid分页时要求返回数据格式为:(不是EgoResult了,否则无法正确显示)
{"rows":当前页数据,"total":总条数}

八.查询功能的代码实现

  • 在commons文件夹下新建EasyUI.go
package commons

type Datagrid struct {
	//当前页显示的数据
	Rows interface{} `json:"rows"`
	//总个数
	Total int `json:"total"`
}
  • 在src下新建文件夹item,并在item文件夹下新建TbItem.go
package item

//商品
type TbItem struct {
	Id int
	Title string
	SellPoint string
	Price int
	Num int
	Barcode string
	Image string
	Cid int
	Status int8
	Created string
	Updated string
}
  • 在item下新建TbItemDao.go实现数据访问,注意当数据库中有NULL值时的转换
package item

import (
	"commons"
	"fmt"
	"database/sql"
)

/*
rows:每页显示的条数
page:当前第几页
 */
func selByPageDao(rows,page int) []TbItem{
	//第一个表示:从哪条开始查询,0算起  第二个:查询几个
	r,err:=commons.Dql("select * from tb_item limit ?,?",rows*(page-1),rows)
	if err!=nil{
		fmt.Println(err)
		return nil
	}
	ts:=make([]TbItem,0)
	for r.Next(){
		var t TbItem
		var s sql.NullString
		//如果直接使用t.Barcode由于数据库中列为Null导致填充错误
		r.Scan(&t.Id,&t.Title,&t.SellPoint,&t.Price,&t.Num,&s,&t.Image,&t.Cid,&t.Status,&t.Created,&t.Updated)
		t.Barcode=s.String
		ts=append(ts,t)
	}
	commons.CloseConn()
	return ts
}
  • 在item文件夹下新建TbItemService.go编写业务代码
    • 目前不考虑总个数的问题
package item

import "commons"

func showItemService(page,rows int) (e *commons.Datagrid){
	ts:=selByPageDao(rows,page)
	if ts!=nil{
		e= new(commons.Datagrid)
		e.Rows=ts
		return
	}
	return nil
}
  • 在item文件夹下新建TbItemController.go编写控制器
package item

import (
	"net/http"
	"strconv"
	"encoding/json"
	"commons"
)
func ItemHandler(){
	commons.Router.HandleFunc("/showItem",showItemController)
}

//显示商品信息
func showItemController(w http.ResponseWriter,r *http.Request){
	page,_:=strconv.Atoi(r.FormValue("page"))
	rows,_:=strconv.Atoi(r.FormValue("rows"))
	datagrid:=showItemService(page,rows)
	b,_:=json.Marshal(datagrid)
	w.Header().Set("Content-Type","application/json;charset=utf-8")
	w.Write(b)
}

  • 修改main.go代码,添加item模块的引用
package main

import (
	"net/http"
	"html/template"
	"user"
	"commons"
	"github.com/gorilla/mux"
	"item"
)

//显示登录页面
func welcome(w http.ResponseWriter, r *http.Request) {
	t, _ := template.ParseFiles("view/login.html")
	t.Execute(w, nil)
}
//restful显示页面
func showPage(w http.ResponseWriter, r *http.Request){
	vars:=mux.Vars(r)
	t,_:=template.ParseFiles("view/"+vars["page"]+".html")
	t.Execute(w,nil)
}
func main() {
	commons.Router.PathPrefix("/static").Handler(http.StripPrefix("/static/",http.FileServer(http.Dir("static"))))
	commons.Router.HandleFunc("/",welcome)
	//满足/page/{page}格式的处理
	commons.Router.HandleFunc("/page/{page}",showPage)
	//用户
	user.UserHandler()
	//商品
	item.ItemHandler()
	http.ListenAndServe(":80",commons.Router)
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值