javaee之黑马乐优商城4

商品规格与数据结构

下面来说一下数据库的设计与分析

其实对于spu这张表来说,大体设计还是比较好设计的

看一下下面这张图是一个产品的规格参数

上面主体就是一个规格参数,基本信息又是一个规格参数

这里就是涉及到了一个商品的具体信息,sku就是一个具体带有了规格参数的商品

先不管上面表设计的具体细节,先来看下面一张图

那我们在来分析几张表与表之间的关系

下面对上面的关系进行拓展,先来看下面几个页面

上面这张图就是我们要用于搜索的规格参数,就是哪些规格参数要拿上来作为参数条件

上面这张图就是讲这些规格参数,都是从什么类型的表上获取数据的方式

有了上面的信息,下面我去看一下上面这些表在数据中的具体信息

先来看分类表

这张表创建了一个相关的分类信息,这张表重点关注parent_id与is_parent这两个字段

下面用一张图来解释这个目录结构

下面在讲解一下sort这个排序指数,越小越靠前

下面我们说一下一般在数据库里面我们都怎样进行查询

1.比如我们查出所有的顶级父类,也就是parent_id = 0 的所有分类

2.下面我们做一个查询是通过某一个父子类,去查找到它下面的所有直接的直接子类,比如下面这样查询

比如点击图书、音像、电子书刊就能找到电子书刊和音像这两个直接子类

首先分析一下,父类与它的直接子类关联的字段就是parent_id,也就是在一棵树中,同级之间的兄弟子类的parent_id都是一样的,于是我们可以进行下面的sql语句查询

如果还要继续深入的往子类与子类的查找,还是查找当前结点的parent_id,然后根据这个parent_id来查找它的直接子类

分类表看了之后,我们来看参数数组表

这个表我们还没有被创建出来,在创建之前,我们先来看一下这张表与tb_category表之间的关系

先用习惯思维考虑一下,一个分类下面肯定有多个参数组的信息,

我们进入淘宝,看一下手机-》华为手机拥有的规格参数信息

上面一个手机分类下面就有很多不同的参数组 ,比如说有基本信息组,有屏幕组,有网络组

下面我们去看一下tb_spec_grop这张表

我们在数据库中还没有构建出来,我们先去把这张表给构建出来

然后现在我们向这个表里面插入一些数据

类似于如下

对于插入做一个简单的数据分析

这个时候我们又要来说到另外一张表

这张表就是规格参数组表的每一个组对应的具体的规格属性,这个可以这样来理解,就是参数组表里面存放的是表头,具体的规格参数名是放在这个规格参数表名里面,这张表的名字是tb_spec_param(明显与参数数组表是一个一(tb_spec_group)对多(tb_spec_param)的关系)

下面我们把这张具体的参数表给创建出来

上面简单分析一下重点字段的得来

上面cid是因为一个分类下面会从sku里面或者spu里面抽取很多参数属性来作为搜索部分的条件

比如下面

其中gid的说明:参数组与参数表是一个1对多的关系,在多的一方肯定引入参数组的id,然后两者才能相互关联

其中generic字段的说明:是否是spu通用属性,意思就是这个属性是不是放到大家都能查找到的部分,也就是规格参数里面共同的部分,比如主体信息,这个字段的重要性在于如果它是ture,也就是通用属性,我们要去spu里面参数值,如果不是通用部分,我们要去sku里面找值

上面就是创建了这张表,下面我们去插入这张表的具体数据

类似于下面这些值

下面我们可以去看一下这张表里面保存的数据信息

下面我们说一下规格参数组页面分析

这里我们要实现点击一个分类之后,他会拿出一个参数组,同时我们还可以拿到这个参数组对应的参数列表

情况如下

其实最后点击啊落到的位置就是一个分类树你下面非父结点的位置,他下面才是保存真正的商品,也就是一个分类树下面,这个节点is_parent = 0 ,他下面就是保存了具体的商品

下面继续分析这个页面布局

上面这是初始页面

我们如果一直点,然后点到最后,他会提示

因为规格是与商品分类绑定的,因此首先会展示商品分类树,提示你要选择的商品分类,才能看到规格参数模板,下面看一下页面实现

这个页面我们简单去了解一下前端

下面就是右侧部分,我们规格参数展示的效果

下面就是展示具体的参数数据

下面这些内容都可以大概的看一看

下面的规格参数组和参数信息都是我们自己定义的组件,去找一下这个组件

找到页面中的点击事件,这个就是我们要清楚页面是怎么发的

在获得分类之后我们有一个点击事件

上面就是handleClick这个点击事件

这个点击事件,我们就可以去获取到这个节点一些信息,并且给它封装到了currentNode这个对象里面

下面我们具体展示规格参数组的组件SpecGroup.vue

上面就会发送一个请求,根据分类来找到参数组

有了这样一个接口之后,我们就可以去写页面

请求方式:get 请求参数是一个cid,请求路径是/spec/groups 返回的是什么?

分析一下这里是一个表

也没有进行分页,所以大概率情况下是返回一个List集合,里面保存的是一个参数规格组的对象

下面就可以去实现这部分的代码

下面看tb_spec_group这个表关联的类SpecGroup

java 复制代码
package com.leyou.item.pojo;

import javax.persistence.*;

@Table(name = "tb_spec_group")
public class SpecGroup {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;//自己的主键id

    private Long cid;//里面维护一个分类id,利用这个id可以找到参数组头

    //我们需要查询一个分组下面的规格参数
    //这个spec_group表与spec_param表是一个1对多的关系
    //所以我们放一个Spec_param的集合对象
    //这个是1的一方,引入集合个多的一方
    @Transient
    private List<SpecParam> params;
}

下面去做tb_spec_param这张表关联的类SpecParam

java 复制代码
package com.leyou.item.pojo;

import javax.persistence.*;

@Table(name="tb_spec_param")
public class SpecParam {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Long cid;
    private Long groupId;
    private String name;
    @Column(name = "`numeric`")
    private Boolean numeric;
    private String unit;
    private Boolean generic;
    private Boolean searching;
    private String segments;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getCid() {
        return cid;
    }

    public void setCid(Long cid) {
        this.cid = cid;
    }

    public Long getGroupId() {
        return groupId;
    }

    public void setGroupId(Long groupId) {
        this.groupId = groupId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Boolean getNumeric() {
        return numeric;
    }

    public void setNumeric(Boolean numeric) {
        this.numeric = numeric;
    }

    public String getUnit() {
        return unit;
    }

    public void setUnit(String unit) {
        this.unit = unit;
    }

    public Boolean getGeneric() {
        return generic;
    }

    public void setGeneric(Boolean generic) {
        this.generic = generic;
    }

    public Boolean getSearching() {
        return searching;
    }

    public void setSearching(Boolean searching) {
        this.searching = searching;
    }

    public String getSegments() {
        return segments;
    }

    public void setSegments(String segments) {
        this.segments = segments;
    }
}

这里有个@Column注解的作用是区分数据库字段这里加上``反引号,是因为numeric这个字段是mysql里面的关键字

下面我们要去编写我们的业务

先去完成mapper这个接口

复制代码
package com.leyou.item.mapper;

import com.leyou.item.pojo.SpecGroup;
import tk.mybatis.mapper.common.Mapper;

public interface SpecGroupMapper extends Mapper<SpecGroup> {
}

上面继承了通用mapper,下面我们去写Controller,写Controller之前,我们先分析一下下面需要的东西,在页面的ajax请求中可以看出

在来说一下这里的Mapper,这里是SpecGroupMapper,为什么不是SpecificationMapper,因为一张表对应一个Mapper,对于规格参数来说,有两个这样类,一个是SpecGroup,一个是SpecParam

SpecificationController.java

java 复制代码
package com.leyou.item.web;

import com.leyou.item.pojo.SpecGroup;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("spec")
public class SpecificationController {
    
    @Autowired
    private SpecificationService specificationService;

    @GetMapping("groups/{cid}")
    public ResponseEntity<List<SpecGroup>> queryGroupsByCid(@PathVariable("cid") Long cid) {
        List<SpecGroup> groups = this.specificationService.queryGroupsByCid(cid);
        if(CollectionUtils.isEmpty(groups)) {
            //如果为空
            //直接构建一个404的状态码
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(groups);
        //另外一种写法
       // return ResponseEntity.status(HttpStatus.OK).body(groups);
    }
}

上面有一个工具类CollectionUtils,这个是spring给我们提供的来处理集合

下面我们又要去完成service里面的方法

java 复制代码
package com.leyou.item.service;

import com.leyou.item.mapper.SpecGroupMapper;
import com.leyou.item.pojo.SpecGroup;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class SpecificationService {

    @Autowired
    private SpecGroupMapper groupMapper;

    public List<SpecGroup> queryGroupsByCid(Long cid) {
        //利用通用mapper中的select完成查询工作,需要传入一个查询的实体类
        SpecGroup specGroup = new SpecGroup();
        specGroup.setCid(cid);
        return this.groupMapper.select(specGroup);
    }


}

下面我们进行一个页面访问测试

重新启动一下ly-item这个微服务

组名没有被查询到

检查了一下代码,发现

根本没有名字给我们返回,原来在下面我忘了加上name这个属性字段

加上重启微服务,同时要注意给这个字段加上set与get方法

上面就完成了参数组的查询操作

下面要去做规格参数的查询

我们可不可以直接找到这个接口

这个接口路径已经被拿到了

按照惯例我们先去分析一下前端页面

这里是点击规格组的时候,就会切换到规格参数的一个显示,那么我们判定肯定是在规格组中绑定了点击事件

下面就会去触发这个方法

这个方法作用是

回到我们的父组件,也就是Specification.vue这个组件

复制代码
<spec-group :cid="currentNode.id" v-show="showGroup" @select="selectGroup"/>

事件处理函数

下面分析一下页面查询规格参数

下面我们去实现代码

先来写上Mapper这个类

然后我们来写我们的Controller类

这个都是规格参数相关的操作,所以用一个SpecificationController类

把请求路径贴过来

方式get,路径是/spec/params

参数是:gid,也就是分组id

返回结果:该分组下的规格参数集合List<SpecParam>

对一这个返回结果来多说一句

一个分类下面的的参数组里面,每一个标题参数对应很多子类参数信息

上面这个主体里面,可能会有多条的记录信息,也就是有多个SpecParam对象

下面我们去完成代码

还是先去写我们的Mapper

再去写我们的service层SpecificationService,这个service还是用之前的SpecificationService,只不过这次使用的Mapper是SpecParamMapper paramMapper

java 复制代码
package com.leyou.item.service;

import com.leyou.item.mapper.SpecGroupMapper;
import com.leyou.item.mapper.SpecParamMapper;
import com.leyou.item.pojo.SpecGroup;
import com.leyou.item.pojo.SpecParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class SpecificationService {

    @Autowired
    private SpecGroupMapper groupMapper;

    @Autowired
    private SpecParamMapper paramMapper;

    public List<SpecGroup> queryGroupsByCid(Long cid) {
        //利用通用mapper中的select完成查询工作,需要传入一个查询的实体类
        SpecGroup specGroup = new SpecGroup();
        specGroup.setCid(cid);
        return this.groupMapper.select(specGroup);
    }

    //之类就是通过参数组的gid来查询参数
    //这里考虑用通用Mapper的select,内部传入一个要返回的集合对象
    public List<SpecParam> queryParams(Long gid) {
        SpecParam param = new SpecParam();
        param.setGroupId(gid);
        return paramMapper.select(param);
    }


}

下面再去写我们的控制层面的代码

它的请求路径我们可以再去看一下

返回的结果就是一个存放很多记录对象的集合,List<SpecParam>

java 复制代码
package com.leyou.item.web;

import com.leyou.item.pojo.SpecGroup;
import com.leyou.item.pojo.SpecParam;
import com.leyou.item.service.SpecificationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("spec")
public class SpecificationController {
    
    @Autowired
    private SpecificationService specificationService;

    @GetMapping("groups/{cid}")
    public ResponseEntity<List<SpecGroup>> queryGroupsByCid(@PathVariable("cid") Long cid) {
        List<SpecGroup> groups = this.specificationService.queryGroupsByCid(cid);
        if(CollectionUtils.isEmpty(groups)) {
            //如果为空
            //直接构建一个404的状态码
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(groups);
        //另外一种写法
       // return ResponseEntity.status(HttpStatus.OK).body(groups);
    }

    //根据参数组的gid查询规格参数
    public ResponseEntity<List<SpecParam>> queryParams(@RequestParam("gid")Long gid) {
       List<SpecParam> params = specificationService.queryParams(gid);
       //对于集合我们通常要做一些安全性检查的判定
        if(CollectionUtils.isEmpty(params)) {
            return ResponseEntity.notFound().build();//直接构建一个404的返回状态码
        }
        return ResponseEntity.ok(params);
    }

}

下面重启商品微服务模块,测试

注意把控制器这里的注解加上

测试一下 ,我们点击了主体这个参数组名,下面就会有很多条记录对象

好了,先写到这,祝大家早安午安晚安。

相关推荐
小陈工1 小时前
Python Web开发入门(十七):Vue.js与Python后端集成——让前后端真正“握手言和“
开发语言·前端·javascript·数据库·vue.js·人工智能·python
科技小花6 小时前
数据治理平台架构演进观察:AI原生设计如何重构企业数据管理范式
数据库·重构·架构·数据治理·ai-native·ai原生
一江寒逸6 小时前
零基础从入门到精通MySQL(中篇):进阶篇——吃透多表查询、事务核心与高级特性,搞定复杂业务SQL
数据库·sql·mysql
D4c-lovetrain6 小时前
linux个人心得22 (mysql)
数据库·mysql
阿里小阿希6 小时前
CentOS7 PostgreSQL 9.2 升级到 15 完整教程
数据库·postgresql
荒川之神6 小时前
Oracle 数据仓库雪花模型设计(完整实战方案)
数据库·数据仓库·oracle
做个文艺程序员7 小时前
MySQL安全加固十大硬核操作
数据库·mysql·安全
不吃香菜学java7 小时前
Redis简单应用
数据库·spring boot·tomcat·maven
一个天蝎座 白勺 程序猿7 小时前
Apache IoTDB(15):IoTDB查询写回(INTO子句)深度解析——从语法到实战的ETL全链路指南
数据库·apache·etl·iotdb
不知名的老吴7 小时前
Redis的延迟瓶颈:TCP栈开销无法避免
数据库·redis·缓存