一、本节主要讲了e3mall购物车的实现方法,我搭建的项目和系统购物车有一些区别,所以这里须要说一下。系统搭建的项目在未登录的状况下也能够经过cookie进行加入购物车,当用户要下单的时候再进行拦截(配置拦截器),若用户没登录。则跳转登录页面,登录完成后继续刚才的操做,同时把cookies中的商品加入到后台redis缓存中(其中须要判断redis中是否含有该商品,若含有,则增长数量),而后进行支付购买。若用户已登录,加入的购物车则直接保存到后台redis缓存中。相似JD。
二、而我搭建的项目购物车是不存入cookies中的,在e3mall-cart这个项目中就配置了拦截器,若用户未登录则强制登录,登录后继续以前的操做,保存的购物车商品数据都是存在redis缓存中的。所以我搭建的业务逻辑稍微简单一点。
三、后面我把留下的做业也作了,就是在修改购物车中商品的数量的时候,该商品的小计不会跟随数量的变化而变化这个BUG。html
用户在购物车选购商品的时候,强制登录。登陆后把购物车数据保存到服务端。须要永久保存,能够保存到数据库中。能够把购物车数据保存到redis中。此处保存到redis中。
redis使用的数据类型(由于购物车的数据不须要使用TTL,所以建议使用hash)
a)使用hash数据类型
b)Hash的key应该是用户id。Hash中的field是商品id,value能够把商品信息转换成json
添加购物车
直接把商品数据保存到redis中。
如何判断是否登陆?
a)从cookie中取token
b)取不到未登陆
c)取到token,到redis中查询token是否过时。
d)若是过时,未登陆状态
e)没过时登陆状态。java
应该使用springmvc拦截器实现。
一、实现一个HandlerInterceptor接口。
二、在执行handler方法以前作业务处理
三、从cookie中取token。使用CookieUtils工具类实现。
四、没有取到token,用户未登陆。拦截,使用response.sendredirect()进行跳转
五、取到token,调用sso系统的服务,根据token查询用户信息。
六、没有返回用户信息(null)。登陆已通过期,未登陆,拦截,使用response.sendredirect()进行跳转
七、返回用户信息。用户是登陆状态。能够把用户对象保存到request中,在Controller中能够经过判断request中是否包含用户对象,肯定是否为登陆状态,放行。web
首先来配置一下登录拦截器
Logininterceptor .javaredis
package cn.tsu.cart.e3mall.interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; import org.jboss.netty.util.internal.StringUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import cn.tsu.cart.e3mall.config.CartConfig; import cn.tsu.cart.e3mall.service.TokenService; import cn.tsu.e3mall.pojo.TbUser; import cn.tsu.e3mall.utils.CookieUtils; import cn.tsu.e3mall.utils.E3Result; import cn.tsu.sso.e3mall.service.UserService; /** * 判断用户是否登陆的拦截器 * @author xiaofeng * */ public class Logininterceptor implements HandlerInterceptor { @Autowired private TokenService tokenService; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //获取请求的连接 String url = request.getRequestURL().toString(); //若是连接中包含cart if (url.contains("cart")) { //从cookie中取token。使用CookieUtils工具类实现 String cookieValue = CookieUtils.getCookieValue(request, "USER_LOGIN_TOKEN"); //若是取到的数据不为空 if (StringUtils.isNotBlank(cookieValue)) { //经过token获取e3result对象 E3Result e3Result = tokenService.getToken(cookieValue); //若是对象的status是200的话,说明取到 if (e3Result.getStatus() == 200) { //转为tbuser对象 TbUser tbUser = (TbUser) e3Result.getData(); request.setAttribute("tbUser", tbUser); return true; } } } //不然则跳转登录页面并把url也传过去。 response.sendRedirect(CartConfig.LOGIN_HEAD+"/page/login?redirect="+url); return false; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // TODO Auto-generated method stub } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // TODO Auto-generated method stub } }
service层代码:
CartServiceImpl.javaspring
package cn.tsu.cart.e3mall.service.impl; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import cn.tsu.cart.e3mall.service.CartService; import cn.tsu.e3mall.dao.TbItemMapper; import cn.tsu.e3mall.jedis.JedisClient; import cn.tsu.e3mall.pojo.TbItem; import cn.tsu.e3mall.utils.E3Result; import cn.tsu.e3mall.utils.JsonUtils; import cn.tsu.sso.e3mall.service.config.UserConfig; /** * 操做购物车 * @author xiaofeng * */ @Service public class CartServiceImpl implements CartService { @Autowired private JedisClient jedisClient; @Autowired private TbItemMapper itemMapper; // 添加购物车 @Override public E3Result addCart(Long userid, Long itemid, int num) { //查询redis缓存中是否含有该field Boolean hexists = jedisClient.hexists(UserConfig.CART_REDIS_PRE+userid,itemid+""); //若是有 if (hexists) { //获取该hash的field的值 String hget = jedisClient.hget(UserConfig.CART_REDIS_PRE+userid,itemid+""); //将string值转化为对象 TbItem tbItem = JsonUtils.jsonToPojo(hget, TbItem.class); //增长数量 tbItem.setNum(tbItem.getNum()+num); // String json = JsonUtils.objectToJson(tbItem); jedisClient.hset(UserConfig.CART_REDIS_PRE+userid, itemid+"", json); }else { TbItem tbItem = itemMapper.selectByPrimaryKey(itemid); tbItem.setNum(num); String images = tbItem.getImage(); if (StringUtils.isNotBlank(images)) { tbItem.setImage(images.split(",")[0]); } jedisClient.hset(UserConfig.CART_REDIS_PRE+userid, itemid+"", JsonUtils.objectToJson(tbItem)); } return E3Result.ok(); } //获取购物车 @Override public List<TbItem> getCart(Long userid) { //经过hashkey获取hash全部的值(不包含field) List<String> list = jedisClient.hvals(UserConfig.CART_REDIS_PRE+userid); List<TbItem> tbItems = new ArrayList<TbItem>(); //遍历list,将list中的json数据转为tbItems对象 for (String string : list) { TbItem tbItem = JsonUtils.jsonToPojo(string, TbItem.class); tbItems.add(tbItem); } return tbItems; } // 更新购物车的num数量 @Override public E3Result updateCartNum(Long userid, Long itemid, int num) { //经过key获取json String hget = jedisClient.hget(UserConfig.CART_REDIS_PRE+userid, itemid+""); //把json转化为tbitem对象 TbItem tbItem = JsonUtils.jsonToPojo(hget, TbItem.class); //把新的num设置到对象中 tbItem.setNum(num); jedisClient.hset(UserConfig.CART_REDIS_PRE+userid, itemid+"", JsonUtils.objectToJson(tbItem)); return E3Result.ok(); } // 根据itemid删除购物车 @Override public E3Result deleteCartByItemId(Long userid, Long itemid) { //直接删除hashkey的field jedisClient.hdel(UserConfig.CART_REDIS_PRE+userid, itemid+""); return E3Result.ok(); } }
controller层:
CartController .java数据库
package cn.tsu.cart.e3mall.controller; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import cn.tsu.cart.e3mall.service.CartService; import cn.tsu.e3mall.pojo.TbItem; import cn.tsu.e3mall.pojo.TbUser; import cn.tsu.e3mall.utils.E3Result; /** * 购物车处理 * @author xiaofeng * */ @Controller public class CartController { @Autowired private CartService cartService; //添加购物车 @RequestMapping("/cart/add/{productid}") //@PathVariable表示须要从url取值 public String AddCart(@PathVariable Long productid,Integer num, HttpServletRequest request,HttpServletResponse response) { //tbUser是loginInterceptor拦截器最后放行的时候set进去的 TbUser tbUser = (TbUser) request.getAttribute("tbUser"); //调用service方法进行添加购物车 if (tbUser !=null) { E3Result e3Result = cartService.addCart(tbUser.getId(), productid, num); } return "cartSuccess"; } //跳转到购物车页面 @RequestMapping("/cart/cart") public String ToCart(Model model,HttpServletRequest request) { TbUser user = (TbUser) request.getAttribute("tbUser"); List<TbItem> cartList = cartService.getCart(user.getId()); model.addAttribute("cartList", cartList); return "cart"; } //修改购物车中的商品数量 @RequestMapping("/cart/update/num/{itemid}/{num}") @ResponseBody public E3Result updateCartNum(@PathVariable Long itemid ,@PathVariable Integer num,HttpServletRequest request) { TbUser tbuser = (TbUser) request.getAttribute("tbUser"); E3Result e3Result = cartService.updateCartNum(tbuser.getId(), itemid, num); return e3Result; } //根据itemid删除redis中的购物车商品 @RequestMapping("cart/delete/{itemid}") public String deleteCartByItemId(@PathVariable Long itemid,HttpServletRequest request) { TbUser tbUser = (TbUser) request.getAttribute("tbUser"); E3Result e3Result = cartService.deleteCartByItemId(tbUser.getId(), itemid); return "redirect:/cart/cart.html"; } }
用户点击-,和用户直接修改数据相似。
cart.js文件apache
var CART = { itemNumChange : function(){ $(".increment").click(function(){//+ var _thisInput = $(this).siblings("input"); _thisInput.val(eval(_thisInput.val()) + 1); $.post("/cart/update/num/"+_thisInput.attr("itemId")+"/"+_thisInput.val() + ".action",function(data){ CART.refreshTotalPrice(); }); //从新计算小计 var htmlvale = $(_thisInput).parent().parent().siblings(".pSubtotal").find("span"); var value =(eval(_thisInput.attr("itemPrice")))*_thisInput.val(); htmlvale.html(new Number(value/100).toFixed(2)).priceFormat({ //价格格式化插件 prefix: '¥', thousandsSeparator: ',', centsLimit: 2 }); }); $(".decrement").click(function(){//- var _thisInput = $(this).siblings("input"); if(eval(_thisInput.val()) == 1){ return ; } _thisInput.val(eval(_thisInput.val()) - 1); $.post("/cart/update/num/"+_thisInput.attr("itemId")+"/"+_thisInput.val() + ".action",function(data){ CART.refreshTotalPrice(); }); //从新计算小计 var htmlvale = $(_thisInput).parent().parent().siblings(".pSubtotal").find("span"); var value =(eval(_thisInput.attr("itemPrice")))*_thisInput.val(); htmlvale.html(new Number(value/100).toFixed(2)).priceFormat({ //价格格式化插件 prefix: '¥', thousandsSeparator: ',', centsLimit: 2 }); }); $(".itemnum").change(function(){ var _thisInput = $(this); $.post("/cart/update/num/"+_thisInput.attr("itemId")+"/"+_thisInput.val() + ".action",function(data){ CART.refreshTotalPrice(); }); //从新计算小计 var htmlvale = $(_thisInput).parent().parent().siblings(".pSubtotal").find("span"); var value =(eval(_thisInput.attr("itemPrice")))*_thisInput.val(); htmlvale.html(new Number(value/100).toFixed(2)).priceFormat({ //价格格式化插件 prefix: '¥', thousandsSeparator: ',', centsLimit: 2 }); }); }, refreshTotalPrice : function(){ //从新计算总价 var total = 0; $(".itemnum").each(function(i,e){ var _this = $(e); total += (eval(_this.attr("itemPrice")) * 10000 * eval(_this.val())) / 10000; }); $("#allMoney2").html(new Number(total/100).toFixed(2)).priceFormat({ //价格格式化插件 prefix: '¥', thousandsSeparator: ',', centsLimit: 2 }); } }; $(function(){ CART.itemNumChange(); });