本文承接上一篇《从0到1搭建精品电商项目(用于毕设、简历等)—— 项目介绍与初步搭建》,上一次只是把项目的地基打好了,还需要继续完善各类功能。
老规矩,源码请联系公众号:
1 首页轮播图 + 分类功能实现
1.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 需求
分类之间存在递归关系,可以将所有的商品放在同一张表中,就可以无限地递归了。
slogan表示如下:
页面加载时,没有必要加载很多的数据,前期只用把大分类加载完毕就行了,当用户把鼠标移过来时进行懒加载,根据鼠标悬停的类别的id再去查询它的子类别。
基本思路:
- 第一次刷新主页查询大分类,渲染展示到首页
- 如果鼠标移到大分类,则加载其子分类的内容,如果已经存在子分类,则不需要加载(懒加载)
1.2.2 分类实现 - 加载与渲染大分类
前端请求:
分类表:
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);
}
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;
左边的是二级分类,右边的是三级分类
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语法
<?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.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"/>
<!--封装三级分类的List集合-->
<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中添加鼠标移动上去后将要实现的查询二、三级分类的功能:
前端请求
@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(