说在前面的话

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。

e3mall商城总结12之购物车的实现、以及购物车小计问题、json406报错的更多相关文章

  1. Starting php-fpm [18-Jun-2019 12:56:59] NOTICE: PHP message: PHP Warning: Version warning提示报错解决

    php-fpm在命令行重启时出现如下提示信息在终端上,虽然不影响使用,但是不够干净利落,参考了一篇国外博客得以解决,参考链接:https://community.centminmod.com/thre ...

  2. oracle之 12.1.0.1.0 C 在 linux 7 上安装报错处理

    环境说明:-- os[root@host-172-16-3-132 ~]# cat /etc/redhat-release CentOS Linux release 7.2.1511 (Core) - ...

  3. e3mall商城的归纳总结6之redis

    一.说在前面的话 前面几节我们主要对该项目的后端进行了增删改查,但是所有的数据都是存放在数据库中,这样的话数据库的压力显而易见是很大的,因此本节学习nosql的缓存,也就是redis的使用,在使用之前 ...

  4. e3mall商城的归纳总结1之项目的架构

    首先来谈谈e3mall商城,e3mall商城是黑马推出一个学习的项目,前身是淘淘商城.两个用的技术差不多.,但由于后期加了一些新技术,更名为e3mall商城.本商城为分布式商城,主要用到的技术使mav ...

  5. Vue nodejs商城项目-商品列表价格过滤和加入购物车功能

    一.价格过滤功能 GoodsList.vue >>点击价格区间时发送请求 methods:{     getGoodsList(flag){         var param = {   ...

  6. 购物车功能:使用jQuery实现购物车全选反选,单选,商品增删,小计等功能

    效果图: html: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...

  7. 简单的angular购物车商品小计

    <!DOCTYPE html> <html lang="en" ng-app="shopApp"> <head> <m ...

  8. 升级到macOS 10.12 mysqlb报错ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)

    系统升级到macOS 10.12后启动mysql后,在终端输入mysql 报错ERROR 1045 (28000): Access denied for user 'root'@'localhost' ...

  9. cocos3.12预编译android报错RuntimeJsImpl.cpp

    从coco官网下载了cocos2d-x-3.12.zip,在gen-libs生成prebuilt时,mac ,ios 平台都正常,android报错: jni/../../Classes/ide-su ...

随机推荐

  1. luogu P4562 [JXOI2018]游戏 组合数学

    LINK:游戏 当L==1的时候 容易想到 答案和1的位置有关. 枚举1的位置 那么剩下的方案为(R-1)! 那么总答案为 (R+1)*R/2(R-1)! 考虑L==2的时候 对于一个排列什么时候会终 ...

  2. Requests接口测试库-官网快速上手

    Requests 一个发送HTTP请求的库基于urllib3,相比自带的库,提供了更高效简洁的可用方法,测试从业者用来做接口测试的一个好工具 文章内容均来自官网:https://requests.re ...

  3. 在Swoole上加速Laravel应用

    Swoole是用于PHP的生产级异步编程框架.它是用纯C语言编写的PHP扩展,它使PHP开发人员可以在PHP中编写高性能,可伸缩的并发TCP,UDP,Unix套接字,HTTP,WebSocket服务, ...

  4. Android Studio--家庭记账本(三)

    点击右上角可以实现将花费以折线图的形式显示出来.同时将同一天的花费自动计算.暂时还没有加x,y轴 ChartsActivity.java: package com.example.family; im ...

  5. spring data jpa 之 通用接口

    园主这一阵子接到一个需求,就是将spring data jpa再进行封装,实现通过调用一个baseRepository,来实现每个类的增删改查操作,结合spring data jpa 原有的便捷操作, ...

  6. 教你看懂Docker和K8S!

    转载于 https://my.oschina.net/jamesview/blog/2994112 2010年,几个搞IT的年轻人,在美国旧金山成立了一家名叫“dotCloud”的公司. 这家公司主要 ...

  7. CentOS7 安装 SonarQube

    安装 SonarQube 环境 系统 CentOS 7 数据库 postgresql 10 系统配置 查看系统配置 sysctl vm.max_map_count sysctl fs.file-max ...

  8. git使用-远程仓库(github为例)

    1.登录github(没有先注册账号) 2.settings>SSH and GPG keys>New SSH key Title(自己填写即可) key需要git命令生成 ssh-key ...

  9. Django-model查询[为空、由某字符串开头、由某字符串结尾、包含某字符串],__isnull、__starswith、__endswith、__contains

    使用属性+__isnull就可以判断此字段为空 a = DatasClass.objects.filter(name__isnull=True) 使用属性+__startswith可以判断属性由某字符 ...

  10. 使用 VMware Workstation Pro 让 PC 提供云桌面服务——学习笔记(二)

    实验效果: 这次希望的效果是能够用远程桌面来实现 . 这里参考了博客 https://www.cnblogs.com/wwang/archive/2011/01/06/1928933.html 操作步 ...