e3mall商城总结12之购物车的实现、以及购物车小计问题、json406报错

说在前面的话

1、本节主要讲了e3mall购物车的实现方法,我搭建的项目和系统购物车有一些区别,因此这里需要说一下。系统搭建的项目在未登陆的情况下也可以通过cookie进行加入购物车,当用户要下单的时候再进行拦截(配置拦截器),若用户没登陆。则跳转登陆页面,登陆完成后继续刚才的操作,同时把cookies中的商品加入到后台redis缓存中(其中需要判断redis中是否含有该商品,若含有,则增加数量),然后进行支付购买。若用户已登陆,加入的购物车则直接保存到后台redis缓存中。类似JD。
2、而我搭建的项目购物车是不存入cookies中的,在e3mall-cart这个项目中就配置了拦截器,若用户未登陆则强制登陆,登陆后继续之前的操作,保存的购物车商品数据都是存在redis缓存中的。因此我搭建的业务逻辑稍微简单一点。
3、后面我把留下的作业也做了,就是在修改购物车中商品的数量的时候,该商品的小计不会跟随数量的变化而变化这个BUG。

说在前面的话

用户在购物车选购商品的时候,强制登陆。登录后把购物车数据保存到服务端。需要永久保存,可以保存到数据库中。可以把购物车数据保存到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)没过期登录状态。

判断用户是否登录

应该使用springmvc拦截器实现。
1、实现一个HandlerInterceptor接口。
2、在执行handler方法之前做业务处理
3、从cookie中取token。使用CookieUtils工具类实现。
4、没有取到token,用户未登录。拦截,使用response.sendredirect()进行跳转
5、取到token,调用sso系统的服务,根据token查询用户信息。
6、没有返回用户信息(null)。登录已经过期,未登录,拦截,使用response.sendredirect()进行跳转
7、返回用户信息。用户是登录状态。可以把用户对象保存到request中,在Controller中可以通过判断request中是否包含用户对象,确定是否为登录状态,放行。

首先来配置一下登陆拦截器
Logininterceptor .java

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.java

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文件

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();
});

json返回406报错问题

406报错有两种可能,一种是jackson的jar包没有加入(90%可能),剩下10%则是因为在springmvc中,若拦截形式是*.html,则是不可以返回json数据的,不然就会报错406。
posted @ 2019-01-23 22:32  拉风的小锋  阅读(428)  评论(0编辑  收藏  举报