01-创建项目 创建数据表-类别管理--添加类别--持久层

1. 关于此项目

此项目是一个自营性质电商类型的项目。

当前目标是设计后台管理相关功能。

2. 关于项目的开发流程

开发项目的标准流程应该有:需求分析、可行性分析、总体设计、详细设计等。

建议课后学习《软件工程》。

在具体开发时,应该先创建数据库、数据表,然后创建项目进行开发。

3. 创建数据库与数据表

创建mall_pms数据库:

CREATE DATABASE mall_pms;

在此数据库中创建数据表:

-- 数据库:mall_pms

-- 相册表:创建数据表
drop table if exists pms_album;
create table pms_album
(
    id           bigint unsigned auto_increment comment '记录id',
    name         varchar(50)      default null comment '相册名称',
    description  varchar(255)     default null comment '相册简介',
    sort         tinyint unsigned default 0 comment '自定义排序序号',
    gmt_create   datetime         default null comment '数据创建时间',
    gmt_modified datetime         default null comment '数据最后修改时间',
    primary key (id)
) comment '相册' charset utf8mb4;

-- 相册表:为相册名称字段添加索引
create index idx_album_name on pms_album (name);

-- 图片表:创建数据表
drop table if exists pms_picture;
create table pms_picture
(
    id           bigint unsigned auto_increment comment '记录id',
    album_id     bigint unsigned   default null comment '相册id',
    url          varchar(255)      default null comment '图片url',
    description  varchar(255)      default null comment '图片简介',
    width        smallint unsigned default null comment '图片宽度,单位:px',
    height       smallint unsigned default null comment '图片高度,单位:px',
    is_cover     tinyint unsigned  default 0 comment '是否为封面图片,1=是,0=否',
    sort         tinyint unsigned  default 0 comment '自定义排序序号',
    gmt_create   datetime          default null comment '数据创建时间',
    gmt_modified datetime          default null comment '数据最后修改时间',
    primary key (id)
) comment '图片' charset utf8mb4;

-- 品牌表:创建数据表
drop table if exists pms_brand;
create table pms_brand
(
    id                     bigint unsigned auto_increment comment '记录id',
    name                   varchar(50)      default null comment '品牌名称',
    pinyin                 varchar(50)      default null comment '品牌名称的拼音',
    logo                   varchar(255)     default null comment '品牌logo的URL',
    description            varchar(255)     default null comment '品牌简介',
    keywords               varchar(255)     default null comment '关键词列表,各关键词使用英文的逗号分隔',
    sort                   tinyint unsigned default 0 comment '自定义排序序号',
    sales                  int unsigned     default 0 comment '销量(冗余)',
    product_count          int unsigned     default 0 comment '商品种类数量总和(冗余)',
    comment_count          int unsigned     default 0 comment '买家评论数量总和(冗余)',
    positive_comment_count int unsigned     default 0 comment '买家好评数量总和(冗余)',
    enable                 tinyint unsigned default 0 comment '是否启用,1=启用,0=未启用',
    gmt_create             datetime         default null comment '数据创建时间',
    gmt_modified           datetime         default null comment '数据最后修改时间',
    primary key (id)
) comment '品牌' charset utf8mb4;

-- 品牌表:为品牌名称字段添加索引
create index idx_brand_name on pms_brand (name);

-- 类别表:创建数据表
drop table if exists pms_category;
create table pms_category
(
    id           bigint unsigned auto_increment comment '记录id',
    name         varchar(50)      default null comment '类别名称',
    parent_id    bigint unsigned  default 0 comment '父级类别id,如果无父级,则为0',
    depth        tinyint unsigned default 1 comment '深度,最顶级类别的深度为1,次级为2,以此类推',
    keywords     varchar(255)     default null comment '关键词列表,各关键词使用英文的逗号分隔',
    sort         tinyint unsigned default 0 comment '自定义排序序号',
    icon         varchar(255)     default null comment '图标图片的URL',
    enable       tinyint unsigned default 0 comment '是否启用,1=启用,0=未启用',
    is_parent    tinyint unsigned default 0 comment '是否为父级(是否包含子级),1=是父级,0=不是父级',
    is_display   tinyint unsigned default 0 comment '是否显示在导航栏中,1=启用,0=未启用',
    gmt_create   datetime         default null comment '数据创建时间',
    gmt_modified datetime         default null comment '数据最后修改时间',
    primary key (id)
) comment '类别' charset utf8mb4;

-- 类别表:为类别名称字段添加索引
create index idx_category_name on pms_category (name);

-- 品牌类别关联表:创建数据表
drop table if exists pms_brand_category;
create table pms_brand_category
(
    id           bigint unsigned auto_increment comment '记录id',
    brand_id     bigint unsigned default null comment '品牌id',
    category_id  bigint unsigned default null comment '类别id',
    gmt_create   datetime        default null comment '数据创建时间',
    gmt_modified datetime        default null comment '数据最后修改时间',
    primary key (id)
) comment '品牌与类别关联' charset utf8mb4;

-- 属性表:创建数据表
drop table if exists pms_attribute;
create table pms_attribute
(
    id                 bigint unsigned auto_increment comment '记录id',
    template_id        bigint unsigned  default null comment '所属属性模版id',
    name               varchar(50)      default null comment '属性名称',
    description        varchar(255)     default null comment '简介(某些属性名称可能相同,通过简介补充描述)',
    type               tinyint unsigned default 0 comment '属性类型,1=销售属性,0=非销售属性',
    input_type         tinyint unsigned default 0 comment '输入类型,0=手动录入,1=单选,2=多选,3=单选(下拉列表),4=多选(下拉列表)',
    value_list         varchar(255)     default null comment '备选值列表',
    unit               varchar(50)      default null comment '计量单位',
    sort               tinyint unsigned default 0 comment '自定义排序序号',
    is_allow_customize tinyint unsigned default 0 comment '是否允许自定义,1=允许,0=禁止',
    gmt_create         datetime         default null comment '数据创建时间',
    gmt_modified       datetime         default null comment '数据最后修改时间',
    primary key (id)
) comment '属性' charset utf8mb4;

-- 属性模版表:创建数据表
drop table if exists pms_attribute_template;
create table pms_attribute_template
(
    id           bigint unsigned auto_increment comment '记录id',
    name         varchar(50)      default null comment '属性模版名称',
    pinyin       varchar(50)      default null comment '属性模版名称的拼音',
    keywords     varchar(255)     default null comment '关键词列表,各关键词使用英文的逗号分隔',
    sort         tinyint unsigned default 0 comment '自定义排序序号',
    gmt_create   datetime         default null comment '数据创建时间',
    gmt_modified datetime         default null comment '数据最后修改时间',
    primary key (id)
) comment '属性模版' charset utf8mb4;

-- 属性模版表:为属性模版名称字段添加索引
create index idx_attribute_template_name on pms_attribute_template (name);

-- 类别与属性模版关联表:创建数据表
drop table if exists pms_category_attribute_template;
create table pms_category_attribute_template
(
    id                    bigint unsigned auto_increment comment '记录id',
    category_id           bigint unsigned default null comment '类别id',
    attribute_template_id bigint unsigned default null comment '属性模版id',
    gmt_create            datetime        default null comment '数据创建时间',
    gmt_modified          datetime        default null comment '数据最后修改时间',
    primary key (id)
) comment '类别与属性模版关联' charset utf8mb4;

-- SPU(Standard Product Unit)表:创建数据表
drop table if exists pms_spu;
create table pms_spu
(
    id                     bigint unsigned not null comment '记录id',
    name                   varchar(50)      default null comment 'SPU名称',
    type_number            varchar(50)      default null comment 'SPU编号',
    title                  varchar(255)     default null comment '标题',
    description            varchar(255)     default null comment '简介',
    list_price             decimal(10, 2)   default null comment '价格(显示在列表中)',
    stock                  int unsigned     default 0 comment '当前库存(冗余)',
    stock_threshold        int unsigned     default 0 comment '库存预警阈值(冗余)',
    unit                   varchar(50)      default null comment '计件单位',
    brand_id               bigint unsigned  default null comment '品牌id',
    brand_name             varchar(50)      default null comment '品牌名称(冗余)',
    category_id            bigint unsigned  default null comment '类别id',
    category_name          varchar(50)      default null comment '类别名称(冗余)',
    attribute_template_id  bigint unsigned  default null comment '属性模版id',
    album_id               bigint unsigned  default null comment '相册id',
    pictures               varchar(500)     default null comment '组图URLs,使用JSON数组表示',
    keywords               varchar(255)     default null comment '关键词列表,各关键词使用英文的逗号分隔',
    tags                   varchar(255)     default null comment '标签列表,各标签使用英文的逗号分隔,原则上最多3个',
    sales                  int unsigned     default 0 comment '销量(冗余)',
    comment_count          int unsigned     default 0 comment '买家评论数量总和(冗余)',
    positive_comment_count int unsigned     default 0 comment '买家好评数量总和(冗余)',
    sort                   tinyint unsigned default 0 comment '自定义排序序号',
    is_deleted             tinyint unsigned default 0 comment '是否标记为删除,1=已删除,0=未删除',
    is_published           tinyint unsigned default 0 comment '是否上架(发布),1=已上架,0=未上架(下架)',
    is_new_arrival         tinyint unsigned default 0 comment '是否新品,1=新品,0=非新品',
    is_recommend           tinyint unsigned default 0 comment '是否推荐,1=推荐,0=不推荐',
    is_checked             tinyint unsigned default 0 comment '是否已审核,1=已审核,0=未审核',
    check_user             varchar(50)      default null comment '审核人(冗余)',
    gmt_check              datetime         default null comment '审核通过时间(冗余)',
    gmt_create             datetime         default null comment '数据创建时间',
    gmt_modified           datetime         default null comment '数据最后修改时间',
    primary key (id)
) comment 'SPU(Standard Product Unit)' charset utf8mb4;

-- SPU详情表:创建数据表
drop table if exists pms_spu_detail;
create table pms_spu_detail
(
    id           bigint unsigned auto_increment comment '记录id',
    spu_id       bigint unsigned default null comment 'SPU id',
    detail       text            default null comment 'SPU详情,应该使用HTML富文本,通常内容是若干张图片',
    gmt_create   datetime        default null comment '数据创建时间',
    gmt_modified datetime        default null comment '数据最后修改时间',
    primary key (id)
) comment 'SPU详情' charset utf8mb4;

-- SKU(Stock Keeping Unit)表:创建数据表
drop table if exists pms_sku;
create table pms_sku
(
    id                     bigint unsigned not null comment '记录id',
    spu_id                 bigint unsigned  default null comment 'SPU id',
    title                  varchar(255)     default null comment '标题',
    bar_code               varchar(255)     default null comment '条型码',
    attribute_template_id  bigint unsigned  default null comment '属性模版id',
    specifications         varchar(2500)    default null comment '全部属性,使用JSON格式表示(冗余)',
    album_id               bigint unsigned  default null comment '相册id',
    pictures               varchar(500)     default null comment '组图URLs,使用JSON格式表示',
    price                  decimal(10, 2)   default null comment '单价',
    stock                  int unsigned     default 0 comment '当前库存',
    stock_threshold        int unsigned     default 0 comment '库存预警阈值',
    sales                  int unsigned     default 0 comment '销量(冗余)',
    comment_count          int unsigned     default 0 comment '买家评论数量总和(冗余)',
    positive_comment_count int unsigned     default 0 comment '买家好评数量总和(冗余)',
    sort                   tinyint unsigned default 0 comment '自定义排序序号',
    gmt_create             datetime         default null comment '数据创建时间',
    gmt_modified           datetime         default null comment '数据最后修改时间',
    primary key (id)
) comment 'SKU(Stock Keeping Unit)' charset utf8mb4;

-- SKU规格参数表(存储各SKU的属性与值,即规格参数):创建数据表
drop table if exists pms_sku_specification;
create table pms_sku_specification
(
    id              bigint unsigned auto_increment comment '记录id',
    sku_id          bigint unsigned  default null comment 'SKU id',
    attribute_id    bigint unsigned  default null comment '属性id',
    attribute_name  varchar(50)      default null comment '属性名称',
    attribute_value varchar(50)      default null comment '属性值',
    unit            varchar(10)      default null comment '自动补充的计量单位',
    sort            tinyint unsigned default 0 comment '自定义排序序号',
    gmt_create      datetime         default null comment '数据创建时间',
    gmt_modified    datetime         default null comment '数据最后修改时间',
    primary key (id)
) comment 'SKU数据' charset utf8mb4;

-- -------------------------- --
-- 以下是插入测试数据及一些测试访问 --
-- -------------------------- --

-- 品牌表:插入测试数据
insert into pms_brand (name, pinyin, description, keywords, enable)
values ('华为', 'huawei', '华为专注网络设备三十年', '华为,huawei,mate,magicbook', 1),
       ('小米', 'xiaomi', '小米,为发烧而生', '小米,xiaomi,发烧', 1),
       ('苹果', 'pingguo', '苹果,全球知名品牌', '苹果,apple,pingguo,iphone,mac', 1);

-- 类别表:插入测试数据
insert into pms_category (name, parent_id, depth, is_parent, keywords, enable, is_display)
values ('手机 / 运营商 / 数码', 0, 1, 1, null, 1, 1),
       ('手机通讯', 1, 2, 1, '手机,电话', 1, 1),
       ('智能手机', 2, 3, 0, null, 1, 1),
       ('非智能手机', 2, 3, 0, null, 1, 1),
       ('电脑 / 办公', 0, 1, 1, null, 1, 1),
       ('电脑整机', 5, 2, 1, '电脑,计算机,微机,服务器,工作站', 1, 1),
       ('电脑配件', 5, 2, 1, '配件,组装,CPU,内存,硬盘', 1, 1),
       ('笔记本', 6, 3, 0, '电脑,笔记本,微机,便携', 1, 1),
       ('台式机 / 一体机', 6, 3, 0, '台式机,一体机', 1, 1);

-- 品牌类别表:插入测试数据
insert into pms_brand_category (brand_id, category_id)
values (1, 3),
       (2, 3),
       (3, 3),
       (1, 8),
       (2, 8),
       (3, 8),
       (1, 9),
       (3, 9);

-- 关联测试查询:各品牌有哪些类别的产品
select pms_brand_category.id, pms_brand.name, pms_category.name
from pms_brand_category
         left join pms_brand
                   on pms_brand_category.brand_id = pms_brand.id
         left join pms_category
                   on pms_brand_category.category_id = pms_category.id
order by pms_brand.pinyin;

-- 属性表:插入测试数据
insert into pms_attribute (name, description, type, input_type, value_list, unit, is_allow_customize)
values ('屏幕尺寸', '智能手机屏幕尺寸', 0, 1, '6.1,6.3', '英寸', 1),
       ('屏幕尺寸', '笔记本电脑屏幕尺寸', 0, 1, '14,15', '英寸', 1),
       ('颜色', '智能手机颜色', 0, 1, '黑色,金色,白色', null, 1),
       ('颜色', '衬衣颜色', 0, 1, '白色,蓝色,灰色,黑色', null, 1),
       ('运行内存', '智能手机运行内存', 0, 1, '4,8,16', 'GB', 1),
       ('CPU型号', '智能手机CPU型号', 0, 1, '骁龙870,骁龙880', null, 1),
       ('机身毛重', '智能手机机身毛重', 0, 0, null, 'g', 0),
       ('机身存储', '智能手机机身存储', 0, 1, '64,128,256,512', 'GB', 0),
       ('操作系统', '智能手机操作系统', 0, 1, 'Android,iOS', null, 0),
       ('操作系统', '电脑操作系统', 0, 1, '无,Windows 7,Windows 10,Ubuntu,Mac OS', null, 0);

-- 属性模版表:插入测试数据
insert into pms_attribute_template (name, pinyin, keywords)
values ('智能手机', 'zhinengshouji', '手机'),
       ('服装-上身', 'fuzhuang', '服装,上衣'),
       ('服装-裤子', 'fuzhuang', '服装,裤'),
       ('笔记本电脑', 'bijibendiannao', '电脑,笔记本'),
       ('台式电脑', 'taishidiannao', '电脑,台式电脑,台式机');

-- 相册表:插入测试数据
insert into pms_album (name, description)
values ('iPhone 13', null),
       ('Mi 11 Ultra', null);

-- 图片表:插入测试数据
insert into pms_picture (album_id, url, description, width, height)
values (1, '模拟数据:iPhone 13图片URL-1', null, 1024, 768),
       (1, '模拟数据:iPhone 13图片URL-2', null, 1024, 768),
       (1, '模拟数据:iPhone 13图片URL-3', null, 1024, 768),
       (1, '模拟数据:iPhone 13图片URL-4', null, 1024, 768),
       (1, '模拟数据:iPhone 13图片URL-5', null, 1024, 768),
       (2, '模拟数据:Mi 11 Ultra图片URL-1', null, 1024, 768),
       (2, '模拟数据:Mi 11 Ultra图片URL-2', null, 1024, 768),
       (2, '模拟数据:Mi 11 Ultra图片URL-3', null, 1024, 768),
       (2, '模拟数据:Mi 11 Ultra图片URL-4', null, 1024, 768),
       (2, '模拟数据:Mi 11 Ultra图片URL-5', null, 1024, 768);

-- SPU表:插入测试数据
insert into pms_spu (id, name, type_number, title, description, list_price, stock, stock_threshold, unit, brand_id,
                     brand_name, category_id, category_name, keywords, tags)
values (202112010000001, 'iPhone 13', 'A2404', '苹果手机iPhone 13(A2404)', '2021年新款,全网首发',
        5199.99, 5000, 20, '部', 3, '苹果', 3, '智能手机', 'ip13,iPhone13,苹果13', '20w快充,NFC,无线充电'),
       (202112010000002, '小米11 Ultra', 'M112021', '小米11 Ultra(M112021)', '2021年最新旗舰机',
        5899.99, 8000, 20, '部', 2, '小米', 3, '智能手机', 'mi11,xiaomi11,ultra', '67w快充,1亿像素,5000毫安电池');

-- SPU详情表:插入测试数据
insert into pms_spu_detail (spu_id, detail)
values (1, '<div>iPhone 13的详情HTML</div>'),
       (2, '<div>小米11 Ultra的详情HTML</div>');

-- SKU(Stock Keeping Unit)表:插入测试数据
insert into pms_sku (id, spu_id, title, attribute_template_id, specifications, price, stock, stock_threshold)
values (202112010000001, 2, '2021年新款,小米11 Ultra黑色512G,16G超大内存120Hz高刷67w快充', 1,
        '{"attributes":[{"id":1,"name":"屏幕尺寸","value":"6.1寸"},{"id":3,"name":"颜色","value":"黑色"},{"id":5,"name":"运行内存","value":"16GB"}]}',
        6999.99, 3000, 50),
       (202112010000002, 2, '2021年新款,小米11 Ultra白色512G,8G超大内存120Hz高刷67w快充', 1,
        '{"attributes":[{"id":1,"name":"屏幕尺寸","value":"6.1寸"},{"id":3,"name":"颜色","value":"白色"},{"id":5,"name":"运行内存","value":"8GB"}]}',
        6499.99, 3000, 50);

-- SKU规格参数表(存储各SKU的属性与值,即规格参数):插入测试数据
insert into pms_sku_specification (sku_id, attribute_id, attribute_name, attribute_value, unit)
values (1, 1, '屏幕尺寸', '6.1', '寸'),
       (1, 3, '颜色', '黑色', null),
       (1, 5, '运行内存', '16', 'GB'),
       (2, 1, '屏幕尺寸', '6.1', '寸'),
       (2, 3, '颜色', '白色', null),
       (2, 5, '运行内存', '8', 'GB');

-- 查看数据表结构
desc pms_album;
desc pms_picture;
desc pms_category;
desc pms_brand;
desc pms_brand_category;
desc pms_attribute;
desc pms_attribute_template;
desc pms_spu;
desc pms_spu_detail;
desc pms_sku;
desc pms_sku_specification;

4. 关于Project与Module

Project:项目 / 工程

Module:模块

在较大规范的项目开发中,可能会把代码区分为多个Module进行开发,即某1个Project中可能有多个Module,各Module允许独立开发、独立运行,并且,可以在Project或某个父级Module中,对其子级的依赖项等部分的内容进行统筹管理。

需要注意:并不是每个Module都是可以独立运行的,在开发实践中,如果某些代码是多个Module都需要使用的,可以把这部分代码写在专门的Module中,其它Module依赖这个专门的Module即可(就像添加某个依赖项一样)。

当使用Project结合多个Module开发时,Project基本上不需要编写任何与功能相关的代码,只需要配置好pom.xml即可。

5. 创建Project

使用Spring Boot创建向导来创建Project,相关参数:

  • Spring Boot父工程版本:2.5.9
  • groupId:cn.tedu
  • artifactId:csmall-server
  • version:0.0.1-SNAPSHOT

由于Project并不需要运行(也不能运行),对于各依赖项,只需要管理即可,并不需要实际的添加!

在Project的pom.xml中,如果直接使用<dependencies>节点配置依赖项,则每个Module可以直接使用这些依赖项!但是,不推荐这样使用,因为Spring Boot的许多依赖都是支持自动配置的,如果在Module中自带了不需要使用的依赖项,反而容易导致错误,即使不会导致错误,也会因为自带了不需要使用的依赖项而导致最终的目标文件大。

通常,会将依赖项的代码放在<dependencyManagement>节点中,则在<dependencyManagement>之下的依赖项都不会默认出现在当前Project及各子级的Module中,其主要作用是配置各依赖项的版本,接下来,无论是在当前Project还是子级Module中,使用<dependencies>添加依赖项时,都可以不指定<version>节点来配置版本,默认使用的就是在<dependencyManagement>中配置的版本。

为了在当前pom.xml集中管理各依赖的版本号,推荐在<properties>中添加一些“变量”,用于配置版本号,在<dependencyManagement><dependencies>中添加依赖时,都可以引用此处的“变量”表示版本,例如:

<properties>
    <java.version>1.8</java.version>
    <spring-boot.version>2.5.9</spring-boot.version>
    <mybatis-boot.version>2.2.2</mybatis-boot.version>
    <mysql.version>8.0.28</mysql.version>
    <lombok.version>1.18.22</lombok.version>
</properties>

另外,由于Project并不实现的编写需要运行的功能代码,更不会直接编译打包或运行,所以,在Project的pom.xml中的<build>节点是不必要的!

最后,把Project的src全部删除!

6. 商品管理模块项目

应该在Project下创建某个Module,用于开发商品管理相关的功能,为了便于过渡到后续将要使用的微服务架构(需要将业务逻辑层的接口声明在专门的Module中,便于被其它微服务Module依赖),商品管理的Module需要再细分为2个,所以,目前项目结构应该是:

cgb2202-csmall-server[project]
	csmall-product
		csmall-product-webapi
		csmall-product-service

当存在Project和Module的“父子关系”或后续可能存在Module与Module的“父子关系”时,应该在父级的pom.xml中添加:

<packaging>pom</packaging>

并且,在父级的pom.xml中,通过<modules>节点配置各子级Module,例如:

<modules>
	<module>csmall-product</module>
</modules>

创建Module的操作步骤为:在cgb2202-csmall-server下创建csmall-product,再在csmall-product下创建csmall-product-webapi

当Project和各Module创建出来后,调整各pom.xml文件。

最终,cgb2202-csmall-server根级Project的pom.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>

    <!-- Spring Boot父项目 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.9</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <!-- 当前项目的信息 -->
    <groupId>cn.tedu</groupId>
    <artifactId>csmall-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <!-- 聚合项目中的父级Project或父级Module都应该做以下配置 -->
    <packaging>pom</packaging>

    <!-- 当前Project的各子级Module -->
    <modules>
        <module>csmall-product</module>
    </modules>

    <!-- 属性配置,主要配置各依赖项的版本号对应的“变量” -->
    <properties>
        <java.version>1.8</java.version>
        <spring-boot.version>2.5.9</spring-boot.version>
        <mybatis-boot.version>2.2.2</mybatis-boot.version>
        <mysql.version>8.0.28</mysql.version>
        <lombok.version>1.18.22</lombok.version>
        <druid.version>1.1.20</druid.version>
    </properties>

    <!-- 依赖管理,主要管理各依赖项的版本,使得子级Module添加依赖时不必指定版本 -->
    <dependencyManagement>
        <dependencies>
            <!-- Spring Boot Validation:验证请求参数的基本格式 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-validation</artifactId>
                <version>${spring-boot.version}</version>
            </dependency>
            <!-- Spring Boot Web:支持Spring MVC -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <version>${spring-boot.version}</version>
            </dependency>
            <!-- Mybatis Spring Boot:Mybatis及对Spring Boot的支持 -->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis-boot.version}</version>
            </dependency>
            <!-- MySQL -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
                <version>${mysql.version}</version>
            </dependency>
            <!-- Lombok -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
                <version>${lombok.version}</version>
            </dependency>
            <!-- Druid数据库连接池 -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>${druid.version}</version>
            </dependency>
            <!-- Spring Boot Test:测试 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
                <version>${spring-boot.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

csmall-productpom.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>cn.tedu</groupId>
        <artifactId>csmall-server</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <!-- 当前项目的信息 -->
    <groupId>cn.tedu</groupId>
    <artifactId>csmall-product</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <!-- 聚合项目中的父级Project或父级Module都应该做以下配置 -->
    <packaging>pom</packaging>

    <!-- 当前Project的各子级Module -->
    <modules>
        <module>csmall-product-webapi</module>
    </modules>

</project>

最后,在csmall-product-webapipom.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>cn.tedu</groupId>
        <artifactId>csmall-product</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <!-- 当前项目的信息 -->
    <groupId>cn.tedu</groupId>
    <artifactId>csmall-product-webapi</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <!-- 当前项目需要使用的依赖项 -->
    <dependencies>
        <!-- Spring Boot Validation:验证请求参数的基本格式 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <!-- Spring Boot Web:支持Spring MVC -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Mybatis Spring Boot:Mybatis及对Spring Boot的支持 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!-- MySQL -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- Druid数据库连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>
        <!-- Spring Boot Test:测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

7. 关于编写代码

根据已经添加的数据表,目前此项目中需要管理的数据类型大致有:

  • 品牌
  • 类别
  • 图片
  • 相册
  • 属性
  • 属性模版
  • SPU
  • SKU
  • 相关的关联表

首先,需要分析以上数据类型的开发先后顺序,部分数据之间存在依赖与被依赖关系,例如SKU肯定归属于某个SPU,在开发时,必须先开发SPU,再开发SKU,同理,必须先开发品牌,才可以开发SPU……

根据分析,必要的顺序为:(品牌 | 类别 | (相册 >>> 图片) | (属性模板 >>> 属性)) >>> SPU >>> SKU。

分析出必要顺序后,存在一些不需要严格区分顺序的数据类型,例如以上的品牌和类型,实际的开发顺序可以是先简单、后复杂,例如品牌数据通常比类别数据更加简单,则应该先开发品牌数据的管理,再开发类别数据的管理。

本次学习过程中,先开发类别,至于品牌,可自行课后完成!

当确定了需要处理类别的数据时,需要规划需要开发此数据的哪些管理功能,例如:添加类别、启用类别、禁用类别、修改类别的基本信息、根据id查询、根据parent_id查询列表……

以上管理类别数据的功能,开发顺序应该是:添加类别 >>> (根据id查询 | 根据parent_id查询列表) >>> (启用类别 | 禁用类别 | 修改类别的基本信息)

8. 类别管理–添加类别–持久层

8.1. 配置

由于目前是本项目第1次开发持久层,必须先完成必要的配置,包括:

  • 连接到数据库(配置连接数据库的参数)
  • 使用@MapperScan指定接口所在的包
  • 配置mybatis.mapper-locations指定XML文件的位置

应该先在csmall-product-webapisrc\main\resources下创建application-dev.properties文件,在其中添加连接数据库的参数:

# 连接数据库的配置信息
spring.datasource.url=jdbc:mysql://localhost:3306/mall_pms?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root

然后,在application.properties中添加配置:

# 激活Profile配置
spring.profiles.active=dev
# 连接数据库的固定配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

# Mybatis的XML文件位置
mybatis.mapper-locations=classpath:mapper/*.xml

然后,需要在src/main/resources下自行创建mapper文件夹,与以上配置对应。

还需要自行创建配置类,用于配置Mapper接口文件所在的包,则在cn.tedu.csmall.product.webapi下创建mapper子包,并在cn.tedu.csmall.product.webapi下创建config.MybatisConfiguration配置类,进行配置:

package cn.tedu.csmall.product.webapi.config;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("cn.tedu.csmall.product.webapi.mapper")
public class MybatisConfiguration {

}

完成后,可以尝试测试连接到数据库,则在src/test/java下找到默认即存在的测试类,编写并执行测试:

package cn.tedu.csmall.product.webapi;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import javax.sql.DataSource;

@SpringBootTest
class CsmallProductWebapiApplicationTests {

    @Autowired
    DataSource dataSource;

    @Test
    void contextLoads() {
    }
    
    @Test
    void testConnection() {
        Assertions.assertDoesNotThrow(() -> {
            dataSource.getConnection();
        });
    }

}

执行整个测试,应该能够通过测试。

8.2. 规划需要执行的SQL语句

此次需要执行的是“增加类别”,其数据操作的本质是向pms_category表中插入数据,需要执行的SQL语句大致是:

insert into pms_category (除了id以外的字段的列表) values (与字段列表匹配的各字段值);

具体表现为:

insert into pms_category (name, parent_id, depth, keywords, sort, icon, enable, is_parent, is_display, gmt_create, gmt_modified) values (值列表);

另外,还应该考虑在“添加类别”时,是否需要执行相关的检查,因为这些检查很可能是通过查询数据库来实现的,则在持久层也需要实现这些功能!

暂定规则“类别的名称不允许重复”,则后续在Service层进行处理时,应该先根据尝试添加的类别的名称进行查询,如果查询结果为null,表示此名称对应的类别尚不存在,将允许添加,如果查询结果不为null,表示此名称对应的类别已经存在,将不允许添加!

要实现以上检查的效果,需要执行的SQL语句可以是:

select * from pms_category where name=?;

或者:

select count(*) from pms_category where name=?;

以上2种做法,第1种做法的查询效率相对较低,或者说性能消耗略高,第2种做法的查询性能消耗更低,但是,第1种做法的查询可能具有复用性,而第2种做法的查询的复用性相对较低。

暂定可以使用以上第1种做法。

8.3. 接口与抽象方法

在插入数据之前,需要先创建“类别”对应的实体类型,而这个实体类型不能直接创建在csmall-product-webapi模块中,而是应该创建在另一个新的模块中,以便于其它各模块都可以使用到相同的实体类型(例如商品的实体类型,在商品管理模块和订单管理模块中都将需要使用)。

在Project中创建新的子模块csmall-pojo,创建出来后,需要:

  • 修改父项目
    • csmall-pojopom.xml中修改
    • 在根项目的pom.xml中添加新的<module>
  • 确定所需的依赖项
    • 需要依赖lombok,其它依赖项暂时不需要
  • 删除不要的代码
    • pom.xml中只需要:父项目、当前项目的信息、依赖项
    • 启动类是不需要的,必须删除(因为没有依赖Spring Boot,不删除则报错)
    • src/main/resource是不需要的(包含其下的application.properties),可以删除
    • src/test是不需要的,必须删除(否则默认的测试类会报错)

然后,在cn.tedu.csmall.pojo.entity包下创建Category类:

package cn.tedu.csmall.pojo.entity;

import lombok.Data;

import java.io.Serializable;
import java.time.LocalDateTime;

@Data
public class Category implements Serializable {

    private Long id;
    private String name;
    private Long parentId;
    private Integer depth;
    private String keywords;
    private Integer sort;
    private String icon;
    private Integer enable;
    private Integer isParent;
    private Integer isDisplay;
    private LocalDateTime gmtCreate;
    private LocalDateTime gmtModified;

}

为了实现其它Module可以依赖csmall-pojo,应该先在根级Project的pom.xml中对csmall-pojo实现依赖管理:

<!-- ===== 其它原有代码 ===== -->

<!-- 属性配置,主要配置各依赖项的版本号对应的“变量” -->
<properties>
    <!-- ===== 其它原有代码 ===== -->
    <csmall.version>0.0.1-SNAPSHOT</csmall.version> <!-- 新增 -->
</properties>

<!-- 依赖管理,主要管理各依赖项的版本,使得子级Module添加依赖时不必指定版本 -->
<dependencyManagement>
    <dependencies>
        <!-- Csmall POJO -->
        <dependency>
            <groupId>cn.tedu</groupId>
            <artifactId>csmall-pojo</artifactId>
            <version>${csmall.version}</version>
        </dependency>
        
        <!-- ===== 其它原有代码 ===== -->

然后,在csmall-product-webapipom.xml中添加依赖:

<!-- ===== 其它原有代码 ===== -->

<!-- 当前项目需要使用的依赖项 -->
<dependencies>
    <!-- Csmall POJO -->
    <dependency>
        <groupId>cn.tedu</groupId>
        <artifactId>csmall-pojo</artifactId>
    </dependency>
    
    <!-- ===== 其它原有代码 ===== -->

至此,在csmall-product-webapi中就已经成功的依赖了csmall-pojo,可以理解为csmall-pojo已经成为csmall-product-webapi的一部分。

cn.tedu.csmall.product.webapi.mapper包下创建CategoryMapper接口,并在接口上添加@Repository注解(主要是避免IntelliJ IDEA在自动装配时的误判错误),并在接口中添加抽象方法:

/**
 * 处理“类别”数据的持久层接口
 */
@Repository
public interface CategoryMapper {

    /**
     * 插入“类别”数据
     * @param category 类别
     * @return 受影响的行数
     */
    int insert(Category category);
    
    // 查询--待定

}

8.4. 配置SQL语句

从其它位置(或项目)中复制粘贴CategoryMapper.xmlcsmall-product-webapisrc/main/resources/mapper下。

关于CategoryMapper.xml文件的配置:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="cn.tedu.csmall.product.webapi.mapper.CategoryMapper">

    <!-- int insert(Category category); -->
    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        insert into pms_category (
            name, parent_id, depth, keywords, sort,
            icon, enable, is_parent, is_display, gmt_create,
            gmt_modified
        ) values (
            #{name}, #{parentId}, #{depth}, #{keywords}, #{sort},
            #{icon}, #{enable}, #{isParent}, #{isDisplay}, #{gmtCreate},
            #{gmtModified}
        )
    </insert>

</mapper>

8.5. 测试

先在src/test下创建resources文件夹,并在此文件夹中创建truncate.sql脚本,此脚本将用于重置数据表:

truncate pms_category;

然后,在src/test/java的根包下创建mapper.CategoryMapperTests,编写并执行测试:

package cn.tedu.csmall.product.webapi.mapper;

import cn.tedu.csmall.pojo.entity.Category;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.jdbc.Sql;

@SpringBootTest
public class CategoryMapperTests {

    @Autowired
    CategoryMapper mapper;

    @Test
    @Sql("classpath:truncate.sql")
    public void testInsert() {
        // 测试数据
        Category category = new Category();
        category.setName("手机");
        // 断言不会抛出异常
        assertDoesNotThrow(() -> {
            int rows = mapper.insert(category);
            assertEquals(1, rows);
            assertEquals(1, category.getId());
        });
    }

}

9. 类别管理–添加类别–业务逻辑层

10. 类别管理–添加类别–控制器层

11. 类别管理–添加类别–前端页面

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青木编码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值