统一表单验证

1、为购物车模块编写符合前端API的类
CartVo.java:

package com.xiaoxin.mall.service.vo;import java.math.BigDecimal;
import java.util.List;public class CartVo {private List<CartProductVo> cartProductVoList;private Boolean selectedAll;private BigDecimal cartTotalPrice;private Integer cartTotalQuantity;}

CartProductVo.java:

package com.xiaoxin.mall.service.vo;import lombok.Data;import java.math.BigDecimal;@Data
public class CartProductVo {private Integer productId;//购买的数量private Integer quantity;private String productName;private String productSubtitle;private String productMainImage;private BigDecimal productPrice;private Integer productStatus;//等于单价乘以购买总数private BigDecimal productTotalPrice;//商品库存private Integer productStock;//是否选中private Boolean productSelected;
}

2、添加商品时需要提供 productId 和 selected 属性,所以为此写一个CartAddForm类:

package com.xiaoxin.mall.form;import lombok.Data;
import lombok.NonNull;import javax.validation.constraints.NotNull;/*** 添加商品时的表单*/
@Data
public class CartAddForm {@NotNullprivate Integer productId;private Boolean selected = true;
}

如果是String类型,可以使用not blank,如果是集合,可以使用not empty,这里是Integer对象,所以使用not null。

3、这次在写controller的时候,我们不写BindingResult

package com.xiaoxin.mall.controller;import com.xiaoxin.mall.form.CartAddForm;
import com.xiaoxin.mall.service.vo.CartVo;
import com.xiaoxin.mall.service.vo.ResponseVo;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;import javax.validation.Valid;@RestController
public class CartController {@PostMapping("/carts")public ResponseVo<CartVo> add(@Valid @RequestBody CartAddForm cartAddForm) {return null;}
}

这时使用postman进行测试时,发现跳转到了/error页面,并且后台抛出MethodArgumentNotValidException异常。

所以这时我们可以捕获这个异常,并进行相应处理。

在RuntimeExceptionHandler.java中编写捕获MethodArgumentNotValidException异常的方法:

@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public ResponseVo notValidExceptionhandle(MethodArgumentNotValidException e) {BindingResult bindingResult = e.getBindingResult();FieldError fieldError = bindingResult.getFieldError();return ResponseVo.error(ResponseEnum.PARAM_ERROR,fieldError.getField() + " " + fieldError.getDefaultMessage());
}

测试发现成功,那UserController中的BindingResult也可以去掉啦!

添加商品到购物车 & 展示购物车的商品

用redis将购物车的信息存到数据库中,我们保存productId, quantity, selected这些信息,所以专门为此写个类。
Cart.java:

package com.xiaoxin.mall.pojo;import lombok.Data;@Data
public class Cart {private Integer productId;private Integer quantity;private boolean productSelected;public Cart() {}public Cart(Integer productId, Integer quantity, boolean productSelected) {this.productId = productId;this.quantity = quantity;this.productSelected = productSelected;}
}

ICartServiceImpl.java:

package com.xiaoxin.mall.service.impl;import com.google.gson.Gson;
import com.xiaoxin.mall.dao.ProductMapper;
import com.xiaoxin.mall.enums.ProductStatusEnum;
import com.xiaoxin.mall.enums.ResponseEnum;
import com.xiaoxin.mall.form.CartAddForm;
import com.xiaoxin.mall.pojo.Cart;
import com.xiaoxin.mall.pojo.Product;
import com.xiaoxin.mall.service.ICartService;
import com.xiaoxin.mall.service.vo.CartProductVo;
import com.xiaoxin.mall.service.vo.CartVo;
import com.xiaoxin.mall.service.vo.ResponseVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Map;
import java.util.List;@Service
public class ICartServiceImpl implements ICartService {private static final String CART_REDIS_KEY_TEMPLATE = "cart_%d";@Autowiredprivate ProductMapper productMapper;@Autowiredprivate StringRedisTemplate redisTemplate;private Gson gson = new Gson();@Overridepublic ResponseVo<CartVo> add(Integer uid, CartAddForm form) {Integer quantity = 1;Product product = productMapper.selectByPrimaryKey(form.getProductId());//商品是否存在if(product == null) {return ResponseVo.error(ResponseEnum.PRODUCT_NOT_EXIST);}//商品是否正常在售if(product.getStatus().equals(ProductStatusEnum.OFF_SALE.getCode()) ||product.getStatus().equals(ProductStatusEnum.DELETE.getCode())) {return ResponseVo.error(ResponseEnum.PRODUCT_OFF_SALE_OR_DELETE);}//商品库存是否充足if(product.getStock() <= 0) {return ResponseVo.error(ResponseEnum.PRODUCT_STOCK_ERROR);}//写入到redis//key: cart_1HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);String value = opsForHash.get(redisKey, String.valueOf(product.getId()));Cart cart = null;if(StringUtils.isEmpty(value)) {//没有该商品,新增cart = new Cart(product.getId(), quantity, form.getSelected());} else {cart = gson.fromJson(value, Cart.class);cart.setQuantity(cart.getQuantity() + quantity);}opsForHash.put(redisKey, String.valueOf(product.getId()), gson.toJson(cart));return list(uid);}@Overridepublic ResponseVo<CartVo> list(Integer uid) {HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);Map<String, String> entries = opsForHash.entries(redisKey);boolean selectedAll = true;Integer cartTotalQuantity = 0;BigDecimal cartTotalPrice = BigDecimal.ZERO;CartVo cartVo = new CartVo();List<CartProductVo> productVoList = new ArrayList<>();for(Map.Entry<String, String> entry : entries.entrySet()) {Integer productId = Integer.valueOf(entry.getKey());Cart cart = gson.fromJson(entry.getValue(), Cart.class);//TODO 不要在for循环里写sql,否则多次查询数据库,时间太多Product product  = productMapper.selectByPrimaryKey(cart.getProductId());if(product != null) {CartProductVo cartProductVo = new CartProductVo(productId,cart.getQuantity(),product.getName(),product.getSubtitle(),product.getMainImage(),product.getPrice(),product.getStatus(),product.getPrice().multiply(BigDecimal.valueOf(cart.getQuantity())),product.getStock(),cart.isProductSelected());productVoList.add(cartProductVo);if(!cart.isProductSelected()) selectedAll = false;//计算总价,只计算选中的if(cart.isProductSelected())cartTotalPrice = cartTotalPrice.add(product.getPrice().multiply(BigDecimal.valueOf(cart.getQuantity())));}cartTotalQuantity += cart.getQuantity();}cartVo.setCartProductVoList(productVoList);cartVo.setCartTotalQuantity(cartTotalQuantity);cartVo.setSelectedAll(selectedAll);cartVo.setCartTotalPrice(cartTotalPrice);return ResponseVo.success(cartVo);}
}

更新、删除购物车的商品

更新时,我们需要提供quantity和selected属性,为此专门写个updateFrom
CartUpdateForm.java:

package com.xiaoxin.mall.form;import lombok.Data;@Data
public class CartUpdateForm {private Integer quantity;private Boolean selected;
}

在ICartServiceImpl.java中添加方法:

@Override
public ResponseVo<CartVo> update(Integer uid, Integer productId, CartUpdateForm form) {HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);String value = opsForHash.get(redisKey, String.valueOf(productId));Cart cart = null;if(StringUtils.isEmpty(value)) {//购物车中无此商品,报错return ResponseVo.error(ResponseEnum.PRODUCT_NOT_IN_CART);}//已经有了,修改内容cart = gson.fromJson(value, Cart.class);if(form.getQuantity() != null&& form.getQuantity() >= 0) {cart.setQuantity(form.getQuantity());}if(form.getSelected() != null) {cart.setProductSelected(form.getSelected());}opsForHash.put(redisKey, String.valueOf(productId), gson.toJson(cart));return list(uid);
}@Override
public ResponseVo<CartVo> delete(Integer uid, Integer productId) {HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);String value = opsForHash.get(redisKey, String.valueOf(productId));Cart cart = null;if(StringUtils.isEmpty(value)) {//购物车中无此商品,报错return ResponseVo.error(ResponseEnum.PRODUCT_NOT_IN_CART);}//已经有了,删除opsForHash.delete(redisKey, String.valueOf(productId));return list(uid);
}

全选、全不选和获取商品总数

在ICartServiceImpl.java中添加方法:

@Override
public ResponseVo<CartVo> selectAll(Integer uid) {HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);for(Cart cart : listForCart(uid)) {if(!cart.isProductSelected()) cart.setProductSelected(true);opsForHash.put(redisKey, String.valueOf(cart.getProductId()), gson.toJson(cart));}return list(uid);
}@Override
public ResponseVo<CartVo> unSelectAll(Integer uid) {HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);for(Cart cart : listForCart(uid)) {if(cart.isProductSelected()) cart.setProductSelected(false);opsForHash.put(redisKey, String.valueOf(cart.getProductId()), gson.toJson(cart));}return list(uid);
}@Override
public ResponseVo<Integer> sum(Integer uid) {Integer quantity = 0;for(Cart cart : listForCart(uid)) {quantity += cart.getQuantity();}return ResponseVo.success(quantity);
}private List<Cart> listForCart(Integer uid) {HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);Map<String, String> entries = opsForHash.entries(redisKey);List<Cart> cartList = new ArrayList<>();for(Map.Entry<String, String> entry : entries.entrySet()) {cartList.add(gson.fromJson(entry.getValue(), Cart.class));}return cartList;
}

编写controller

package com.xiaoxin.mall.controller;import com.xiaoxin.mall.consts.MallConst;
import com.xiaoxin.mall.form.CartAddForm;
import com.xiaoxin.mall.form.CartUpdateForm;
import com.xiaoxin.mall.pojo.User;
import com.xiaoxin.mall.service.ICartService;
import com.xiaoxin.mall.service.vo.CartVo;
import com.xiaoxin.mall.service.vo.ResponseVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpSession;
import javax.validation.Valid;@RestController
public class CartController {@Autowiredprivate ICartService cartService;@GetMapping("/carts")public ResponseVo<CartVo> list(HttpSession session) {User user = (User) session.getAttribute(MallConst.CURRENT_USER);return cartService.list(user.getId());}@PostMapping("/carts")public ResponseVo<CartVo> add(@Valid @RequestBody CartAddForm cartAddForm,HttpSession session) {User user = (User) session.getAttribute(MallConst.CURRENT_USER);return cartService.add(user.getId(), cartAddForm);}@PutMapping("/carts/{productId}")public ResponseVo<CartVo> update(@Valid @RequestBody CartUpdateForm cartUpdateForm,@PathVariable Integer productId,HttpSession session) {User user = (User) session.getAttribute(MallConst.CURRENT_USER);return  cartService.update(user.getId(), productId, cartUpdateForm);}@DeleteMapping("/carts/{productId}")public ResponseVo<CartVo> delete(HttpSession session,@PathVariable Integer productId) {User user = (User) session.getAttribute(MallConst.CURRENT_USER);return cartService.delete(user.getId(), productId);}@PutMapping("/carts/selectAll")public ResponseVo<CartVo> selectAll(HttpSession session) {User user = (User) session.getAttribute(MallConst.CURRENT_USER);return cartService.selectAll(user.getId());}@PutMapping("/carts/unSelectAll")public ResponseVo<CartVo> unSelectAll(HttpSession session) {User user = (User) session.getAttribute(MallConst.CURRENT_USER);return cartService.unSelectAll(user.getId());}@GetMapping("/carts/products/sum")public ResponseVo<Integer> sum(HttpSession session) {User user = (User) session.getAttribute(MallConst.CURRENT_USER);return cartService.sum(user.getId());}
}

支付项目:9、购物车模块相关推荐

  1. Vue3电商项目实战-购物车模块2【04-头部购物车-商品列表-本地、05-头部购物车-删除操作-本地、06-购物车页面-基础布局】

    文章目录 04-头部购物车-商品列表-本地 05-头部购物车-删除操作-本地 06-购物车页面-基础布局 04-头部购物车-商品列表-本地 目的:根据本地存储的商品获取最新的库存价格和有效状态. 大致 ...

  2. web day25 web day24 小项目练习图书商城, 购物车模块,订单模块,支付(易宝支付)

    购物车模块 购物车存储: 保存在session中(本次使用的) 保存在cookie中 保存在数据库中 购物车相关类 购物车结构 CartItem:包含图书和数量,小计 Cart:包含一个Map< ...

  3. 企业级项目分享:购物车模块(一)2021-06-08

    购物车模块 目录 购物车模块 前言 1.搭建购物车服务 1.1步骤一:创建changgou4-service-cart 项目 1.2步骤二:修改pom.xml文件,添加坐标 1.3步骤三:创建yml文 ...

  4. mmall 学习笔记--分类管理模块,商品管理模块,购物车模块,收货地址模块,支付模块,订单管理模块,云服务器线上部署,自动发布,

    ()数据库配置 常见语句 Create table 'my_table'( int id not null auto_increment ) () 建表的时候出现text,bigInt,decimal ...

  5. 企业级项目分享:购物车模块( 二) 21-06-09

    购物车模块( 二) 目录 购物车模块( 二) 前言 查看购物车 1.分析 2.接口 3.后端实现 3.1步骤一:修改CartService,添加 queryCartList 方法,从redis查询的购 ...

  6. 购物车模块设计及实现(SSH架构)

    一.系统需求分析 1.系统介绍 2.系统功能性需求 ①用户浏览应用,即登录首页,在首页中主页列出最新出版的4本书,和几本主编推荐的书. ②在首页中提供购物车的链接.分类浏览的链接.结账的链接.查看订单 ...

  7. javaaop模式供其他项目调用_Java 分布式架构的 开源的支付项目 调试实战

    开源分布式架构的Java 支付项目调试实战 支付项目也有开源的?当然也有,今天就来撸一个gitee上开源的,调试一下.该项目包含微信支付.支付宝支付.银联支付,对于大多数公司来说够用了.而且该项目st ...

  8. python购物车模块

    # 代码实现: 购物车# 功能要求: 1.用户输入总资产,例如:2000.# 2.显示商品列表,让用户根据序号选择商品,加入购物车购买# 3.如果商品总额大于总资产,提示账户余额不足,否则,购买成功# ...

  9. 购物车模块如何进行测试?

    目录 一. 验证购物车界面设计 二. 购物车功能测试 三. 购物车非功能 测试工作中遇到有商品购买类的项目时,对于购物车模块的测试是无法绕开的.鉴于购物车模块在项目业务中的复杂性,想要对购物车功能模块 ...

最新文章

  1. 元宇宙深度报告,共177页!
  2. ie9怎么开兼容模式
  3. DataFrame挑选其中两列,带列名
  4. python 数组 运算_python数据分析(二) python numpy--数组和矢量运算--数组对象
  5. 深入浅出mysql gtid_深入理解MySQL GTID
  6. Java性能调优笔记
  7. 15. Scala并发编程模型Akka
  8. Samba配置文件常用参数详解-OK
  9. 如何用adb链接手机,并异常情况下的处理(转)
  10. 【语音处理】基于matlab GUI录音信号时域频域分析(带面板)【含Matlab源码 064期】
  11. 罗技G29方向盘linux下的开发
  12. ubuntu设置成中文详细贴图教程
  13. 马拉车算法(不懂问我)
  14. 菜鸟之如何让项目跑起来(适合小白看,不是小白的不要进来看了,浪费时间)
  15. 2015.3.30第一次博客测试
  16. 数据结构--一元多项式
  17. Vitamio 依赖导入 步骤
  18. 复变函数可视化以及代数基本定理
  19. C++ cout输出中文信息乱码问题解决
  20. 黑苹果 【 I7 8700K z370 1060 和 I7 7700K z270 集显 的安装记录】

热门文章

  1. Mac彻底删除mysql,重新安装mysql,修改mysql用户权限
  2. 百度依存句法分析标识说明
  3. atoi()函数的实现
  4. m8 windows android,M8刷M9 Android ROM完全教程
  5. 8086/88系统中CLK引脚需要的8284时钟发生器
  6. 表白爱心HTML制作
  7. 掌握4C原则,设计高效的系统架构
  8. CentOS之vim操作
  9. hdlc协议解码的四种方法
  10. 以自己的电脑作为服务器,搭建网站,外网可访问