从课程内容来说,对于初学者来说 十分我给7分。。。
加分的是 秒杀这种场景使用的技术,
但想入手iris框架 还是看看其他的课吧~
在window启动RabitMq 启动出现如下错误,请看这篇博客
DIAGNOSTICS
===========
attempted to contact: [rabbit@MVUIBUDNQI33TUM]
rabbit@MVUIBUDNQI33TUM:
* connected to epmd (port 4369) on MVUIBUDNQI33TUM
* epmd reports node 'rabbit' uses port 25672 for inter-node and CLI tool traffic
* TCP connection succeeded but Erlang distribution failed
* Authentication failed (rejected by the remote node), please check the Erlang cookie
1、以应用方式启动
rabbitmq-server -detached 后台启动
Rabbitmq-server 直接启动,如果你关闭窗口或者需要在改窗口使用其他命令时应用就会停止
关闭:rabbitmqctl stop
2、以服务方式启动(安装完之后在任务管理器中服务一栏能看到RabbtiMq)
rabbitmq-service install 安装服务
rabbitmq-service start 开始服务
Rabbitmq-service stop 停止服务
Rabbitmq-service enable 使服务有效
Rabbitmq-service disable 使服务无效
rabbitmq-service help 帮助
当rabbitmq-service install之后默认服务是enable的,如果这时设置服务为disable的话,rabbitmq-service start就会报错。
当rabbitmq-service start正常启动服务之后,使用disable是没有效果的
关闭:rabbitmqctl stop
3、Rabbitmq 管理插件启动,可视化界面
rabbitmq-plugins enable rabbitmq_management 启动
rabbitmq-plugins disable rabbitmq_management 关闭
Connection: 连接,应用程序与Broker的网络连接。
**Channel: **网络信道,几乎所有的操作都在 Channel 中进行,Channel是进行消息读写的通道。客户端可建立多个Channel:,每个Channel代表一个会话任务。
**Virtual host: **虚似地址,用于迸行逻辑隔离,是最上层的消息路由。一个 Virtual Host 里面可以有若干个 Exchange和 Queue ,同一个 VirtualHost 里面不能有相同名称的 Exchange 或 Queue。权限控制的最小粒度是Virtual Host。
Binding: Exchange 和 Queue 之间的虚拟连接,binding 中可以包含 routing key。
Routing key: 一 个路由规则,虚拟机可用它来确定如何路由一个特定消息,即交换机绑定到 Queue 的键。
Queue: 也称为Message Queue,消息队列,保存消息并将它们转发给消费者。
建立账号
3-4 RabbitMQ工作模式—Simple模式(上)
https://www.cnblogs.com/haixiang/p/10853467.html
3-5 RabbitMQ工作模式—Simple模式(中)
package main
import (
"fmt"
"log"
"github.com/streadway/amqp"
)
const MQURL = "amqp://immocuser:[email protected]:5672/imoooc"
type RabbitMQ struct {
conn *amqp.Connection
channel *amqp.Channel
QueueName string
Exchange string
Key string
Mqurl string
}
// 创建RabbitMQ 结构体实例
func NewRabbitMQ(queueName string, exchange string, key string) *RabbitMQ {
rabbitmq := &RabbitMQ{QueueName: queueName, Exchange: exchange, Key: key, Mqurl: MQURL}
// 创建简单模式的RabbitMQ实例
var err error
// 连接 rabbitmq
rabbitmq.conn, err = amqp.Dial(rabbitmq.Mqurl)
rabbitmq.failOnErr(err, "创建连接错误")
rabbitmq.channel, err = rabbitmq.conn.Channel()
rabbitmq.failOnErr(err, "获取channel 失败")
return rabbitmq
}
// close RabbitMQ channel and connection
func (r *RabbitMQ) Destory() {
r.channel.Close()
r.conn.Close()
}
// err handler
func (r *RabbitMQ) failOnErr(err error, message string) {
if err != nil {
log.Fatalf("%s%:s", message, err)
panic(fmt.Sprintf("%s:%s", message, err))
}
}
// 创建简单模式的RabbitMQ实例
func NewRabbitSimple(queueName string) *RabbitMQ {
return NewRabbitMQ(queueName, "", "")
}
// 简单模式
func (r *RabbitMQ) PublishSimple(message string) {
// 1. 申请队列, 不存在则自动创建, 存在则跳过
// 作用: 保证消息发送队列中
_, err := r.channel.QueueDeclare(
r.QueueName,
// 是否持久化
false,
//是否自动删除
false,
// 是否排他
false,
// 是否阻塞
false,
nil,
)
if err != nil {
fmt.Println(err)
}
// 发送消息到队列中
r.channel.Publish(
// 交换机
r.Exchange,
r.QueueName,
// true会根据Exchange类型如果无法找到条件的队列,会把消息返回
false,
// true Exchange发送消息到队列上,没有发现绑定消费者,会返回
false,
// 发送信息格式
amqp.Publishing{
ContentType:"text/plain",
Body:[]byte(message),
}
)
}
func main() {
fmt.Print("6666")
fmt.Println("")
fmt.Println("666")
}
自闭中。。。后续再写这个项目吧。。。
3-6 RabbitMQ工作模式—Simple模式(下)
3-7 RabbitMQ工作模式—Work模式
3-8 RabbitMQ工作模式—Publish模式试看
3-9 RabbitMQ工作模式—Routing模式
3-10 RabbitMQ工作模式—Topic模式
3-11 【扩展资料】CentOS7 之基础设置及常见操作命令
3-12 【阶段总结】环境搭建之初识RabbitMQ
3-13 【勤于思考,夯实学习成果】阶段练习题
package datamodels
// 商品
type Product struct {
Id int64 `json:"Id" sql:"id" imooc:"Id"`
ProductName string `json:"ProductName" sql:"productName" imooc:"ProductName"`
ProductNum int64 `json:"ProductNum" sql:"productNum" imooc:"ProductNum"`
ProductImage string `json:"ProductImage" sql:"productImage" imooc:"ProductImage"`
ProductUrl string `json:"ProductUrl" sql:"productUrl" imooc:"ProductUrl"`
}
package common
import (
"database/sql"
)
import _ "github.com/go-sql-driver/mysql"
func NewMysqlConn() (db *sql.DB, err error) {
db, err = sql.Open("mysql", "root:root123@tcp(127.0.0.1:3306)/imooc?charset=utf8")
return
}
func GetResultRow(rows *sql.Rows) map[string]string {
columns, _ := rows.Columns()
scanArgs := make([]interface{}, len(columns))
values := make([][]byte, len(columns))
for j := range values {
scanArgs[j] = &values[j]
}
record := make(map[string]string)
for rows.Next() {
rows.Scan(scanArgs...)
for i, v := range values {
if v != nil {
record[columns[i]] = string(v)
}
}
}
return record
}
func GetResultRows(rows *sql.Rows) map[int]map[string]string {
columns, _ := rows.Columns()
vals := make([][]byte, len(columns))
scans := make([]interface{}, len(columns))
for k, _ := range vals {
scans[k] = &vals[k]
}
i := 0
result := make(map[int]map[string]string)
for rows.Next() {
rows.Scan(scans...)
row := make(map[string]string)
for k, v := range vals {
key := columns[k]
row[key] = string(v)
}
result[i] = row
i++
}
return result
}
package repositories
import (
"database/sql"
"imooc-product/common"
"imooc-product/datamodels"
"strconv"
)
//先开发接口
//实现定义的接口
type IProduct interface {
//连接数据库
Conn() error
Insert(*datamodels.Product)(int64, error)
Delete(int64) bool
Update(*datamodels.Product) error
SelectByKey(int64)(*datamodels.Product, error)
SelectAll() ([]*datamodels.Product, error)
SubProductNum (productId int64) error
}
type ProductManager struct {
table string
mysqlConn *sql.DB
}
func NewProductManager(table string, db *sql.DB) IProduct {
return &ProductManager{table:table,mysqlConn:db}
}
func (p *ProductManager) Conn() (err error) {
if p.mysqlConn == nil {
mysql, err := common.NewMysqlConn()
if err != nil {
return err
}
p.mysqlConn = mysql
}
if p.table == "" {
p.table = "product"
}
return
}
func (p *ProductManager) Insert(product *datamodels.Product) (productId int64,err error) {
if err = p.Conn();err != nil {
return
}
sql := "insert into product(productName, productNum, productImage, productUrl) values (?, ?, ?, ?)"
stmt, err := p.mysqlConn.Prepare(sql)
if err != nil {
return
}
result, err := stmt.Exec(product.ProductName, product.ProductNum, product.ProductImage, product.ProductUrl)
if err != nil {
return
}
productId, err = result.LastInsertId()
return
}
func (p *ProductManager) Delete(productId int64) bool {
if err := p.Conn();err != nil {
return false
}
sql := "delete from product where id = ?"
stmt, err := p.mysqlConn.Prepare(sql)
if err != nil {
return false
}
_, err = stmt.Exec(productId)
if err != nil {
return false
}
return true
}
func (p *ProductManager) Update(product *datamodels.Product) error {
if err := p.Conn();err != nil {
return err
}
sql := "update product set productName = ? , productNum = ? , productImage = ?, productUrl = ? where id=" + strconv.FormatInt(product.Id, 10)
stmt, err := p.mysqlConn.Prepare(sql)
if err != nil {
return err
}
_, err = stmt.Exec(product.ProductName, product.ProductNum, product.ProductImage, product.ProductUrl)
if err != nil {
return err
}
return nil
}
func (p *ProductManager) SelectByKey(productId int64) (product *datamodels.Product, err error) {
if err = p.Conn();err != nil {
return &datamodels.Product{}, err
}
sql := "select * from " + p.table + " where id = " + strconv.FormatInt(productId, 10)
row, err := p.mysqlConn.Query(sql)
if err != nil {
return &datamodels.Product{}, err
}
defer row.Close()
result := common.GetResultRow(row)
if len(result) == 0 {
return &datamodels.Product{}, nil
}
product = &datamodels.Product{}
common.DataToStructByTagSql(result, product)
return product, nil
}
查找到条记录
func GetResultRow(rows *sql.Rows) map[string]string {
columns, _ := rows.Columns()
scanArgs := make([]interface{}, len(columns))
values := make([][]byte, len(columns))
for j := range values {
scanArgs[j] = &values[j]
}
record := make(map[string]string)
for rows.Next() {
rows.Scan(scanArgs...)
for i, v := range values {
if v != nil {
record[columns[i]] = string(v)
}
}
}
return record
}
根据结构体中sql标签映射数据到结构体中并且转换类型
package common
import (
"errors"
"reflect"
"strconv"
"time"
)
func DataToStructByTagSql(data map[string]string, obj interface{}) {
objValue := reflect.ValueOf(obj).Elem()
for i := 0; i < objValue.NumField(); i++ {
//获取sql对应的值
value := data[objValue.Type().Field(i).Tag.Get("sql")]
//获取对应字段的名称
name := objValue.Type().Field(i).Name
//获取对应字段类型
structFieldType := objValue.Field(i).Type()
//获取变量类型,也可以直接写"string类型"
val := reflect.ValueOf(value)
var err error
if structFieldType != val.Type() {
//类型转换
val, err = TypeConversion(value, structFieldType.Name()) //类型转换
if err != nil {
}
}
//设置类型值
objValue.FieldByName(name).Set(val)
}
}
func (p *ProductManager) SelectAll() ([]*datamodels.Product,error) {
if err := p.Conn();err != nil {
return nil, err
}
sql := "select * from " + p.table
rows,err := p.mysqlConn.Query(sql)
if err != nil {
return nil, err
}
defer rows.Close()
result := common.GetResultRows(rows)
if len(result) == 0 {
return nil, nil
}
productArray := make([]*datamodels.Product, 0)
for _, v := range result {
product := &datamodels.Product{}
common.DataToStructByTagSql(v, product)
productArray = append(productArray, product)
}
return productArray, nil
}
func (p *ProductManager) SubProductNum(productId int64) error {
if err := p.Conn();err != nil {
return err
}
sql := "update " + p.table + " set productNum=productNum -1 where id=" + strconv.FormatInt(productId, 10)
stmt, err := p.mysqlConn.Prepare(sql)
if err != nil {
return err
}
_, err = stmt.Exec()
return err
}
package main
import (
gcontext "context"
"github.com/kataras/iris"
"github.com/kataras/iris/context"
"github.com/kataras/iris/mvc"
"imooc-product/backend/web/controllers"
"imooc-product/common"
"imooc-product/repositories"
"imooc-product/services"
"log"
)
func main() {
//创建iris实例
app := iris.New()
//设置错误模式,在mvc模式下提示错误
app.Logger().SetLevel("debug")
//注册模版
template := iris.HTML("./backend/web/views", ".html").Layout("shared/layout.html").Reload(true)
app.RegisterView(template)
//设置模版目标
app.StaticWeb("/assets", "./backend/web/assets")
//出现异常跳转导指定页面
app.OnAnyErrorCode(func(ctx context.Context) {
ctx.ViewData("message", ctx.Values().GetStringDefault("message", "访问的页面出错!"))
ctx.ViewLayout("")
ctx.View("shared/error.html")
})
//注册控制器
db, err := common.NewMysqlConn()
if err != nil {
log.Fatal(err)
}
ctx, cancel := gcontext.WithCancel(gcontext.Background())
defer cancel()
// NewProductManager中定义所有的db sql查询
productRepository := repositories.NewProductManager("product", db)
// services层用来配合controller层与db交互
productService := services.NewProductService(productRepository)
productParty := app.Party("/product")
product := mvc.New(productParty)
product.Register(ctx, productService)
product.Handle(new(controllers.ProductController))
orderRepository := repositories.NewOrderManagerRepository("`order`", db)
orderService := services.NewOrderService(orderRepository)
orderParty := app.Party("/order")
order := mvc.New(orderParty)
order.Register(ctx, orderService)
order.Handle(new(controllers.OrderController))
//启动服务
app.Run(
iris.Addr("localhost:8081"),
iris.WithoutServerError(iris.ErrServerClosed),
iris.WithOptimizations,
)
}
services.IProductService 存放着对数据库的操作
package controllers
import (
"github.com/kataras/iris"
"github.com/kataras/iris/mvc"
"imooc-product/common"
"imooc-product/datamodels"
"imooc-product/services"
"strconv"
)
type ProductController struct {
Ctx iris.Context
ProductService services.IProductService
}
func (p *ProductController) GetAll() mvc.View {
productArray , _ := p.ProductService.GetAllProduct()
return mvc.View{
Name:"product/view.html",
Data:iris.Map{
"productArray":productArray,
},
}
}
func (p *ProductController) PostUpdate() {
product := &datamodels.Product{}
p.Ctx.Request().ParseForm()
dec := common.NewDecoder(&common.DecoderOptions{TagName:"imooc"})
if err := dec.Decode(p.Ctx.Request().Form, product);err != nil {
p.Ctx.Application().Logger().Debug(err)
}
err := p.ProductService.UpdateProduct(product)
if err != nil {
p.Ctx.Application().Logger().Debug(err)
}
p.Ctx.Redirect("/product/all")
}
// NewProductManager中定义所有的db sql查询
productRepository := repositories.NewProductManager("product", db)
// services层用来配合controller层与db交互
productService := services.NewProductService(productRepository)
productParty := app.Party("/product")
product := mvc.New(productParty)
product.Register(ctx, productService)
product.Handle(new(controllers.ProductController))
的结构 都类似,就不再描述了。。。
一些总结
package encrypt
import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
)
var PwdKey = []byte("fwerc3e2ex21e234x3565v4v")
// aes加密+crt
func aesEncrypt(plainText, key []byte) ([]byte, error) {
// 1.创建一个底层使用aes的密码接口的对象
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
// 3.创建一个使用ctr加密接口对象
iv := []byte("12345678abcdefgh") //初始化向量
stream := cipher.NewCTR(block, iv)
// 4.加密
cipherText := make([]byte, len(plainText))
stream.XORKeyStream(cipherText, plainText)
return cipherText, nil
}
// aes解密
func aesDecrypt(cipherText, key []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
iv := []byte("12345678abcdefgh")
stream := cipher.NewCTR(block, iv)
plainText := make([]byte, len(cipherText))
stream.XORKeyStream(plainText, cipherText)
return plainText
}
// base64编码密文
func EnPwdCode(pwd []byte) (string, error) {
result, err := aesEncrypt(pwd, PwdKey)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(result), nil
}
// base64解码,并解密aes
func DePwdCode(pwd string) ([]byte, error) {
pwdByte, err := base64.StdEncoding.DecodeString(pwd)
if err != nil {
return nil, err
}
return aesDecrypt(pwdByte, PwdKey), nil
}
package middleware
import (
"imooc-product/encrypt"
"github.com/kataras/golog"
"github.com/kataras/iris"
)
// 校验cookie是否存在
func AuthConProduct(ctx iris.Context) {
userID := ctx.GetCookie("uid")
signKey := ctx.GetCookie("sign")
if userID == "" || signKey == "" {
golog.Debug("用户未登录")
ctx.Redirect("/user/login")
return
}
strByte, err := encrypt.DePwdCode(signKey)
if err != nil {
golog.Error("cookie解密失败", err)
return
}
if userID != string(strByte) {
golog.Debug("用户校验失败")
return
}
golog.Debug("当前用户校验成功", userID)
ctx.Next()
}