从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)

文章目录

  • 1 首页轮播图 + 分类功能实现
    • 1.1 实现电商首页轮播图功能
    • 1.2 首页分析
      • 1.2.1 需求
      • 1.2.2 分类实现 - 加载与渲染大分类
      • 1.2.2 分类实现 - 自连接查询子分类
      • 1.2.3 分类实现 - 自定义mapper实现懒加载子分类展示
  • 2 商品推荐 + 搜索功能实现
    • 2.1 商品推荐 - 需求分析与sql查询
    • 2.2 商品推荐 - 实现接口与联调
    • 2.3 搜索 - 商品详情功能分析
    • 2.4 搜索 - 编写商品相关查询service
    • 2.5 搜索 - 联调详情页与排查bug
  • 3 商品评价功能开发
    • 3.1 数据库设计
    • 3.2 实现评价等级数量查询
    • 3.3 编写自定义mapper查询
    • 3.4 编写service
      • 3.4.1 基础实现
      • 3.4.2 添加分页功能
    • 3.5 商品评价Controller
    • 3.6 信息脱敏
  • 4 商品搜索功能开发
    • 4.1 sql编写
    • 4.2 实现搜索功能
    • 4.3 前端业务与分类搜索查询
    • 4.4 实现分类搜索商品查询
  • 5 购物车功能开发
    • 5.1 购物车的存储形式
    • 5.2 未登录已登录加入购物车业务代码
    • 5.3 渲染(刷新)购物车
    • 5.4 选中商品的计算业务
    • 5.5 删除商品业务讲解
    • 5.6 提交购物车至结算页

  本文承接上一篇《从0到1搭建精品电商项目(用于毕设、简历等)—— 项目介绍与初步搭建》,上一次只是把项目的地基打好了,还需要继续完善各类功能。

老规矩,源码请联系公众号:
在这里插入图片描述

1 首页轮播图 + 分类功能实现

1.1 实现电商首页轮播图功能

先看下数据库
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第1张图片
背景色需要和图片的颜色一致。

还是从service层写起。

创建操作轮播图的service接口:

package com.wjw.service;

import com.wjw.pojo.Carousel;

import java.util.List;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/12/24 15:08
 * 4
 */
public interface CarouselService {
     

    /**
     * 查询所有轮播图列表
     * @param isShow
     * @return
     */
    public List<Carousel> queryAll(Integer isShow);
    
}

创建接口实现类:

package com.wjw.service.impl;

import com.wjw.mapper.CarouselMapper;
import com.wjw.pojo.Carousel;
import com.wjw.service.CarouselService;
import org.springframework.beans.factory.annotation.Autowired;
import tk.mybatis.mapper.entity.Example;

import java.util.List;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/12/24 15:11
 * 4
 */
public class CarouselServiceImpl implements CarouselService {
     

    @Autowired
    private CarouselMapper carouselMapper;


    /**
     * 查询所有轮播图列表
     *
     * @param isShow
     * @return
     */
    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public List<Carousel> queryAll(Integer isShow) {
     
        Example example = new Example(Carousel.class);
        example.orderBy("sort").desc();

        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("isShow", isShow);

        List<Carousel> result = carouselMapper.selectByExample(example);

        return result;
    }
}

创建表示“是否”的枚举(common模块):

package com.wjw.enums;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/12/21 21:04
 * 4
 */
public enum YesOrNo {
     

    NO(0, "否"),
    YES(1, "是");

    public final Integer type;
    public final String value;

    YesOrNo(Integer type, String value) {
     
        this.type = type;
        this.value = value;
    }

}

创建控制器IndexController用于控制首页的展示:

package com.wjw.controller;

import com.wjw.enums.YesOrNo;
import com.wjw.pojo.Carousel;
import com.wjw.service.CarouselService;
import com.wjw.utils.WJWJSONResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.List;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/12/20 16:29
 * 4
 */
@Api(value = "首页", tags = {
     "首页展示的相关接口"})
@RestController
@RequestMapping("index")
public class IndexController {
     

    @Autowired
    private CarouselService carouselService;

    @ApiOperation(value = "获取首页轮播图列表", notes = "获取首页轮播图列表", httpMethod = "GET")
    @GetMapping("/carousel")
    public WJWJSONResult carousel() {
     
        List<Carousel> list = carouselService.queryAll(YesOrNo.YES.type);
        return WJWJSONResult.ok(list);
    }

}

1.2 首页分析

1.2.1 需求

从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第2张图片
  分类之间存在递归关系,可以将所有的商品放在同一张表中,就可以无限地递归了。
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第3张图片
slogan表示如下:
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第4张图片
页面加载时,没有必要加载很多的数据,前期只用把大分类加载完毕就行了,当用户把鼠标移过来时进行懒加载,根据鼠标悬停的类别的id再去查询它的子类别。

基本思路:

  1. 第一次刷新主页查询大分类,渲染展示到首页
  2. 如果鼠标移到大分类,则加载其子分类的内容,如果已经存在子分类,则不需要加载(懒加载)

1.2.2 分类实现 - 加载与渲染大分类

前端请求:
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第5张图片
分类表:

从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第6张图片
type字段表示是第几级分类。

创建商品分类服务接口:

package com.wjw.service;

import com.wjw.pojo.Carousel;
import com.wjw.pojo.Category;

import java.util.List;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/12/24 15:08
 * 4
 */
public interface CategoryService {
     

    /**
     * 查询所有一级分类
     * @return
     */
    public List<Category> queryAllRootLevelCat();

}

创建相应的实现类:

package com.wjw.service.impl;

import com.wjw.mapper.CarouselMapper;
import com.wjw.mapper.CategoryMapper;
import com.wjw.pojo.Carousel;
import com.wjw.pojo.Category;
import com.wjw.service.CarouselService;
import com.wjw.service.CategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import java.util.List;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/12/24 15:11
 * 4
 */
@Service
public class CategoryServiceImpl implements CategoryService {
     

    @Autowired
    private CategoryMapper categoryMapper;

    /**
     * 查询所有一级分类
     *
     * @return
     */
    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public List<Category> queryAllRootLevelCat() {
     

        Example example = new Example(Category.class);

        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("type", 1);

        List<Category> result = categoryMapper.selectByExample(example);
        return result;
    }
}

在首页IndexController中添加获取商品一级分类的方法:

@Autowired
private CategoryService categoryService;

@ApiOperation(value = "获取商品分类(一级分类)", notes = "获取商品分类(一级分类)", httpMethod = "GET")
@GetMapping("/cats")
public WJWJSONResult cats(){
     
    List<Category> list = categoryService.queryAllRootLevelCat();
    return WJWJSONResult.ok(list);
}

从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第7张图片
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第8张图片

1.2.2 分类实现 - 自连接查询子分类

  自连接相当于变种的多表查询,通用mapper做不到多表查询,所以要写自定义sql语句。

SELECT 
	f.id as id,
	f.`name` as	`name`,
	f.type as type,
	f.father_id as fatherId,
	c.id as subId,
	c.`name` as	subName,
	c.type as subType,
	c.father_id as subFatherId
FROM 
	`category` f
LEFT JOIN
	`category` c
ON
	f.id = c.father_id
WHERE
	f.father_id = 1;

左边的是二级分类,右边的是三级分类

从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第9张图片

1.2.3 分类实现 - 自定义mapper实现懒加载子分类展示

  将自动生成的CategoryMapper拷贝一份命名为CategoryMapperCustom

package com.wjw.mapper;

import com.wjw.my.mapper.MyMapper;
import com.wjw.pojo.Category;
import com.wjw.pojo.vo.CategoryVO;

import java.util.List;

public interface CategoryMapperCustom {
     

    public List<CategoryVO> getSubCatList(Integer rootCatId);

}

定义相应的vo:
  vo和bo类似,是业务型的,从前端封装过后的数据传入到后端;从内部传给前端显示需要定义为vo。
  分类表一般不纳入后续的分库分表的考虑,所以这里的id是int型。

三级分类的VO:

package com.wjw.pojo.vo;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/12/24 16:46
 * 4  三级子分类的vo
 */
public class SubCategoryVO {
     

    private Integer subId;
    private String subName;
    private String subType;
    private Integer subFatherId;

    ......
}

二级分类的VO:

package com.wjw.pojo.vo;

import java.util.List;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/12/24 16:42
 * 4 二级分类VO
 */
public class CategoryVO {
     

    private Integer id;
    private String name;
    private String type;
    private Integer fatherId;

    /**
     * 三级分类vo list
     */
    private List<SubCategoryVO> subCatList;

}

定义相应的mapper.xml文件,同样先复制CategoryMapper.xml:
再将上面写好的sql语句转化为Mybatis的xml语法


DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.wjw.mapper.CategoryMapperCustom" >

    <resultMap id="myCategoryVO" type="com.wjw.pojo.vo.CategoryVO">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="type" property="type"/>
        <result column="fatherId" property="fatherId"/>

        
        <collection property="subCatList" ofType="com.wjw.pojo.vo.SubCategoryVO">
            <id column="subId" property="subId"/>
            <result column="subName" property="subName"/>
            <result column="subType" property="subType"/>
            <result column="subFatherId" property="subFatherId"/>
        collection>
    resultMap>

    <select id="getSubCatList" resultMap="myCategoryVO" parameterType="int">
        SELECT
          f.id as id,
          f.`name` as  `name`,
          f.type as type,
          f.father_id as fatherId,
          c.id as subId,
          c.`name` as  subName,
          c.type as subType,
          c.father_id as subFatherId
        FROM
          `category` f
        LEFT JOIN
          `category` c
        ON
          f.id = c.father_id
        WHERE
          f.father_id = #{rootCatId};
    select>
mapper>

定义查询二、三级分类的service接口:
CategoryServiceImpl中添加方法

@Autowired
private CategoryMapperCustom categoryMapperCustom;

/**
 * 根据一级分类id查询子分类信息
 *
 * @param rootCatId
 * @return
 */
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public List<CategoryVO> getSubCatList(Integer rootCatId) {
     
    return categoryMapperCustom.getSubCatList(rootCatId);
}

IndexController中添加鼠标移动上去后将要实现的查询二、三级分类的功能:
前端请求
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第10张图片

@ApiOperation(value = "获取商品子分类", notes = "获取商品子分类", httpMethod = "GET")
@GetMapping("/subCat/{rootCatId}")
public WJWJSONResult subCat(
        @ApiParam(name = "rootCatId", value = "一级分类id", required = true)
        @PathVariable Integer rootCatId){
     

    if (rootCatId == null) {
     
        return WJWJSONResult.errorMsg("分类不存在");
    }

    List<CategoryVO> list = categoryService.getSubCatList(rootCatId);
    return WJWJSONResult.ok(list);
}

从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第11张图片
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第12张图片

2 商品推荐 + 搜索功能实现

2.1 商品推荐 - 需求分析与sql查询

前端依然使用的懒加载模式,前端会根据页面的滚动进行加载。
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第13张图片
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第14张图片
页面上每个种类下面包含了六个子类。

相应的数据库:
category 表:
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第15张图片
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第16张图片
cat_id是子分类的id,root_cat_id是一级分类id,商品推荐是按照一级分类去分的。

从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第17张图片
is_main是商品详情页里最先展示的那张图片。

定义三表联合查询的sql:

SELECT
	f.id as rootCatId,
	f.`name` as rootCatName,
	f.slogan as slogan,
	f.cat_image as catImage,
	f.bg_color as bgColor,
	i.id as itemId,
	i.item_name as itemName,
	ii.url as itemUrl,
	i.created_time as createdTime
FROM
	category f
LEFT JOIN
	items i
ON
	f.id = i.root_cat_id
LEFT JOIN
	items_img ii
ON
	i.id = ii.item_id
WHERE
	f.type = 1			# 固定不变
AND
	i.root_cat_id = 7		# 根据具体的类别确定
AND
	ii.is_main = 1			# 判断是否是主图,固定不变
ORDER BY
	i.created_time DESC
LIMIT 0,6;				# 每个大类查6个,固定不变

从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第18张图片

2.2 商品推荐 - 实现接口与联调

CategoryService中添加查询六个商品的懒加载接口:

/**
 * 查询首页每个一级分类下的6条最新商品数据
 * @param rootCatId
 * @return
 */
public List getSixNewItemLazy(Integer rootCatId);

和之前获得子分类一样,修改mapper,在CategoryMapperCustom中追加接口:

public List getSixNewItemLazy(@Param("paramsMap") Map<String, Object> map);

这里用map传参。


  基于上面的sql语句,CategoryMapperCustom.xml中追加:

<resultMap id="myNewItemsVO" type="com.wjw.pojo.vo.NewItemsVO">
    <id column="rootCatId" property="rootCatId"/>
    <result column="rootCatName" property="rootCatName"/>
    <result column="slogan" property="slogan"/>
    <result column="catImage" property="catImage"/>
    <result column="bgColor" property="bgColor"/>

    
    <collection property="simpleItemList" ofType="com.wjw.pojo.vo.SimpleItemVO">
        <id column="itemId" property="itemId"/>
        <result column="itemName" property="itemName"/>
        <result column="itemUrl" property="itemUrl"/>
    collection>
resultMap>

<select id="getSixNewItemLazy" resultMap="myNewItemsVO" parameterType="Map">
    SELECT
        f.id as rootCatId,
        f.`name` as rootCatName,
        f.slogan as slogan,
        f.cat_image as catImage,
        f.bg_color as bgColor,
        i.id as itemId,
        i.item_name as itemName,
        ii.url as itemUrl,
        i.created_time as createdTime
    FROM
        category f
    LEFT JOIN items i ON f.id = i.root_cat_id
    LEFT JOIN items_img ii ON i.id = ii.item_id
    WHERE
        f.type = 1
    AND
        i.root_cat_id = #{paramsMap.rootCatId}
    AND
        ii.is_main = 1
    ORDER BY
        i.created_time DESC
    LIMIT 0,6;
select>

其中涉及到NewItemsVO

package com.wjw.pojo.vo;

import java.util.List;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/12/24 16:42
 * 4 最新商品推荐VO
 */
public class NewItemsVO {
     

    private Integer rootCatId;
    private String rootCatName;
    private String slogan;
    private String catImage;
    private String bgColor;

    private List<SimpleItemVO>  simpleItemList;
    
    ......
}

simpleItemList中保存了SQL语句中查询出来的
在这里插入图片描述
SimpleItemVO的定义为:

package com.wjw.pojo.vo;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/12/25 15:57
 * 4   6个最新商品的简单数据类型
 */
public class SimpleItemVO {
     

    private String itemId;
    private String itemName;
    private String itemUrl;
    
    ......

}

设置CategoryMapperCustomCategoryService的返回值类型:
在这里插入图片描述
在这里插入图片描述
  由于mapper中定义了我们传进去的参数是一个Map,所以service实现类中要声明一个map

/**
 * 查询首页每个一级分类下的6条最新商品数据
 *
 * @param rootCatId
 * @return
 */
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public List getSixNewItemLazy(Integer rootCatId) {
     

    HashMap<String, Object> map = new HashMap<>();
    map.put("rootCatId", rootCatId);
    return categoryMapperCustom.getSixNewItemLazy(map);
}

IndexController中添加相应的接口:

@ApiOperation(value = "查询每个一级分类下的最新6条商品数据", notes = "查询每个一级分类下的最新6条商品数据", httpMethod = "GET")
@GetMapping("/sixNewItems/{rootCatId}")
public WJWJSONResult sixNewItems(
        @ApiParam(name = "rootCatId", value = "一级分类id", required = true)
        @PathVariable Integer rootCatId){
     

    if (rootCatId == null) {
     
        return WJWJSONResult.errorMsg("分类不存在");
    }

    List<NewItemsVO> list = categoryService.getSixNewItemLazy(rootCatId);
    return WJWJSONResult.ok(list);
}

启动测试可以发现随着鼠标慢慢往下划,页面慢慢的被加载出来。

2.3 搜索 - 商品详情功能分析

从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第19张图片
左边的图片是存放于items_img表中的:
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第20张图片
详情中的信息存放于items表和items_spec表:
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第21张图片
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第22张图片
规格名称对应口味
在这里插入图片描述
宝贝详情存储在items_param表中
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第23张图片
  对于不同部分的加载,可以分开发送多个请求,用多个controller进行接收,将请求分散开来,速度稍微快一点。这里为了简便起见,还是用一次请求加载全部。

2.4 搜索 - 编写商品相关查询service

定义商品查询的接口:

package com.wjw.service;

import com.wjw.pojo.Items;
import com.wjw.pojo.ItemsImg;
import com.wjw.pojo.ItemsParam;
import com.wjw.pojo.ItemsSpec;

import java.util.List;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/12/25 16:47
 * 4
 */
public interface ItemService {
     

    /**
     * 根据商品id查询详情
     * @param itemId
     * @return
     */
    public Items queryItemById(String itemId);

    /**
     * 根据商品id查询商品图片列表
     * @param itemId
     * @return
     */
    public List<ItemsImg> queryItemImgList(String itemId);

    /**
     * 根据商品id查询商品规格
     * @param itemId
     * @return
     */
    public List<ItemsSpec> queryItemSpecList(String itemId);

    /**
     * 根据商品id查询商品参数
     * @param itemId
     * @return
     */
    public ItemsParam queryItemParam(String itemId);

}

相应的具体实现(4个查询):

package com.wjw.service.impl;

import com.wjw.mapper.ItemsImgMapper;
import com.wjw.mapper.ItemsMapper;
import com.wjw.mapper.ItemsParamMapper;
import com.wjw.mapper.ItemsSpecMapper;
import com.wjw.pojo.Items;
import com.wjw.pojo.ItemsImg;
import com.wjw.pojo.ItemsParam;
import com.wjw.pojo.ItemsSpec;
import com.wjw.service.ItemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.List;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/12/25 16:47
 * 4
 */
@Service
public class ItemServiceImpl implements ItemService {
     

    @Autowired
    private ItemsMapper itemsMapper;

    @Autowired
    private ItemsImgMapper itemsImgMapper;

    @Autowired
    private ItemsSpecMapper itemsSpecMapper;

    @Autowired
    private ItemsParamMapper itemsParamMapper;

    /**
     * 根据商品id查询详情
     *
     * @param itemId
     * @return
     */
    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public Items queryItemById(String itemId) {
     
        return itemsMapper.selectByPrimaryKey(itemId);
    }

    /**
     * 根据商品id查询商品图片列表
     *
     * @param itemId
     * @return
     */
    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public List<ItemsImg> queryItemImgList(String itemId) {
     
        Example itemsImgExp = new Example(ItemsImg.class);
        Example.Criteria criteria = itemsImgExp.createCriteria();
        criteria.andEqualTo("itemId", itemId);

        return itemsImgMapper.selectByExample(itemsImgExp);
    }

    /**
     * 根据商品id查询商品规格
     *
     * @param itemId
     * @return
     */
    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public List<ItemsSpec> queryItemSpecList(String itemId) {
     
        Example itemsSpecExp = new Example(ItemsSpec.class);
        Example.Criteria criteria = itemsSpecExp.createCriteria();
        criteria.andEqualTo("itemId", itemId);

        return itemsSpecMapper.selectByExample(itemsSpecExp);
    }

    /**
     * 根据商品id查询商品参数
     *
     * @param itemId
     * @return
     */
    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public ItemsParam queryItemParam(String itemId) {
     
        Example itemsParamExp = new Example(ItemsParam.class);
        Example.Criteria criteria = itemsParamExp.createCriteria();
        criteria.andEqualTo("itemId", itemId);

        return itemsParamMapper.selectOneByExample(itemsParamExp);
    }
}

2.5 搜索 - 联调详情页与排查bug

前端请求url:
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第24张图片
创建ItemsController:
由于这里一下查了四组参数要同时返回,所以还要借助VO

package com.wjw.pojo.vo;

import com.wjw.pojo.Items;
import com.wjw.pojo.ItemsImg;
import com.wjw.pojo.ItemsParam;
import com.wjw.pojo.ItemsSpec;

import java.util.List;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/12/25 18:49
 * 4  商品详情VO
 */
public class ItemInfoVO {
     

    private Items item;
    private List<ItemsImg> itemImgList;
    private List<ItemsSpec> itemSpecList ;
    private ItemsParam itemParams;
    
    ......
}

controller:

package com.wjw.controller;

import com.wjw.pojo.Items;
import com.wjw.pojo.ItemsImg;
import com.wjw.pojo.ItemsParam;
import com.wjw.pojo.ItemsSpec;
import com.wjw.pojo.vo.ItemInfoVO;
import com.wjw.service.ItemService;
import com.wjw.utils.WJWJSONResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
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;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/12/25 17:15
 * 4
 */
@Api(value = "商品接口", tags = {
     "商品信息展示的相关接口"})
@RestController
@RequestMapping("items")
public class ItemsController {
     

    @Autowired
    private ItemService itemService;

    @ApiOperation(value = "查询商品详情", notes = "查询商品详情", httpMethod = "GET")
    @GetMapping("/info/{itemId}")
    public WJWJSONResult info(
            @ApiParam(name = "itemId", value = "商品id", required = true)
            @PathVariable String itemId){
     
        if (StringUtils.isBlank(itemId)){
     
            return WJWJSONResult.errorMsg(null);
        }

        Items item = itemService.queryItemById(itemId);
        List<ItemsImg> itemImgList = itemService.queryItemImgList(itemId);
        List<ItemsSpec> itemSpecList = itemService.queryItemSpecList(itemId);
        ItemsParam itemParams = itemService.queryItemParam(itemId);

        ItemInfoVO itemInfoVO = new ItemInfoVO();
        itemInfoVO.setItem(item);
        itemInfoVO.setItemImgList(itemImgList);
        itemInfoVO.setItemSpecList(itemSpecList);
        itemInfoVO.setItemParams(itemParams);

        return WJWJSONResult.ok(itemInfoVO);
    }


}

从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第25张图片
要注意VO的字段名一定要和前端定义的一样:
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第26张图片
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第27张图片

3 商品评价功能开发

3.1 数据库设计

  订单完成之后,在用户中心可以进行评价操作,展示评论时还要把用户信息进行一个隐私处理。还要涉及分页、分类操作。
在这里插入图片描述
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第28张图片
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第29张图片
  表的设计要和用户表商品表关联,商品有不同规格所以要有规格id、名称

  评价等级:1:好评 2:中评 3:差评

3.2 实现评价等级数量查询

在ItemService中添加和评价有关的查询:

/**
 * 根据商品id查询商品的评价等级数量
 * @param itemId
 */
public CommentLevelCountsVO queryCommentCounts(String itemId);

将商品评价的展示封装成为VO:

package com.wjw.pojo.vo;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/12/25 20:33
 * 4   用于展示商品评价数量的VO
 */
public class CommentLevelCountsVO {
     
    /**
     * 总评价数
     */
    public  Integer totalCounts;
    /**
     * 好评
     */
    public  Integer goodCounts;
    /**
     * 中评
     */
    public  Integer normalCounts;
    /**
     * 差评
     */
    public  Integer badCounts;

}

创建评价等级的枚举:

package com.wjw.enums;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/12/21 21:04
 * 4   商品评价等级枚举
 */
public enum CommentLevel {
     

    GOOD(1, "好评"),
    NORMAL(2, "中评"),
    BAD(3, "差评");

    public final Integer type;
    public final String value;

    CommentLevel(Integer type, String value) {
     
        this.type = type;
        this.value = value;
    }

}

service的具体实现:

@Autowired
private ItemsCommentsMapper itemsCommentsMapper;

/**
 * 根据商品id查询商品的评价等级数量
 *
 * @param itemId
 */
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public CommentLevelCountsVO queryCommentCounts(String itemId) {
     
    Integer goodCounts = getCommentCounts(itemId, CommentLevel.GOOD.type);
    Integer normalCounts = getCommentCounts(itemId, CommentLevel.NORMAL.type);
    Integer badCounts = getCommentCounts(itemId, CommentLevel.BAD.type);
    Integer totalCounts = goodCounts + normalCounts + badCounts;

    CommentLevelCountsVO countsVO = new CommentLevelCountsVO();
    countsVO.setTotalCounts(totalCounts);
    countsVO.setGoodCounts(goodCounts);
    countsVO.setNormalCounts(normalCounts);
    countsVO.setBadCounts(badCounts);

    return countsVO;
}

/**
 * 查询某个评价等级的通用方法
 * @param itemId
 * @param level
 * @return
 */
Integer getCommentCounts(String itemId, Integer level) {
     
    ItemsComments condition = new ItemsComments();
    condition.setItemId(itemId);
    if (level != null){
     
        condition.setCommentLevel(level);
    }
    return itemsCommentsMapper.selectCount(condition);
}

在IndexController中添加查询评价等级数量的接口:
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第30张图片
注意这里路径用的是?这种形式,不是前面的/这种形式,所以对应的参数的注解为@RequestParam

@ApiOperation(value = "查询商品评价等级", notes = "查询商品评价等级", httpMethod = "GET")
@GetMapping("/commentLevel")
public WJWJSONResult commentLevel(
        @ApiParam(name = "itemId", value = "商品id", required = true)
        @RequestParam String itemId){
     
    if (StringUtils.isBlank(itemId)){
     
        return WJWJSONResult.errorMsg(null);
    }

    CommentLevelCountsVO countsVO = itemService.queryCommentCounts(itemId);
    
    return WJWJSONResult.ok(countsVO);
}

从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第31张图片
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第32张图片

3.3 编写自定义mapper查询

SELECT
	ic.comment_level as commentLevel,
	ic.content as content,
	ic.sepc_name as specName,
	ic.created_time as createdTime,
	u.face as userFace,
	u.nickname as nickname
FROM
	items_comments as ic
LEFT JOIN
	users as u
ON
	ic.user_id = u.id
WHERE
	ic.item_id = 'cake-1001'	# 指定查哪个商品评价
AND
	ic.comment_level = 1;		# 查好评

创建自定义ItemsMapperCustom.xml:

<?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.wjw.mapper.ItemsMapperCustom" >
  <select id="queryItemComments" parameterType="Map" resultType="">
    SELECT
        ic.comment_level as commentLevel,
        ic.content as content,
        ic.sepc_name as specName,
        ic.created_time as createdTime,
        u.face as userFace,
        u.nickname as nickname
    FROM
        items_comments as ic
    LEFT JOIN
        users as u
    ON
        ic.user_id = u.id
    WHERE
        ic.item_id =
        <if test="">
        AND
            ic.comment_level = 1
        </if>
  </select>
</mapper>

自定义mapper接口:

package com.wjw.mapper;

public interface ItemsMapperCustom {
     

}

上面两个文件未编写完毕,下面继续。

Sql语句的输出要返回给前端进行展示,所以要定义一个VO:

package com.wjw.pojo.vo;

import java.util.Date;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/12/26 10:31
 * 4   用于展示商品评价的VO
 */
public class ItemCommentVO {
     

    private Integer commentLevel;
    private String content;
    private String specName;
    private Date createdTime;
    private String userFace;
    private String nickname;
    
    ......
}

在xml文件的namespace中添加相应的方法:

package com.wjw.mapper;


import com.wjw.pojo.vo.ItemCommentVO;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Map;

public interface ItemsMapperCustom {
     

    public List<ItemCommentVO> queryItemComments(@Param("paramsMap") Map<String, Object> map);
}

将上面的VO作为resultType补全xml文件:
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第33张图片

3.4 编写service

3.4.1 基础实现

ItemService中添加接口:

/**
 * 根据商品id和评价等级查询评价(分页)
 * @param itemId
 * @param level
 * @return
 */
public List<ItemCommentVO> queryPagedComments(String itemId, Integer level);

具体实现:

@Autowired
private ItemsMapperCustom itemsMapperCustom;

@Transactional(propagation = Propagation.SUPPORTS)
@Override
public List<ItemCommentVO> queryPagedComments(String itemId, Integer level) {
     
    // 请求参数
    HashMap<String, Object> map = new HashMap<>();
    map.put("itemId", itemId);
    map.put("level", level);

    List<ItemCommentVO> list = itemsMapperCustom.queryItemComments(map);

    return list;
}

3.4.2 添加分页功能

1. 父工程引入分页插件依赖


<dependency>
    <groupId>com.github.pagehelpergroupId>
    <artifactId>pagehelper-spring-boot-starterartifactId>
    <version>1.2.12version>
dependency>

2. foodie-dev-api配置yml

# 分页插件配置
pagehelper:
  helperDialect: mysql
  supportMethodsArguments: true

3. 使用分页插件,在查询前使用分页插件,原理:统一拦截sql,为其提供分页功能

/**
* page: 第几页
* pageSize: 每页显示条数
*/
PageHelper.startPage(page, pageSize);

其中pagepageSize应该是前端传进来的。既然有分页,所以要对queryPagedComments再添加两个参数。

从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第34张图片
4.分页数据封装到PagedGridResult.java 传给前端

PageInfo<?> pageList = new PageInfo<>(list);
PagedGridResult grid = new PagedGridResult();
grid.setPage(page);
grid.setRows(list);
grid.setTotal(pageList.getPages());
grid.setRecords(pageList.getTotal());

其中PagedGridResult是自己封装的类。

package com.wjw.utils;

import java.util.List;

/**
 * 
 * @Title: PagedGridResult.java
 * @Package com.wjw.utils
 * @Description: 用来返回分页Grid的数据格式
 * Copyright: Copyright (c) 2019
 */
public class PagedGridResult {
     
   
   private int page;        // 当前页数
   private int total;       // 总页数 
   private long records;     // 总记录数
   private List<?> rows;     // 每行显示的内容

   ......
}

同时service方法的返回值也要改变。
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第35张图片
完整的queryPagedComments实现:

@Transactional(propagation = Propagation.SUPPORTS)
@Override
public PagedGridResult queryPagedComments(String itemId, Integer level,
                                              Integer page, Integer pageSize) {
     
    // 请求参数
    HashMap<String, Object> map = new HashMap<>();
    map.put("itemId", itemId);
    map.put("level", level);

    /**
     * page: 第几页
     * pageSize: 每页显示条数
     */
    PageHelper.startPage(page, pageSize);

    List<ItemCommentVO> list = itemsMapperCustom.queryItemComments(map);
    
    return setterPagedGrid(list, page);
}

/**
 * 抽取设置分页对象的方法
 * @param list
 * @param page
 * @return
 */
private PagedGridResult setterPagedGrid(List<?> list, Integer page){
     
    PageInfo<?> pageList = new PageInfo<>(list);
    PagedGridResult grid = new PagedGridResult();
    grid.setPage(page);
    grid.setRows(list);
    grid.setTotal(pageList.getPages());
    grid.setRecords(pageList.getTotal());
    return grid;
}

3.5 商品评价Controller

从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第36张图片
为了更通用化,创建一个BaseController:

package com.wjw.controller;

import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/12/20 16:29
 * 4
 */
@Controller
public class BaseController {
     

    public static final Integer COMMENT_PAGE_SIZE = 10;

}

ItemsController中添加方法:
先继承BaseController
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第37张图片

@ApiOperation(value = "查询商品评价", notes = "查询商品评价", httpMethod = "GET")
@GetMapping("/comments")
public WJWJSONResult comments(
        @ApiParam(name = "itemId", value = "商品id", required = true)
        @RequestParam String itemId,
        @ApiParam(name = "level", value = "评价等级", required = false)
        @RequestParam Integer level,
        @ApiParam(name = "page", value = "查询下一页的第几页", required = false)
        @RequestParam Integer page,
        @ApiParam(name = "pageSize", value = "每一页显示的记录数", required = false)
        @RequestParam Integer pageSize){
     

    if (StringUtils.isBlank(itemId)){
     
        return WJWJSONResult.errorMsg(null);
    }

    if (page == null){
     
        page = 1;
    }

    if (pageSize == null){
     
        pageSize = COMMENT_PAGE_SIZE;
    }

    PagedGridResult grid = itemService.queryPagedComments(itemId, level, page, pageSize);

    return WJWJSONResult.ok(grid);
}

3.6 信息脱敏

通用脱敏工具类:

package com.wjw.utils;

import sun.applet.Main;

/**
 * 通用脱敏工具类
 * 可用于:
 *      用户名
 *      手机号
 *      邮箱
 *      地址等
 */
public class DesensitizationUtil {
     

    private static final int SIZE = 6;
    private static final String SYMBOL = "*";

	public static void main(String[] args) {
     
        String name = commonDisplay("N小王日记");
        String mobile = commonDisplay("13900000000");
        String mail = commonDisplay("[email protected]");
        String address = commonDisplay("南京北京东路888号");

        System.out.println(name);
        System.out.println(mobile);
        System.out.println(mail);
        System.out.println(address);
    }

    /**
     * 通用脱敏方法
     * @param value
     * @return
     */
    public static String commonDisplay(String value) {
     
        if (null == value || "".equals(value)) {
     
            return value;
        }
        int len = value.length();
        int pamaone = len / 2;
        int pamatwo = pamaone - 1;
        int pamathree = len % 2;
        StringBuilder stringBuilder = new StringBuilder();
        if (len <= 2) {
     
            if (pamathree == 1) {
     
                return SYMBOL;
            }
            stringBuilder.append(SYMBOL);
            stringBuilder.append(value.charAt(len - 1));
        } else {
     
            if (pamatwo <= 0) {
     
                stringBuilder.append(value.substring(0, 1));
                stringBuilder.append(SYMBOL);
                stringBuilder.append(value.substring(len - 1, len));

            } else if (pamatwo >= SIZE / 2 && SIZE + 1 != len) {
     
                int pamafive = (len - SIZE) / 2;
                stringBuilder.append(value.substring(0, pamafive));
                for (int i = 0; i < SIZE; i++) {
     
                    stringBuilder.append(SYMBOL);
                }
                if ((pamathree == 0 && SIZE / 2 == 0) || (pamathree != 0 && SIZE % 2 != 0)) {
     
                    stringBuilder.append(value.substring(len - pamafive, len));
                } else {
     
                    stringBuilder.append(value.substring(len - (pamafive + 1), len));
                }
            } else {
     
                int pamafour = len - 2;
                stringBuilder.append(value.substring(0, 1));
                for (int i = 0; i < pamafour; i++) {
     
                    stringBuilder.append(SYMBOL);
                }
                stringBuilder.append(value.substring(len - 1, len));
            }
        }
        return stringBuilder.toString();
    }

}

从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第38张图片

修改service层queryPagedComments
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第39张图片
从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第40张图片

4 商品搜索功能开发

4.1 sql编写

从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第41张图片
搜索出来的结果要展示图片,价格,描述,销量,所以涉及到多表关联查询。

商品表关联商品规格表和商品图片表。

从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第42张图片

SELECT
	i.id as itemId,
	i.item_name as itemName,
	i.sell_counts as sellConuts,
	ii.url as imgUrl,
	tempSpec.price_discount as price
FROM
	items as i
LEFT JOIN
	items_img ii
ON
	i.id = ii.item_id
LEFT JOIN
	(
		SELECT
			item_id, MIN(price_discount) as price_discount
		FROM
			items_spec
		GROUP BY
			item_id
	) as tempSpec
ON
	i.id = tempSpec.item_id
WHERE
	ii.is_main = 1;

4.2 实现搜索功能

创建搜索结果展示VO:

后端涉及到的金额是以“分”为单位的int型数据,前端负责做除以100的展示

package com.wjw.pojo.vo;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/12/26 14:33
 * 4   用于展示商品搜索列表的VO
 */
public class SearchItemsVO {
     

    private String itemId;
    private String itemName;
    private int sellCounts;
    private String imgUrl;
    private int price;

    ......

}

实现mapper,在ItemsMapperCustom.xml中添加查询语句:

  • 拼接字符串要用$符,而不是#占位符
  • 规定默认排序(根据name)传入的参数为 paramsMap.sort = k;
  • 销量排序 paramsMap.sort = c;
  • 价格排序 paramsMap.sort = p;

mybatis中单引号要转义 "

<select id="searchItems" parameterType="Map" resultType="com.wjw.pojo.vo.SearchItemsVO">
        SELECT
            i.id as itemId,
            i.item_name as itemName,
            i.sell_counts as sellCounts,
            ii.url as imgUrl,
            tempSpec.price_discount as price
        FROM
            items as i
        LEFT JOIN
            items_img ii
        ON
            i.id = ii.item_id
        LEFT JOIN
            ( SELECT item_id, MIN(price_discount) as price_discount FROM items_spec GROUP BY item_id ) as tempSpec
        ON
            i.id = tempSpec.item_id
        WHERE
            ii.is_main = 1
            <if test="paramsMap.keywords != null and paramsMap.keywords != ''">
                AND i.item_name like '%${paramsMap.keywords}%'
            if>
            order by
            <choose>
                <when test="paramsMap.sort == "c" ">
                    i.sell_counts desc
                when>
                <when test="paramsMap.sort == "p" ">
                    tempSpec.price_discount asc
                when>
                <otherwise>
                    i.item_name asc
                otherwise>
            choose>
    select>



在mapper的命名空间ItemsMapperCustom中添加searchItems方法:

public List<SearchItemsVO> searchItems(@Param("paramsMap") Map<String, Object> map);

编写service层,ItemService中添加:

/**
 * 搜索商品列表
 * @param keyword
 * @param sort 排序类型:k,c,p
 * @param page
 * @param pageSize
 * @return
 */
public PagedGridResult searchItems(String keyword, String sort, Integer page, Integer pageSize);

service层对应实现类:

@Transactional(propagation = Propagation.SUPPORTS)
@Override
public PagedGridResult searchItems(String keywords, String sort, Integer page, Integer pageSize) {
     
    // 请求参数
    HashMap<String, Object> map = new HashMap<>();
    map.put("keywords", keywords);
    map.put("sort", sort);

    PageHelper.startPage(page, pageSize);

    List<SearchItemsVO> list = itemsMapperCustom.searchItems(map);

    return setterPagedGrid(list, page);
}

ItemsController中添加相应的接口:

前端请求地址:

从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第43张图片

@ApiOperation(value = "搜索商品列表", notes = "搜索商品列表", httpMethod = "GET")
@GetMapping("/search")
public WJWJSONResult search(
        @ApiParam(name = "keywords", value = "关键字", required = true)
        @RequestParam String keywords,
        @ApiParam(name = "sort", value = "排序", required = false)
        @RequestParam String sort,
        @ApiParam(name = "page", value = "查询下一页的第几页", required = false)
        @RequestParam Integer page,
        @ApiParam(name = "pageSize", value = "每一页显示的记录数", required = false)
        @RequestParam Integer pageSize){
     

    if (StringUtils.isBlank(keywords)){
     
        return WJWJSONResult.errorMsg(null);
    }

    if (page == null){
     
        page = 1;
    }

    if (pageSize == null){
     
        pageSize = PAGE_SIZE;
    }

    PagedGridResult grid = itemService.searchItems(keywords, sort, page, pageSize);

    return WJWJSONResult.ok(grid);
}

从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第44张图片

4.3 前端业务与分类搜索查询

从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第45张图片
  点击按钮查找是按照其三级分类的id来查找该分类下的所有商品。所以前端就有两种方式跳转到搜索的结果页面。

  • 一种是输入关键字搜索:
    在这里插入图片描述
  • 另一种是点击了三级分类标签后的搜索:
    从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第46张图片
  • 搜索界面进行展示时也会判断是属于哪一类的搜索:

从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第47张图片

在ItemsMapperCustom.xml中添加根据三级标签搜索的功能:
类似上面的根据关键词的搜索

<select id="searchItemsByThirdCat" parameterType="Map" resultType="com.wjw.pojo.vo.SearchItemsVO">
    SELECT
        i.id as itemId,
        i.item_name as itemName,
        i.sell_counts as sellCounts,
        ii.url as imgUrl,
        tempSpec.price_discount as price
    FROM
        items as i
    LEFT JOIN
        items_img ii
    ON
        i.id = ii.item_id
    LEFT JOIN
        ( SELECT item_id, MIN(price_discount) as price_discount FROM items_spec GROUP BY item_id ) as tempSpec
    ON
        i.id = tempSpec.item_id
    WHERE
        ii.is_main = 1
    AND
        i.cat_id = #{paramsMap.catId}
    order by
    <choose>
        <when test="paramsMap.sort == "c" ">
            i.sell_counts desc
        </when>
        <when test="paramsMap.sort == "p" ">
            tempSpec.price_discount asc
        </when>
        <otherwise>
            i.item_name asc
        </otherwise>
    </choose>
</select>

在xml文件的namespace中定义searchItemsByThirdCat方法:

public List<SearchItemsVO> searchItemsByThirdCat(@Param("paramsMap") Map<String, Object> map);

4.4 实现分类搜索商品查询

service层实现,在ItemService中追加接口:

/**
 * 根据三级分类id搜索商品列表
 * @param catId
 * @param sort 排序类型:k,c,p
 * @param page
 * @param pageSize
 * @return
 */
public PagedGridResult searchItems(Integer catId, String sort, Integer page, Integer pageSize);

对应的service层具体实现:
类似上面的根据关键词的搜索

@Transactional(propagation = Propagation.SUPPORTS)
@Override
public PagedGridResult searchItems(Integer catId, String sort, Integer page, Integer pageSize) {
     
    // 请求参数
    HashMap<String, Object> map = new HashMap<>();
    map.put("catId", catId);
    map.put("sort", sort);

    PageHelper.startPage(page, pageSize);

    List<SearchItemsVO> list = itemsMapperCustom.searchItemsByThirdCat(map);

    return setterPagedGrid(list, page);
}

ItemsController中追加相应的接口:

@ApiOperation(value = "通过分类id搜索商品列表", notes = "通过分类id搜索商品列表", httpMethod = "GET")
@GetMapping("/catItems")
public WJWJSONResult catItems(
        @ApiParam(name = "catId", value = "三级分类id", required = true)
        @RequestParam Integer catId,
        @ApiParam(name = "sort", value = "排序", required = false)
        @RequestParam String sort,
        @ApiParam(name = "page", value = "查询下一页的第几页", required = false)
        @RequestParam Integer page,
        @ApiParam(name = "pageSize", value = "每一页显示的记录数", required = false)
        @RequestParam Integer pageSize){
     

    if (catId == null){
     
        return WJWJSONResult.errorMsg(null);
    }

    if (page == null){
     
        page = 1;
    }

    if (pageSize == null){
     
        pageSize = PAGE_SIZE;
    }

    PagedGridResult grid = itemService.searchItems(catId, sort, page, pageSize);

    return WJWJSONResult.ok(grid);
}

从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第48张图片

从0到1搭建精品电商项目(用于毕设、简历等)—— 项目完善首页,搜索,评价,购物车开发(2)_第49张图片

5 购物车功能开发

5.1 购物车的存储形式

5.2 未登录已登录加入购物车业务代码

5.3 渲染(刷新)购物车

5.4 选中商品的计算业务

5.5 删除商品业务讲解

5.6 提交购物车至结算页

你可能感兴趣的:(JAVA)