一、購物車的存儲形式
1、cookie存放數據
無須登錄、無須查庫、保存在瀏覽器端
優點:性能好、訪問快、沒有和數據庫交互。
缺點1:換瀏覽器購物車數據會丟失。
缺點2:電腦被他人使用,存在隱私安全。
2、session存放數據
用戶登錄后,購物車數據放入用戶會話
優點:初期性能較好、訪問快。
缺點1:session基於內存、用戶量龐大影響服務器性能。
缺點2:只能存在於當前回話,不適用集群與分布式系統。
3、數據庫存放數據
用戶登錄后,購物車數據存入數據庫
優點:數據持久化,可在任何地點任何時間訪問。
缺點:頻繁讀寫數據庫,造成數據庫壓力。
4、Redis存放數據
用戶登錄后,購物車數據存入redis緩存
優點1:數據持久化,可以在任何地點任何時間訪問。
優點2:頻繁讀寫只基於緩存,不會造成數據庫壓力。
優點3:適用於集群與分布式系統,可擴展性強
系統使用的是cookie+redis的形式,用戶未登陸用的是cookie,登陸后用的cookie+redis相互結合
二、未登錄已登錄加入購物車業務代碼
1、前端vue構建購物車的商品對象
2、前端購物車的數據覆蓋本地的cookie
3、前端是在這里調用后端服務的。傳遞了shopcartItem這個對象。
3、服務端
1) 創建ShopcartBO對象

package com.imooc.pojo.bo; public class ShopcartBO { private String itemId; private String itemImgUrl; private String itemName; private String specId; private String specName; private Integer buyCounts; private String priceDiscount; private String priceNormal; public String getItemId() { return itemId; } public void setItemId(String itemId) { this.itemId = itemId; } public String getItemImgUrl() { return itemImgUrl; } public void setItemImgUrl(String itemImgUrl) { this.itemImgUrl = itemImgUrl; } public String getItemName() { return itemName; } public void setItemName(String itemName) { this.itemName = itemName; } public String getSpecId() { return specId; } public void setSpecId(String specId) { this.specId = specId; } public String getSpecName() { return specName; } public void setSpecName(String specName) { this.specName = specName; } public Integer getBuyCounts() { return buyCounts; } public void setBuyCounts(Integer buyCounts) { this.buyCounts = buyCounts; } public String getPriceDiscount() { return priceDiscount; } public void setPriceDiscount(String priceDiscount) { this.priceDiscount = priceDiscount; } public String getPriceNormal() { return priceNormal; } public void setPriceNormal(String priceNormal) { this.priceNormal = priceNormal; } @Override public String toString() { return "ShopcartBO{" + "itemId='" + itemId + '\'' + ", itemImgUrl='" + itemImgUrl + '\'' + ", itemName='" + itemName + '\'' + ", specId='" + specId + '\'' + ", specName='" + specName + '\'' + ", buyCounts=" + buyCounts + ", priceDiscount='" + priceDiscount + '\'' + ", priceNormal='" + priceNormal + '\'' + '}'; } }
2)添加商品到購物車
3、 后端方法設計到cookie。那么就會用到request對象。

package com.imooc.controller; import com.imooc.pojo.bo.ShopcartBO; import com.imooc.utils.IMOOCJSONResult; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.apache.commons.lang3.StringUtils; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Api(value = "購物車接口controller",tags = {"購物車接口相關的api"}) @RequestMapping("shopcart") @RestController public class ShopcartController { @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(); } }
待完善方法體
登陸后后端的接口要判斷相應的權限等等,那么這個權限又和redis,分布式會話有關,並且還涉及到攔截器。這些內容我們都會在分布式緩存里面所涉及到。
完善用戶登陸的TODO

package com.imooc.controller; import com.imooc.pojo.Users; import com.imooc.pojo.bo.UserBO; import com.imooc.service.UserService; import com.imooc.utils.CookieUtils; import com.imooc.utils.IMOOCJSONResult; import com.imooc.utils.JsonUtils; import com.imooc.utils.MD5Utils; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Api(value = "注冊登錄",tags = "用於注冊和登錄的相關接口") @RestController @RequestMapping("passport") public class PassportController { @Autowired private UserService userService; @ApiOperation(value="用戶名是否存在",notes = "用戶名是否存在",httpMethod = "GET") @GetMapping("/usernameIsExist") public IMOOCJSONResult usernameIsExist(@RequestParam String username){ //1. if(StringUtils.isBlank(username)) { return IMOOCJSONResult.errorMsg("用戶名不能為空"); } //2. boolean isExist=userService.queryUsernameIsExist(username); if (isExist) { return IMOOCJSONResult.errorMsg("用戶名已經存在"); } //3.請求成功 return IMOOCJSONResult.ok(); } @ApiOperation(value="用戶注冊",notes = "用戶注冊",httpMethod = "POST") @PostMapping("/regist") public IMOOCJSONResult regist(@RequestBody UserBO userBO){ String username = userBO.getUsername(); String password = userBO.getPassword(); String confirmPwd=userBO.getConfirmPassword(); //0 if(StringUtils.isBlank(username) || StringUtils.isBlank(password)|| StringUtils.isBlank(confirmPwd)){ return IMOOCJSONResult.errorMsg("用戶名或密碼不能為空"); } //1 boolean isExist=userService.queryUsernameIsExist(username); if (isExist) { return IMOOCJSONResult.errorMsg("用戶名已經存在"); } //2 if(password.length()<6) { return IMOOCJSONResult.errorMsg("用戶密碼不能少於6位"); } //3 //2 if(!password.equals(confirmPwd)) { return IMOOCJSONResult.errorMsg("兩次密碼不一致"); } //4 userService.creatUser(userBO); //TODO 生成用戶token,存入redis //TODO 同步購物車數據 return IMOOCJSONResult.ok(); } @ApiOperation(value="用戶登錄",notes = "用戶登錄",httpMethod = "POST") @PostMapping("/login") public IMOOCJSONResult login(@RequestBody UserBO userBO, HttpServletRequest request, HttpServletResponse response) throws Exception{ String username = userBO.getUsername(); String password = userBO.getPassword(); //String confirmPwd=userBO.getConfirmPassword(); //0 if(StringUtils.isBlank(username) || StringUtils.isBlank(password) ){ return IMOOCJSONResult.errorMsg("用戶名或密碼不能為空"); } Users user= userService.queryUserForLogin(username, MD5Utils.getMD5Str(password)); if(user==null) { return IMOOCJSONResult.errorMsg("用戶名和密碼不正確"); } user=setNullProperty(user); CookieUtils.setCookie(request, response,"user", JsonUtils.objectToJson(user),true); //TODO 生成用戶token,存入redis //TODO 同步購物車數據 return IMOOCJSONResult.ok(user); } @ApiOperation(value="用戶退出登錄",notes = "用戶退出登錄",httpMethod = "POST") @PostMapping("/logout") public IMOOCJSONResult logout(@RequestParam String userId,HttpServletRequest request, HttpServletResponse response){ //1 CookieUtils.deleteCookie(request, response, "user"); //TODO 用戶退出登錄,需要清空購物車 //TODO 分布式會話中需要清除用戶數據 //2 return IMOOCJSONResult.ok(); } private Users setNullProperty(Users user) { user.setPassword(null); user.setNickname(null); user.setCreatedTime(null); return user; } }
三、刷新購物車
cookie中的數據拿出來在頁面上做渲染是可以的嗎?答案是不可以。這是因為我們的數據保存在前端,它只是一種臨時的數據。購物車里面的數據,它不可能馬上去結算去買單的。他有可能明天后天甚至過一個禮拜再打開。那么再打開購物車的時候,價格還是cookie里面的價格。當用戶進入到購物車這個頁面的時候,我們一定要刷新一下購物車里面的商品數據。如果說價格發生了更改,商品的圖片、規則、名稱都發生更改的話,我們就需要重新的刷新相關的數據。商品的數量是不需要做更新。尤其是金額需要做刷新。所以我們要把相應的數據,尤其是購物車里規格的id發發送到后端。讓后端去查詢出來購物車相關的數據,再放到頁面上展示。
1、前端業務
(1)在聲明周期函數里面找到renderShopcart方法,首先獲取cookie中購物車的數據,如果沒有就返回空
(2)for循環拼接購物車的數據
拼接完就是以逗號分隔開的字符串,如下: 1001,1002,3003,4004
(3)請求后端的接口
2、后端接口
(1)我們要查的就是購物車里面的對象。除了buyCounts其余的內容我們都需要。
(2)自定義sql查詢語句

SELECT i.id AS itemId, ii.url AS itemImgUrl, i.item_name AS itemName, sp.id AS specId, sp.`name` AS specName, sp.price_discount AS priceDiscount, sp.price_normal AS priceNormal FROM items_spec sp LEFT JOIN items i ON i.id = sp.item_id LEFT JOIN items_img ii ON i.id = ii.item_id WHERE ii.is_main = 1 AND sp.id IN ( 'bingan-1001-spec-1', 'bingan-1001-spec-2', 'bingan-1001-spec-3')
(3)把sql復制到自定義的mapper里面。我們要返回的VO類型和之前寫好的ShopcartBO基本是一樣的,除了bugCounts這個屬性沒有。
傳入的結合對象命名為paramsList,標簽的閉合,循環的內容要在括號內部。里面的每一項元素使用逗號進行間隔。

<?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.imooc.mapper.ItemsMapperCustom" > <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.priceDiscount 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 priceDiscount 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.priceDiscount desc </when> <otherwise> i.item_name asc </otherwise> </choose> </select> <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.priceDiscount 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 priceDiscount 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.priceDiscount desc </when> <otherwise> i.item_name asc </otherwise> </choose> </select> <!-- k:默認,代表默認排序,根據name --> <!-- c:根據銷量排序 --> <!-- p:根據價格排序 --> <select id="queryItemsBySpecIds" parameterType="List" resultType="com.imooc.pojo.vo.ShopcartVO"> SELECT i.id AS itemId, ii.url AS itemImgUrl, i.item_name AS itemName, sp.id AS specId, sp.`name` AS specName, sp.price_discount AS priceDiscount, sp.price_normal AS priceNormal FROM items_spec sp LEFT JOIN items i ON i.id = sp.item_id LEFT JOIN items_img ii ON i.id = ii.item_id WHERE ii.is_main = 1 AND sp.id IN <foreach collection="paramsList" index="index" item="specId" open="(" separator="," close=")"> #{specId} </foreach> </select> </mapper>

package com.imooc.pojo.vo; public class ShopcartVO { private String itemId; private String itemImgUrl; private String itemName; private String specId; private String specName; private String priceDiscount; private String priceNormal; public String getItemId() { return itemId; } public void setItemId(String itemId) { this.itemId = itemId; } public String getItemImgUrl() { return itemImgUrl; } public void setItemImgUrl(String itemImgUrl) { this.itemImgUrl = itemImgUrl; } public String getItemName() { return itemName; } public void setItemName(String itemName) { this.itemName = itemName; } public String getSpecId() { return specId; } public void setSpecId(String specId) { this.specId = specId; } public String getSpecName() { return specName; } public void setSpecName(String specName) { this.specName = specName; } public String getPriceDiscount() { return priceDiscount; } public void setPriceDiscount(String priceDiscount) { this.priceDiscount = priceDiscount; } public String getPriceNormal() { return priceNormal; } public void setPriceNormal(String priceNormal) { this.priceNormal = priceNormal; } }
(4)定義接口方法
注意參數名稱和xml內保持一致

package com.imooc.mapper; import com.imooc.pojo.vo.ItemCommentVO; import com.imooc.pojo.vo.SearchItemsVO; import com.imooc.pojo.vo.ShopcartVO; 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); public List<SearchItemsVO> searchItems(@Param("paramsMap") Map<String, Object> map); public List<SearchItemsVO> searchItemsByThirdCat(@Param("paramsMap") Map<String, Object> map); public List<ShopcartVO> queryItemsBySpecIds(@Param("paramsList") List<String> specIds); }
(5)service層

package com.imooc.service; import com.imooc.pojo.Items; import com.imooc.pojo.ItemsImg; import com.imooc.pojo.ItemsParam; import com.imooc.pojo.ItemsSpec; import com.imooc.pojo.vo.CommentLevelCountsVO; import com.imooc.pojo.vo.ItemCommentVO; import com.imooc.pojo.vo.SearchItemsVO; import com.imooc.pojo.vo.ShopcartVO; import com.imooc.utils.PagedGridResult; import org.apache.ibatis.annotations.Param; import java.util.List; import java.util.Map; 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); /** * 根據商品id查詢商品的評價等級數量 * @param itemId */ public CommentLevelCountsVO queryItemCommentCounts(String itemId); /** * 根據商品id查詢商品評價(分頁) * @param itemId * @param leve * @return */ public PagedGridResult queryPagedComments (String itemId, Integer leve,Integer page,Integer pageSize); /** * 搜索商品列表 * @param keyWords * @param sort * @param page * @param pageSize * @return */ public PagedGridResult searchItems(String keyWords,String sort,Integer page,Integer pageSize); /** * 三級分類商品列表 * @param catId * @param sort * @param page * @param pageSize * @return */ public PagedGridResult searchItemsByThirdCat(Integer catId,String sort,Integer page,Integer pageSize); /** * 根據規格ids查詢最新的購物車中商品數據(用於刷新渲染購物車中的商品數據) * @param specIds * @return */ public List<ShopcartVO> queryItemsBySpecIds(String specIds); }

package com.imooc.service.impl; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.imooc.enums.CommentLevel; import com.imooc.mapper.*; import com.imooc.pojo.*; import com.imooc.pojo.vo.CommentLevelCountsVO; import com.imooc.pojo.vo.ItemCommentVO; import com.imooc.pojo.vo.SearchItemsVO; import com.imooc.pojo.vo.ShopcartVO; import com.imooc.service.ItemService; import com.imooc.utils.DesensitizationUtil; import com.imooc.utils.PagedGridResult; import io.swagger.annotations.ApiParam; 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.*; @Service public class ItemServiceImpl implements ItemService { @Autowired ItemsMapper itemsMapper; @Autowired ItemsImgMapper itemsImgMapper; @Autowired ItemsSpecMapper itemsSpecMapper; @Autowired ItemsParamMapper itemsParamMapper; @Autowired ItemsCommentsMapper itemsCommentsCommentsMapper; @Autowired 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 queryItemCommentCounts(String itemId) { //Integer totalCounts=getCommentCounts(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 commentLevelCountsVO=new CommentLevelCountsVO(); commentLevelCountsVO.setTotalCounts(totalCounts); commentLevelCountsVO.setGoodCounts(goodCounts); commentLevelCountsVO.setNormalCounts(normalCounts); commentLevelCountsVO.setBadCounts(badCounts); return commentLevelCountsVO; } @Transactional(propagation = Propagation.SUPPORTS) Integer getCommentCounts(String itemId,Integer level){ ItemsComments confdition =new ItemsComments(); confdition.setItemId(itemId); if (level != null) { confdition.setCommentLevel(level); } return itemsCommentsCommentsMapper.selectCount(confdition); } @Transactional(propagation = Propagation.SUPPORTS) @Override public PagedGridResult queryPagedComments(String itemId, Integer level, Integer page, Integer pageSzie) { Map<String,Object> map =new HashMap<>(); map.put("itemId",itemId); map.put("level",level); /** * page:第幾頁 * pageSize:每頁顯示多少條 */ PageHelper.startPage(page,pageSzie); 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 searchItems(String keywords, String sort, Integer page, Integer pageSize) { Map<String,Object> map =new HashMap<>(); map.put("keywords",keywords); map.put("sort",sort); /** * page:第幾頁 * pageSize:每頁顯示多少條 */ PageHelper.startPage(page,pageSize); List<SearchItemsVO> list=itemsMapperCustom.searchItems(map); return setterPagedGrid(list,page); } @Transactional(propagation = Propagation.SUPPORTS) @Override public PagedGridResult searchItemsByThirdCat(Integer catId, String sort, Integer page, Integer pageSize) { Map<String,Object> map =new HashMap<>(); map.put("catId",catId); map.put("sort",sort); /** * page:第幾頁 * pageSize:每頁顯示多少條 */ 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> specIdList = new ArrayList<>(); Collections.addAll(specIdList,ids); return itemsMapperCustom.queryItemsBySpecIds(specIdList); } }
(6)Api子模塊 (controller層)
、

package com.imooc.controller; import com.imooc.enums.YesOrNo; import com.imooc.pojo.*; import com.imooc.pojo.vo.*; import com.imooc.service.CarouselService; import com.imooc.service.CategoryService; import com.imooc.service.ItemService; import com.imooc.utils.IMOOCJSONResult; import com.imooc.utils.PagedGridResult; 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.*; import java.util.List; @Api(value = "商品接口",tags = "商品信息展示的相關接口") @RestController @RequestMapping("item") public class ItemController { @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(""); } Items item = itemService.queryItemById(itemId); List<ItemsImg> itemImgList=itemService.queryItemImgList(itemId); List<ItemsSpec> itemSpecList=itemService.queryItemSpecList(itemId); ItemsParam itemParam=itemService.queryItemParam(itemId); ItemInfoVO itemInfoVO=new ItemInfoVO(); itemInfoVO.setItem(item); itemInfoVO.setItemImgList(itemImgList); itemInfoVO.setItemSpecList(itemSpecList); itemInfoVO.setItemParam(itemParam); return IMOOCJSONResult.ok(itemInfoVO); } @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(""); } if(page==null) { page=1; } if(pageSize==null) { pageSize=10; } PagedGridResult grid = itemService.queryPagedComments(itemId,level,page,pageSize); return IMOOCJSONResult.ok(grid); } @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(""); } CommentLevelCountsVO countsVO = itemService.queryItemCommentCounts(itemId); return IMOOCJSONResult.ok(countsVO); } @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(""); } if (page == null) { page = 1; } if(pageSize==null) { pageSize=20; } PagedGridResult grid = itemService.searchItems(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(""); } if (page == null) { page = 1; } if(pageSize==null) { pageSize=20; } PagedGridResult grid = itemService.searchItemsByThirdCat(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,1002,1103") @RequestParam() String itemSpecIds ) { if(StringUtils.isBlank(itemSpecIds)) { return IMOOCJSONResult.ok(); } List<ShopcartVO> list=itemService.queryItemsBySpecIds(itemSpecIds); return IMOOCJSONResult.ok(list); } }
7、前端代碼
四、刪除商品
購物車內商品的刪除,考慮兩種情況,一個是用戶未登陸,一個是用戶已登錄。
如果未登陸直接在前端刪除,如果用戶已登錄,那么就要拿着這條數據到后端的購物車里面刪除。這樣也是保證我們前后端數據的同步。
1、前端代碼分析
刪除的方法傳入的是商品的規格id。購物車里面,商品是以規格作為單位的。
刪除前端對象中的這個規格的商品
新的list重新放到cookie里面
2、用戶登陸的情況,把商品的規格id傳遞到后端
3.后端接口

package com.imooc.controller; import com.imooc.pojo.bo.ShopcartBO; import com.imooc.utils.IMOOCJSONResult; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.apache.commons.lang3.StringUtils; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Api(value = "購物車接口controller",tags = {"購物車接口相關的api"}) @RequestMapping("shopcart") @RestController public class ShopcartController { @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(); } }
五、提交購物車至結算頁
判斷用戶是否登陸
支付頁面的聲明周期函數
最終的商品數據