乐优商城搭建中的笔记

请求流程先在网页上请求然后传到nginx再到eureka容器再到zuul再到微服务:

leyou-registry是eureka的module
leyou-geteway是zuul网关的module
leyou-item是一个聚合模块,<packaging>pom</packaging>是声明打包方式为pom,声明是聚合模块
leyou-item里面有一个leyou-item-interface,它的作用是相当于存放一些pojo对象的,也存放一些异常,iangge工程调用都可以用这些异常放在goods,也存放其他的工程需要的东西
leyou-item里面有一个leyou-item-service是微服务模块,对商品的管理增删改查都是在这个模块中进行的
leyou-common是存放工具类

每个包具体功能如下:


如下图 ,goods是商品,当商品服务工程需要处理goods就要用goods对象,当商品管理工程处理
goods也要弄一个对象,这样就会发生当一个goods发生变化而另外的工程的goods还没有反应过来,可以将goods做成一个依赖,这样就两个工程都可以用它。

如下图的是扫描的pojo对象,但是就要有这个路径让他扫描,所以以后到这一步就要想起来有没有这个路径,而且这个路径是在interface中,但是这个application.yml是在leyou-item-service中的,不过leyou-item-service中引入了leyou-item-interface依赖,所以即使application.yml是在leyou-item-service中的也是可以扫描application.yml是在leyou-item-interface中的路径

 注意:npm install vue@2.5.16 --save其中@2.5.16就是项目需要什么版本的版本号就下载这个的版本号
后台前端已经搭建完毕
build:是webpack的一些文件。
config:webpack运行的一些环境参数,例如运行完以后的端口为9001就是在在config中的index.js改的。
diat:打包的一个目录,比如vue就有dist
static:静态资源
package:比较重要,就相当于pom.xlm,添加依赖和配置
src:assets是存放资源的,图片,scc啥的
components:全局定义我们的组件
pages:是页面本质也是组件,pages下的layou.vue下的<template>存放模板,<script>存放vue实例的js代码。后台管理的前台是一个单页面应用,如图:

 这里面只有一个app容器,它的实例在src下的main.js中

项目后台前端的运行流程

Vuetify框架,基于vue的UI框架





其中在controller的“Responseentity,这个的作用就是将tostring的字符数据转化为json的数据格式,我认为这是它的最大作用。
跨域问题:

 

 
 

 解决问题:本项目采用的是cors的反向代理

 什么是cors

简单请求是八种

特殊请求

 
 

 在网关里添加一个config包,里面有一个LeyouCorsConfiguration类就是配置的跨域请求,别的里面也能陪但是为什么配到网关里?因为每个服务都要访问这个网关的,所以都可以用,如果只配置到单一的服务里,以后别的服务在访问就又要配置了。

请求处理过程红色线是处理数据请求,黑色线是处理显示页面过程

 比如一个http://api.leyou.com/api/item/category/list?pid=0的地址,先去host看是不是本地地址然后去nginx中根据设置的server_name:api.leyou.com      proxy_pass:http://127.0.0.1:10010在后边根据10010监听到找到10010以后还剩api/item/category/list?pid=0,然后去zuul网关里面找到prefix为api的routers为中根据网址的api的后面的网址找到相对应的routers,例子是item所以就去找微服务名字为item-service的微服务,进去名字为item-service的微服务以后网址中路径还剩category/list?pid=0,进入Controller中找到Mapper为category的然后再去找list下边的方法将pid参数传进去然后再原路返回



响应数据添加@ResponseEntity,接收数据加@ResquesdBody
如果前台传过的数据是json数据再Controller里面只能有一个对象为参数,这时候可以用一个第三方工具qs工具,可以用命令npm install qs --save将json转换成一个一个的字符串

页面的校验

 

 如上图红色的提示就是在BrandFrom.vue文件的required  :rules:"nameRules"就是规定必填还有填入的规则

图片上传: 图片上传绕过网关:再nginx中修改然后直接绕过zuul网关到微服务


因为文件上传的都是有upload的路径,所以在配置文件中判如果是这个路径的就路由到8082其他的都到10010中 

在nginx中location越大的越给后边放

fastDFS:是分布式文件系统->


规格参数:SPU       SKU

 sku才是一个商品的细分,比如手机金色还是黑色每一个颜色都是一个sku
spu包含一推东西,比如手机是小米八怎么换颜色换内存都是小米八,是一个总的集合就是spu
如下图中有个

是否为通用字段回传给数据库的 tb_spec_param然后有个是否通用,前端传过去的是flase或者true,但是数据库是0或1,这是因为generic的数据类型tinyint,然后如果在前台显示的话先判断是不是通用的字段。如果是flase那就去tb_sku里的own_spec找相关的内容,如果是ture那就去tb_spu_detail里面generic_spec找内容

数据库表的关系

表结构场景解析:渲染前端的商品详情页的参数:

先点击商品获取spu_id

那个数字就是sku表的spu_id可以查询到spu表的信息,spu表中有个三级分类cid1,cid2,cid3.根据三级的分类可以定位到组也就是tb_spec_group表所对应的cid字段渲染到页面如下图

可以渲染成这样

然后如果想看

标记这一点是tb_spec_group里面通过cid去tb_spec_param找对应的cid然后渲染出来 
想要有详情介绍就是字段就是在上边说的有spu_id然后去spu_detial表中拿到相关的数据包括generic_spec的json字段。
  如何渲染下边这个页面

根据spu_id去spuDetial找到special_spec字段的值渲染到上边再获取special_spec渲染多少GB等等


产品参数规格的设置:后台设置:SpecificationController和SpecificationService是同时处理SpecGroupMapper和SpecParamMapper以及这两个的pojo实体类。

注意:在开发过程中发现一个通用Mapper的一点注意点(没学过Mapper),例如查询代码:


 


 

CollectionUtils是来处理集合的,基本是用来判断集合是否为空集合的长度如下图:

如果不加 注释掉的那一行specParam.setGroupId(gid);那么就是查询的全部的,因为return里面用的通用Mapper的select个人实验是:因为select括号里是一个对象specParam(实体类),所以呢这个对象很对字段,它是根据字段查询的,比如现在加了注释赋值的地方,所以这个实体类的字段都是空的,所以查询的时候都是全部显示出来,如果有一个字段有值的话那么就按照这个值来查询,如果有两个的话就多条件查询,显示同时满足这里这两个字段的。
在处理新增的数据的时候,在controller层中添加@RequestBody注解来响应;
再给后台的商品管理里面的规格参数里里做增删改查,里面的接口名称一样但是为什么访问的不一样呢,是因为里面的而访问请求不一样如下图:

 一个是post一个是put,所以前端的请求post的去后端的postMapping,请求put的去putMapping。
修改我用的是通用mapper的updateByPrimaryKey如下图:

package com.leyou.item.service;


import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.leyou.common.pojo.PageResult;
import com.leyou.item.bo.SpuBo;
import com.leyou.item.mapper.BrandMapper;
import com.leyou.item.mapper.SpuDetailMapper;
import com.leyou.item.mapper.SpuMapper;
import com.leyou.item.pojo.Brand;
import com.leyou.item.pojo.Spu;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Lym
 * @version 1.0
 * @date 2021/11/12 17:30
 */
@Service
public class GoodsServise {

    @Autowired
    private SpuMapper spuMapper;

    @Autowired
    private SpuDetailMapper spuDetailMapper;

    @Autowired
    private BrandMapper brandMapper;

    @Autowired
    private CategoryService categoryService;

    public PageResult<SpuBo> querSpuByPage(String key, Boolean saleable, Integer page, Integer rows) {

        Example example = new Example(Spu.class);
        Example.Criteria criteria = example.createCriteria();


        //添加条件查询
        if (StringUtils.isNotBlank(key)) {
            criteria.andLike("title", "%" + key + "%");
        }

        //添加上下架的过滤条件
        if (saleable != null) {
            criteria.andEqualTo("saleable", saleable);
        }
        //添加分页
        PageHelper.startPage(page, rows);
        //执行查询,获取spu集合
        List<Spu> spus = this.spuMapper.selectByExample(example);
        PageInfo<Spu> pageInfo = new PageInfo<>(spus);
        //spu集合转化成spubo集合
        List<SpuBo> spuBos = spus.stream().map(spu -> {
            SpuBo spuBo = new SpuBo();
            BeanUtils.copyProperties(spu, spuBo);

            //查询品牌名称
            Brand brand = this.brandMapper.selectByPrimaryKey(spu.getBrandId());
            spuBo.setBname(brand.getName());
            //查询分类名称
            List<String> names = this.categoryService.queryNameById(Arrays.asList(spu.getCid1(), spu.getCid2(), spu.getCid3()));
            spuBo.setCname(StringUtils.join(names, "-"));
            return spuBo;
        }).collect(Collectors.toList());

        //返回PageResult<SpuBo>
        return new PageResult<>(pageInfo.getTotal(),spuBos);
    }

}

如上图,这是一个想要展示一个页面所需的几个步骤,这只是例子,具体想要怎么弄看情况


 如上图两个空是下拉选择框,第一个之前做了一个分类,但是第二个空是再第一个选择完以后根据他的三级目录的id来查询,所以要做一个新的功能,因为通用mapper没有这个查询方法,所以写了个sql语句
 

@Select("SELECT * FROM tb_brand a INNER JOIN tb_category_brand b ON a.id=b.brand_id WHERE b.category_id=#{cid}")
   List<Brand> selectBrandsByCid(Long cid);

这是内连接,为什么要用内连接,是因为他的品牌名称在tb_brand的表中,而前边三级目录选择下拉是在tb_—category—brand表中,所以需要两张表链接,为什么不left jion?因为如果左连接,这样的话如果穿的是空的id也会出现品牌,这样就会出现第一个下拉框没有传进去id第二个下拉框就会出现品牌,右链接是传进去id可能会出现空的品牌,这样下拉框下拉选择的时候会出现空的品牌选择这样都是不合理的。

 

 如上两个图的实现功能代码如下
 

public List<SpecParam> queryParams(Long gid,Long cid,Boolean generic,Boolean searching) {
        SpecParam specParam = new SpecParam();
        specParam.setGroupId(gid);
        specParam.setCid(cid);
        specParam.setSearching(searching);
        specParam.setGeneric(generic);
        return this.specParamMapper.select(specParam);
    }

是实现在tb_spec_param这张表,这张表就是手机的参数。一共四个参数,可以选择如果gid是空就查cid以此类推。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值