黄小华的个人网站
熬过无人问津的日子才有诗和远方!
项目中遇到的问题

1.String id不能自增长 使用了UUID工具类

3.session失效

5.发现购物车也要表 发现数据库设计有问题,要重改有点麻烦,所以引用了Redis非关系性数据库

4.redis序列化serialVersionUID不匹配 报错 反序列化报错

任何存储都需要序列化。只不过常规你在用DB一类存储的时候,这个事情DB帮你在内部搞定了(直接把SQL带有类型的数据转换成内部序列化的格式,存储;读取时再解析出来)。而Redis并不会帮你做这个事情。当你用Redis的key和value时,value对于redis来讲就是个byte array。你要自己负责把你的数据结构转换成byte array,等读取时再读出来。一个特例是字符串,因为字符串自己几乎就已经是byte array了,所以不需要自己处理。因此当你要用redis存一个东西,你可能会遇到如果是boolean类型的true/false;你要自己定义redis里怎么表示true和false。比如你可以用1代表true,0代表false;也可以用“true”这个字符串代表true,“false”这个字符串代表false。如果是数字,可以直接存储数字的字符串表示(5 --> '5'),然后读取时再把数字字符串转回来(parseInt/parseDouble/...)。如果是时间/日期,可以自己定义一种字符串表达,比如epoc timestamp这个数的字符串表示,又或者是ISO8601的格式。如果是一个复杂的数据结构,你需要自己用某种序列化格式来存,可以是json, protobuf, avro, java serialization, python pickle……回到Spring这边。Spring的redisTemplate默认会使用java serialization做序列化。你也可以用StringRedisTemplate,那么你set的所有数据都会被toString一下再存到redis里。但这个toString不一定能反解析的回来……总之简单一句话,你要形成一个序列化的约定,确保存进去的东西能解析回来不出错。也许你可以和你的team商量一个规范。

2.购物车设计卡住

像在线购物网站,需要登录的网站等等,马上就面临一个问题,那就是要管理会话,必须记住哪些人登录系统, 哪些人往自己的购物车中放商品, 也就是说我必须把每个人区分开,这就是一个不小的挑战,因为HTTP请求是无状态的,所以想出的办法就是给大家发一个会话标识(session id), 说白了就是一个随机的字串,每个人收到的都不一样, 每次大家向我发起HTTP请求的时候,把这个字符串给一并捎过来, 这样我就能区分开谁是谁了
购物车: 即使用户不登录也可以将商品加入购物车,购物车使用session实现. 封装实体对象:
购物项:CartItem
商品基本信息: product
购买数量: count
小计: subtotal
购物车:Cart
多个购物项: List<购物项>

总金额: total
案例1-将商品加入购物车
需求分析:
在商品详情页面上,当点击"加入购物车"按钮时,向服务器发送一个加入购物车的请求.
技术分析:
封装商品信息,并将封装好的商品信息放入购物车实体内,再将购物车实体放入session中.
session
步骤分析:
前台:
发送加入购物车的请求
/day03store/cart?method=addCartItemToCart
pid
count
后台: 编写CartServlet 继承 BaseServlet
//编写公共的 addCartItemToCart 方法
//1.获取请求携带的商品pid
//2.获取请求携带的count的值
//3.将 要加入购物车中的商品信息拼成购物项
//商品的基本信息 购买数量 小计

//4.将封装好的购物项加入购物车实体中,并将购物车实体放入session中.
案例2-将商品从购物车中删除

需求分析:
在购物车详情页面上,当点击"删除"超链接时,向服务器发送一个删除购物项的请求.
步骤分析: 前台: /day03store/cart?method=removeCartItemFromCart pid=10 后台:
web:
编写公共的 removeCartItemFromCart 方法
//1.获取请求携带的商品pid
//2.获取session中的购物车对象
//3.将该购物项从购物车中删除.
//4.将购物车实体放回session中
案例3-清空购物车
需求分析:
在购物车详情页面上,当点击"清空购物车"超链接时,向服务器发送一个清空购物车的请求.
步骤分析:
前台:
/day03store/cart?method=clearCart
后台:
web:
编写公共的 clearCart 方法
//1.获取session中的购物车实体对象
//2.调用方法清空
//3.将购物车实体放回session中
案例4-生成订单
需求分析:
在购物车详情页面上,点击"提交订单"按钮时,向服务器发送一个生成订单的请求.
将购物车中的商品信息,转成订单所需要的信息,并保存到数据库中.
将购物车中的商品信息 ==== 订单所需要的商品信息
订单实体:
订单id : 后台生成
收货地址:待定
收货人:待定
联系方式:待定
用户实体(用户id):从session中获取
订单状态: 后台定义
订单生成日期: 后台定义
订单总金额:从购物车中获取
订单项集合: 从购物车中获取
订单项实体:
订单项id
商品信息
购买数量
小计
所属订单实体(订单id)

步骤分析:
前台:
点击"提交订单"按钮时,直接方法生成订单的请求
/day03store/cart?method=createOrder
后台:
web:
//零: 判断用户是否登录
HttpSession session = request.getSession();
user = session.getAttr("user");
if(user!=null){
//一: 生成订单实体信息
Orders order = new Orders();
//1.1订单id : 后台生成
orders.setOid(UUID);
//1.2用户实体(用户id):从session中获取
orders.setUser(user);
//1.3订单状态: 后台定义
orders.setState(0);
//1.4订单生成日期: 后台定义
orders.setOrdertime(new Date());
//1.5订单总金额:从购物车中获取
cart = session.getAttr("cart");
orders.setTotal(cart.getTotal());
//1.6订单项集合: 从购物车中获取
// 将购物项转成订单项
//获取所有的购物项集合 List cartItemList = cart.getCartItemList(); for(CartItem ci:cartItemList){ // 将每一个购物项转成订单项 OrderItem oi = new OrderItem(); //订单项id oi.setItemId(UUID); //商品信息 oi.setProduct(ci.getProduct()); //购买数量
oi.setCount(ci.getCount());
//小计
oi.setSubTotal(ci.getSubTotal());
//所属订单实体(订单id)
oi.setOrders(order);
// 将订单项放入订单项集合中
orders.getList().add(oi);
}
//二: 调用sevice完成订单的添加功能
service.createOrder(order);
} service:
createOrder(order){
//开启手动事务
//调用dao添加订单的基本信息
dao.addOrder(order);
//遍历订单项list
//调用dao添加订单项的基本信息
dao.addCartItem(cartItem);
}
dao:
//添加订单的基本信息
addOrder(order){

}
//添加订单项的基本信息
addCartItem(cartItem){

}

1、商城购物车系统实现的三种方案
1.1、session

  将购物车直接存放到与用户相关的session中。
优点:
  代码实现超级简单。
缺点:
  购物车存在session当中,如果session销毁,购物车就没有了。(session只存在于一次会话中。)
  用户未登录的时候不能添加购物车。
  购物车使用了session,而session是存在于内存资源中,消耗了大量的内存资源。非常不好。
  集群情况下,session很难共享,无法进行水平扩展。(tomcat的session广播对资源消耗严重,即tomcat的带宽不干别的了,就去广播了。)
1.2、cookie

  将购物车直接存放到浏览器的cookie中。
优点:
  在不登陆的情况下也可以添加购物车。
  不占用服务端存储空间。
  用户体验好。
  代码实现简单。
缺点:
  cookie中保存的容量有限。最大4k。
  cookie占用的是浏览器的缓存,可能用户会定期删除cookie。
  把购物车信息保存在cookie中,更换设备购物车信息不能同步。
1.3、cookie+入库 / 直接入库

  对于未登陆用户,将购物车放到cookie中,对于已登陆用户将购物车放入数据库中。
  将购物车持久化到数据库中。这里的数据库指的是关系型数据库或者非关系型数据库。
优点:
  关系型数据库:mysql数据库(数据完整性比较好)
  非关系型数据库:redis数据库(读写速度快)
缺点:
  相对于session和cookie,没啥缺点。
  占用服务端资源。
2、购物车实现总结

  自己写着玩的代码可以使用cookie+session。
  真实场景应该是要使用cookie+入库,或者直接入库。
  京东准许未登录状态添加购物车,应该采用的是cookie+入库。
  淘宝并不准许用户未登录添加购物车,应该采用的是直接入库。