分析
- 用户如果没有登录,购物车存放在浏览器端的localStorage处,且以数组的方式进行存储。
- 用户如果登录了,购物车存放在redis中,以Cart对象字符串方式存储。
- 问题:前后端数据不一致,无法使用一个也flow1.vue进行数据展示
解决方案:将后端cart数据进行简化,Cart对象-->Map(data)-->List(values)
结论:前端提供给页面统一数组,页面进行数据展示即可。
接口
GET http://localhost:10010/cart-service/carts
{ "code": 1, "message": "查询成功", "data": { "data": { "2600242": { "skuid": 2600242, "spuid": 2, "price": 84900.0, "count": 17, "checked": true, "midlogo": null, "goods_name": "华为 G9 青春版 白色 移动联通电信4G手机 双卡双待", "spec_info": "{\"id_list\":\"1:1|2:6|6:22\",\"id_txt\":\"{\\\"机身颜色\\\":\\\"白色\\\",\\\"内存\\\":\\\"3GB\\\",\\\"机身存储\\\":\\\"16GB\\\"}\"}" } }, "total": 1443300.0 }, "other": {} }
后端实现
步骤一:修改CartService,添加 queryCartList 方法,从redis查询的购物车信息
步骤二:修改CartController,添加queryCartList 方法,仅返回购物车中的数据
步骤一:修改CartService,添加 queryCartList 方法,
/** * * @param user * @return */ public Cart queryCartList(User user);
步骤二:修改CartServiceImpl,从redis查询的购物车信息
/** * 查询购物车 * @param user * @return */ public Cart queryCartList(User user) { String key = "cart" + user.getId(); // 获取hash操作对象 String cartString = this.stringRedisTemplate.opsForValue().get(key); // 2 获得购物车,如果没有创建一个 return JSON.parseObject(cartString, Cart.class); }
步骤三:修改CartController,添加queryCartList 方法,仅返回购物车中的数据
/** * 查询购物车 * @return */ @GetMapping public BaseResult queryCartList() { //1 获得用户信息 // 1.1 获得token String token = request.getHeader("Authorization"); // 1.2 解析token User loginUser = null; try { loginUser = JwtUtils.getObjectFromToken(token, jwtProperties.getPublicKey(),User.class); } catch (Exception e) { return BaseResult.error("token失效或未登录"); } Cart cart = this.cartService.queryCartList(loginUser); return BaseResult.ok("查询成功", cart.getData().values()); }
前端实现:显示页面
步骤一:创建 ~/pages/flow1.vue 组件,拷贝 ~/static/flow1.html内容
步骤二:导入js和css
head: { title: '首页', link: [ {rel:'stylesheet',href: '/style/cart.css'}, ], script: [ { type: 'text/javascript', src: '/js/cart1.js' }, ] },
步骤三:添加公共组件
<script> import TopNav from '../components/TopNav' import Footer from '../components/Footer' export default { head: { title: '首页', link: [ {rel:'stylesheet',href: '/style/cart.css'}, ], script: [ { type: 'text/javascript', src: '/js/cart1.js' }, ] }, components: { TopNav, Footer, }, } </script>
前端实现:显示购物车信息
步骤一:修改api.js 查询购物车信息
步骤二:页面加载成功后,获得购物车信息(如果登录从后端获取,如果没有登录从浏览器端获得)
步骤三:遍历显示购物车信息,
步骤四:通过计算属性,计算总价格
步骤一:修改apiclient.js 查询购物车信息
1. //查询购物车 2. getCart : () => { 3. return axios.get("/cart-service/carts") 4. },
步骤二:页面加载成功后,获得购物车信息(如果登录从后端获取,如果没有登录从浏览器端获得)
data() { return { cart : [], //购物车对象 } }, async mounted() { //获得token信息,表示登录 this.token = sessionStorage.getItem("token") if(this.token != null) { //登陆:服务器获得数据 let { data } = await this.$request.getCart() this.cart = data.data } else { //未登录:从浏览器本地获得购物车 let cartStr = localStorage.getItem("cart"); if(cartStr != null) { this.cart = JSON.parse(cartStr); } } },
步骤三:遍历显示购物车信息
<tbody> <!-- 购物车列表 start --> <tr v-for="(goods,k) in cart" :key="k"> <td class="col1"> <a href=""><img :src="goods.midlogo" alt="" /></a> <strong><a href="">{{goods.goods_name}}</a></strong> </td> <td class="col2"> <span style="display: block;" v-for="(value,key,index) in JSON.parse(JSON.parse(goods.spec_info).id_txt)" :key="index">{{key}}:{{value}}</span> </td> <td class="col3">¥<span>{{ (goods.price/100).toFixed(2) }}</span></td> <td class="col4"> <a href="javascript:;" class="reduce_num" @click.prevent="minus(goods)"></a> <input type="text" name="amount" v-model="goods.count" @keyup="updateCount(goods,$event)" value="1" class="amount"/> <a href="javascript:;" class="add_num" @click.prevent="plus(goods)"></a> </td> <td class="col5">¥<span>{{ (goods.price / 100 * goods.count).toFixed(2) }}</span></td> <td class="col6"><a href="" @click.prevent="del(k)">删除</a></td> </tr> <!-- 购物车列表 end --> </tbody>
步骤四:通过计算属性,计算总价格
computed : { totalPrice : function(){ //计算总价格 //所有小计的和 let sum = 0 ; this.cart.forEach( g => { sum += (g.price * g.count); }); return (sum/100).toFixed(2); } },