云商城业务+架构学习和环境准备
B2B:Business to Business,交易双方的身份都是商家,也就是商家将商品卖给商家,类似采购、批发类购物,国内代表性网站阿里巴巴批发网
C2C:Customer to Customer,交易双方都可以是个人,比如淘宝网
O2O:Online To Offline,线上线下模式,典型的代表饿了么,在线上支付了,在线下获取商品
B2B2C:大型的电商平台,允许商家入驻,允许会员在平台买卖商品,京东和天猫都属于这类型网站
1.云商城业务场景
1.1 业务学习
云商城是基于SpringCloud Alibaba技术栈研发的B2C电商平台,平台拥有核心的电商业务功能。运营商在后台管理商品,前台能通过搜索引擎实时搜索到最新商品,用户注册后可以直接在平台购买商品,并通过微信支付实现线上支付。用户还能参与平台秒杀抢购,并实现线上支付秒杀商品
1.2 功能学习
1.商品管理
2.商城首页
3.海量商品实时搜索
4.商品及时秒杀
5.购物车管理
6.在线微信支付
2.商城架构设计
云商城采用了微服务技术架构,采用了当前主流的SpringCloud Alibaba技术栈,从接入层、网关层、服务层、数据同步、服务治理、数据处理、第三方接口多个方面进行了精心设计
具体流程:LVS四层负载,抗压能力更强(LVS一般能到达400万并发),然后lvs会把请求路由给nginx七层负载(抗压能力能达到5万)经过了nginx,然后通过网关gateway(路由、限流、鉴权),然后路由到不同的服务(取决于我们的业务),利用分布式事务解决数据不一致性问题,涉及到的数据库包括MySQL、redis、es
3.云商城表结构
3.1 商品数据库
品牌表:brand
sql
CREATE TABLE `brand` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '品牌id',
`name` varchar(100) NOT NULL COMMENT '品牌名称',
`image` varchar(1000) DEFAULT '' COMMENT '品牌图片地址',
`initial` varchar(1) DEFAULT '' COMMENT '品牌的首字母',
`sort` int(11) DEFAULT NULL COMMENT '排序',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=325475 DEFAULT CHARSET=utf8 COMMENT='品牌表';
商品分类表:category
sql
CREATE TABLE `category` (
`id` int(20) NOT NULL AUTO_INCREMENT COMMENT '分类ID',
`name` varchar(50) DEFAULT NULL COMMENT '分类名称',
`sort` int(11) DEFAULT NULL COMMENT '排序',
`parent_id` int(20) DEFAULT NULL COMMENT '上级ID',#这个parent_id就是id,自己查自己,自关联表
PRIMARY KEY (`id`),
KEY `parent_id` (`parent_id`)
) ENGINE=InnoDB AUTO_INCREMENT=11177 DEFAULT CHARSET=utf8 COMMENT='商品类目';
品牌分类关联表:category_brand
sql
CREATE TABLE `category_brand` (
`category_id` int(11) NOT NULL COMMENT '分类ID',
`brand_id` int(11) NOT NULL COMMENT '品牌ID',
PRIMARY KEY (`brand_id`,`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
商品属性表:sku_attribute
sql
CREATE TABLE `sku_attribute` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`name` varchar(50) DEFAULT NULL COMMENT '属性名称',
`options` varchar(2000) DEFAULT NULL COMMENT '属性选项',
`sort` int(11) DEFAULT NULL COMMENT '排序',
`category_id` varchar(100) DEFAULT NULL COMMENT '分类ID集合',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=140 DEFAULT CHARSET=utf8;
商品SPU表:spu
sql
CREATE TABLE `spu` (
`id` varchar(60) NOT NULL COMMENT '主键',
`name` varchar(100) DEFAULT NULL COMMENT 'SPU名',
`intro` varchar(200) DEFAULT NULL COMMENT '商品简介',
`brand_id` int(11) DEFAULT NULL COMMENT '品牌ID',
`category_one_id` int(20) DEFAULT NULL COMMENT '一级分类',
`category_two_id` int(10) DEFAULT NULL COMMENT '二级分类',
`category_three_id` int(10) DEFAULT NULL COMMENT '三级分类',
`images` varchar(1000) DEFAULT NULL COMMENT '图片列表',
`after_sales_service` varchar(50) DEFAULT NULL COMMENT '售后服务',
`content` longtext COMMENT '介绍',
`attribute_list` varchar(3000) DEFAULT NULL COMMENT '规格列表',
`is_marketable` int(1) DEFAULT '0' COMMENT '是否上架,0已下架,1已上架',
`is_delete` int(1) DEFAULT '0' COMMENT '是否删除,0:未删除,1:已删除',
`status` int(1) DEFAULT '0' COMMENT '审核状态,0:未审核,1:已审核,2:审核不通过',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
商品SKU表:sku
sql
CREATE TABLE `sku` (
`id` varchar(60) NOT NULL COMMENT '商品id',
`name` varchar(200) NOT NULL COMMENT 'SKU名称',
`price` int(20) NOT NULL DEFAULT '1' COMMENT '价格(分)',
`num` int(10) DEFAULT '100' COMMENT '库存数量',
`image` varchar(200) DEFAULT NULL COMMENT '商品图片',
`images` varchar(2000) DEFAULT NULL COMMENT '商品图片列表',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`spu_id` varchar(60) DEFAULT NULL COMMENT 'SPUID',
`category_id` int(10) DEFAULT NULL COMMENT '类目ID',
`category_name` varchar(200) DEFAULT NULL COMMENT '类目名称',
`brand_name` varchar(100) DEFAULT NULL COMMENT '品牌名称',
`sku_attribute` varchar(200) DEFAULT NULL COMMENT '规格',
`status` int(1) DEFAULT '1' COMMENT '商品状态 1-正常,2-下架,3-删除',
PRIMARY KEY (`id`),
KEY `cid` (`category_id`),
KEY `status` (`status`),
KEY `updated` (`update_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商品表';
3.2 订单数据库
订单表:order
sql
CREATE TABLE `order` (
`id` varchar(50) COLLATE utf8_bin NOT NULL COMMENT '订单id',
`total_num` int(11) DEFAULT NULL COMMENT '数量合计',
`moneys` int(11) DEFAULT NULL COMMENT '金额合计',
`pay_type` varchar(1) COLLATE utf8_bin DEFAULT NULL COMMENT '支付类型,1、在线支付、0 货到付款',
`create_time` datetime DEFAULT NULL COMMENT '订单创建时间',
`update_time` datetime DEFAULT NULL COMMENT '订单更新时间',
`pay_time` datetime DEFAULT NULL COMMENT '付款时间',
`consign_time` datetime DEFAULT NULL COMMENT '发货时间',
`end_time` datetime DEFAULT NULL COMMENT '交易完成时间',
`username` varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '用户名称',
`recipients` varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '收货人',
`recipients_mobile` varchar(12) COLLATE utf8_bin DEFAULT NULL COMMENT '收货人手机',
`recipients_address` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '收货人地址',
`weixin_transaction_id` varchar(30) COLLATE utf8_bin DEFAULT NULL COMMENT '交易流水号',
`order_status` int(1) COLLATE utf8_bin DEFAULT NULL COMMENT '订单状态,0:未完成,1:已完成,2:已退货',
`pay_status` int(1) COLLATE utf8_bin DEFAULT NULL COMMENT '支付状态,0:未支付,1:已支付,2:支付失败',
`is_delete` int(1) COLLATE utf8_bin DEFAULT NULL COMMENT '是否删除',
PRIMARY KEY (`id`),
KEY `create_time` (`create_time`),
KEY `status` (`order_status`),
KEY `payment_type` (`pay_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
订单明细表:order_sku
sql
CREATE TABLE `order_sku` (
`id` varchar(50) COLLATE utf8_bin NOT NULL COMMENT 'ID',
`category_one_id` int(11) DEFAULT NULL COMMENT '1级分类',
`category_two_id` int(11) DEFAULT NULL COMMENT '2级分类',
`category_three_id` int(11) DEFAULT NULL COMMENT '3级分类',
`spu_id` varchar(60) COLLATE utf8_bin DEFAULT NULL COMMENT 'SPU_ID',
`sku_id` varchar(60) COLLATE utf8_bin DEFAULT NULL COMMENT 'SKU_ID',
`order_id` varchar(50) COLLATE utf8_bin NOT NULL COMMENT '订单ID',
`name` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '商品名称',
`price` int(20) DEFAULT NULL COMMENT '单价',
`num` int(10) DEFAULT NULL COMMENT '数量',
`money` int(20) DEFAULT NULL COMMENT '总金额',
`image` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '图片地址',
PRIMARY KEY (`id`),
KEY `item_id` (`sku_id`),
KEY `order_id` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
3.3 秒杀数据库
秒杀商品表:seckill_goods
sql
CREATE TABLE `seckill_goods` (
`id` varchar(60) NOT NULL,
`sup_id` varchar(60) DEFAULT NULL COMMENT 'spu ID',
`sku_id` varchar(60) DEFAULT NULL COMMENT 'sku ID',
`name` varchar(100) DEFAULT NULL COMMENT '标题',
`images` varchar(150) DEFAULT NULL COMMENT '商品图片',
`price` int(20) DEFAULT NULL COMMENT '原价格',
`seckill_price` double(20,0) DEFAULT NULL COMMENT '秒杀价格',
`create_time` datetime DEFAULT NULL COMMENT '添加日期',
`start_time` datetime DEFAULT NULL COMMENT '开始时间',
`end_time` datetime DEFAULT NULL COMMENT '结束时间',
`num` int(11) DEFAULT NULL COMMENT '秒杀商品数',
`store_count` int(11) DEFAULT NULL COMMENT '剩余库存数',
`content` varchar(2000) DEFAULT NULL COMMENT '描述',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
秒杀订单表:seckill_order
sql
CREATE TABLE `seckill_order` (
`id` varchar(60) NOT NULL COMMENT '主键',
`seckill_goods_id` varchar(60) DEFAULT NULL COMMENT '秒杀商品ID',
`money` int(10) DEFAULT NULL COMMENT '支付金额',
`username` varchar(50) DEFAULT NULL COMMENT '用户',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`pay_time` datetime DEFAULT NULL COMMENT '支付时间',
`status` int(1) DEFAULT NULL COMMENT '状态,0未支付,1已支付',
`weixin_transaction_id` varchar(30) DEFAULT NULL COMMENT '交易流水',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3.4 用户数据库
省份表:provinces
sql
CREATE TABLE `provinces` (
`provinceid` varchar(20) NOT NULL COMMENT '省份ID',
`province` varchar(50) NOT NULL COMMENT '省份名称',
PRIMARY KEY (`provinceid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='省份信息表';
城市表:cities
sql
CREATE TABLE `cities` (
`cityid` varchar(20) NOT NULL COMMENT '城市ID',
`city` varchar(50) NOT NULL COMMENT '城市名称',
`provinceid` varchar(20) NOT NULL COMMENT '省份ID',
PRIMARY KEY (`cityid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='行政区域地州市信息表';
区域表:areas
sql
CREATE TABLE `areas` (
`areaid` varchar(20) NOT NULL COMMENT '区域ID',
`area` varchar(50) NOT NULL COMMENT '区域名称',
`cityid` varchar(20) NOT NULL COMMENT '城市ID',
PRIMARY KEY (`areaid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='行政区域县区信息表';
收件信息表:address
sql
CREATE TABLE `address` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) DEFAULT NULL COMMENT '用户名',
`provinceid` varchar(20) DEFAULT NULL COMMENT '省',
`cityid` varchar(20) DEFAULT NULL COMMENT '市',
`areaid` varchar(20) DEFAULT NULL COMMENT '县/区',
`phone` varchar(20) DEFAULT NULL COMMENT '电话',
`address` varchar(200) DEFAULT NULL COMMENT '详细地址',
`contact` varchar(50) DEFAULT NULL COMMENT '联系人',
`is_default` int(1) DEFAULT NULL COMMENT '是否是默认 1默认 0否',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=utf8;
4.工程搭建
4.1 环境准备
这里需要用到数据库MySQL
和注册中心Nacos
,数据库和注册中心全部已经安装在了虚拟机中.
properties
虚拟机ip:192.168.100.130
虚拟机账号:root
账号密码:pcb
数据库账号:root
数据库密码:123456
Nacos url http://192.168.100.130:8848/nacos
账号:nacos
密码:nacos
基于Docker安装Nacos:
properties
docker run -d -p 8848:8848 -e MODE=standalone -v /opt/nacos/init.d/custom.properties:/home/nacos/init.d/custom.properties -v /opt/nacos/logs:/home/nacos/logs --restart always --name nacos nacos/nacos-server
安装好了后,访问http://192.168.100.130:8848/nacos 账号密码都是nacos
基于Docker安装MySQL:
properties
docker run -di --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
4.2 工程结构分析
4.3 公共工程搭建
4.3.1 父工程搭建(顶级)
工程坐标:
xml
<groupId>com.gupaoedu.vip.mall</groupId>
<artifactId>gupaoedu-vip-mall</artifactId>
<version>0.0.1-SNAPSHOT</version>
我们选择用Spring Initializr创建父工程
选择需要的应用场景
整理下pom.xml,在pom.xml中只留部分包,其他包是创建微服务时需要(所有模块都要用的包)
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.gupaoedu.vip.mall</groupId>
<artifactId>gupaoedu-vip-mall</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gupaoedu-vip-mall</name>
<!--父工程-->
<packaging>pom</packaging>
<description>云商城</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version>
</properties>
<dependencies>
<!--lombok,方便创建Bean对象和日志操作-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--Test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--热部署插件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<!--alibaba-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
4.3.2 子项目父工程创建
我们可以按照功能分类,给每类工程创建一个父工程,方便管理(建maven模块)
properties
mall-api:存储所有数据库表对应的Bean和Feign接口
mall-gateway:存储所有微服务网关
mall-service:存储所有微服务工程
mall-util:存储公共工程
mall-web:存储所有和页面渲染有关的工程
mall-api的pom.xml:
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>gupaoedu-vip-mall</artifactId>
<groupId>com.gupaoedu.vip.mall</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<artifactId>mall-api</artifactId>
<description>
存放所有JavaBean和Feign接口
</description>
</project>
mall-gateway的pom.xml:
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>gupaoedu-vip-mall</artifactId>
<groupId>com.gupaoedu.vip.mall</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<artifactId>mall-gateway</artifactId>
<description>
存放微服网关集群
</description>
</project>
mall-service的pom.xml:
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>gupaoedu-vip-mall</artifactId>
<groupId>com.gupaoedu.vip.mall</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<artifactId>mall-service</artifactId>
<description>所有的应用服务</description>
</project>
mall-util的pom.xml:
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>gupaoedu-vip-mall</artifactId>
<groupId>com.gupaoedu.vip.mall</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<artifactId>mall-util</artifactId>
<description>
存放所有公共工程
</description>
</project>
mall-web的pom.xml:
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>gupaoedu-vip-mall</artifactId>
<groupId>com.gupaoedu.vip.mall</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<artifactId>mall-web</artifactId>
<description>
存放所有和页面渲染有关的工程,不建议放在service中,所有service只提供基于RESTful的服务
</description>
</project>
4.3.3 公共工程创建
4.3.3.1 公共依赖汇总
service中以后要创建微服务工程操作数据库,我们可以把所有service需要用到的包以及所有service需要初始化的对象放到一个独立的工程中,以后哪个工程要用,直接依赖即可。
在mall-util
中创建mall-service-dependency
,pom.xml依赖如下:
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>mall-util</artifactId>
<groupId>com.gupaoedu.vip.mall</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mall-service-dependency</artifactId>
<description>
所有service工程依赖的包汇总以及初始化工具包
</description>
<dependencies>
<!--web包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--MyBatis Plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<!--MySQL-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--Redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--Nacos-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
</project>
4.3.3.2 公共工具包
我们需要用到的工具包也可以单独放到一个工程中,每次要用,直接依赖即可
在mall-util
中创建mall-common
,我们在工程中创建2个对象:
用于指定响应状态码的枚举对象:com.gupaoedu.mall.util.RespCode
java
public enum RespCode {
SUCCESS(200, "操作成功"),
ERROR(500, "操作失败"),
SYSTEM_ERROR(501, "系统错误");
private Integer code;
private String message;
RespCode(Integer code, String message) {
this.code = code;
this.message = message;
}
RespCode() {
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
用于响应用户信息封装的对象:com.gupaoedu.mall.util.RespResult
java
public class RespResult<T> implements Serializable {
//响应数据结果集
private T data;
/**
* 状态码
* 200 操作成功
* 500 操作失败
*/
private Integer code;
/***
* 响应信息
*/
private String message;
public RespResult() {
}
public RespResult(RespCode resultCode) {
this.code = resultCode.getCode();
this.message = resultCode.getMessage();
}
public RespResult(T data, RespCode resultCode) {
this.data = data;
this.code = resultCode.getCode();
this.message = resultCode.getMessage();
}
public static RespResult ok() {
return new RespResult(null, RespCode.SUCCESS);
}
public static RespResult ok(Object data) {
return new RespResult(data, RespCode.SUCCESS);
}
public static RespResult error() {
return new RespResult(null, RespCode.ERROR);
}
public static RespResult error(String message) {
return secByError(RespCode.ERROR.getCode(),message);
}
//自定义异常
public static RespResult secByError(Integer code,String message) {
RespResult err = new RespResult();
err.setCode(code);
err.setMessage(message);
return err;
}
public static RespResult error(RespCode resultCode) {
return new RespResult(resultCode);
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
4.3.3.3 依赖管理
service工程一定会依赖mall-service-dependency
和mall-common
,我们可以修改mall-service
将这两个工程添加到依赖中:
xml
<dependencies>
<!--依赖mall-service-dependency-->
<dependency>
<groupId>com.gupaoedu.vip.mall</groupId>
<artifactId>mall-service-dependency</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!--依赖mall-common-->
<dependency>
<groupId>com.gupaoedu.vip.mall</groupId>
<artifactId>mall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
5.品牌管理实现
5.1 集成MyBatisPlus
5.1.1 MyBatis Plus介绍
MyBatis-Plus(简称 MP)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
MyBatis Plus特性:
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
- 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
- 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
- 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
- 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
- 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
5.1.2 MyBatisPlus集成
1)引入依赖包
在mall-service-dependency
中引入如下依赖(这个依赖包之前已经引入了,这里无需再次引入):
xml
<!--MyBatis Plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
在mall-api
中引入如下依赖(编写JavaBean会用到MyBatis Plus的相关注解,引入依赖防止程序编译不通过):
xml
<!--MyBatis Plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
<scope>provided</scope>
</dependency>
2)创建goods-api
工程
在mall-api
中创建子工程goods-api
,用于创建shop_goods
数据库表对应的实体Bean和Feign接口
pom.xml:
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>mall-api</artifactId>
<groupId>com.gupaoedu.vip.mall</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>goods-api</artifactId>
<description>
shop_goods数据库表对应的JavaBean
</description>
</project>
在goods-api
中创建com.gupaoedu.vip.mall.goods.Brand
,代码如下:
javaBean与数据库表的对应
java
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("brand") //MyBatisPlus表映射注解
public class Brand {
//品牌ID
//MyBatisPlus主键策略注解
@TableId(type = IdType.AUTO)
private Integer id;
//品牌名字
private String name;
//品牌图片
private String image;
//品牌首字母
private String initial;
//品牌排序
private Integer sort;
}
主键生成策略
AUTO | 数据库ID自增 |
---|---|
NONE | 无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT) |
INPUT | insert前自行set主键值 |
ASSIGN_ID | 分配ID(主键类型为Number(Long和Integer)或String),使用接口IdentifierGenerator 的方法nextId (默认实现类为DefaultIdentifierGenerator 雪花算法) |
ASSIGN_UUID | 分配UUID,主键类型为String(since 3.3.0),使用接口IdentifierGenerator 的方法nextUUID (默认default方法) |
ID_WORKER | 分布式全局唯一ID 长整型类型(please use ASSIGN_ID ) ,已过时 |
UUID | 32位UUID字符串,已过时 |
ID_WORKER_STR | 分布式全局唯一ID 字符串类型(please use ASSIGN_ID ) ,已过时 |
3)商品微服务
在mall-service
中创建mall-goods-service
微服务,用于操作shop_goods
数据库
pom.xml代码如下:
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>mall-service</artifactId>
<groupId>com.gupaoedu.vip.mall</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mall-goods-service</artifactId>
<description>
shop_goods微服务
</description>
<dependencies>
<!--goods-api依赖,需要brand实体类-->
<dependency>
<groupId>com.gupaoedu.vip.mall</groupId>
<artifactId>goods-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
创建bootstrap.yml
,配置如下:
yaml
server:
port: 8081
spring:
application:
name: mall-goods #服务名
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/shop_goods?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: 123456
cloud:
nacos:
config:
file-extension: yaml
server-addr: 192.168.1.11:8848
discovery:
#Nacos的注册地址
server-addr: 192.168.1.11:8848
# ====================MybatisPlus====================
mybatis-plus:
mapper-locations: mapper/*.xml
type-aliases-package: com.gupaoedu.vip.mall.*.model #javaBean取别名的位置
configuration:
map-underscore-to-camel-case: true #驼峰命名法,eg:t_user
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#日志配置
logging:
pattern:
console: "%msg%n"
配置说明:
properties
type-aliases-package:指定JavaBean的别名包,和MyBatis用法一样
mapper-locations:复杂的操作可能需要自己写SQL,SQL可以写到xml文件中,这里指定和Dao对应的xml文件,此时我们需要在resources中创建一个mapper目录
map-underscore-to-camel-case:开启驼峰功能,数据库表列名如果有_,可以自动按驼峰命名规则转换
log-impl:日志开启,方便测试
创建启动类com.gupaoedu.vip.mall.MallGoodsServiceApplication
:
java
/**
* 商品服务启动类
*/
@SpringBootApplication
@MapperScan(basePackages = {"com.gupaoedu.vip.mall.goods.mapper"})
public class MallGoodsApplication {
public static void main(String[] args) {
SpringApplication.run(MallGoodsApplication.class,args);
}
}
此时启动程序,查看Nacos控制台:< http://192.168.1.11:8848/nacos/index.html\> 账号和密码都是nacos,效果如下:
5.2 MyBatisPlus操作
我们创建一个品牌操作的功能,实现品牌增删改查,分别创建model
、mapper
、service
、controller
。
MyBatisPlus提供了很多通用方法:
properties
mapper(接口)->extends BaseMapper【增删改查】
service(接口)->extends IService【增删改查】
serviceImpl->extends ServiceImpl【增删改查】
5.2.1 Mapper创建
在mall-goods-service
创建com.gupaoedu.vip.mall.goods.mapper.BrandMapper
接口,代码如下:
java
public interface BrandMapper extends BaseMapper<Brand> {
}
代码说明:BaseMapper中已经存在了很多常见数据库操作方法,可以大幅提升开发速度
5.2.2 Service创建
在mall-goods-service
创建com.gupaoedu.vip.mall.goods.service.BrandService
接口,代码如下:
java
public interface BrandService extends IService<Brand>{
}
在mall-goods-service
创建com.gupaoedu.vip.mall.goods.service.impl.BrandServiceImpl
实现类,代码如下:
java
@Service
public class BrandServiceImpl extends ServiceImpl<BrandMapper,Brand> implements BrandService {}
代码说明:IService
和ServiceImpl
中已经创建好了很多常用的增删改查方法,我们写常用的增删改查,几乎不用写方法
5.2.3 增删改功能
增删改功能在IService
和ServiceImpl
中已经全部存在, 不需要额外添加方法,只需要在Controller调用即可
在mall-goods-service
创建com.gupaoedu.vip.mall.goods.controller.BrandController
,代码如下:
注意:@PathVariable 映射 URL 绑定的占位符,通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中
java
@RestController
@RequestMapping(value = "/brand")
public class BrandController {
@Autowired
private BrandService brandService;
/***
* 增加品牌 http://localhost:8081/brand
*/
@PostMapping
public RespResult add(@RequestBody Brand brand){
// 增加品牌
brandService.save(brand);
return RespResult.ok();
}
/****
* 修改
*/
@PutMapping
public RespResult update(@RequestBody Brand brand){
//修改品牌
brandService.updateById(brand);
return RespResult.ok();
}
/****
* 删除品牌
*/
@DeleteMapping("/{id}")
public RespResult delete(@PathVariable(value = "id") Integer id){
//删除品牌
brandService.removeById(id);
return RespResult.ok();
}
}
使用postman测试增删改,增删改mp提供了很多的方法,不需要自己去写,查询有条件查询,需要自己手写
5.2.4 条件查询/分页
条件查询需要封装条件信息,MyBatis Plus提供了条件封装对象Wrapper
(它的子类QueryWrapper
可以直接使用),我们可以用它的子类QueryWrapper
实现封装查询条件
6.2.4.1 条件查询
在BrandService
中创建如下方法:
List<Brand> queryList(Brand brand);
在BrandServiceImpl
中创建条件查询方法实现(不要忘了注入brandMapper
):
java
/**
* 多条件查询
*/
@Override
public List<Brand> queryList(Brand brand) {
// 多条件构造器
QueryWrapper<Brand> queryWrapper = new QueryWrapper<Brand>();
if(!StringUtils.isEmpty(brand.getName())){
queryWrapper.like("name",brand.getName());
}
if(!StringUtils.isEmpty(brand.getName())){
queryWrapper.eq("initial",brand.getInitial());
}
return brandMapper.selectList(queryWrapper);
}
注意:like:表示模糊查询;eq:表示等值查询
在BrandController
中创建条件查询方法:
java
/**
* 条件查询
*/
@PostMapping(value = "/list")
public RespResult<List<Brand>> list(@RequestBody(required = false) Brand brand){
// 查询
List<Brand> brands = brandService.queryList(brand);
return RespResult.ok(brands);
}
6.2.4.2 分页查询
在BrandService
中创建如下方法:
Page<Brand> queryPageList(Long currentPage,Long size,Brand brand);
在BrandServiceImpl
中创建条件查询方法实现(不要忘了注入brandMapper
):
java
/***
* 分页查询
*/
@Override
public Page<Brand> queryPageList(Long currentPage, Long size, Brand brand) {
// 封装查询条件
Page<Brand> page = brandMapper.selectPage(
new Page<Brand>(currentPage, size),
new QueryWrapper<Brand>()
.like("name", brand.getName()));
return page;
}
在BrandController
中创建条件查询方法:
java
/**
* 条件分页查询
*/
@PostMapping(value = "/list/{page}/{size}")
public RespResult<Page<Brand>> list(
@PathVariable(value = "page")Long currentPage,
@PathVariable(value = "size")Long size,
@RequestBody(required = false) Brand brand){
// 分页查询
Page<Brand> brandPage = brandService.queryPageList(currentPage,size,brand);
return RespResult.ok(brandPage);
}
测试结果如下:
注意:mp的分页查询,需要写分页拦截器,不然就不起作用
java
package com.gupaoedu.vip.mall.config;
@Configuration
public class StartConfig {
/****
* 分页插件(分页拦截器),必须写拦截器,不然mp的分页功能不生效
*/
@Bean
public PaginationInterceptor paginationInterceptor(){
PaginationInterceptor pageInterceptor = new PaginationInterceptor();
// 设置数据类型
pageInterceptor.setDbType(DbType.MYSQL);
return pageInterceptor;
}
}