先安装包:
bash
go install github.com/peterbourgon/diskv/v3
go install github.com/rabbitmq/amqp091-go
go install github.com/rs/zerolog
go install github.com/joho/godotenv
go get github.com/mattn/go-sqlite3
go get github.com/google/uuid
go get github.com/rabbitmq/amqp091-go
//go get github.com/glebarez/sqlite
如果遇到不是WIN32程序时,终端命令行执行:
$env:CGO_ENABLED=0; go build -o bin/godesginpattern.exe .
go run main.go
项目结构:

Go
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:20
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : settings.go
*/
package config
import (
"github.com/joho/godotenv"
"os"
"strconv"
)
var (
LogLevel = "INFO"
LogDir = "./logs"
LogRotateDays = 7
DBPath = "./jewelry_msg.db"
AsyncWorkerNum = 5
UseRabbitMQ = false
RabbitHost string
RabbitPort int
RabbitUser string
RabbitPwd string
RabbitVhost = "/"
)
func InitConfig() {
_ = godotenv.Load()
RabbitHost = getEnv("RABBIT_HOST", "127.0.0.1")
portStr := getEnv("RABBIT_PORT", "5672")
RabbitPort, _ = strconv.Atoi(portStr)
RabbitUser = getEnv("RABBIT_USER", "guest")
RabbitPwd = getEnv("RABBIT_PWD", "guest")
}
func getEnv(key, def string) string {
val := os.Getenv(key)
if val == "" {
return def
}
return val
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:28
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : topics.go
*/
package config
type Topic struct {
RawMaterialPurchase string
JewelryProduction string
QualityInspection string
StoreDistribution string
JewelrySale string
AfterSalesCare string
}
var TopicConst = Topic{
RawMaterialPurchase: "RawMaterialPurchase",
JewelryProduction: "JewelryProduction",
QualityInspection: "QualityInspection",
StoreDistribution: "StoreDistribution",
JewelrySale: "JewelrySale",
AfterSalesCare: "AfterSalesCare",
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:29
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : model.go
*/
package domain
import "encoding/json"
type JewelryMessage struct {
Title string `json:"title"`
Content string `json:"content"`
Department string `json:"department"`
}
type RawMaterialPurchaseMsg struct {
JewelryMessage
Material string `json:"material"`
Quantity string `json:"quantity"`
}
type JewelryProductionMsg struct {
JewelryMessage
ProductCount int `json:"product_count"`
ProductType string `json:"product_type"`
}
type QualityInspectionMsg struct {
JewelryMessage
QualifiedCount int `json:"qualified_count"`
HasCertificate bool `json:"has_certificate"`
}
type StoreDistributionMsg struct {
JewelryMessage
StoreName string `json:"store_name"`
DistributeCount int `json:"distribute_count"`
}
type JewelrySaleMsg struct {
JewelryMessage
ProductName string `json:"product_name"`
Amount float64 `json:"amount"`
Store string `json:"store"`
}
type AfterSalesCareMsg struct {
JewelryMessage
CustomerName string `json:"customer_name"`
ServiceType string `json:"service_type"`
}
func ToJson(v any) string {
b, _ := json.MarshalIndent(v, "", " ")
return string(b)
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:30
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : log.go
*/
package logger
import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"godesginpattern/publishsubscribe/config"
"os"
"path/filepath"
)
var Logger zerolog.Logger
func InitLogger() {
_ = os.MkdirAll(config.LogDir, 0755)
logPath := filepath.Join(config.LogDir, "jewelry_pubsub.log")
f, _ := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
multi := zerolog.MultiLevelWriter(os.Stdout, f)
zerolog.TimeFieldFormat = "2006-01-02 15:04:05"
Logger = zerolog.New(multi).With().Timestamp().Caller().Logger()
log.Logger = Logger
}
Go
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:38
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : async_publisher.go
*/
package messaging
import (
"godesginpattern/publishsubscribe/config"
"godesginpattern/publishsubscribe/logger"
"sync"
)
// 统一两种发布方法的兼容包装:统一成无返回签名
type PublishFunc func(topic string, msg any)
type AsyncPublisher struct {
workerNum int
taskChan chan func()
wg sync.WaitGroup
}
var AsyncPub = NewAsyncPublisher(config.AsyncWorkerNum)
func NewAsyncPublisher(worker int) *AsyncPublisher {
ap := &AsyncPublisher{
workerNum: worker,
taskChan: make(chan func(), 100),
}
for i := 0; i < worker; i++ {
go ap.worker()
}
return ap
}
func (ap *AsyncPublisher) worker() {
for task := range ap.taskChan {
task()
ap.wg.Done()
}
}
func (ap *AsyncPublisher) PublishAsync(pub PublishFunc, topic string, msg any) {
ap.wg.Add(1)
ap.taskChan <- func() {
defer func() {
if r := recover(); r != nil {
logger.Logger.Error().Any("panic", r).Str("topic", topic).Msg("async publish panic")
}
}()
pub(topic, msg)
}
}
func (ap *AsyncPublisher) WaitAndClose() {
ap.wg.Wait()
close(ap.taskChan)
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:39
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : broker.go
*/
package messaging
import (
"godesginpattern/publishsubscribe/logger"
"sync"
)
type SubCallback func(msg any)
type PubSubBroker struct {
mu sync.RWMutex
subscribers map[string][]SubCallback
}
var LocalBroker = &PubSubBroker{
subscribers: make(map[string][]SubCallback),
}
func (b *PubSubBroker) Subscribe(topic string, cb SubCallback) {
b.mu.Lock()
defer b.mu.Unlock()
b.subscribers[topic] = append(b.subscribers[topic], cb)
logger.Logger.Info().Str("topic", topic).Str("handler", getFuncName(cb)).Msg("subscribe register success")
}
func (b *PubSubBroker) UnSubscribe(topic string, cb SubCallback) {
b.mu.Lock()
defer b.mu.Unlock()
list, ok := b.subscribers[topic]
if !ok {
return
}
newList := make([]SubCallback, 0)
for _, item := range list {
if &item != &cb {
newList = append(newList, item)
}
}
b.subscribers[topic] = newList
logger.Logger.Info().Str("topic", topic).Str("handler", getFuncName(cb)).Msg("unsubscribe success")
}
func (b *PubSubBroker) Publish(topic string, msg any) {
b.mu.RLock()
list, ok := b.subscribers[topic]
b.mu.RUnlock()
msgID := MsgStore.SavePublish(topic, msg)
logger.Logger.Info().Str("topic", topic).Str("msgID", msgID).Int("subCount", len(list)).Msg("publish message")
if !ok || len(list) == 0 {
logger.Logger.Warn().Str("topic", topic).Msg("no subscriber, only persist")
return
}
allSuccess := true
for _, cb := range list {
func() {
defer func() {
if r := recover(); r != nil {
allSuccess = false
logger.Logger.Error().Any("panic", r).Str("handler", getFuncName(cb)).Str("topic", topic).Msg("sub callback panic")
}
}()
cb(msg)
}()
}
if allSuccess {
MsgStore.MarkConsumed(msgID)
}
}
func getFuncName(f SubCallback) string {
return "callback"
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:33
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : exception.go
*/
package messaging
type PubSubException struct {
Msg string
}
func (e PubSubException) Error() string {
return e.Msg
}
type SubscriberInvalidError struct {
PubSubException
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:34
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : message_store.go
*/
package messaging
import (
"database/sql"
"github.com/google/uuid"
"godesginpattern/publishsubscribe/config"
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/logger"
_ "modernc.org/sqlite"
"time"
)
type MessageStore struct {
dbPath string
db *sql.DB
}
var MsgStore = &MessageStore{dbPath: config.DBPath}
func (m *MessageStore) initDB() error {
if m.db != nil {
return nil
}
db, err := sql.Open("sqlite", m.dbPath)
if err != nil {
return err
}
db.SetMaxOpenConns(1)
db.SetMaxIdleConns(1)
m.db = db
return nil
}
func (m *MessageStore) getConn() (*sql.DB, error) {
if err := m.initDB(); err != nil {
return nil, err
}
return m.db, nil
}
func (m *MessageStore) CreateTable() {
db, err := m.getConn()
if err != nil {
logger.Logger.Error().Err(err).Msg("open db failed")
return
}
sqlCreate := `CREATE TABLE IF NOT EXISTS message_record (
msg_id TEXT PRIMARY KEY,
topic TEXT NOT NULL,
msg_data TEXT NOT NULL,
publish_time TEXT NOT NULL,
consume_status INTEGER DEFAULT 0
)`
_, err = db.Exec(sqlCreate)
if err != nil {
logger.Logger.Error().Err(err).Msg("create table failed")
}
}
func (m *MessageStore) SavePublish(topic string, msg any) string {
msgID := uuid.NewString()
jsonStr := domain.ToJson(msg)
now := time.Now().Format("2006-01-02 15:04:05")
db, err := m.getConn()
if err != nil {
logger.Logger.Error().Err(err).Msg("save publish get conn err")
return msgID
}
_, err = db.Exec(`INSERT INTO message_record(msg_id,topic,msg_data,publish_time) VALUES (?,?,?,?)`,
msgID, topic, jsonStr, now)
if err != nil {
logger.Logger.Error().Err(err).Str("msgID", msgID).Msg("insert msg failed")
} else {
logger.Logger.Debug().Str("msgID", msgID).Str("topic", topic).Msg("message saved")
}
return msgID
}
func (m *MessageStore) MarkConsumed(msgID string) {
db, err := m.getConn()
if err != nil {
logger.Logger.Error().Err(err).Msg("mark consumed get conn err")
return
}
res, err := db.Exec(`UPDATE message_record SET consume_status=1 WHERE msg_id=?`, msgID)
if err != nil {
logger.Logger.Error().Err(err).Str("msgID", msgID).Msg("update consume status failed")
return
}
rowCnt, _ := res.RowsAffected()
if rowCnt > 0 {
logger.Logger.Debug().Str("msgID", msgID).Msg("marked consumed")
} else {
logger.Logger.Warn().Str("msgID", msgID).Msg("no record to mark consumed")
}
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:40
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : rabbit_broker.go
*/
package messaging
import (
"encoding/json"
"fmt"
"github.com/rabbitmq/amqp091-go"
"godesginpattern/publishsubscribe/config"
"godesginpattern/publishsubscribe/logger"
"sync"
)
type RabbitBroker struct {
mu sync.Mutex
conn *amqp091.Connection
channel *amqp091.Channel
subMap map[string]bool
}
var RabbitBrokerIns = &RabbitBroker{
subMap: make(map[string]bool),
}
func (r *RabbitBroker) connect() error {
r.mu.Lock()
defer r.mu.Unlock()
if r.conn != nil && !r.conn.IsClosed() {
return nil
}
url := fmt.Sprintf("amqp://%s:%s@%s:%d/%s",
config.RabbitUser, config.RabbitPwd, config.RabbitHost, config.RabbitPort, config.RabbitVhost)
conn, err := amqp091.Dial(url)
if err != nil {
return err
}
ch, err := conn.Channel()
if err != nil {
return err
}
r.conn = conn
r.channel = ch
logger.Logger.Info().Msg("rabbitmq connect success")
return nil
}
func (r *RabbitBroker) Subscribe(topic string, cb SubCallback) error {
if err := r.connect(); err != nil {
return err
}
exName := topic
_ = r.channel.ExchangeDeclare(exName, "fanout", true, false, false, false, nil)
q, err := r.channel.QueueDeclare("", true, true, true, false, nil)
if err != nil {
return err
}
_ = r.channel.QueueBind(q.Name, "", exName, false, nil)
msgs, err := r.channel.Consume(q.Name, "", false, false, false, false, nil)
if err != nil {
return err
}
go func() {
for d := range msgs {
var data map[string]any
_ = json.Unmarshal(d.Body, &data)
cb(data["data"])
_ = d.Ack(false)
}
}()
r.subMap[topic] = true
logger.Logger.Info().Str("topic", topic).Str("queue", q.Name).Msg("rabbit subscribe ok")
return nil
}
func (r *RabbitBroker) Publish(topic string, msg any) error {
if err := r.connect(); err != nil {
return err
}
exName := topic
_ = r.channel.ExchangeDeclare(exName, "fanout", true, false, false, false, nil)
msgID := MsgStore.SavePublish(topic, msg)
payload := map[string]any{
"msg_id": msgID,
"data": msg,
}
b, _ := json.Marshal(payload)
err := r.channel.Publish(exName, "", false, false, amqp091.Publishing{
Body: b,
})
if err != nil {
logger.Logger.Error().Err(err).Str("topic", topic).Msg("rabbit publish failed")
return err
}
logger.Logger.Info().Str("topic", topic).Str("msgID", msgID).Msg("rabbit publish ok")
return nil
}
func (r *RabbitBroker) WrapPublish(topic string, msg any) {
_ = r.Publish(topic, msg)
}
订阅者服务
Go
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:46
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : customer.go
*/
package subscribers
import (
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/logger"
)
func CustomerHandle(msg any) {
m, ok := msg.(domain.JewelryMessage)
if !ok {
logger.Logger.Info().Any("customer raw msg", msg)
return
}
logger.Logger.Info().Str("dept", "👥客户部").Str("title", m.Title).Str("content", m.Content).Msg("receive msg")
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:44
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : finance.go
*/
package subscribers
import (
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/logger"
)
func FinanceHandle(msg any) {
m, ok := msg.(domain.JewelryMessage)
if !ok {
logger.Logger.Info().Any("finance raw msg", msg)
return
}
logger.Logger.Info().Str("dept", "💰财务部").Str("title", m.Title).Str("content", m.Content).Msg("receive msg")
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:45
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : quality.go
*/
package subscribers
import (
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/logger"
)
func QualityHandle(msg any) {
m, ok := msg.(domain.JewelryMessage)
if !ok {
logger.Logger.Info().Any("quality raw msg", msg)
return
}
logger.Logger.Info().Str("dept", "🔍质检部").Str("title", m.Title).Str("content", m.Content).Msg("receive msg")
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:45
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : sales.go
*/
package subscribers
import (
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/logger"
)
func SalesHandle(msg any) {
m, ok := msg.(domain.JewelryMessage)
if !ok {
logger.Logger.Info().Any("sales raw msg", msg)
return
}
logger.Logger.Info().Str("dept", "🛍️销售部").Str("title", m.Title).Str("content", m.Content).Msg("receive msg")
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:46
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : store.go
*/
package subscribers
import (
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/logger"
)
func StoreHandle(msg any) {
m, ok := msg.(domain.JewelryMessage)
if !ok {
logger.Logger.Info().Any("store raw msg", msg)
return
}
logger.Logger.Info().Str("dept", "🏪门店").Str("title", m.Title).Str("content", m.Content).Msg("receive msg")
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:47
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : tech.go
*/
package subscribers
import (
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/logger"
)
func TechHandle(msg any) {
m, ok := msg.(domain.JewelryMessage)
if !ok {
logger.Logger.Info().Any("tech raw msg", msg)
return
}
logger.Logger.Info().Str("dept", "🔧技术部").Str("title", m.Title).Str("content", m.Content).Msg("receive msg")
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:43
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : warehouse.go
*/
package subscribers
import (
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/logger"
)
func WarehouseHandle(msg any) {
m, ok := msg.(domain.JewelryMessage)
if !ok {
logger.Logger.Info().Any("warehouse raw msg", msg)
return
}
logger.Logger.Info().Str("dept", "🏬仓库部").Str("title", m.Title).Str("content", m.Content).Msg("receive msg")
}
发布者服务
Go
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:50
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : after_sales.go
*/
package publishers
import (
"fmt"
"godesginpattern/publishsubscribe/config"
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/messaging"
)
func AfterSalesPublish(customerName, serviceType string) {
msg := domain.AfterSalesCareMsg{
JewelryMessage: domain.JewelryMessage{
Title: "客户售后保养申请",
Content: fmt.Sprintf("客户%s申请%s服务,已受理", customerName, serviceType),
Department: "客服部",
},
CustomerName: customerName,
ServiceType: serviceType,
}
pubFunc := getBroker()
messaging.AsyncPub.PublishAsync(pubFunc, config.TopicConst.AfterSalesCare, msg)
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:49
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : distribution.go
*/
package publishers
import (
"fmt"
"godesginpattern/publishsubscribe/config"
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/messaging"
)
func DistributionPublish(storeName string, distributeCount int) {
msg := domain.StoreDistributionMsg{
JewelryMessage: domain.JewelryMessage{
Title: "门店铺货完成",
Content: fmt.Sprintf("向%s铺货%d件珠宝,已出库发货", storeName, distributeCount),
Department: "仓库部",
},
StoreName: storeName,
DistributeCount: distributeCount,
}
pubFunc := getBroker()
messaging.AsyncPub.PublishAsync(pubFunc, config.TopicConst.StoreDistribution, msg)
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:49
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : inspection.go
*/
package publishers
import (
"fmt"
"godesginpattern/publishsubscribe/config"
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/messaging"
)
func InspectionPublish(qualifiedCount int, hasCertificate bool) {
certStr := "未出具证书"
if hasCertificate {
certStr = "已出具证书"
}
msg := domain.QualityInspectionMsg{
JewelryMessage: domain.JewelryMessage{
Title: "珠宝质量检测完成",
Content: fmt.Sprintf("总计%d件珠宝,全部合格,%s", qualifiedCount, certStr),
Department: "质检部",
},
QualifiedCount: qualifiedCount,
HasCertificate: hasCertificate,
}
pubFunc := getBroker()
messaging.AsyncPub.PublishAsync(pubFunc, config.TopicConst.QualityInspection, msg)
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:48
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : production.go
*/
package publishers
import (
"fmt"
"godesginpattern/publishsubscribe/config"
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/messaging"
)
func ProductionPublish(productType string, count int) {
msg := domain.JewelryProductionMsg{
JewelryMessage: domain.JewelryMessage{
Title: "珠宝生产完成",
Content: productType + fmt.Sprintf("%d件,待质检", count),
Department: "生产部",
},
ProductCount: count,
ProductType: productType,
}
pubFunc := getBroker()
messaging.AsyncPub.PublishAsync(pubFunc, config.TopicConst.JewelryProduction, msg)
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:48
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : purchase.go
*/
package publishers
import (
"godesginpattern/publishsubscribe/config"
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/messaging"
)
func getBroker() messaging.PublishFunc {
if config.UseRabbitMQ {
// 使用包装后的无返回方法
return messaging.RabbitBrokerIns.WrapPublish
}
// 本地Broker原生无返回,直接返回
return messaging.LocalBroker.Publish
}
func PurchasePublish(material, quantity string) {
msg := domain.RawMaterialPurchaseMsg{
JewelryMessage: domain.JewelryMessage{
Title: "原材料采购完成",
Content: material + " " + quantity + ",待入库",
Department: "采购部",
},
Material: material,
Quantity: quantity,
}
pubFunc := getBroker()
messaging.AsyncPub.PublishAsync(pubFunc, config.TopicConst.RawMaterialPurchase, msg)
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:50
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : sale.go
*/
package publishers
import (
"fmt"
"godesginpattern/publishsubscribe/config"
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/messaging"
)
func SalePublish(productName string, amount float64, store string) {
msg := domain.JewelrySaleMsg{
JewelryMessage: domain.JewelryMessage{
Title: "珠宝销售成功",
Content: fmt.Sprintf("%s售出%s,收款%.2f元,库存已扣减", store, productName, amount),
Department: "门店",
},
ProductName: productName,
Amount: amount,
Store: store,
}
pubFunc := getBroker()
messaging.AsyncPub.PublishAsync(pubFunc, config.TopicConst.JewelrySale, msg)
}
调用:
Go
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:51
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : publishsubscribebll.go
*/
package bll
import (
"godesginpattern/publishsubscribe/config"
"godesginpattern/publishsubscribe/logger"
"godesginpattern/publishsubscribe/messaging"
"godesginpattern/publishsubscribe/service/publishers"
"godesginpattern/publishsubscribe/service/subscribers"
)
func registerSubscribers() {
t := config.TopicConst
b := messaging.LocalBroker
if config.UseRabbitMQ {
panic("本地测试请将UseRabbitMQ置false")
}
b.Subscribe(t.RawMaterialPurchase, subscribers.WarehouseHandle)
b.Subscribe(t.RawMaterialPurchase, subscribers.FinanceHandle)
b.Subscribe(t.JewelryProduction, subscribers.QualityHandle)
b.Subscribe(t.JewelryProduction, subscribers.WarehouseHandle)
b.Subscribe(t.QualityInspection, subscribers.SalesHandle)
b.Subscribe(t.QualityInspection, subscribers.WarehouseHandle)
b.Subscribe(t.QualityInspection, subscribers.FinanceHandle)
b.Subscribe(t.StoreDistribution, subscribers.StoreHandle)
b.Subscribe(t.StoreDistribution, subscribers.SalesHandle)
b.Subscribe(t.JewelrySale, subscribers.FinanceHandle)
b.Subscribe(t.JewelrySale, subscribers.WarehouseHandle)
b.Subscribe(t.AfterSalesCare, subscribers.CustomerHandle)
b.Subscribe(t.AfterSalesCare, subscribers.TechHandle)
}
func PublishSubscribeMain() {
// 初始化配置、日志、数据库表
config.InitConfig()
logger.InitLogger()
messaging.MsgStore.CreateTable()
logger.Logger.Info().Msg("===== Go珠宝企业PubSub系统启动 =====")
registerSubscribers()
// 完整业务流程
publishers.PurchasePublish("18K金+天然钻石", "500克+100颗")
publishers.ProductionPublish("钻石戒指、黄金项链", 80)
publishers.InspectionPublish(80, true)
publishers.DistributionPublish("北京朝阳店、上海南京路店", 80)
publishers.SalePublish("经典六爪钻戒", 12800.0, "上海南京路店")
publishers.AfterSalesPublish("张先生", "钻石清洗、抛光保养")
// 取消订阅测试
logger.Logger.Info().Msg("执行取消仓库【珠宝销售】主题订阅")
messaging.LocalBroker.UnSubscribe(config.TopicConst.JewelrySale, subscribers.WarehouseHandle)
publishers.SalePublish("足金素圈项链", 3800.0, "北京朝阳店")
// 等待异步任务执行完成
messaging.AsyncPub.WaitAndClose()
logger.Logger.Info().Msg("===== Go珠宝企业PubSub系统运行结束 =====")
}
输出:

另一种输出:
Go
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:20
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : settings.go
*/
package config
import (
"github.com/joho/godotenv"
"os"
"strconv"
)
var (
LogLevel = "INFO"
LogDir = "./logs"
LogRotateDays = 7
DBPath = "./jewelry_msg.db"
AsyncWorkerNum = 5
UseRabbitMQ = false
RabbitHost string
RabbitPort int
RabbitUser string
RabbitPwd string
RabbitVhost = "/"
)
func InitConfig() {
_ = godotenv.Load()
RabbitHost = getEnv("RABBIT_HOST", "127.0.0.1")
portStr := getEnv("RABBIT_PORT", "5672")
RabbitPort, _ = strconv.Atoi(portStr)
RabbitUser = getEnv("RABBIT_USER", "guest")
RabbitPwd = getEnv("RABBIT_PWD", "guest")
}
func getEnv(key, def string) string {
val := os.Getenv(key)
if val == "" {
return def
}
return val
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:28
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : topics.go
*/
package config
type Topic struct {
RawMaterialPurchase string
JewelryProduction string
QualityInspection string
StoreDistribution string
JewelrySale string
AfterSalesCare string
}
var TopicConst = Topic{
RawMaterialPurchase: "RawMaterialPurchase",
JewelryProduction: "JewelryProduction",
QualityInspection: "QualityInspection",
StoreDistribution: "StoreDistribution",
JewelrySale: "JewelrySale",
AfterSalesCare: "AfterSalesCare",
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:29
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : model.go
*/
package domain
import "encoding/json"
type JewelryMessage struct {
Title string `json:"title"`
Content string `json:"content"`
Department string `json:"department"`
}
type RawMaterialPurchaseMsg struct {
JewelryMessage
Material string `json:"material"`
Quantity string `json:"quantity"`
}
type JewelryProductionMsg struct {
JewelryMessage
ProductCount int `json:"product_count"`
ProductType string `json:"product_type"`
}
type QualityInspectionMsg struct {
JewelryMessage
QualifiedCount int `json:"qualified_count"`
HasCertificate bool `json:"has_certificate"`
}
type StoreDistributionMsg struct {
JewelryMessage
StoreName string `json:"store_name"`
DistributeCount int `json:"distribute_count"`
}
type JewelrySaleMsg struct {
JewelryMessage
ProductName string `json:"product_name"`
Amount float64 `json:"amount"`
Store string `json:"store"`
}
type AfterSalesCareMsg struct {
JewelryMessage
CustomerName string `json:"customer_name"`
ServiceType string `json:"service_type"`
}
func ToJson(v any) string {
b, _ := json.MarshalIndent(v, "", " ")
return string(b)
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:30
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : log.go
*/
package logger
import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"godesginpattern/publishsubscribe/config"
"os"
"path/filepath"
)
var Logger zerolog.Logger
func InitLogger() {
_ = os.MkdirAll(config.LogDir, 0755)
logPath := filepath.Join(config.LogDir, "jewelry_pubsub.log")
f, _ := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
consoleWriter := &zerolog.ConsoleWriter{
Out: os.Stdout,
TimeFormat: "2006-01-02 15:04:05",
NoColor: true,
}
multi := zerolog.MultiLevelWriter(consoleWriter, f)
zerolog.TimeFieldFormat = "2006-01-02 15:04:05"
zerolog.SetGlobalLevel(zerolog.InfoLevel)
Logger = zerolog.New(multi).With().Timestamp().Logger()
log.Logger = Logger
}
//message 中的同上用,不用再改
订阅者服务
Go
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:46
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : customer.go
*/
package subscribers
import (
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/logger"
)
func CustomerHandle(msg any) {
var m domain.JewelryMessage
switch v := msg.(type) {
case domain.RawMaterialPurchaseMsg:
m = v.JewelryMessage
case domain.JewelryProductionMsg:
m = v.JewelryMessage
case domain.QualityInspectionMsg:
m = v.JewelryMessage
case domain.StoreDistributionMsg:
m = v.JewelryMessage
case domain.JewelrySaleMsg:
m = v.JewelryMessage
case domain.AfterSalesCareMsg:
m = v.JewelryMessage
default:
logger.Logger.Info().Any("customer raw msg", msg)
return
}
logger.Logger.Info().Msgf("👥 客户服务部 | 接收: %s | %s", m.Title, m.Content)
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:44
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : finance.go
*/
package subscribers
import (
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/logger"
)
func FinanceHandle(msg any) {
var m domain.JewelryMessage
switch v := msg.(type) {
case domain.RawMaterialPurchaseMsg:
m = v.JewelryMessage
case domain.JewelryProductionMsg:
m = v.JewelryMessage
case domain.QualityInspectionMsg:
m = v.JewelryMessage
case domain.StoreDistributionMsg:
m = v.JewelryMessage
case domain.JewelrySaleMsg:
m = v.JewelryMessage
case domain.AfterSalesCareMsg:
m = v.JewelryMessage
default:
logger.Logger.Info().Any("finance raw msg", msg)
return
}
logger.Logger.Info().Msgf("💰 财务部 | 接收: %s | %s", m.Title, m.Content)
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:45
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : quality.go
*/
package subscribers
import (
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/logger"
)
func QualityHandle(msg any) {
var m domain.JewelryMessage
switch v := msg.(type) {
case domain.RawMaterialPurchaseMsg:
m = v.JewelryMessage
case domain.JewelryProductionMsg:
m = v.JewelryMessage
case domain.QualityInspectionMsg:
m = v.JewelryMessage
case domain.StoreDistributionMsg:
m = v.JewelryMessage
case domain.JewelrySaleMsg:
m = v.JewelryMessage
case domain.AfterSalesCareMsg:
m = v.JewelryMessage
default:
logger.Logger.Info().Any("quality raw msg", msg)
return
}
logger.Logger.Info().Msgf("🔍 质检部 | 接收: %s | %s", m.Title, m.Content)
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:45
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : sales.go
*/
package subscribers
import (
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/logger"
)
func SalesHandle(msg any) {
var m domain.JewelryMessage
switch v := msg.(type) {
case domain.RawMaterialPurchaseMsg:
m = v.JewelryMessage
case domain.JewelryProductionMsg:
m = v.JewelryMessage
case domain.QualityInspectionMsg:
m = v.JewelryMessage
case domain.StoreDistributionMsg:
m = v.JewelryMessage
case domain.JewelrySaleMsg:
m = v.JewelryMessage
case domain.AfterSalesCareMsg:
m = v.JewelryMessage
default:
logger.Logger.Info().Any("sales raw msg", msg)
return
}
logger.Logger.Info().Msgf("🛍️ 营销部 | 接收: %s | %s", m.Title, m.Content)
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:46
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : store.go
*/
package subscribers
import (
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/logger"
)
func StoreHandle(msg any) {
var m domain.JewelryMessage
switch v := msg.(type) {
case domain.RawMaterialPurchaseMsg:
m = v.JewelryMessage
case domain.JewelryProductionMsg:
m = v.JewelryMessage
case domain.QualityInspectionMsg:
m = v.JewelryMessage
case domain.StoreDistributionMsg:
m = v.JewelryMessage
case domain.JewelrySaleMsg:
m = v.JewelryMessage
case domain.AfterSalesCareMsg:
m = v.JewelryMessage
default:
logger.Logger.Info().Any("store raw msg", msg)
return
}
logger.Logger.Info().Msgf("🏪 品牌门店 | 接收: %s | %s", m.Title, m.Content)
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:47
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : tech.go
*/
package subscribers
import (
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/logger"
)
func TechHandle(msg any) {
var m domain.JewelryMessage
switch v := msg.(type) {
case domain.RawMaterialPurchaseMsg:
m = v.JewelryMessage
case domain.JewelryProductionMsg:
m = v.JewelryMessage
case domain.QualityInspectionMsg:
m = v.JewelryMessage
case domain.StoreDistributionMsg:
m = v.JewelryMessage
case domain.JewelrySaleMsg:
m = v.JewelryMessage
case domain.AfterSalesCareMsg:
m = v.JewelryMessage
default:
logger.Logger.Info().Any("tech raw msg", msg)
return
}
logger.Logger.Info().Msgf("🔧 技术部 | 接收: %s | %s", m.Title, m.Content)
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:43
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : warehouse.go
*/
package subscribers
import (
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/logger"
)
func WarehouseHandle(msg any) {
var m domain.JewelryMessage
switch v := msg.(type) {
case domain.RawMaterialPurchaseMsg:
m = v.JewelryMessage
case domain.JewelryProductionMsg:
m = v.JewelryMessage
case domain.QualityInspectionMsg:
m = v.JewelryMessage
case domain.StoreDistributionMsg:
m = v.JewelryMessage
case domain.JewelrySaleMsg:
m = v.JewelryMessage
case domain.AfterSalesCareMsg:
m = v.JewelryMessage
default:
logger.Logger.Info().Any("warehouse raw msg", msg)
return
}
logger.Logger.Info().Msgf("🏬 仓库部 | 接收消息: %s | %s", m.Title, m.Content)
}
发布者服务
Go
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:50
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : after_sales.go
*/
package publishers
import (
"fmt"
"godesginpattern/publishsubscribe/config"
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/messaging"
)
func AfterSalesPublish(customerName, serviceType string) {
msg := domain.AfterSalesCareMsg{
JewelryMessage: domain.JewelryMessage{
Title: "客户售后保养申请",
Content: fmt.Sprintf("客户%s申请%s服务,已受理", customerName, serviceType),
Department: "客服部",
},
CustomerName: customerName,
ServiceType: serviceType,
}
pubFunc := getBroker()
messaging.AsyncPub.PublishAsync(pubFunc, config.TopicConst.AfterSalesCare, msg)
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:49
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : distribution.go
*/
package publishers
import (
"fmt"
"godesginpattern/publishsubscribe/config"
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/messaging"
)
func DistributionPublish(storeName string, distributeCount int) {
msg := domain.StoreDistributionMsg{
JewelryMessage: domain.JewelryMessage{
Title: "门店铺货完成",
Content: fmt.Sprintf("向%s铺货%d件珠宝,已出库发货", storeName, distributeCount),
Department: "仓库部",
},
StoreName: storeName,
DistributeCount: distributeCount,
}
pubFunc := getBroker()
messaging.AsyncPub.PublishAsync(pubFunc, config.TopicConst.StoreDistribution, msg)
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:49
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : inspection.go
*/
package publishers
import (
"fmt"
"godesginpattern/publishsubscribe/config"
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/messaging"
)
func InspectionPublish(qualifiedCount int, hasCertificate bool) {
certStr := "未出具证书"
if hasCertificate {
certStr = "已出具证书"
}
msg := domain.QualityInspectionMsg{
JewelryMessage: domain.JewelryMessage{
Title: "珠宝质量检测完成",
Content: fmt.Sprintf("总计%d件珠宝,全部合格,%s", qualifiedCount, certStr),
Department: "质检部",
},
QualifiedCount: qualifiedCount,
HasCertificate: hasCertificate,
}
pubFunc := getBroker()
messaging.AsyncPub.PublishAsync(pubFunc, config.TopicConst.QualityInspection, msg)
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:48
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : production.go
*/
package publishers
import (
"fmt"
"godesginpattern/publishsubscribe/config"
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/messaging"
)
func ProductionPublish(productType string, count int) {
msg := domain.JewelryProductionMsg{
JewelryMessage: domain.JewelryMessage{
Title: "珠宝生产完成",
Content: productType + fmt.Sprintf("%d件,待质检", count),
Department: "生产部",
},
ProductCount: count,
ProductType: productType,
}
pubFunc := getBroker()
messaging.AsyncPub.PublishAsync(pubFunc, config.TopicConst.JewelryProduction, msg)
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:48
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : purchase.go
*/
package publishers
import (
"godesginpattern/publishsubscribe/config"
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/messaging"
)
func getBroker() messaging.PublishFunc {
if config.UseRabbitMQ {
// 使用包装后的无返回方法
return messaging.RabbitBrokerIns.WrapPublish
}
// 本地Broker原生无返回,直接返回
return messaging.LocalBroker.Publish
}
func PurchasePublish(material, quantity string) {
msg := domain.RawMaterialPurchaseMsg{
JewelryMessage: domain.JewelryMessage{
Title: "原材料采购完成",
Content: material + " " + quantity + ",待入库",
Department: "采购部",
},
Material: material,
Quantity: quantity,
}
pubFunc := getBroker()
messaging.AsyncPub.PublishAsync(pubFunc, config.TopicConst.RawMaterialPurchase, msg)
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Publish/Subscribe Pattern 发布订阅模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/6/24 20:50
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : sale.go
*/
package publishers
import (
"fmt"
"godesginpattern/publishsubscribe/config"
"godesginpattern/publishsubscribe/domain"
"godesginpattern/publishsubscribe/messaging"
)
func SalePublish(productName string, amount float64, store string) {
msg := domain.JewelrySaleMsg{
JewelryMessage: domain.JewelryMessage{
Title: "珠宝销售成功",
Content: fmt.Sprintf("%s售出%s,收款%.2f元,库存已扣减", store, productName, amount),
Department: "门店",
},
ProductName: productName,
Amount: amount,
Store: store,
}
pubFunc := getBroker()
messaging.AsyncPub.PublishAsync(pubFunc, config.TopicConst.JewelrySale, msg)
}
//调用,和上面一样
输出:
SQLite:
