购物车实现(cookie+redis)
用户未登录, 添加商品到购物车时, 将购物车信息存储到cookie中
用户登录后,将cookie中的购物车合并到redis中,删除cookie信息,添加商品时,直接添加到redis中
1.controller
@Autowired
private HttpServletResponse response;controller中可以直接autowired response request
不会发生线程安全问题, spring框架已经处理好了
package com.pyg.cart.controller;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.pyg.cart.service.CartService;
import com.pyg.pojogroup.Cart;
import com.pyg.util.CookieUtil;
import entity.Result;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* @Title: CartController
* @ProjectName PYG
* @Description: TODO
*/
@RestController
@RequestMapping("/cart")
public class CartController {
@Reference
private CartService cartService;
@Autowired
private HttpServletRequest request;
@Autowired
private HttpServletResponse response;
/**
* @Description: 添加商品到购物车 cookie
* @param itemId
* @param num
* @return entity.Result
*/
@RequestMapping("/addGoodsToCartList")
//解决js跨域问题 origins 允许访问这个controller的请求地址
//allowCredentials 默认为true 请求中携带着cookie来时,必须为true
@CrossOrigin(origins = "http://localhost:9105",allowCredentials="true")
public Result addGoodsToCartList(Long itemId, Integer num){
try{
//Security获取用户名
String username = SecurityContextHolder.getContext().getAuthentication().getName();
//获得购物车列表
List<Cart> cartList = findCartList();
//调用service更新购物车
cartList=cartService.addGoodsToCartList(cartList,itemId,num);
if("anonymousUser".equals(username)){
//未登录 将更新后的购物车写回cookie
String cartListStr = JSON.toJSONString(cartList);
CookieUtil.setCookie(request,response,"cartList",cartListStr,3600*24,"utf-8");
}else{
//登录 写回到redis
cartService.saveCartListToRedis(cartList,username);
}
return new Result(true,"添加成功");
}catch (Exception e){
e.printStackTrace();
return new Result(false,"添加失败");
}
}
@RequestMapping("/findCartList")
public List<Cart> findCartList(){
//获取当前登录用户名
String username = SecurityContextHolder.getContext().getAuthentication().getName();
String cartListCookie = CookieUtil.getCookieValue(request, "cartList", "utf-8");
if(StringUtils.isEmpty(cartListCookie)){
cartListCookie="[]";
}
List<Cart> cookie_cartList = JSON.parseArray(cartListCookie, Cart.class);
if("anonymousUser".equals(username)){
//未登录 cookie中取出购物车数据
return cookie_cartList;
}else{
//登录状态 从redis取出购物车
List<Cart> redis_cartList=cartService.findCartListFromRedis(username);
//合并购物车
if(cookie_cartList!=null && cookie_cartList.size()>0){
redis_cartList=cartService.mergeCartList(redis_cartList,cookie_cartList);
cartService.saveCartListToRedis(redis_cartList,username);
//删除cookie中的购物车
CookieUtil.deleteCookie(request,response,"cartList");
}
return redis_cartList;
}
}
}
2.service
package com.pyg.cart.service.impl;
import com.alibaba.dubbo.config.annotation.Service;
import com.pyg.cart.service.CartService;
import com.pyg.mapper.TbItemMapper;
import com.pyg.pojo.TbItem;
import com.pyg.pojo.TbOrderItem;
import com.pyg.pojogroup.Cart;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* @Title: CartServiceImpl
* @ProjectName PYG
* @Description: TODO
*/
@Service
public class CartServiceImpl implements CartService {
@Autowired
private TbItemMapper itemMapper;
@Autowired
private RedisTemplate redisTemplate;
/**
* @param cartList
* @param itemId
* @param num
* @return java.util.List<com.pyg.pojogroup.Cart>
* @Description: 添加商品到购物车
*/
@Override
public List<Cart> addGoodsToCartList(List<Cart> cartList, Long itemId, Integer num) {
TbItem item = itemMapper.selectByPrimaryKey(itemId);
if(item==null){
throw new RuntimeException("商品不存在");
}
if(!item.getStatus().equals("1")){
throw new RuntimeException("商品状态无效");
}
Cart cart = searchCartBySellerId(cartList, item.getSellerId());
//商家不存在
if(cart==null){
cart = new Cart();
cart.setSellerId(item.getSellerId());
cart.setSellerName(item.getSeller());
List<TbOrderItem> orderItemList = new ArrayList<>();
orderItemList.add(createOrderItem(item,num));
cart.setOrderItemList(orderItemList);
cartList.add(cart);
}else{
//商家存在
TbOrderItem orderItem = searchOrderItemByItemId(cart.getOrderItemList(), itemId);
if(orderItem==null){
//该商品不在列表中
TbOrderItem orderItem1 = createOrderItem(item, num);
cart.getOrderItemList().add(orderItem1);
}else{
orderItem.setNum(orderItem.getNum()+num);
orderItem.setTotalFee(new BigDecimal(orderItem.getNum()*orderItem.getPrice().doubleValue()));
if(orderItem.getNum()<=0){
cart.getOrderItemList().remove(orderItem);
}
if(cart.getOrderItemList().size()<=0){
cartList.remove(cart);
}
}
}
return cartList;
}
/**
* @Description: 判断商家是否在购物车中
* @param cartList
* @param sellerId
* @return com.pyg.pojogroup.Cart
*/
private Cart searchCartBySellerId(List<Cart> cartList,String sellerId){
for (Cart cart : cartList) {
if(cart.getSellerId().equals(sellerId)){
return cart;
}
}
return null;
}
/**
* @Description: 判断商品是否在购物车对应的商家商品列表中
* @param orderItemList
* @param itemId
* @return com.pyg.pojo.TbOrderItem
*/
private TbOrderItem searchOrderItemByItemId(List<TbOrderItem> orderItemList,Long itemId){
for (TbOrderItem orderItem : orderItemList) {
if(orderItem.getItemId().longValue()==itemId.longValue()){
return orderItem;
}
}
return null;
}
/**
* @Description: 创建一个OrderItem存入购物车对应的商家商品列表中
* @param item
* @param num
* @return com.pyg.pojo.TbOrderItem
*/
private TbOrderItem createOrderItem(TbItem item,Integer num){
if(num<=0){
throw new RuntimeException("数量非法!");
}
TbOrderItem tbOrderItem=new TbOrderItem();
tbOrderItem.setItemId(item.getId());
tbOrderItem.setGoodsId(item.getGoodsId());
tbOrderItem.setTitle(item.getTitle());
tbOrderItem.setPrice(item.getPrice());
tbOrderItem.setNum(num);
tbOrderItem.setTotalFee(new BigDecimal(tbOrderItem.getNum()*tbOrderItem.getPrice().doubleValue()));
tbOrderItem.setPicPath(item.getImage());
tbOrderItem.setSellerId(item.getSellerId());
return tbOrderItem;
}
/**
* @Description: 从redis中查找对应用户的购物车信息
* @param username
* @return java.util.List<com.pyg.pojogroup.Cart>
*/
@Override
public List<Cart> findCartListFromRedis(String username) {
Object obj = redisTemplate.boundHashOps("cartList").get(username);
if(obj==null){
return new ArrayList<>();
}
return (List<Cart>) obj;
}
/**
* @Description: 保存购物车信息到redis中
* @param cartList
* @param username
* @return void
*/
@Override
public void saveCartListToRedis(List<Cart> cartList, String username) {
redisTemplate.boundHashOps("cartList").put(username,cartList);
}
/**
* @Description: 合并cookie和redis购物车
* @param redis_cartList
* @param cookie_cartList
* @return java.util.List<com.pyg.pojogroup.Cart>
*/
@Override
public List<Cart> mergeCartList(List<Cart> redis_cartList, List<Cart> cookie_cartList) {
for (Cart cart : cookie_cartList) {
for (TbOrderItem tbOrderItem : cart.getOrderItemList()) {
redis_cartList = addGoodsToCartList(redis_cartList, tbOrderItem.getItemId(), tbOrderItem.getNum());
}
}
return redis_cartList;
}
}
3.springsecurity.xml 小问题
access=“IS_AUTHENTICATED_ANONYMOUSLY” 用于设置资源可以在不登陆时可以访问。
拦截了但是给了一个默认的权限
SecurityContextHolder.getContext().getAuthentication().getName(); 用户名为anonymousUser
此配置与 security="none"的区别在于当用户未登陆时获取登陆人账号的值为anonymousUser ,
而security="none"的话,无论是否登陆都不能获取登录人账号的值,因为springsecutiry压根没拦截cart.do 不存在上下文 所以getName时是null。
<!-- 匿名访问资源 -->
<http pattern="/css/**" security="none"></http>
<http pattern="/js/**" security="none"></http>
<http pattern="/img/**" security="none"></http>
<http pattern="/plugins/**" security="none"></http>
<http pattern="/cart.html" security="none"></http>
<!---->
<http use-expressions="false" entry-point-ref="casProcessingFilterEntryPoint">
<intercept-url pattern="/cart/*.do" access="IS_AUTHENTICATED_ANONYMOUSLY"></intercept-url>
<intercept-url pattern="/**" access="ROLE_USER"/>
<csrf disabled="true"/>
<custom-filter ref="casAuthenticationFilter" position="CAS_FILTER"/>
<custom-filter ref="requestSingleLogoutFilter" before="LOGOUT_FILTER"/>
<custom-filter ref="singleLogoutFilter" before="CAS_FILTER"/>
</http>