分类
<resultMap id="myCategoryVO" type="com.imooc.pojo.vo.CategoryVO">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="type" property="type"/>
<result column="fatherId" property="fatherId"/>
<!--
collection 标签:用于定义关联的list集合类型的封装规则
property:对应三级分类的list属性名
ofType:集合的类型,三级分类的vo
-->
<collection property="subCatList" ofType="com.imooc.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>
<resultMap id="myNewItemsVO" type="com.imooc.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.imooc.pojo.vo.SimpleItemVO">
<id column="itemId" property="itemId"/>
<result column="itemName" property="itemName"/>
<result column="itemUrl" property="itemUrl"/>
</collection>
</resultMap>
<select id="getSixNewItemsLazy" 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>
@Service
public class CategoryServiceImpl implements CategoryService {
@Autowired
private CategoryMapper categoryMapper;
@Autowired
private CategoryMapperCustom categoryMapperCustom;
@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;
}
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public List<CategoryVO> getSubCatList(Integer rootCatId) {
return categoryMapperCustom.getSubCatList(rootCatId);
}
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public List<NewItemsVO> getSixNewItemsLazy(Integer rootCatId) {
Map<String, Object> map = new HashMap<>();
map.put("rootCatId", rootCatId);
return categoryMapperCustom.getSixNewItemsLazy(map);
}
}
/**
* 首页分类展示需求:
* 1. 第一次刷新主页查询大分类,渲染展示到首页
* 2. 如果鼠标上移到大分类,则加载其子分类的内容,如果已经存在子分类,则不需要加载(懒加载)
*/
@ApiOperation(value = "获取商品分类(一级分类)", notes = "获取商品分类(一级分类)", httpMethod = "GET")
@GetMapping("/cats")
public IMOOCJSONResult cats() {
List<Category> list = categoryService.queryAllRootLevelCat();
return IMOOCJSONResult.ok(list);
}
@ApiOperation(value = "获取商品子分类", notes = "获取商品子分类", httpMethod = "GET")
@GetMapping("/subCat/{rootCatId}")
public IMOOCJSONResult subCat(
@ApiParam(name = "rootCatId", value = "一级分类id", required = true)
@PathVariable Integer rootCatId) {
if (rootCatId == null) {
return IMOOCJSONResult.errorMsg("分类不存在");
}
List<CategoryVO> list = categoryService.getSubCatList(rootCatId);
return IMOOCJSONResult.ok(list);
}
@ApiOperation(value = "查询每个一级分类下的最新6条商品数据", notes = "查询每个一级分类下的最新6条商品数据", httpMethod = "GET")
@GetMapping("/sixNewItems/{rootCatId}")
public IMOOCJSONResult sixNewItems(
@ApiParam(name = "rootCatId", value = "一级分类id", required = true)
@PathVariable Integer rootCatId) {
if (rootCatId == null) {
return IMOOCJSONResult.errorMsg("分类不存在");
}
List<NewItemsVO> list = categoryService.getSixNewItemsLazy(rootCatId);
return IMOOCJSONResult.ok(list);
}
搜索
@Api(value = "商品接口", tags = {"商品信息展示的相关接口"})
@RestController
@RequestMapping("items")
public class ItemsController extends BaseController {
@Autowired
private ItemService itemService;
@ApiOperation(value = "查询商品详情", notes = "查询商品详情", httpMethod = "GET")
@GetMapping("/info/{itemId}")
public IMOOCJSONResult info(
@ApiParam(name = "itemId", value = "商品id", required = true)
@PathVariable String itemId) {
if (StringUtils.isBlank(itemId)) {
return IMOOCJSONResult.errorMsg(null);
}
Items item = itemService.queryItemById(itemId);
List<ItemsImg> itemImgList = itemService.queryItemImgList(itemId);
List<ItemsSpec> itemsSpecList = itemService.queryItemSpecList(itemId);
ItemsParam itemsParam = itemService.queryItemParam(itemId);
ItemInfoVO itemInfoVO = new ItemInfoVO();
itemInfoVO.setItem(item);
itemInfoVO.setItemImgList(itemImgList);
itemInfoVO.setItemSpecList(itemsSpecList);
itemInfoVO.setItemParams(itemsParam);
return IMOOCJSONResult.ok(itemInfoVO);
}
@ApiOperation(value = "查询商品评价等级", notes = "查询商品评价等级", httpMethod = "GET")
@GetMapping("/commentLevel")
public IMOOCJSONResult commentLevel(
@ApiParam(name = "itemId", value = "商品id", required = true)
@RequestParam String itemId) {
if (StringUtils.isBlank(itemId)) {
return IMOOCJSONResult.errorMsg(null);
}
CommentLevelCountsVO countsVO = itemService.queryCommentCounts(itemId);
return IMOOCJSONResult.ok(countsVO);
}
@ApiOperation(value = "查询商品评论", notes = "查询商品评论", httpMethod = "GET")
@GetMapping("/comments")
public IMOOCJSONResult 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 IMOOCJSONResult.errorMsg(null);
}
if (page == null) {
page = 1;
}
if (pageSize == null) {
pageSize = COMMON_PAGE_SIZE;
}
PagedGridResult grid = itemService.queryPagedComments(itemId,
level,
page,
pageSize);
return IMOOCJSONResult.ok(grid);
}
@ApiOperation(value = "搜索商品列表", notes = "搜索商品列表", httpMethod = "GET")
@GetMapping("/search")
public IMOOCJSONResult 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 IMOOCJSONResult.errorMsg(null);
}
if (page == null) {
page = 1;
}
if (pageSize == null) {
pageSize = PAGE_SIZE;
}
PagedGridResult grid = itemService.searhItems(keywords,
sort,
page,
pageSize);
return IMOOCJSONResult.ok(grid);
}
@ApiOperation(value = "通过分类id搜索商品列表", notes = "通过分类id搜索商品列表", httpMethod = "GET")
@GetMapping("/catItems")
public IMOOCJSONResult 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 IMOOCJSONResult.errorMsg(null);
}
if (page == null) {
page = 1;
}
if (pageSize == null) {
pageSize = PAGE_SIZE;
}
PagedGridResult grid = itemService.searhItems(catId,
sort,
page,
pageSize);
return IMOOCJSONResult.ok(grid);
}
// 用于用户长时间未登录网站,刷新购物车中的数据(主要是商品价格),类似京东淘宝
@ApiOperation(value = "根据商品规格ids查找最新的商品数据", notes = "根据商品规格ids查找最新的商品数据", httpMethod = "GET")
@GetMapping("/refresh")
public IMOOCJSONResult refresh(
@ApiParam(name = "itemSpecIds", value = "拼接的规格ids", required = true, example = "1001,1003,1005")
@RequestParam String itemSpecIds) {
if (StringUtils.isBlank(itemSpecIds)) {
return IMOOCJSONResult.ok();
}
List<ShopcartVO> list = itemService.queryItemsBySpecIds(itemSpecIds);
return IMOOCJSONResult.ok(list);
}
}
@Service
public class ItemServiceImpl implements ItemService {
@Autowired
private ItemsMapper itemsMapper;
@Autowired
private ItemsImgMapper itemsImgMapper;
@Autowired
private ItemsSpecMapper itemsSpecMapper;
@Autowired
private ItemsParamMapper itemsParamMapper;
@Autowired
private ItemsCommentsMapper itemsCommentsMapper;
@Autowired
private ItemsMapperCustom itemsMapperCustom;
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public Items queryItemById(String itemId) {
return itemsMapper.selectByPrimaryKey(itemId);
}
@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);
}
@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);
}
@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);
}
@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;
}
@Transactional(propagation = Propagation.SUPPORTS)
Integer getCommentCounts(String itemId, Integer level) {
ItemsComments condition = new ItemsComments();
condition.setItemId(itemId);
if (level != null) {
condition.setCommentLevel(level);
}
return itemsCommentsMapper.selectCount(condition);
}
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public PagedGridResult queryPagedComments(String itemId,
Integer level,
Integer page,
Integer pageSize) {
Map<String, Object> map = new HashMap<>();
map.put("itemId", itemId);
map.put("level", level);
// mybatis-pagehelper
/**
* page: 第几页
* pageSize: 每页显示条数
*/
PageHelper.startPage(page, pageSize);
List<ItemCommentVO> list = itemsMapperCustom.queryItemComments(map);
for (ItemCommentVO vo : list) {
vo.setNickname(DesensitizationUtil.commonDisplay(vo.getNickname()));
}
return setterPagedGrid(list, page);
}
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;
}
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public PagedGridResult searhItems(String keywords, String sort, Integer page, Integer pageSize) {
Map<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);
}
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public PagedGridResult searhItems(Integer catId, String sort, Integer page, Integer pageSize) {
Map<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);
}
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public List<ShopcartVO> queryItemsBySpecIds(String specIds) {
String ids[] = specIds.split(",");
List<String> specIdsList = new ArrayList<>();
Collections.addAll(specIdsList, ids);
return itemsMapperCustom.queryItemsBySpecIds(specIdsList);
}
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public ItemsSpec queryItemSpecById(String specId) {
return itemsSpecMapper.selectByPrimaryKey(specId);
}
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public String queryItemMainImgById(String itemId) {
ItemsImg itemsImg = new ItemsImg();
itemsImg.setItemId(itemId);
itemsImg.setIsMain(YesOrNo.YES.type);
ItemsImg result = itemsImgMapper.selectOne(itemsImg);
return result != null ? result.getUrl() : "";
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void decreaseItemSpecStock(String specId, int buyCounts) {
// synchronized 不推荐使用,集群下无用,性能低下
// 锁数据库: 不推荐,导致数据库性能低下
// 分布式锁 zookeeper redis
// lockUtil.getLock(); -- 加锁
// 1. 查询库存
// int stock = 10;
// 2. 判断库存,是否能够减少到0以下
// if (stock - buyCounts < 0) {
// 提示用户库存不够
// 10 - 3 -3 - 5 = -1
// }
// lockUtil.unLock(); -- 解锁
int result = itemsMapperCustom.decreaseItemSpecStock(specId, buyCounts);
if (result != 1) {
throw new RuntimeException("订单创建失败,原因:库存不足!");
}
}
}
<select id="queryItemComments" parameterType="Map" resultType="com.imooc.pojo.vo.ItemCommentVO">
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 ic
LEFT JOIN
users u
ON
ic.user_id = u.id
WHERE
ic.item_id = #{paramsMap.itemId}
<if test=" paramsMap.level != null and paramsMap.level != '' ">
AND ic.comment_level = #{paramsMap.level}
</if>
</select>
<select id="searchItems" parameterType="Map" resultType="com.imooc.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 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) 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>
<!-- k: 默认,代表默认排序,根据name-->
<!-- c: 根据销量排序-->
<!-- p: 根据价格排序-->
<select id="searchItemsByThirdCat" parameterType="Map" resultType="com.imooc.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 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) 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>
<select id="queryItemsBySpecIds" parameterType="List" resultType="com.imooc.pojo.vo.ShopcartVO">
SELECT
t_items.id as itemId,
t_items.item_name as itemName,
t_items_img.url as itemImgUrl,
t_items_spec.id as specId,
t_items_spec.`name` as specName,
t_items_spec.price_discount as priceDiscount,
t_items_spec.price_normal as priceNormal
FROM
items_spec t_items_spec
LEFT JOIN
items t_items
ON
t_items.id = t_items_spec.item_id
LEFT JOIN
items_img t_items_img
on
t_items_img.item_id = t_items.id
WHERE
t_items_img.is_main = 1
AND
t_items_spec.id IN
<foreach collection="paramsList" index="index" item="specId" open="(" separator="," close=")">
#{specId}
</foreach>
</select>
<update id="decreaseItemSpecStock">
update
items_spec
set
stock = stock - #{pendingCounts}
where
id = #{specId}
and
stock >= #{pendingCounts}
</update>
购物车
购物车存储方案(Cookie,Session,DB,Redis)
@Api(value = "购物车接口controller", tags = {"购物车接口相关的api"})
@RequestMapping("shopcart")
@RestController
public class ShopcatController {
@ApiOperation(value = "添加商品到购物车", notes = "添加商品到购物车", httpMethod = "POST")
@PostMapping("/add")
public IMOOCJSONResult add(
@RequestParam String userId,
@RequestBody ShopcartBO shopcartBO,
HttpServletRequest request,
HttpServletResponse response
) {
if (StringUtils.isBlank(userId)) {
return IMOOCJSONResult.errorMsg("");
}
System.out.println(shopcartBO);
// TODO 前端用户在登录的情况下,添加商品到购物车,会同时在后端同步购物车到redis缓存
return IMOOCJSONResult.ok();
}
@ApiOperation(value = "从购物车中删除商品", notes = "从购物车中删除商品", httpMethod = "POST")
@PostMapping("/del")
public IMOOCJSONResult del(
@RequestParam String userId,
@RequestParam String itemSpecId,
HttpServletRequest request,
HttpServletResponse response
) {
if (StringUtils.isBlank(userId) || StringUtils.isBlank(itemSpecId)) {
return IMOOCJSONResult.errorMsg("参数不能为空");
}
// TODO 用户在页面删除购物车中的商品数据,如果此时用户已经登录,则需要同步删除后端购物车中的商品
return IMOOCJSONResult.ok();
}
}