商城-购物车
作者:互联网
购物车
购物车分为用户登录购物车和未登录购物车操作,国内知名电商京东用户登录和不登录都可以操作
购物车,如果用户不登录,操作购物车可以将数据存储到Cookie或者
WebSQL或者SessionStorage中,用户登录后购物车数据可以存储到Redis中,再将之前未登录加
入的购物车合并到Redis中即可。
淘宝天猫则采用了另外一种实现方案,用户要想将商品加入购物车,必须先登录才能操作购物车。
我们今天实现的购物车是天猫解决方案,即用户必须先登录才能使用购物车功能。
购物车分析
(1)需求分析
用户在商品详细页点击加入购物车,提交商品SKU编号和购买数量,添加到购物车。购物车展示页
面如下:
(2)购物车实现思路
我们实现的是用户登录后的购物车,用户将商品加入购物车的时候,直接将要加入购物车的详情存
入到Redis即可。每次查看购物车的时候直接从Redis中获取。
(3)表结构分析
用户登录后将商品加入购物车,需要存储商品详情以及购买数量,购物车详情表如下:
changgou_order数据中tb_order_item表:
CREATE TABLE `tb_order_item` (
`id` varchar(20) COLLATE utf8_bin NOT NULL COMMENT 'ID',
`category_id1` int(11) DEFAULT NULL COMMENT '1级分类',
`category_id2` int(11) DEFAULT NULL COMMENT '2级分类',
`category_id3` int(11) DEFAULT NULL COMMENT '3级分类',
`spu_id` varchar(20) COLLATE utf8_bin DEFAULT NULL COMMENT 'SPU_ID',
`sku_id` bigint(20) NOT NULL COMMENT 'SKU_ID',
`order_id` bigint(20) NOT NULL COMMENT '订单ID',
`name` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '商品名称',
`price` int(20) DEFAULT NULL COMMENT '单价',
`num` int(10) DEFAULT NULL COMMENT '数量',
`money` int(20) DEFAULT NULL COMMENT '总金额',
`pay_money` int(11) DEFAULT NULL COMMENT '实付金额',
`image` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '图片地址',
`weight` int(11) DEFAULT NULL COMMENT '重量',
`post_fee` int(11) DEFAULT NULL COMMENT '运费',
`is_return` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '是否退货',
PRIMARY KEY (`id`),
KEY `item_id` (`sku_id`),
KEY `order_id` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
购物车详情表其实就是订单详情表结构,只是目前临时存储数据到Redis,等用户下单后才将数据
从Redis取出存入到MySQL中。
借用它的实体bean,不能用它的表,数据往redis中存,存Hash类型。
订单购物车微服务
我们先搭建一个订单购物车微服务工程,按照如下步骤实现即可。
(1)搭建订单购物车微服务changgou-service-order
依赖引入:
<dependencies>
<dependency>
<groupId>com.changgou</groupId>
<artifactId>changgou-service-order-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
后面查询商品会用到goods,这里先补上依赖
API工程:
(2)application.yml配置
在changgou-service-order的resources中添加application.yml配置文件,代码如下:
server:
port: 18088
spring:
application:
name: order
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.2.132:3306/changgou_order?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: 123456
redis:
host: 192.168.2.132
port: 6379
main:
allow-bean-definition-overriding: true
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:7001/eureka
instance:
prefer-ip-address: true
feign:
hystrix:
enabled: true
(3)创建启动类
package com.changgou;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import tk.mybatis.spring.annotation.MapperScan;
@SpringBootApplication
@EnableEurekaClient
@MapperScan(basePackages = {"com.changgou.order.dao"})
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class,args);
}
}
代码生成器生成pojo,拷贝到api工程中来
其他controller、service、dao拷贝到订单购物车微服务中(出现红叉,手动导入Date包即可,
import java.util.Date;)
添加购物车
用户添加购物车,只需要将要加入购物车的商品存入到Redis中即可。一个用户可以将多件商品加
入购物车,存储到Redis中的数据可以采用Hash类型。
选Hash类型可以将用户的用户名作为namespace的一部分,将指定商品加入购物车,则往对应的
namespace中增加一个key和value,
key是商品ID,value是加入购物车的商品详情,如下图:
代码实现
feign创建,下订单需要调用feign查看商品信息
新建一个SpuFeign
在changgou-service-order微服务中创建com.changgou.order.controller.CartController,
在changgou-service-order微服务中创建com.changgou.order.service.CartService接口,
在changgou-service-order微服务中创建接口实现类com.changgou.order.service.impl.CartServiceImpl,
代码如下:
package com.changgou.order.controller;
import com.changgou.order.service.CartService;
import entity.Result;
import entity.StatusCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin
@RequestMapping(value = "/cart")
public class CartController {
@Autowired
private CartService cartService;
/***
* 加入购物车
* @param num:购买的数量
* @param id:购买的商品(SKU)ID
* @return
*/
@RequestMapping(value = "/add")
public Result add(Integer num, Long id){
//用户名
String username="szitheima";
//将商品加入购物车
cartService.add(num,id,username);
return new Result(true, StatusCode.OK,"加入购物车成功!");
}
}
package com.changgou.order.service;
public interface CartService {
/***
* 添加购物车
* @param num:购买商品数量
* @param id:购买ID
* @param username:购买用户
* @return
*/
void add(Integer num, Long id, String username);
}
package com.changgou.order.service.impl;
import com.changgou.goods.feign.SkuFeign;
import com.changgou.goods.feign.SpuFeign;
import com.changgou.goods.pojo.Sku;
import com.changgou.goods.pojo.Spu;
import com.changgou.order.pojo.OrderItem;
import com.changgou.order.service.CartService;
import entity.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
@Service
public class CartServiceImpl implements CartService {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private SkuFeign skuFeign;
@Autowired
private SpuFeign spuFeign;
@Override
public void add(Integer num, Long id, String username) {
//查询SKU
Result<Sku> resultSku = skuFeign.findById(id);
if(resultSku!=null && resultSku.isFlag()){
//获取SKU
Sku sku = resultSku.getData();
//获取SPU
Result<Spu> resultSpu = spuFeign.findById(sku.getSpuId());
//将SKU转换成OrderItem
OrderItem orderItem = sku2OrderItem(sku,resultSpu.getData(), num);
/******
* 购物车数据存入到Redis
* namespace = Cart_[username]
* key=id(sku)
* value=OrderItem
*/
redisTemplate.boundHashOps("Cart_"+username).put(id,orderItem);
}
}
/***
* SKU转成OrderItem
* @param sku
* @param num
* @return
*/
private OrderItem sku2OrderItem(Sku sku,Spu spu,Integer num){
OrderItem orderItem = new OrderItem();
orderItem.setSpuId(sku.getSpuId());
orderItem.setSkuId(sku.getId());
orderItem.setName(sku.getName());
orderItem.setPrice(sku.getPrice());
orderItem.setNum(num);
orderItem.setMoney(num*orderItem.getPrice()); //单价*数量
orderItem.setPayMoney(num*orderItem.getPrice()); //实付金额
orderItem.setImage(sku.getImage());
orderItem.setWeight(sku.getWeight()*num); //重量=单个重量*数量
//分类ID设置
orderItem.setCategoryId1(spu.getCategory1Id());
orderItem.setCategoryId2(spu.getCategory2Id());
orderItem.setCategoryId3(spu.getCategory3Id());
return orderItem;
}
}
测试:启动注册中心,goods微服务,订单微服务
启动报错:
注意@Service注解不要少了,不然会报错:
启动报错:
排查了一顿之后,发现没有@EnableFeignClients注解
加上即可:
package com.changgou;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import tk.mybatis.spring.annotation.MapperScan;
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = {"com.changgou.goods.feign"})
@MapperScan(basePackages = {"com.changgou.order.dao"})
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class,args);
}
}
注册中心启动成功:
http://localhost:18088/cart/add?num=6&id=1148477873175142400
查看redis缓存中的数据,已经有数据了,成功
购物车列表
因为存的时候是根据用户名往Redis中存储用户的购物车数据的,所以我们这里可以将用户的名字
作为key去Redis中查询对应的数据。
代码实现
控制层
修改changgou-service-order微服务的com.changgou.order.controller.CartController类,添加购物
车列表查询方法,代码如下:
/***
* 查询用户购物车列表
* @return
*/
@GetMapping(value = "/list")
public Result list(){
//用户名
String username="szitheima";
List<OrderItem> orderItems = cartService.list(username);
return new Result(true,StatusCode.OK,"购物车列表查询成功!",orderItems);
}
业务层接口
修改changgou-service-order微服务的com.changgou.order.service.CartService接口,添加购物车
列表方法,代码如下:
/***
* 查询用户的购物车数据
* @param username
* @return
*/
List<OrderItem> list(String username);
业务层接口实现类
修改changgou-service-order微服务的com.changgou.order.service.impl.CartServiceImpl类,添加
购物车列表实现方法,代码如下:
/***
* 查询用户购物车数据
* @param username
* @return
*/
@Override
public List<OrderItem> list(String username) {
//查询所有购物车数据
List<OrderItem> orderItems = redisTemplate.boundHashOps("Cart_"+username).values();
return orderItems;
}
测试:
http://localhost:18090/cart/list
问题处理
我们发现个问题,就是用户将商品加入购物车,无论数量是正负,都会执行添加购物车,如果数量如果<=0,应该移除该商品的。
(1)删除商品购物车
修改changgou-service-order的com.changgou.order.service.impl.CartServiceImpl的add方法,添加如下代码:
(2)数据精度丢失问题
SkuId是Long类型,在页面输出的时候会存在精度丢失问题,我们只需要在OrderItem的SkuId上加上字符串序列化类型就可以了,
代码如下:
Springboot自定义序列化器@JsonSerialize 格式化后端数据,使用 @JsonSerialize(using = 自定义序列化器类.class)
去序列化指定的属性。例如:
标签:service,购物车,商城,import,com,order,changgou 来源: https://blog.csdn.net/ZHOU_VIP/article/details/118498691