Go项目(商品微服务-1)
文章目录
- 简介
- 建表
- proto
- handler
- 商品
- 小结
简介
- 商品微服务主要在于表的设计,建哪些表?表之间的关系是怎样的?
- 主要代码就是 CURD
- 表和字段的设计是一个比较有挑战性的工作,比较难说清楚,也需要经验的积累,这里关注点在微服务,暂时先 “借鉴” 别人的设计
- 一般需要多次迭代才能设计出比较合理的表结构
- 我们将商品相关的服务都放在这部分,方便建表和管理;微服务并不是越多越好,分成太多服务可能会让系统太复杂难以管理
- 如何划分微服务需要积累经验,也有针对性的方法可以套用,需要单独学习
建表
- 新建商品微服务 Service 层,直接把 user_srv 的目录拷过来,整体替换相关路径

- 表设计及相关操作,主要有四张表

- 放个商品表的结构
// 商品表 // 某一个具体的商品 type Goods struct {BaseModelCategoryID int32 `gorm:"type:int;not null"`Category Category // 一对多/一对一BrandsID int32 `gorm:"type:int;not null"`Brands Brands // 一对一OnSale bool `gorm:"default:false;not null"`ShipFree bool `gorm:"default:false;not null"`IsNew bool `gorm:"default:false;not null"`IsHot bool `gorm:"default:false;not null"`Name string `gorm:"type:varchar(50);not null"`GoodsSn string `gorm:"type:varchar(50);not null"`ClickNum int32 `gorm:"type:int;default:0;not null"`SoldNum int32 `gorm:"type:int;default:0;not null"`FavNum int32 `gorm:"type:int;default:0;not null"`MarketPrice float32 `gorm:"not null"`ShopPrice float32 `gorm:"not null"`GoodsBrief string `gorm:"type:varchar(100);not null"`Images GormList `gorm:"type:varchar(1000);not null"`DescImages GormList `gorm:"type:varchar(1000);not null"`GoodsFrontImage string `gorm:"type:varchar(200);not null"` } - 对字段的限制一般都要求
not null,也就是必须有值,然后限制用户必须输入或者我们设置default- 设置为 null 带来的问题
- 定义 model
- 注意表之间的关联关系,查看 gorm 文档了解使用方式
- 生成表结构
- 新建数据库,直接在(109.128)机器上操作,方便启动项目
CREATE DATABASE IF NOT EXISTS shop_goods_srv DEFAULT CHARSET utf8 COLLATE utf8_general_ci;- 一个微服务对应一个数据库,要和其他微服务隔离开
- 还是在 model/main 下面运行一次 main 方法即可

- 运行 sql 文件,导入数据;将上面创建的表结构全部删掉(不删也行),因为 SQL 文件里包含了建表语句

proto
- proto 文件的设计又是一个重点,首先要根据页面进行需求分析(前端页面和后台管理页面),需要哪些接口?传递哪些参数?会有什么响应?
- 接口定义也不是一蹴而就的,后面可能会修改,不必在一开始追求完美
protoc -I . goods.proto --go_out=plugins=grpc:.生成 stub 文件- 遇到点小问题,empty.proto 找不到,拷过来放到 proto/google/protobuf 下面试试
- 定义 Service 层(Server端)接口(handler),直接搜
GoodsServer,将接口定义拷过来- 这里接口太多,我们分在不同 handler 文件实现,不着急实现,先把接口定义拷过去修改一下引用,因为没有实现的话项目无法启动,
- 再修改 main.go 和 nacos 配置文件(本地/中心配置),启动项目看能否注册成功

handler
- 具体实现各接口,先从品牌和轮播图开始,这里放个获取品牌列表的例子
// 品牌 func (s *GoodsServer) BrandList(ctx context.Context, req *proto.BrandFilterRequest) (*proto.BrandListResponse, error) {brandListResponse := proto.BrandListResponse{}var brands []model.Brands// 分页:第几页,每页数量// Scopes 需要传一个匿名函数进去,在里面做一些判断并查询数据result := global.DB.Scopes(Paginate(int(req.Pages), int(req.PagePerNums))).Find(&brands)if result.Error != nil {return nil, result.Error}var total int64global.DB.Model(&model.Brands{}).Count(&total) // 单独再获取一次品牌总数brandListResponse.Total = int32(total)// 准备响应数据,单个品牌的BrandInfoResponse 和品牌列表的 brandListResponse,要根据 proto 定义的 message 安排好var brandResponses []*proto.BrandInfoResponsefor _, brand := range brands {brandResponses = append(brandResponses, &proto.BrandInfoResponse{Id: brand.ID,Name: brand.Name,Logo: brand.Logo,})}brandListResponse.Data = brandResponsesreturn &brandListResponse, nil } - 回答一个上一篇的问题:查询数据时不传表名,传入 model 定义的 struct 就可以吗?
- 是的,比如
DB.First(&model.Brands{}),因为 struct 名就是表名,改表名也是通过绑在 struct 上的函数进行的
- 是的,比如
- 商品分类
- 先看 GetAllCategorysList,这里比较 tricky,因为有多级分类,需要同时查询两级 subCategory
- 我们希望得到的数据格式
[{"id":xxx,"name":"","level":1,"is_tab":false,"parent":13xxx,"sub_category":["id":xxx,"name":"","level":1,"is_tab":false,"sub_category":["id":xxx,"name":"",]]} ] - 通过 gorm 提供的预加载(反向查询)实现
- 条件查询一级目录:
global.DB.Where(&model.Category{Level: 1}) - 反向查询两级子类目:
Preload("SubCategory.SubCategory") - 再贴一个获取子分类的函数,grpc 的接口实现都是三步走
// 获取子分类,传入一级或二级类别ID func (s *GoodsServer) GetSubCategory(ctx context.Context, req *proto.CategoryListRequest) (*proto.SubCategoryListResponse, error) {// 1.准备返回值categoryListResponse := proto.SubCategoryListResponse{} // total, info(parent), sub// 2.根据请求参数查询数据+判空var category model.Categoryif result := global.DB.First(&category, req.Id); result.RowsAffected == 0 {return nil, status.Errorf(codes.NotFound, "商品分类不存在")}// 3.填充返回值各字段-InfocategoryListResponse.Info = &proto.CategoryInfoResponse{Id: category.ID,Name: category.Name,Level: category.Level,IsTab: category.IsTab,ParentCategory: category.ParentCategoryID,}var subCategorys []model.Categoryvar subCategoryResponse []*proto.CategoryInfoResponse// 如果要获取三级子分类,默认获取下面一级//preloads := "SubCategory"//if category.Level == 1 {// preloads = "SubCategory.SubCategory"//}// 只有在一级时才有获取三级的需求,但是这里没必要,这里把这个接口做的小一点,限制在只获取下一级,需要三级的话再在二级一一请求global.DB.Where(&model.Category{ParentCategoryID: req.Id}).Find(&subCategorys)for _, subCategory := range subCategorys {subCategoryResponse = append(subCategoryResponse, &proto.CategoryInfoResponse{Id: subCategory.ID,Name: subCategory.Name,Level: subCategory.Level,IsTab: subCategory.IsTab,ParentCategory: subCategory.ParentCategoryID,})}// 3.填充返回值各字段-SubCategoryscategoryListResponse.SubCategorys = subCategoryResponsereturn &categoryListResponse, nil } - 这里需要写接口测试,可以在 test 目录写 UT 或者每个 handler 新建目录在 main 函数运行看效果(一个目录下只能有一个main)
- 品牌分类
- 查询品牌和分类数据表,这是个中间表,内容较多,相关操作也较为复杂一点

- model 定义如下
type GoodsCategoryBrand struct {BaseModelCategoryID int32 `gorm:"type:int;index:idx_category_brand,unique"` // 外键Category Category // 外键约束,约束谁就指向谁BrandsID int32 `gorm:"type:int;index:idx_category_brand,unique"` // 外键Brands Brands }
- 查询品牌和分类数据表,这是个中间表,内容较多,相关操作也较为复杂一点
- 这些接口都是给 web 层调用,但有的是给用户准备数据,有的是给后台管理员准备
商品
- 商品接口,关系到最终展示给用户的数据,最重要
- 注:这部分有很多入口:搜索、新品、热门、价格区间、商品分类,都需要调用接口获取对应商品,这些都可以看做是查询条件
- 注意下面几点
- 条件是可以叠加的,所有用
localDB接收前面过滤出的数据体 - 分类条件要考虑层级
- 条件是可以叠加的,所有用
- 后续会集成 elastic 用于搜索
小结
- 快速开发了商品微服务的 Service 层,服务配置项还是和 user_srv 相同,包括 nacos,mysql,consul,serverConfig,不需要更改定义
- 接下来是商品微服务 API 层的快速开发
相关文章:
Go项目(商品微服务-1)
文章目录简介建表protohandler商品小结简介 商品微服务主要在于表的设计,建哪些表?表之间的关系是怎样的? 主要代码就是 CURD表和字段的设计是一个比较有挑战性的工作,比较难说清楚,也需要经验的积累,这里…...
机器学习——集成学习
引言 集成学习:让机器学习效果更好,单个不行,群殴走起。 分类 1. Bagging:训练多个分类器取平均(m代表树的个数)。 2.Boosting(提升算法):从弱学习器开始加,通过加权来进行训练。…...
VS编译系统 实用调试技巧
目录什么是bug?调试是什么?有多重要?debug和release的介绍windows环境调试介绍、一些调试实例如何写出(易于调试)的代码编程常见的错误什么是bug?其实bug在英文翻译中有表示臭虫的含义,因为第一次被发现的导致计算机…...
【华为OD机试模拟题】用 C++ 实现 - GPU 调度(2023.Q1)
最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 去重求和(2023.Q1) 文章目录 最近更新的博客使用说明GPU 调度题目输入输出示例一输入输出说明示例二输入输出说明Code使用说明 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。...
腾讯前端必会react面试题合集
React-Router的路由有几种模式? React-Router 支持使用 hash(对应 HashRouter)和 browser(对应 BrowserRouter) 两种路由规则, react-router-dom 提供了 BrowserRouter 和 HashRouter 两个组件来实现应用的…...
Linux搭建SVN服务器,并内网穿透实现公网远程访问
文章目录1. Ubuntu安装SVN服务2. 修改配置文件2.1 修改svnserve.conf文件2.2 修改passwd文件2.3 修改authz文件3. 启动svn服务4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射本地端口5. 测试公网访问6. 配置固定公网TCP端口地址6.1 保留一个固定的公网TCP端口地址6.2 配置…...
C++STL之list的模拟实现
目录 一.list准备 二. iterator迭代器 1._list_iterator 2.begin()、end() 3.const_begin()、const_end() 4.!&& 5. && -- 6.operator* 7.operator-> 三.Modify(修改) 1.insert() 2.erase() 3.push_back() && push_front() 4.pop_bac…...
为什么硬件性能监控很重要
当今的混合网络环境平衡了分布式网络和现代技术的实施。但它们并不缺少一个核心组件:服务器。保持网络正常运行时间归结为监控和管理导致网络停机的因素。极有可能导致性能异常的此类因素之一是硬件。使用硬件监控器监控网络硬件已成为一项关键需求。 硬件监视器是…...
HTTP缓存
HTTP缓存HTTP缓存引发的一个问题HTTP缓存的作用HTTP缓存的分类强制缓存协商缓存(解决强缓存下资源不更新问题)缓存策略HTTP缓存引发的一个问题 有一次在开发移动端H5项目,UI提了几个UI问题,经过样式调试,android上没有…...
SPI设备树处理过程
SPI设备树处理过程 文章目录SPI设备树处理过程参考资料:一、 spi_device结构体二、 SPI设备树格式2.1 SPI Master2.2 SPI Device2.3 设备树示例三、设备树实例3.1 使用GPIO模拟的SPI控制器3.2 IMX6ULL SPI控制器四、 设备树处理过程致谢参考资料: 内核头…...
数据有哪些重要的作用?
我们正处在科技高速发展的时代,如今互联网已经与我们的生活息息相关,我们每天在互联网产生大量的数据,这些数据散落在网络中看似没有怎么作用,但是这些数据经过系统的处理整合起来确实非常有价值的。 一、 发展大数据技术可以提高…...
spring面试题总结
1、spring是什么? spring是一个轻量级IOC和AOP容器框架,是为Java应用程序提供基础性服务的一套框架,目的是用于简化企业应用的开发,开发者只需要关注业务需求即可: core container 容器组件 spring context,…...
使用MUI与H5+构建移动端app
前言 通过mui构建APP 效果图: <!DOCTYPE html> <html> <head><meta charset...
第17篇:Java变量总结
目录 1.变量的概念 1.1 变量来源 1.2 计算机中的变量 1.3 变量如何在内存中存储 2.Java变量...
使用51单片机的GPIO输出占空比可调节的PWM波
一、前言 在一些单片机或微控制器中,通用GPIO可以被配置为产生PWM信号。PWM即脉冲宽度调制,是一种用于模拟输出的技术。它可以通过改变输出信号的脉冲宽度来控制电路中的电平,从而实现对电路的控制。 二、什么是PWM波? PWM波&a…...
从产品经理的角度如何提升项目的交付质量?
提高交付质量 ,对于每个IT公司都是永恒的话题。 交付质量其实包含2重意义, 一是交付的高质量(客户角度),即客户的满意度;二是高质量的交付(交付团队的角度),这里是指如何…...
JavaScript BOM【快速掌握知识点】
目录 Window对象的常用属性 语法: Window对象的常用方法 语法: open()和close()方法 History对象 常用属性和方法 示例 Location对象 常用属性 常用方法 Document对象的常用方法 定时函数 超时调用:setTimeout() 间歇调用&…...
【算法】哈希表
作者:指针不指南吗 专栏:算法篇 🐾或许会很慢,但是不可以停下来🐾 文章目录1.定义2.优点3.数字哈希3.1拉链法3.2开放寻址法3.3 例题4.字符串哈希1.定义 哈希表(Hash table),是根据键…...
彻底搞懂React-hook链表构建原理
写在前面的小结 每一个 hook 函数都有对应的 hook 对象保存状态信息useContext是唯一一个不需要添加到 hook 链表的 hook 函数只有 useEffect、useLayoutEffect 以及 useImperativeHandle 这三个 hook 具有副作用,在 render 阶段需要给函数组件 fiber 添加对应的副…...
【数据挖掘实战】——应用系统负载分析与容量预测(ARIMA模型)
项目地址:Datamining_project: 数据挖掘实战项目代码 目录 一、背景和挖掘目标 1、问题背景 2、传统方法的不足 2、原始数据 3、挖掘目标 二、分析方法与过程 1、初步分析 2、总体流程 第一步:数据抽取 第二步:探索分析 第三步&a…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
tomcat入门
1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效,稳定,易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...
恶补电源:1.电桥
一、元器件的选择 搜索并选择电桥,再multisim中选择FWB,就有各种型号的电桥: 电桥是用来干嘛的呢? 它是一个由四个二极管搭成的“桥梁”形状的电路,用来把交流电(AC)变成直流电(DC)。…...
高效的后台管理系统——可进行二次开发
随着互联网技术的迅猛发展,企业的数字化管理变得愈加重要。后台管理系统作为数据存储与业务管理的核心,成为了现代企业不可或缺的一部分。今天我们要介绍的是一款名为 若依后台管理框架 的系统,它不仅支持跨平台应用,还能提供丰富…...
算法刷题-回溯
今天给大家分享的还是一道关于dfs回溯的问题,对于这类问题大家还是要多刷和总结,总体难度还是偏大。 对于回溯问题有几个关键点: 1.首先对于这类回溯可以节点可以随机选择的问题,要做mian函数中循环调用dfs(i&#x…...
LINUX编译vlc
下载 VideoLAN / VLC GitLab 选择最新的发布版本 准备 sudo apt install -y xcb bison sudo apt install -y autopoint sudo apt install -y autoconf automake libtool编译ffmpeg LINUX FFMPEG编译汇总(最简化)_底部的附件列表中】: ffmpeg - lzip…...
【R语言编程——数据调用】
这里写自定义目录标题 可用库及数据集外部数据导入方法查看数据集信息 在R语言中,有多个库支持调用内置数据集或外部数据,包括studentdata等教学或示例数据集。以下是常见的库和方法: 可用库及数据集 openintro库 该库包含多个教学数据集&a…...
