1.   学习计划

1、购物车实现

2、未登录状态下使用购物车

3、登录状态下使用购物车

2.   购物车的实现

2.1. 功能分析

1、购物车是一个独立的表现层工程。

2、添加购物车不要求登录。可以指定购买商品的数量。

3、展示购物车列表页面

4、修改购物车商品数量

5、删除购物车商品

2.2. 工程搭建

可以参考e3-content创建。

e3-car(聚合工程pom)

|--e3-car-interface(jar)

|--e3-car-Service(war)

e3-car-web(war)

3.   未登录状态下使用购物车

3.1. 添加购物车

3.1.1.    功能分析

在不登陆的情况下也可以添加购物车。把购物车信息写入cookie。

优点:

1、不占用服务端存储空间

2、用户体验好。

3、代码实现简单。

缺点:

1、cookie中保存的容量有限。最大4k

2、把购物车信息保存在cookie中,更换设备购物车信息不能同步。

改造商品详情页面

请求的url:/cart/add/{itemId}

参数:

1)商品id: Long itemId
2)商品数量: int num

业务逻辑:

1、从cookie中查询商品列表。

2、判断商品在商品列表中是否存在。

3、如果存在,商品数量相加。

4、不存在,根据商品id查询商品信息。

5、把商品添加到购车列表。

6、把购车商品列表写入cookie。

返回值:逻辑视图

Cookie保存购物车

1)key:TT_CART

2)Value:购物车列表转换成json数据。需要对数据进行编码。

3)Cookie的有效期:保存7天。

商品列表:

List<TbItem>,每个商品数据使用TbItem保存。当根据商品id查询商品信息后,取第一张图片保存到image属性中即可。

读写cookie可以使用CookieUtils工具类实现。

3.1.2.    Controller

@Controller
public class CarController { @Value("${CART_EXPIRE}")
private Integer CART_EXPIRE; @Autowired
private ItemService itemService; @RequestMapping("/cart/add/{itemId}")
public String addCartItem(@PathVariable Long itemId, Integer num,
HttpServletRequest request, HttpServletResponse response) {
// 1、从cookie中查询商品列表。
List<TbItem> cartList = getCartList(request);
// 2、判断商品在商品列表中是否存在。
boolean hasItem = false;
for (TbItem tbItem : cartList) {
//对象比较的是地址,应该是值的比较
if (tbItem.getId() == itemId.longValue()) {
// 3、如果存在,商品数量相加。
tbItem.setNum(tbItem.getNum() + num);
hasItem = true;
break;
}
}
if (!hasItem) {
// 4、不存在,根据商品id查询商品信息。
TbItem tbItem = itemService.getItemById(itemId);
//取一张图片
String image = tbItem.getImage();
if (StringUtils.isNoneBlank(image)) {
String[] images = image.split(",");
tbItem.setImage(images[0]);
}
//设置购买商品数量
tbItem.setNum(num);
// 5、把商品添加到购车列表。
cartList.add(tbItem);
}
// 6、把购车商品列表写入cookie。
CookieUtils.setCookie(request, response, "car", JsonUtils.objectToJson(cartList), CART_EXPIRE, true);
return "cartSuccess";
} /**
* 从cookie中取购物车列表
* <p>Title: getCartList</p>
* <p>Description: </p>
* @param request
* @return
*/
private List<TbItem> getCartList(HttpServletRequest request) {
//取购物车列表
String json = CookieUtils.getCookieValue(request, "car", true);
//判断json是否为null
if (StringUtils.isNotBlank(json)) {
//把json转换成商品列表返回
List<TbItem> list = JsonUtils.jsonToList(json, TbItem.class);
return list;
}
return new ArrayList<>();
} }

3.2. 展示购物车商品列表

请求的url:/cart/cart

参数:无

返回值:逻辑视图

业务逻辑:

1、从cookie中取商品列表。

2、把商品列表传递给页面。

 Controller

    @RequestMapping("/cart/cart")
public String showCartList(HttpServletRequest request, Model model) {
//取购物车商品列表
List<TbItem> cartList = getCartList(request);
//传递给页面
model.addAttribute("cartList", cartList);
return "cart";
}

3.3. 修改购物车商品数量

3.3.1.    功能分析

1、在页面中可以修改商品数量

2、重新计算小计和总计。

3、修改需要写入cookie。

4、每次修改都需要向服务端发送一个ajax请求,在服务端修改cookie中的商品数量。

请求的url:/cart/update/num/{itemId}/{num}

参数:long itemId、int num

业务逻辑:

1、接收两个参数

2、从cookie中取商品列表

3、遍历商品列表找到对应商品

4、更新商品数量

5、把商品列表写入cookie。

6、响应e3Result。Json数据。

返回值:

e3Result。Json数据

3.3.2.    Controller

/*修改购物车商品数量*/
@RequestMapping("/cart/update/num/{itemId}/{num}")
public E3Result updateNum(@PathVariable Long itemId,@PathVariable Integer num,HttpServletRequest request,HttpServletResponse response){
//从cookie中查询商品列表。
List<TbItem> cartList = getCartList(request);
for (TbItem tbItem : cartList) {
if(tbItem.getId()==itemId.longValue()){
tbItem.setNum(num);
}
}
CookieUtils.setCookie(request, response, "car", JsonUtils.objectToJson(cartList), CART_EXPIRE, true);
return E3Result.ok();
}

3.3.3.    解决请求*.html后缀无法返回json数据的问题

在springmvc中请求*.html不可以返回json数据。

修改web.xml,添加url拦截格式。

</servlet-mapping>
<servlet-mapping>
<servlet-name>e3-car-web</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>

3.4. 删除购物车商品

3.4.1.    功能分析

请求的url:/cart/delete/{itemId}

参数:商品id

返回值:展示购物车列表页面。Url需要做redirect跳转。

业务逻辑:

1、从url中取商品id

2、从cookie中取购物车商品列表

3、遍历列表找到对应的商品

4、删除商品。

5、把商品列表写入cookie。

6、返回逻辑视图:在逻辑视图中做redirect跳转。

3.4.2.    Controller

    @RequestMapping("/cart/delete/{itemId}")
public String deleteCarItem(@PathVariable Long itemId,HttpServletRequest request,HttpServletResponse response){
//从cookie中查询商品列表。
List<TbItem> cartList = getCartList(request);
for (TbItem tbItem : cartList) {
if(tbItem.getId()==itemId.longValue()){
cartList.remove(tbItem);
break;
}
}
CookieUtils.setCookie(request, response, "car", JsonUtils.objectToJson(cartList), CART_EXPIRE, true);
return "redirect:/cart/cart.html";
}

3.5. 小结

使用cookie实现购物车:

优点:

1、实现简单

2、不需要占用服务端存储空间。

缺点:

1、存储容量有限

2、更换设备购车信息不能同步。

实现购车商品数据同步:

1、要求用户登录。

2、把购物车商品列表保存到数据库中。推荐使用redis。

3、Key:用户id,value:购车商品列表。推荐使用hash,hash的field:商品id,value:商品信息。

4、在用户未登录情况下写cookie。当用户登录后,访问购物车列表时,

a)         把cookie中的数据同步到redis。

b)        把cookie中的数据删除

c)         展示购物车列表时以redis为准。

d)        如果redis中有数据cookie中也有数据,需要做数据合并。相同商品数量相加,不同商品添加一个新商品。

5、如果用户登录状态,展示购物车列表以redis为准。如果未登录,以cookie为准。

4.   登录状态下使用购物车

4.1. 功能分析

1、购物车数据保存的位置:

未登录状态下,把购物车数据保存到cookie中。

登录状态下,需要把购物车数据保存到服务端。需要永久保存,可以保存到数据库中。可以把购物车数据保存到redis中。

2、redis使用的数据类型

  a)使用hash数据类型

  b)Hash的Key应该是用户id。Hash中的field是商品id,value可以把商品信息转成json

3、添加购物车

  登录状态下直接把商品数据保存到redis中。

  未登录状态保存到cookie中。

4、如何判断是否登录

  a)从cookie中取token

  b)取不到未登录

  c)取到token,到redis中查询token是否过期

  d)如果过期,未登录状态

  e)没过期,登录状态

4.2. 判断用户是否登录

4.2.1.   功能分析

应该使用拦截器实现。

1、实现一个HandlerInterceptor接口。

2、在执行handler方法之前做业务处理

3、从cookie中取token。使用CookieUtils工具类实现。

4、没有取到token,用户未登录,放行。

5、取到token,调用sso系统的服务,根据token查询用户信息。

6、没有返回用户信息。登录已经过期,未登录,放行。

7.返回用户信息。用户是登录状态。可以把用户对象保存到request中,在Controller中可以通过判断request中是否包含用户对象,确定是否为登录状态。

4.2.2.   拦截器

pom.xml

        <dependency>
<groupId>cn.e3mall</groupId>
<artifactId>e3-sso-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

引用服务

    <dubbo:reference interface="cn.e3mall.sso.service.TokenService" id="tokenService" /> 
public class LoginInterceptor implements HandlerInterceptor{

    @Autowired
private TokenService tokenService; @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 前处理,执行handler之前执行此方法
//返回true,放行 false:拦截
//从cookie中取token
String token=CookieUtils.getCookieValue(request, "token");
//如果没有token,未登录,直接放行
if(StringUtils.isBlank(token)){
return true;
}
//取到token,需要调用sso的服务,根据token取用户信息
E3Result e3Result = tokenService.getUserByToken(token);
//没有取到,登录过期,放行。
if(e3Result.getStatus()!=200){
return true;
}
//取到用户信息,登录状态。
TbUser user = (TbUser) e3Result.getData();
//把用户信息放到request中。只需要在Controller中判断request中是否包含user信息,放行
request.setAttribute("user", user);
return true;
} @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 } }

4.2.3.   配置拦截器

    <!-- 拦截器配置 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="cn.e3mall.car.interceptor.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>

4.3. 添加购物车

4.3.1.   Service

@Service
public class CartServiceImpl implements CartService{ @Autowired
private JedisClient jedisClient;
@Autowired
private TbItemMapper itemMapper; @Override
public E3Result addCart(long userId, long itemId, int num) {
//判断商品是否存在
Boolean hexists = jedisClient.hexists("Cart:" + userId, itemId + "");
//如果存在数量相加
if (hexists) {
String json = jedisClient.hget("Cart:" + userId, itemId + "");
//把json转换成TbItem
TbItem item = JsonUtils.jsonToPojo(json, TbItem.class);
item.setNum(item.getNum() + num);
//写回redis
jedisClient.hset("Cart:" + userId, itemId + "", JsonUtils.objectToJson(item));
return E3Result.ok();
}
//如果不存在,根据商品id取商品信息
TbItem item = itemMapper.selectByPrimaryKey(itemId);
//设置购物车数据量
item.setNum(num);
//取一张图片
String image = item.getImage();
if (StringUtils.isNotBlank(image)) {
item.setImage(image.split(",")[0]);
}
//添加到购物车列表
jedisClient.hset("Cart:" + userId, itemId + "", JsonUtils.objectToJson(item));
return E3Result.ok();
} }

发布服务

<dubbo:service interface="cn.e3mall.car.service.CartService" ref="cartServiceImpl" timeout="600000"/>

4.3.2.   Controller

引用服务

 <dubbo:reference interface="cn.e3mall.car.service.CartService" id="cartService" /> 

4.4. 展示购物车

4.4.1.   Service

    @Override
public E3Result mergeCart(long userId, List<TbItem> itemList) {
//遍历商品列表
//把列表添加到购物车
//判断购物车是否有此商品
//如果有, 数量相加
//如果没有,添加新的商品
for (TbItem tbItem : itemList) {
addCart(userId, tbItem.getId(), tbItem.getNum());
}
return E3Result.ok();
} //获得购物车列表
@Override
public List<TbItem> getCartList(long userId) {
//根据用户id查询购物车列表
List<String> jsonList = jedisClient.hvals("Cart:" + userId);
ArrayList<TbItem> itemList = new ArrayList<>();
for (String string : jsonList) {
TbItem item = JsonUtils.jsonToPojo(string, TbItem.class);
itemList.add(item);
}
return itemList;
}

4.4.2.   Controller

@RequestMapping("/cart/cart")
public String showCartList(HttpServletRequest request, HttpServletResponse response,Model model) {
//从cookie中取购物车列表
List<TbItem> cartList = getCartList(request);
//判断用户是否为登录状态
TbUser user = (TbUser) request.getAttribute("user");
//如果是登录状态
if (user != null) {
//从cookie中取购物车列表
//如果不为空,把cookie中的购物车商品和服务端的购物车商品合并。
cartService.mergeCart(user.getId(), cartList);
//把cookie中的购物车删除
CookieUtils.deleteCookie(request, response, "cart");
//从服务端取购物车列表
cartList = cartService.getCartList(user.getId()); }
//传递给页面
model.addAttribute("cartList", cartList);
return "cart";
}

4.5. 更新购物车数量

4.5.1.   Service

    @Override
public E3Result updateCart(long userId, long itemId, int num) {
//从redis中取商品信息
String json = jedisClient.hget("Cart:" + userId, itemId + "");
//更新商品数量
TbItem tbItem = JsonUtils.jsonToPojo(json, TbItem.class);
tbItem.setNum(num);
//写入redis
jedisClient.hset("Cart:" + userId, itemId + "",JsonUtils.objectToJson(tbItem));
return E3Result.ok();
}

4.5.2.   Controller

4.6. 删除购物车

4.6.1.   Service

    @Override
public E3Result deleteCartItem(long userId, long itemId) {
//删除购物车商品
jedisClient.hdel("Cart:" + userId, itemId + "");
return E3Result.ok();
}

4.6.2.   Controller

SSM商城项目(十二)的更多相关文章

  1. SSM商城项目(二)

    1. 学习计划 1.将工程改造为基于SOA架构 2.商品列表查询功能实现. 2. 将工程改造为SOA架构 2.1. 分析 由于商城是基于soa的架构,表现层和服务层是不同的工程.所以要实现商品列表查询 ...

  2. 品优购商城项目(二)mybatis分页插件

    品优购商城项目第二天,使用mybatis分页插件实现分页.主要实现的是 SSM整合mybatis分页. 一.引用mybatis分页插件 SqlMapConfig.xml <?xml versio ...

  3. SSM商城项目(十)

    1.   学习计划 1.使用freemarker实现网页静态化 a)Freemarker的使用方法 b)Freemarker模板的语法 c)Freemarker整合springmvc 2.Active ...

  4. SSM商城项目(一)

    1. 学习计划 1.电商行业的背景. 2.宜立方商城介绍 3.宜立方商城的系统架构 a) 功能介绍 b) 架构讲解 4.工程搭建-后台工程 a) 使用maven搭建工程 b) 使用maven的tomc ...

  5. SSM商城项目(八)

    1.   学习计划 1.solr集群搭建 2.使用solrj管理solr集群 3.把搜索功能切换到集群版 4.添加商品同步到索引库 2.   什么是SolrCloud SolrCloud(solr 云 ...

  6. SSM商城项目(四)

    1. 学习计划 1.图片服务器 2.图片服务器安装 3.图片服务器的使用 4.图片上传功能 5.富文本编辑器的使用方法 6.商品添加功能实现 2. 图片服务器 1.存储空间可扩展. 2.提供一个统一的 ...

  7. 品优购商城项目(二)AngularJS、自动代码生成器、select2下拉多选框

    品优购商城想项目第二阶段 AngularJS.自动代码生成器.select2下拉多选框 完成了课程第三天.第四天的的任务. 1.学习了AngularJs前端的mvc分层思想,js部分分成control ...

  8. SSM商城项目(十一)

    1.   学习计划 1.sso注册功能实现 2.sso登录功能实现 3.通过token获得用户信息 Ajax跨域请求(jsonp) 2.   Sso系统工程搭建 需要创建一个sso服务工程,可以参考e ...

  9. Spring Boot 构建电商基础秒杀项目 (十二) 总结 (完结)

    SpringBoot构建电商基础秒杀项目 学习笔记 系统架构 存在问题 如何发现容量问题 如何使得系统水平扩展 查询效率低下 活动开始前页面被疯狂刷新 库存行锁问题 下单操作步骤多,缓慢 浪涌流量如何 ...

随机推荐

  1. React 思维索引

    关于分析React源码的文章已经有比较多,我就不献丑了. 根据分析的结果把React的大致流程和思维导图做了一点总结,图片如下: 源码在: https://github.com/laryosbert/ ...

  2. [蓝桥杯]PREV-26.历届试题_最大子阵

    问题描述 给定一个n*m的矩阵A,求A中的一个非空子矩阵,使这个子矩阵中的元素和最大. 其中,A的子矩阵指在A中行和列均连续的一块. 输入格式 输入的第一行包含两个整数n, m,分别表示矩阵A的行数和 ...

  3. MySql 的SQL执行计划查看,判断是否走索引

    在select窗口中,执行以下语句: set profiling =1; -- 打开profile分析工具show variables like '%profil%'; -- 查看是否生效show p ...

  4. Kafka基本命令

    1.创建自定义的topic 在bin目录下执行: sh kafka-topics.sh --create --zookeeper hadoop01:2181 --replication-factor ...

  5. 如何破解QQ空间相册密码访问权限2019方法

    今天小编给大家介绍一下最新的QQ空间相册破解方法,是2019年最新方法,本方法来自互联网,下面开始方法教程 教程之前我们需要下载软件,地址我发在下方 软件切图 1.首先我们打开软件,然后在“操作界面” ...

  6. mybatis的plugin

    1.Mybatis-Plugin的设计思路 听起来一个挺神奇的单词,插件.说白了就是使用了Jdk自带的动态代理.在需要的时候进行代理.AOP怎么用,他就怎么用. Plugin类等价于Invocatio ...

  7. 记录4-Ubuntu 16.04用gparted调整分区

    几天在安装双系统时,没注意居然把swap分区设置成了50G.今天才发现,于是用gparted重新分区. 1. sudo apt-get install gparted 2. 重新用u盘启动进入ubun ...

  8. springboot+VUE(一)

    https://segmentfault.com/blog/wangjihong 安装nodejs与NPM 下载nodejs的LTL版本,并安装 https://nodejs.org/en/ 执行no ...

  9. Quick Search Articles in My Blog

    === Quickly Search Articles in My Blog: === 本文介绍了如何快速在主流搜索引擎搜索本专栏内文章的方法. Use Google's Search :  pres ...

  10. OO第一单元(求导)单元总结

    OO第一单元(求导)单元总结 这是我们oo课程的第一个单元,也是意在让我们接触了解掌握oo思想的一个单元,这个单元的作业以求导为主题,从一开始的加减多项式求导再到最后的嵌套多项式求导,难度逐渐提高,编 ...