上节 我们实现了仿jd的轮播广告以及商品分类的功能,并且讲解了不同的注入方式,本节我们将继续实现我们的电商主业务,商品信息的展示。
需求分析首先,在我们开始本节编码之前,我们先来分析一下都有哪些地方会对商品进行展示,打开jd首页,鼠标下拉可以看到如下:
可以看到,在大类型下查询了部分商品在首页进行展示(可以是最新的,也可以是网站推荐等等),然后点击任何一个分类,可以看到如下:
我们一般进到电商网站之后,最常用的一个功能就是搜索,搜索钢琴 结果如下:
选择任意一个商品点击,都可以进入到详情页面,这个是单个商品的信息展示。
综上,我们可以知道,要实现一个电商平台的商品展示,最基本的包含:
首页推荐/最新上架商品
分类查询商品
关键词搜索商品
商品详情展示
...
接下来,我们就可以开始商品相关的业务开发了。
首页商品列表|IndexProductList 开发梳理我们首先来实现在首页展示的推荐商品列表,来看一下都需要展示哪些信息,以及如何进行展示。
商品主键(product_id)
展示图片(image_url)
商品名称(product_name)
商品价格(product_price)
分类说明(description)
分类名称(category_name)
分类主键(category_id)
其他...
编码实现 根据一级分类查询遵循开发顺序,自下而上,如果基础mapper解决不了,那么优先编写SQL mapper,因为我们需要在同一张表中根据parent_id递归的实现数据查询,当然我们这里使用的是表链接的方式实现。因此,common mapper无法满足我们的需求,需要自定义mapper实现。
Custom Mapper实现和上节根据一级分类查询子分类一样,在项目mscx-shop-mapper中添加一个自定义实现接口com.liferunner.custom.ProductCustomMapper,然后在resources\mapper\custom路径下同步创建xml文件mapper/custom/ProductCustomMapper.xml,此时,因为我们在上节中已经配置了当前文件夹可以被容器扫描到,所以我们添加的新的mapper就会在启动时被扫描加载,代码如下:
/** * ProductCustomMapper for : 自定义商品Mapper */ public interface ProductCustomMapper { /*** * 根据一级分类查询商品 * * @param paramMap 传递一级分类(map传递多参数) * @return java.util.List<com.liferunner.dto.IndexProductDTO> */ List<IndexProductDTO> getIndexProductDtoList(@Param("paramMap") Map<String, Integer> paramMap); } <?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="com.liferunner.custom.ProductCustomMapper"> <resultMap type="com.liferunner.dto.IndexProductDTO"> <id column="rootCategoryId" property="rootCategoryId"/> <result column="rootCategoryName" property="rootCategoryName"/> <result column="slogan" property="slogan"/> <result column="categoryImage" property="categoryImage"/> <result column="bgColor" property="bgColor"/> <collection property="productItemList" ofType="com.liferunner.dto.IndexProductItemDTO"> <id column="productId" property="productId"/> <result column="productName" property="productName"/> <result column="productMainImageUrl" property="productMainImageUrl"/> <result column="productCreateTime" property="productCreateTime"/> </collection> </resultMap> <select resultMap="IndexProductDTO" parameterType="Map"> SELECT c.id as rootCategoryId, c.name as rootCategoryName, c.slogan as slogan, c.category_image as categoryImage, c.bg_color as bgColor, p.id as productId, p.product_name as productName, pi.url as productMainImageUrl, p.created_time as productCreateTime FROM category c LEFT JOIN products p ON c.id = p.root_category_id LEFT JOIN products_img pi ON p.id = pi.product_id WHERE c.type = 1 AND p.root_category_id = #{paramMap.rootCategoryId} AND pi.is_main = 1 LIMIT 0,10; </select> </mapper> Service实现在serviceproject 创建com.liferunner.service.IProductService接口以及其实现类com.liferunner.service.impl.ProductServiceImpl,添加查询方法如下:
public interface IProductService { /** * 根据一级分类id获取首页推荐的商品list * * @param rootCategoryId 一级分类id * @return 商品list */ List<IndexProductDTO> getIndexProductDtoList(Integer rootCategoryId); ... } --- @Slf4j @Service @RequiredArgsConstructor(onConstructor = @__(@Autowired)) public class ProductServiceImpl implements IProductService { // RequiredArgsConstructor 构造器注入 private final ProductCustomMapper productCustomMapper; @Transactional(propagation = Propagation.SUPPORTS) @Override public List<IndexProductDTO> getIndexProductDtoList(Integer rootCategoryId) { log.info("====== ProductServiceImpl#getIndexProductDtoList(rootCategoryId) : {}=======", rootCategoryId); Map<String, Integer> map = new HashMap<>(); map.put("rootCategoryId", rootCategoryId); val indexProductDtoList = this.productCustomMapper.getIndexProductDtoList(map); if (CollectionUtils.isEmpty(indexProductDtoList)) { log.warn("ProductServiceImpl#getIndexProductDtoList未查询到任何商品信息"); } log.info("查询结果:{}", indexProductDtoList); return indexProductDtoList; } } Controller实现