商城三级分类的设计与开发

数据库的结构设计

三级分类的sql如下,要有三级分类,那就需要两层的父类id(cat_id,parent_cid)需要有商品的名称和层级及其显示状态,还需要有各自的优先级,单位,每层的数量,还有图片信息。

DROP TABLE IF EXISTS `pms_category`;

CREATE TABLE `pms_category` (
  `cat_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '分类id',
  `name` char(50) DEFAULT NULL COMMENT '分类名称',
  `parent_cid` bigint(20) DEFAULT NULL COMMENT '父分类id',
  `cat_level` int(11) DEFAULT NULL COMMENT '层级',
  `show_status` tinyint(4) DEFAULT NULL COMMENT '是否显示[0-不显示,1显示]',
  `sort` int(11) DEFAULT NULL COMMENT '排序',
  `icon` char(255) DEFAULT NULL COMMENT '图标地址',
  `product_unit` char(50) DEFAULT NULL COMMENT '计量单位',
  `product_count` int(11) DEFAULT NULL COMMENT '商品数量',
  PRIMARY KEY (`cat_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1433 DEFAULT CHARSET=utf8mb4 COMMENT='商品三级分类';

如下为京东的主页三级分类在这里插入图片描述
淘宝的三级分类
在这里插入图片描述

前端开发

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
上图中创建的菜单路由也就是vue模块之间的路由信息,在后台管理面板创建的内容,都应该在对于路径下编写一个自定义模块(菜单路由的- 就相当于目录的/)
在这里插入图片描述
创建category.vue,参照官方文档的分类tree组件很简单的就可以完成功能

<template>
  <el-tree :data="menus" :props="defaultProps" @node-click="handleNodeClick"></el-tree>
</template>

<script>
export default {
  data() {
    // menus就是菜单全部内容    defaultProps就是指定子树的属性   label就是真正显示的属性
    return {
      menus: [],
      defaultProps: {
        children: "children",
        label: "name"
      }
    };
  },
  methods: {
    handleNodeClick(data) {
      console.log(data);
    },
    //    获取三级三级分类菜单
    getMenus() {
      this.dataListLoading = true;
      this.$http({
        url: this.$http.adornUrl("/product/category/list/tree"),
        method: "get"
        //   将data结构出来,代表的是data.data,避免加载一些不需要的内容
      }).then(({ data }) => {
        console.log(data.data);
        this.menus = data.data;
      });
    }
  },
  created() {
    this.getMenus();
  }
};
</script>
<style>
</style>

修改项目发送请求的url地址,让给后台配置的网关发送请求
在这里插入图片描述

后端开发

首先对mall-product微服务配置服务发现与注册,还有配置中心相关内容

编写bootstrap.properties并添加配置信息

spring.application.name=mall-product
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=e0f2063f-fdeb-4b7f-a728-41451d323ebe

在以前的基础上添加服务发现与注册

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://192.168.142.3:3306/gulimall_pms
    driver-class-name: com.mysql.cj.jdbc.Driver
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
  application:
    name: mall-product

# 配置xml映射文件  设置id-type  auto  自增主键
mybatis-plus:
  mapper-locations: classpath*:/mapper/**/*.xml
  global-config:
    db-config:
      id-type: auto
server:
  port: 10001

在启动类上添加开启服务发现

@MapperScan("com.wrial.mall.product.dao")
@EnableDiscoveryClient
@SpringBootApplication
public class MallProductApplication {

    public static void main(String[] args) {
        SpringApplication.run(MallProductApplication.class, args);
    }

}

将product注册完成后,在controller中编写对应的API

package com.wrial.mall.product.controller;

/**
 * 商品三级分类
 *
 * @author wrial
 * @email 2806935450@qq.com
 * @date 2020-05-01 17:11:57
 */
@RestController
@RequestMapping("product/category")
public class CategoryController {
    @Autowired
    private CategoryService categoryService;

    /**
     * 查询所有分类及其子分类,分类树
     */
    @RequestMapping("/list/tree")
    public R list(){
        List<CategoryEntity> tree = categoryService.listWithTree();
        return R.ok().put("data", tree);
    }

}

对CategoryEntity进行扩展

package com.wrial.mall.product.entity;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

import lombok.Data;

/**
 * 商品三级分类
 * 
 * @author wrial
 * @email 2806935450@qq.com
 * @date 2020-05-01 17:11:57
 */
@Data
@TableName("pms_category")
public class CategoryEntity implements Serializable {
	private static final long serialVersionUID = 1L;

	/**
	 * 分类id
	 */
	@TableId
	private Long catId;
	/**
	 * 分类名称
	 */
	private String name;
	/**
	 * 父分类id
	 */
	private Long parentCid;
	/**
	 * 层级
	 */
	private Integer catLevel;
	/**
	 * 是否显示[0-不显示,1显示]
	 */
	private Integer showStatus;
	/**
	 * 排序
	 */
	private Integer sort;
	/**
	 * 图标地址
	 */
	private String icon;
	/**
	 * 计量单位
	 */
	private String productUnit;
	/**
	 * 商品数量
	 */
	private Integer productCount;

	/**
	 * 当前分类下的子分类,不是数据库中有的,所以进行标记 (扩展)
	 */
	@TableField(exist = false)
	private List<CategoryEntity> children;

}

在service层中调用dao层查出所有category,然后使用streamAPI完成组装

package com.wrial.mall.product.service.impl;
@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<CategoryEntity> page = this.page(
                new Query<CategoryEntity>().getPage(params),
                new QueryWrapper<CategoryEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public List<CategoryEntity> listWithTree() {
        // 1.查询出所有
        List<CategoryEntity> all = baseMapper.selectList(null);
        // 2.查询出所有一级分类(parentId=0) 然后递归查询下面的分类信息,并按照sort进行排序
        List<CategoryEntity> level1 = all.stream()
                .filter(categoryEntity -> categoryEntity.getParentCid() == 0)
                .map((currentCategory) -> {
                    currentCategory.setChildren(getChildren(currentCategory, all));
                    return currentCategory;
                })
                .sorted(Comparator.comparingInt(cat -> (cat.getSort() == null ? 0 : cat.getSort())))
                .collect(Collectors.toList());

        return level1;
    }

    private List<CategoryEntity> getChildren(CategoryEntity parentCategory, List<CategoryEntity> all) {

        List<CategoryEntity> children = all.stream().filter(currentCategory -> parentCategory.getCatId().equals(currentCategory.getParentCid()))
                .map(currentCategory -> {
                    currentCategory.setChildren(getChildren(currentCategory, all));
                    return currentCategory;
                }).sorted(Comparator.comparingInt(cat -> (cat.getSort() == null ? 0 : cat.getSort())))
                .collect(Collectors.toList());

        return children;
    }

}

编写完逻辑代码,接下来进对网关进行设置,在前面已经对网关服务发现与注册,以及配置中心都进行了配置,下面主要是对网关的路由进行配置,添加一条路由(一定要放在renren-fast前,因为最左前缀匹配原则)

# 可以配多个route
spring:
  cloud:
    gateway:
      routes:
        - id: product_route
          uri: lb://mall-product
          predicates:
            - Path=/api/product/**
          filters:
            - RewritePath=/api/(?<segment>/?.*), /$\{segment}
        - id: admin_route
          uri: lb://renren-fast
          predicates:
            - Path=/api/**
          filters:
            - RewritePath=/api(?<segment>/?.*), /renren-fast/$\{segment}


    #  前端项目都带一个api就转给renren-fast
    #  http://localhost:88/api/captcha.jpg => http://localhost:8080/renren-fast/captcha.jpg
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
  application:
    name: mall-gateway

也可以通过配置类的方式来给容器中放入一个路由的Bean实例

    @Bean
    public RouteLocator rewritePath(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("admin_route", r ->
                        r.path("/api/**").filters(f -> f.rewritePath("/api/(?<segment>.*)","/renren-fast/$\\{segment}"))
                                .uri("lb://renren-fast"))
                .build();
    }

这样,启动服务进行测试,发现还是不能通过,因为还未进行跨域处理
下面编写了一个针对跨域的配置类,当然方法有很多不局限于这一种
在这里插入图片描述

package com.wrial.mall.gateway.config;
/*
 * @Author  Wrial
 * @Date Created in 17:44 2020/5/5
 * @Description 配置跨域信息
 */

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;

@Configuration
public class MallCorsConfiguration {

    @Bean
    public CorsWebFilter corsWebFilter(){
        UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();

        CorsConfiguration corsConfiguration = new CorsConfiguration();

        // 配置
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.setAllowCredentials(true);  // 允许携带cookie

        corsConfigurationSource.registerCorsConfiguration("/**",corsConfiguration);
        return new CorsWebFilter(corsConfigurationSource);
    }
}

演示

启动项目
在这里插入图片描述
在这里插入图片描述
一个简单的三级分类这样就展示了出来,后边就再完成其增删改以及其他优化

  • 0
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值