SSM商城项目(十二)
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商城项目(十二)的更多相关文章
- SSM商城项目(二)
1. 学习计划 1.将工程改造为基于SOA架构 2.商品列表查询功能实现. 2. 将工程改造为SOA架构 2.1. 分析 由于商城是基于soa的架构,表现层和服务层是不同的工程.所以要实现商品列表查询 ...
- 品优购商城项目(二)mybatis分页插件
品优购商城项目第二天,使用mybatis分页插件实现分页.主要实现的是 SSM整合mybatis分页. 一.引用mybatis分页插件 SqlMapConfig.xml <?xml versio ...
- SSM商城项目(十)
1. 学习计划 1.使用freemarker实现网页静态化 a)Freemarker的使用方法 b)Freemarker模板的语法 c)Freemarker整合springmvc 2.Active ...
- SSM商城项目(一)
1. 学习计划 1.电商行业的背景. 2.宜立方商城介绍 3.宜立方商城的系统架构 a) 功能介绍 b) 架构讲解 4.工程搭建-后台工程 a) 使用maven搭建工程 b) 使用maven的tomc ...
- SSM商城项目(八)
1. 学习计划 1.solr集群搭建 2.使用solrj管理solr集群 3.把搜索功能切换到集群版 4.添加商品同步到索引库 2. 什么是SolrCloud SolrCloud(solr 云 ...
- SSM商城项目(四)
1. 学习计划 1.图片服务器 2.图片服务器安装 3.图片服务器的使用 4.图片上传功能 5.富文本编辑器的使用方法 6.商品添加功能实现 2. 图片服务器 1.存储空间可扩展. 2.提供一个统一的 ...
- 品优购商城项目(二)AngularJS、自动代码生成器、select2下拉多选框
品优购商城想项目第二阶段 AngularJS.自动代码生成器.select2下拉多选框 完成了课程第三天.第四天的的任务. 1.学习了AngularJs前端的mvc分层思想,js部分分成control ...
- SSM商城项目(十一)
1. 学习计划 1.sso注册功能实现 2.sso登录功能实现 3.通过token获得用户信息 Ajax跨域请求(jsonp) 2. Sso系统工程搭建 需要创建一个sso服务工程,可以参考e ...
- Spring Boot 构建电商基础秒杀项目 (十二) 总结 (完结)
SpringBoot构建电商基础秒杀项目 学习笔记 系统架构 存在问题 如何发现容量问题 如何使得系统水平扩展 查询效率低下 活动开始前页面被疯狂刷新 库存行锁问题 下单操作步骤多,缓慢 浪涌流量如何 ...
随机推荐
- S50 抓取pattern数据
S50(原V50) 测试机台湾久元电子研发的一款数字芯片测试系统,行业内有很多人使用: 现在记录下S50抓取pattern数据的一些方法: 程序主要是通过read_log配合c代码实现,pattern ...
- 【转】META标签指南:哪些meta标签该用哪些不该用?
以下内容来源:http://lusongsong.com/reed/8766.html META标签是网页代码中HEAD区的一个关键标签,其提供的信息虽然用户不可见,但却是文档的最基本的元信息.说起m ...
- 前端学习之jquery(二)
操作元素(属性,css,文档处理) 1.1 属性操作 --------------------------属性 $("").attr(); $("").remo ...
- python 调用C的DLL案例
前言: python不能直接调用C++只能调用纯C的DLL 此处案例是python模仿opencv的cv2包,但是用c的DLL调用 import osimport csvimport timeim ...
- NET-SNMP基本命令
当环境设置好后,运行snmpd,即snmp代理进程,就可以使用管理工具查询其中的信息了.Net- snmp提供的查询工具有很多,这里只介绍常用的几个,而且大部分查询命令的格式都大同小异.这里以.iso ...
- LeetCode【112. 路径总和】
思路就是从根节点开始向下选节点,依次与sum比较大小,若小,则向下选左右节点其中一个,若大,则接下来判断是否是叶子节点,若是,则返回false 若不是,则上一步选另一节点,再将上述重新执行. 对于叶子 ...
- logging模块初识
日志级别 import logging logging.debug("debug message")logging.info("info message")lo ...
- 学习MeteoInfo二次开发教程(十)
1.复制文件cloud_1009271330.000,I-01.pal 2.改: GridData cloud = aDataInfo.GetGridData(""); 为: Gr ...
- sqlserver2008 查看数据库自带的索引建议
SELECT [Total Cost] = ROUND(avg_total_user_cost * avg_user_impact * (user_seeks + user_scans),0) , a ...
- 2018-2019-2 20175328李欣颖实验二《Java面向对象程序设计》实验报告
2018-2019-2 20175328李欣颖实验二<Java面向对象程序设计>实验报告 面向对象程序设计-1 用程序解决问题时,要会写三种码: 1.伪代码 此处百分制转五分制: 如果成绩 ...