本篇文章主要介绍一下这个项目中电商系统的分类模块开发。电商系统有很多模块,除了分类模块,还有用户模块,购物车模块,订单模块等等。上一篇文章已经讲了用户模块,这篇文章我们讲讲项目中的分类模块。
有的人可能会很懵,分类模块是个啥?你说的用户模块是针对用户的,购物车模块是针对购物车的,分类模块是什么?其实,在电商系统中,分类模块是用于对商品进行分类和组织的功能模块。它允许商家将商品按照一定的标准进行分类,以便用户能够更容易地浏览和搜索他们感兴趣的商品。
通过上面两幅图,先带大家直观感受下分类模块大概是个啥,脑子里有个画面。
再来通过一个例子了解一下商品分类层级结构:
- 服装(Clothing)
- 男装(Men's Clothing)
- 衬衫(Shirts)
- 裤子(Pants)
- 外套(Jackets)
- 女装(Women's Clothing)
- 连衣裙(Dresses)
- 上衣(Tops)
- 裙子(Skirts)
- 男装(Men's Clothing)
- 鞋类(Shoes)
- 男鞋(Men's Shoes)
- 运动鞋(Athletic Shoes)
- 皮鞋(Dress Shoes)
- 女鞋(Women's Shoes)
- 高跟鞋(High Heels)
- 平底鞋(Flats)
- 男鞋(Men's Shoes)
在导航菜单中显示主分类(例如"服装"和"鞋类"),在各自的子菜单中显示子分类(例如"男装"和"女装")。
了解完分类模块到底是什么后,我们应该想想如何设计分类模块的代码?我们还是从Dao层->service层->controller层这个开发顺序。
设计Dao层
package com.imooc.mall.dao;import com.imooc.mall.pojo.Category;import java.util.List;public interface CategoryMapper {int deleteByPrimaryKey(Integer id); //根据主键id删除对应的商品分类记录int insert(Category record); //插入一条商品分类记录int insertSelective(Category record); //选择性地插入一条商品分类记录,只插入非空字段Category selectByPrimaryKey(Integer id); //根据主键id查询对应的商品分类记录int updateByPrimaryKeySelective(Category record); //选择性地更新商品分类记录,只更新非空字段int updateByPrimaryKey(Category record); //更新商品分类记录的所有字段List<Category> selectAll(); //查询所有的商品分类记录,返回一个商品分类列表
}
上面的代码是一个名为CategoryMapper
的接口,它定义了对商品分类数据进行操作的方法。这些方法定义了对商品分类表的常见操作,包括插入、更新、删除和查询等。它们提供了对商品分类数据的基本访问功能,供其他组件(如服务层)使用。实际的数据操作逻辑需要在CategoryMapper
的实现类中进行实现。
关于这些方法的实现类真的很复杂,我的建议是了解一下就好,不算太重点,实现类其实就长这样:
Dao层设计好了我们接着来设计service层
设计service层
package com.imooc.mall.service;import com.imooc.mall.vo.CategoryVo;
import com.imooc.mall.vo.ResponseVo;import java.util.List;
import java.util.Set;public interface ICategoryService {ResponseVo<List<CategoryVo>> selectAll();void findSubCategoryId(Integer id, Set<Integer> resultSet);
}
上面的代码是一个名为ICategoryService
的接口,它定义了商品分类相关的服务方法。
这些方法定义了商品分类服务的功能,主要用于查询和处理商品分类相关的业务逻辑。
selectAll()
方法用于获取所有商品分类的信息,而findSubCategoryId()
方法用于查找指定分类下的所有子分类的主键id。这些方法可以被其他组件(如控制器层)调用,以实现具体的业务需求。
这里只提供了接口定义,并没有给出具体的实现逻辑。实际的业务逻辑需要在ICategoryService
的实现类中进行编写。我们接下来就讲讲怎么编写这些实现类。
package com.imooc.mall.service.impl;import com.imooc.mall.dao.CategoryMapper;
import com.imooc.mall.pojo.Category;
import com.imooc.mall.service.ICategoryService;
import com.imooc.mall.vo.CategoryVo;
import com.imooc.mall.vo.ResponseVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;import static com.imooc.mall.consts.MallConst.ROOT_PARENT_ID;@Service
public class CategoryServiceImpl implements ICategoryService {@Autowiredprivate CategoryMapper categoryMapper;/*** 耗时:http(请求微信api) > 磁盘 > 内存* mysql(内网+磁盘)* @return*/@Overridepublic ResponseVo<List<CategoryVo>> selectAll() {List<Category> categories = categoryMapper.selectAll();//查出parent_id=0
// for (Category category : categories) {
// if (category.getParentId().equals(ROOT_PARENT_ID)) {
// CategoryVo categoryVo = new CategoryVo();
// BeanUtils.copyProperties(category, categoryVo);
// categoryVoList.add(categoryVo);
// }
// }//lambda + streamList<CategoryVo> categoryVoList = categories.stream().filter(e -> e.getParentId().equals(ROOT_PARENT_ID)).map(this::category2CategoryVo).sorted(Comparator.comparing(CategoryVo::getSortOrder).reversed()).collect(Collectors.toList());//查询子目录findSubCategory(categoryVoList, categories);return ResponseVo.success(categoryVoList);}@Overridepublic void findSubCategoryId(Integer id, Set<Integer> resultSet) {List<Category> categories = categoryMapper.selectAll();findSubCategoryId(id, resultSet, categories);}private void findSubCategoryId(Integer id, Set<Integer> resultSet, List<Category> categories) {for (Category category : categories) {if (category.getParentId().equals(id)) {resultSet.add(category.getId());findSubCategoryId(category.getId(), resultSet, categories);}}}private void findSubCategory(List<CategoryVo> categoryVoList, List<Category> categories) {for (CategoryVo categoryVo : categoryVoList) {List<CategoryVo> subCategoryVoList = new ArrayList<>();for (Category category : categories) {//如果查到内容,设置subCategory, 继续往下查if (categoryVo.getId().equals(category.getParentId())) {CategoryVo subCategoryVo = category2CategoryVo(category);subCategoryVoList.add(subCategoryVo);}subCategoryVoList.sort(Comparator.comparing(CategoryVo::getSortOrder).reversed());categoryVo.setSubCategories(subCategoryVoList);findSubCategory(subCategoryVoList, categories);}}}private CategoryVo category2CategoryVo(Category category) {CategoryVo categoryVo = new CategoryVo();BeanUtils.copyProperties(category, categoryVo);return categoryVo;}
}
我说实话,这里的实现类确实是有点难以理解的,所以我的建议是能看懂最好,看不懂就放一放,到时候等对项目有一个整体的了解再看也不迟。现在你要知道的就是service层有两个方法,一个方法是获取所有商品的分类信息,另一个方法是查找指定分类下的所有子分类的主键id。
设计完service层之后,我们来设计controller层。
设计controller层
package com.imooc.mall.controller;import com.imooc.mall.service.ICategoryService;
import com.imooc.mall.vo.CategoryVo;
import com.imooc.mall.vo.ResponseVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;@RestController
public class CategoryController {@Autowiredprivate ICategoryService categoryService;@GetMapping("/categories")public ResponseVo<List<CategoryVo>> selectAll() {return categoryService.selectAll();}
}
这段代码是一个CategoryController
类,它是一个基于Spring的RESTful风格的控制器。
通过定义这个控制器类,我们就可以将"/categories"路径映射到selectAll()
方法,并在客户端发起GET请求时返回所有商品分类的信息。这样,当你访问"/categories"路径时,控制器会调用categoryService.selectAll()
方法获取商品分类信息,并将结果封装在ResponseVo
对象中返回给客户端。
这个控制器类的作用是将客户端请求与商品分类的业务逻辑进行关联,通过调用categoryService
中的方法来处理和返回相应的结果。
怎么样?我讲的已经很明白了吧!
通过上面的讲解,我相信你应该知道分类模块是怎么用代码实现的了。这篇文章我讲了我是如何设计电商系统的分类模块的,当然,电商系统还有很多其他的模块,比如用户模块,购物车模块,订单模块等,我只是介绍了其中的一个模块,其他的模块等我下几篇文章会详细介绍!