最近剛做了一個分佈式的電商項目,關於購物車模塊,借鑑了某東的購物車系統。
結合國內兩大電商巨頭某寶和某東,發現某寶中要向使用購物車就必要先登錄,而某東可以不需要登錄就添加商品到購物車中。
由於項目借鑑了某東的方式,所以在未登錄的時候也是可以使用購物車的。
步驟:
一、用戶在對商品進行添加到購物車操作時,通過cookie中的token和redis中的token判斷用戶是否登錄,如果未登錄狀態時,從cookie中獲取到購物車。如果不存在就新建一個。
如果用戶登錄了,就從redis中獲取到購物車,key是用戶id,以String方式存儲的。
二、在用戶進行登錄操作的時候,通過MQ發送消息到購物車系統,將用戶cookie中的購物車與用戶id發送過去。購物車系統的消息監聽器監聽到消息數據,將cookie中的購物車獲取到並與redis中的購物車進行合併。
(當然我這邊是把cookie中的購物車也是存在了redis作爲臨時購物車,具體操作是在新建購物車的時候生成一個不重複的隨機字符串,將字符串作爲value存入到cookie,同時將字符串作爲key,臨時購物車作爲value存入到redis中。這樣就可以通過獲取到cookie中的value向redis中查詢到臨時購物車進行相關操作了)
代碼如下:
購物車合併
public class CartLoginListener implements MessageListener{
@Autowired
private JedisClient jedisClient;
@Value("${REDIS_CART}")
private String REDIS_CART;
public void onMessage(Message message) {
TextMessage textMessage=(TextMessage)message;
try {
String text = textMessage.getText();
String[] strings = text.split(",");
//獲取到用戶id
String uid=strings[0];
//獲取到cookie中保存的臨時購物車的value
String value=strings[1];
//獲取到專屬購物車
String redisCart = jedisClient.get(REDIS_CART+uid);
List<CartItem> cartList=null;
if(StringUtils.isBlank(redisCart)){
//用戶購物車在redis中不存在,說明購物車時間過期了,或者是個新用戶
//創建一個購物車
cartList=new ArrayList<CartItem>();
}else{
cartList=JsonUtils.jsonToList(redisCart, CartItem.class);
}
//獲取臨時購物車
if(StringUtils.isNotBlank(value)&&!value.equals("1")){
//有商品被添加到購物車中,那麼將cookie中的購物車信息添加到redis的購物車中
//從redis中獲取到臨時購物車
String string = jedisClient.get(value);
List<CartItem> carts = JsonUtils.jsonToList(string, CartItem.class);
//循環遍歷cookie中的購物車商品
if(cartList==null||cartList.size()==0){
//說明是個空車,將每個cookie中的商品直接添加到redis中的購物車即可
for(int j=0;j<carts.size();j++){
cartList.add(carts.get(j));
}
}else{
//redis中的購物車不是空車
for(int j=0;j<carts.size();j++){
//默認redis中沒有cookie中的商品
boolean flag=false;
//遍歷cookie中的購物車
for(int i=0;i<cartList.size();i++){
//遍歷redis中的購物車,看看是否有同一件商品
if(carts.get(j).getId().equals(cartList.get(i).getId())){
//有同一件商品,更新數量即可
cartList.get(i).setNum(cartList.get(i).getNum()+carts.get(j).getNum());
flag=true;
break;
}
}
if(!flag){
//如果遍歷完之後redis中沒有cookie中同一件商品
//將該商品添加到redis中
cartList.add(carts.get(j));
}
}
}
//將合併後的購物車存放到redis
jedisClient.set(REDIS_CART+uid, JsonUtils.objectToJson(cartList));
//設置購物車存在redis最大時間爲七天
jedisClient.expire(REDIS_CART+uid, 86400);
//同時刪除redis中的臨時購物車
jedisClient.expire(value, 0);
}
}
}
獲取到購物車
//獲取到購物車
private CartMaster getCartList(HttpServletRequest request,HttpServletResponse response){
CartMaster master=new CartMaster();
//檢查用戶是否登錄
//獲取到cookie中的token
String token = CookieUtils.getCookieValue(request, SESSION_TOKEN);
if(StringUtils.isNotBlank(token)){
//說明cookie中有token,即用戶登錄過
JDResult result = userService.getUserByToken(token);
if(result.getStatus()==200){
//說明用戶登錄正常,未超時,獲取到當前登錄對象
TbUser user=(TbUser)result.getData();
//從redis中取出購物車
String redisCart = jedisClient.get(REDIS_CART+user.getId());
if(StringUtils.isBlank(redisCart)){
List<CartItem> list=new ArrayList<CartItem>();
master.setCartList(list);
}else{
master.setCartList(JsonUtils.jsonToList(redisCart, CartItem.class));
}
master.setUserId(user.getId());
master.setCartFrom(1);
return master;
}
}
//用戶未登錄,或者登錄超時,從cookie中獲取臨時購物車的號碼
String cookieValue = CookieUtils.getCookieValue(request, SHOPPONG_CART,CHARSET);
if(StringUtils.isNotBlank(cookieValue)){
//說明cookie中有了臨時購物車號碼,根據號碼從redis中獲取到該用戶的臨時購物車
String temporaryCart = jedisClient.get(cookieValue);
if(StringUtils.isNotBlank(temporaryCart)){
List<CartItem> list = JsonUtils.jsonToList(temporaryCart, CartItem.class);
master.setCartFrom(2);
master.setCartList(list);
return master;
}
}
//說明cookie中沒有購物車的號碼,或者cookie中有,reids沒有,創建購物車
String cartId=UUID.randomUUID().toString();
//創建一個購物車
List<CartItem> list=new ArrayList<CartItem>();
//將購物車存入redis,設置過期時間七天
jedisClient.set(cartId, JsonUtils.objectToJson(list));
jedisClient.expire(cartId, COOKIE_TIME);
//將id作爲value存入到cookie中
CookieUtils.setCookie(request, response, SHOPPONG_CART, cartId, COOKIE_TIME);
master.setCartFrom(2);
master.setCartList(list);
return master;
}