当前位置: 首页 > news >正文

做设计常用网站plc培训机构哪家最好

做设计常用网站,plc培训机构哪家最好,单页面网站入侵,郑州网站外包公司最近再写支付模块就到处借鉴 旨在回顾一下。 1.确认订单功能 使用场景是:用户在选择好购物车后,或者是直接选择商品后(选择商品封装为购物车) 这样做是根据尚硅谷来学习的 目前需要这些属性,原因是在确认订单页面后…

最近再写支付模块就到处借鉴 旨在回顾一下。

1.确认订单功能

使用场景是:用户在选择好购物车后,或者是直接选择商品后(选择商品封装为购物车)

这样做是根据尚硅谷来学习的 目前需要这些属性,原因是在确认订单页面后 展现一个最优惠的状态 

1.1实体类

    /*** 用户id*/@ApiModelProperty("用户id")private Integer userId;/*** 购物车列表*/@ApiModelProperty("购物车中已选中商品")private List<CartInfo> cartItemsList;@ApiModelProperty("最优惠的优惠券id")private Integer userCouponsId;/*** 总金额*/@ApiModelProperty("总金额")private Double totalAmount;/*** 优惠金额*/@ApiModelProperty("优惠金额")private Double discount;/*** 实付金额*/@ApiModelProperty("实付金额")private Double actuallyPay;

1.2确认订单实现类

期间做了一些修改 之前是设置的有购物车状态 这些步骤都是在后端处理 

后来又采用了前端传递购物车属性 美其名曰叫 减少io次数 缓解数据库压力

通过传入的userId 查找 订单列表 购物车列表

期间有个redis操作 是根据时间 来生成 后续在生成订单时会用到

 public OrderConfirmVo confirmOrder(CartConfirmDto cartConfirmDto) {//获取用户id参数 以方便后续使用//获取用户地址列表Integer userId = cartConfirmDto.getUserId();List<Addresses> addressesList = addressesDao.getByUserId(userId);//获取购物车中已经选中的商品List<CartInfo> cartItemsList = cartConfirmDto.getCartItemsList();
//        List<CartItems> cartItemsList = cartItemsDao.querySelectedCartItems(userId);if (cartItemsList.isEmpty()){throw new PorkException("您购物车中未选中商品",500);}for (CartInfo cartInfo : cartItemsList) {Integer productId = cartInfo.getProductId();Products products = productsDao.queryById(productId);cartInfo.setMainPhoto(products.getMainPhoto());cartInfo.setName(products.getName());Integer flavorId = cartInfo.getFlavorId();String flavorDescription = flavorsService.queryNameById(flavorId);cartInfo.setFlavorDescription(flavorDescription);}//生成订单唯一标示String orderNo = System.currentTimeMillis()+"";redisTemplate.opsForValue().set(RedisConst.ORDER_REPEAT+orderNo,orderNo,24, TimeUnit.HOURS);//1.获取最优惠优惠券//2.先获取订单价格//3.找到实付金额
//        Double totalPrice = cartItemsDao.getActuallyPay(userId);
//        UserCoupons userCoupon = userCouponsDao.queryOptimalUserCoupon(totalPrice, userId);
//        Double discount = userCoupon.getCoupons().getDiscount();
//        Double actuallyPay = totalPrice - discount;Double totalPrice = cartConfirmDto.getTotalAmount();Integer userCouponId = cartConfirmDto.getUserCouponsId();Double discount = cartConfirmDto.getDiscount();Double actuallyPay = cartConfirmDto.getActuallyPay();UserCoupons userCoupon = userCouponsDao.queryById(userCouponId);//查询可用优惠券List<UserCoupons> userCoupons = userCouponsDao.queryAvailableUserCoupons(totalPrice, userId);//进行封装OrderConfirmVo orderConfirmVo = new OrderConfirmVo(userId,totalPrice,userCoupon,discount,actuallyPay,orderNo,userCoupons,addressesList,cartItemsList);return orderConfirmVo;}

1.3返回类

    */@ApiModelProperty("用户id")private Integer userId;/*** 总金额*/@ApiModelProperty("总金额")private Double totalAmount;@ApiModelProperty("最优惠的优惠券")private UserCoupons userCoupons;/*** 优惠金额*/@ApiModelProperty("优惠金额")private Double discount;/*** 实付金额*/@ApiModelProperty("实付金额")private Double actuallyPay;/*** 订单号*/@ApiModelProperty("订单号")private String orderNo;/*** 用户所有优惠券*/@ApiModelProperty("用户优惠券")private List<UserCoupons> userCouponsList;/*** 用户地址*/@ApiModelProperty("用户地址列表")private List<Addresses> addressesList;/*** 购物车列表*/@ApiModelProperty("购物车列表")private List<CartInfo> cartItemsList;

2.生成订单

2.1请求实体类

生成订单后里面的属性

 @ApiModelProperty(value = "使用预生产订单号防重")private String orderNo;@ApiModelProperty(value = "用户id")private Integer userId;@ApiModelProperty(value = "下单时所使用的地址信息")private Integer addressesId;@ApiModelProperty(value = "下单选中的优惠券id")private Integer userCouponId;@ApiModelProperty(value = "订单备注")private String comment;@ApiModelProperty(value = "所选中商品")private List<CartInfo> cartItemsList;@ApiModelProperty(value = "最后订单总价")private Double totalPrice;@ApiModelProperty(value = "优惠金额")private Double discount;@ApiModelProperty("订单实付金额")private Double ActuallyPay;

2.2生成订单方法实体类

使用lua脚本来保证原子性 

如果redis中有相同orderNo 则说明正常提交订单 然后把redis删除

期间也有锁单 

2.2.1检查锁

    @Overridepublic Boolean checkAndLock(List<ProductStockVo> productStockVoList, String orderNo) {//1.判断productStockVoList是否为空if (CollectionUtils.isEmpty(productStockVoList)){throw new PorkException(ResultCodeEnum.DATA_ERROR);}//2.遍历productStockVoList得到每个商品,验证库存并锁定库存,具备原子性productStockVoList.stream().forEach(productStockVo -> {this.checkLock(productStockVo);});//3.只要有一个商品锁定失败,所有锁定成功的商品都解锁 用于检查流中是否至少有一个元素满足指定的条件boolean flag = productStockVoList.stream().anyMatch(productStockVo -> !productStockVo.getIsLock());if (flag){//所有锁定成功的商品都解锁productStockVoList.stream().filter(ProductStockVo::getIsLock).forEach(productStockVo -> {flavorsDao.unlockStock(productStockVo.getFlavorId(),productStockVo.getSkuNum());});return false;}
//4 如果所有商品都锁定成功了,redis缓存相关数据,为了方便后面解锁和减库存redisTemplate.opsForValue().set(RedisConst.SROCK_INFO+orderNo,productStockVoList,33, TimeUnit.MINUTES);return true;}

2.2.2获得公平锁

    private void checkLock(ProductStockVo productStockVo) {//获取锁 公平锁:谁等待时间长给谁发锁RLock rLock = this.redissonClient.getFairLock(RedisConst.SKUKEY_PREFIX+productStockVo.getFlavorId());rLock.lock();try {//验证库存Flavors flavors = flavorsDao.checkStock(productStockVo.getFlavorId(),productStockVo.getSkuNum());//判断没有满足条件商品,设置isLock值为false,返回if (flavors == null){productStockVo.setIsLock(false);return;}//又满足条件商品,锁定库存 update rows 影响行数Integer rows =  flavorsDao.lockStock(productStockVo.getFlavorId(),productStockVo.getSkuNum());if (rows == 1) {productStockVo.setIsLock(true);}}finally {//解锁rLock.unlock();}}

2.2.3提交订单 

  public OrderGenerateInfo submitOrder(OrderSubmitVo orderSubmitVo) {//第一步拿出userId确定给那个用户设置订单Integer userId = orderSubmitVo.getUserId();//第二步 订单不能重复提交,重复提交验证//通过redis + lua 脚本实现  //lua脚本保证原子性//1.获取传递过来的orderNoString orderNo = orderSubmitVo.getOrderNo();if (orderNo.isEmpty()){throw new PorkException(ResultCodeEnum.ILLEGAL_REQUEST);}//2.拿着orderNo到redis中查询   此lua脚本解析 如果redis中存在的值 = 这一个值 那么 这个值 , 不过没有存在 就返回0 然后结束String script = "if(redis.call('get', KEYS[1]) == ARGV[1]) then return redis.call('del', KEYS[1]) else return 0 end";//3.如果redis有相同orderNo,表示正常提交订单 ,把redis的orderNo删除Boolean flag = (Boolean) redisTemplate.execute(new DefaultRedisScript(script, Boolean.class),Arrays.asList(RedisConst.ORDER_REPEAT + orderNo),orderNo);//4.如果redis没有相同orderNo,表示重复提交了,不能再往后进行if (!flag){throw new PorkException(ResultCodeEnum.REPEAT_SUBMIT);}//第三步 验证库存 并且 锁定库存(订单在30分钟内锁定库存 没有真正减库存)//获取当前购物车商品List<CartInfo> cartItemsList = orderSubmitVo.getCartItemsList();//新建一个锁单Vo 然后把商品信息封装到 Vo里面if (!CollectionUtils.isEmpty(cartItemsList)){List<ProductStockVo> productStockVoList =cartItemsList.stream().map(item ->{ProductStockVo productStockVo = new ProductStockVo();productStockVo.setFlavorId(item.getFlavorId());productStockVo.setSkuNum(item.getQuantity());return productStockVo;}).collect(Collectors.toList());//验证库存,保证具备原子性 解决超卖问题Boolean isLockSuccess = flavorsService.checkAndLock(productStockVoList, orderNo);if (!isLockSuccess){throw new PorkException(ResultCodeEnum.ORDER_STOCK_FALL);}}//第四步 下单过程OrderGenerateInfo orderGenerateInfo = this.saveOrder(orderSubmitVo);//对已生成订单的购物车进行删除List<Integer> cartIdList = cartItemsList.stream().map(CartInfo::getId).collect(Collectors.toList());cartItemsDao.deleteBatchIds(cartIdList);//1.向两张表中添加数据 order_info order_item//返回订单id
return orderGenerateInfo;}

2.2.4保存订单

  @Transactional(rollbackFor = {Exception.class})public OrderGenerateInfo saveOrder(OrderSubmitVo orderSubmitVo) {Integer userId = orderSubmitVo.getUserId();List<CartInfo> cartItemsList = orderSubmitVo.getCartItemsList();if (CollectionUtils.isEmpty(cartItemsList)){throw new PorkException(ResultCodeEnum.DATA_ERROR);}List<String> goodInfoList = new ArrayList<String>();String goodInfo = "";for (CartInfo cartInfo : cartItemsList) {Integer flavorId = cartInfo.getFlavorId();Integer productId = cartInfo.getProductId();Integer quantity = cartInfo.getQuantity();String productName = productsService.queryNameById(productId);String flavorName = flavorsService.queryNameById(flavorId);goodInfo = productName+":"+flavorName+"*"+quantity;goodInfoList.add(goodInfo);}//查数据 顾客收货地址Integer addressesId = orderSubmitVo.getAddressesId();Addresses addresses = addressesDao.queryById(addressesId);if (addresses == null){throw new PorkException(ResultCodeEnum.DATA_ERROR);}String recipientName = addresses.getRecipientName();String recipientPhone = addresses.getRecipientPhone();String province = addresses.getProvince();String city = addresses.getCity();String district = addresses.getDistrict();String detail = addresses.getDetail();String orderAddress = province + city + district + detail;//计算金额Double totalPrice = orderSubmitVo.getTotalPrice();Double discount = orderSubmitVo.getDiscount();Double actuallyPay = orderSubmitVo.getActuallyPay();//原金额
//        Double totalAmount = cartItemsDao.getActuallyPay(userId);
//        Double discount = 0.00;
//        Double actuallyPay = totalAmount;
//        Integer couponId = 0;Integer userCouponId = orderSubmitVo.getUserCouponId();
//        UserCoupons userCoupons = userCouponsDao.queryById(userCouponId);//把优惠券设置为已使用userCouponsDao.update(userCouponId);
//        if (userCoupons!=null){
//            couponId = userCoupons.getCouponId();
//        }//优惠券金额
//        if (userCouponId != null){
//            UserCoupons userCoupons = userCouponsDao.queryById(userCouponId);
//          couponId = userCoupons.getCouponId();
//             discount = couponsDao.queryById(couponId).getDiscount();
//        }
//        //实付金额
//        actuallyPay = totalPrice - discount;//封装订单项List<OrderItems> orderItemsList = new ArrayList<>();for (CartInfo cartItems : cartItemsList) {OrderItems orderItem = new OrderItems();orderItem.setProductId(cartItems.getProductId());orderItem.setFlavorId(cartItems.getFlavorId());orderItem.setQuantity(cartItems.getQuantity());orderItem.setPrice(cartItems.getPrice());orderItem.setStatus(0);orderItemsList.add(orderItem);}Orders order = new Orders();order.setUserId(userId);order.setTotalAmount(totalPrice);order.setStatus(0);order.setConsignee(recipientName);order.setPhone(recipientPhone);order.setAddress(orderAddress);order.setDiscount(discount);order.setOrderNo(orderSubmitVo.getOrderNo());order.setComment(orderSubmitVo.getComment());order.setActuallyPay(actuallyPay);order.setCouponId(userCouponId);order.setGoodInfo(String.join(", ", goodInfoList));//添加数据到订单基本表ordersDao.insert(order);//添加订单里面的订单项orderItemsList.forEach(orderItems -> {orderItems.setOrderId(order.getId());orderItemsDao.insert(orderItems);});//如果当前订单使用优惠券更新优惠券状态if (order.getCouponId()!= null){userCouponsDao.update(userCouponId);}//在redis中记录用户购物数量//hash类型   key(userId)  -  field(skuId)-value(skuNum)String orderSkuKey = RedisConst.ORDER_SKU_MAP + orderSubmitVo.getUserId();BoundHashOperations<String, String, Integer> hashOperations = redisTemplate.boundHashOps(orderSkuKey);cartItemsList.forEach(cartInfo -> {if(hashOperations.hasKey(cartInfo.getFlavorId().toString())) {Integer orderSkuNum = hashOperations.get(cartInfo.getFlavorId().toString()) + cartInfo.getQuantity();hashOperations.put(cartInfo.getFlavorId().toString(), orderSkuNum);}});redisTemplate.expire(orderSkuKey, DateUtil.getCurrentExpireTimes(), TimeUnit.SECONDS);//设置订单过期时间 30分钟后取消订单long orderTimeOut = 1;String keyRedis = String.valueOf(StrUtil.format("{}:{}",RedisConst.REDIS_ORDER_KEY_IS_PAY_0,order.getId()));//设置过期时间redisTemplate.opsForValue().set(keyRedis,order.getOrderNo(),orderTimeOut,TimeUnit.MINUTES);//订单idOrderGenerateInfo orderGenerateInfo  = new OrderGenerateInfo(order.getId(),orderTimeOut);return orderGenerateInfo;}

3.讲讲Redis过期键监听器

redis过期键监听器 实现对键的监听 

如果该键过期了,则进行注册过的操作

3.1配置监听器

像只注册了订单服务的话 你就只能使用订单服务 

若使用其他服务的话 也要进行集成

@Configuration
@AllArgsConstructor
public class RedisListenerConfig {private final RedisTemplate<String, String> redisTemplate;private final RedissonConfig redisConfigProperties;private final OrdersService ordersService;//	private final OrderItemsService orderItemsService;@BeanRedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {RedisMessageListenerContainer container = new RedisMessageListenerContainer();container.setConnectionFactory(connectionFactory);container.addMessageListener(new RedisKeyExpirationListener(redisTemplate, redisConfigProperties, ordersService), new PatternTopic(StrUtil.format("__keyevent@{}__:expired", redisConfigProperties.getDatabase())));return container;}
}

3.2配置redis 开启监听器

3.3写监听器

@Component
public class RedisKeyExpirationListener implements MessageListener {private RedisTemplate<String, String> redisTemplate;private RedissonConfig redisConfigProperties;private OrdersService ordersService;//    private OrderItemsService orderItemsService;public RedisKeyExpirationListener(RedisTemplate<String, String> redisTemplate,RedissonConfig redisConfigProperties,OrdersService orderInfoService){this.redisTemplate = redisTemplate;this.redisConfigProperties = redisConfigProperties;this.ordersService = orderInfoService;
//        this.orderItemsService = orderItemsService;}@Overridepublic void onMessage(Message message, byte[] bytes) {RedisSerializer<?> serializer = redisTemplate.getValueSerializer();String channel = String.valueOf(serializer.deserialize(message.getChannel()));String body = String.valueOf(serializer.deserialize(message.getBody()));//key过期监听if(StrUtil.format("__keyevent@{}__:expired", redisConfigProperties.getDatabase()).equals(channel)){//订单自动取消if(body.contains(RedisConst.REDIS_ORDER_KEY_IS_PAY_0)) {body = body.replace(RedisConst.REDIS_ORDER_KEY_IS_PAY_0, "");String[] str = body.split(":");String wxOrderId = str[1];System.out.println(wxOrderId);Orders orders = ordersService.queryById(Integer.valueOf(wxOrderId));if(orders != null && orders.getStatus() == 0){//只有待支付的订单能取消//TODO 订单取消 库存增加 减优惠券
//                    orderItemsService.toCancel(orders.getId());ordersService.cancelOrder(orders.getId());System.out.println("订单id:"+orders.getId()+"已删除");}}


文章转载自:
http://dinncoarmer.ydfr.cn
http://dinncoinsonify.ydfr.cn
http://dinncoposterization.ydfr.cn
http://dinncoskirting.ydfr.cn
http://dinncokenbei.ydfr.cn
http://dinncolycine.ydfr.cn
http://dinncomaieutic.ydfr.cn
http://dinncozyzzyva.ydfr.cn
http://dinncobiotherapy.ydfr.cn
http://dinncomalentendu.ydfr.cn
http://dinncocasquet.ydfr.cn
http://dinncohipster.ydfr.cn
http://dinncoishtar.ydfr.cn
http://dinncocontumacy.ydfr.cn
http://dinncotranspadane.ydfr.cn
http://dinncoappeasable.ydfr.cn
http://dinncospissated.ydfr.cn
http://dinncokwangchowan.ydfr.cn
http://dinncoanilide.ydfr.cn
http://dinncooverladen.ydfr.cn
http://dinncomisaim.ydfr.cn
http://dinncoracerunner.ydfr.cn
http://dinncounprepared.ydfr.cn
http://dinncomythopoetry.ydfr.cn
http://dinncovilayet.ydfr.cn
http://dinnconidget.ydfr.cn
http://dinncosavagery.ydfr.cn
http://dinncoangelino.ydfr.cn
http://dinncoanopisthograph.ydfr.cn
http://dinncohomeostatically.ydfr.cn
http://dinncotoxophily.ydfr.cn
http://dinncohemoflagellate.ydfr.cn
http://dinncoelectrotherapist.ydfr.cn
http://dinncolinac.ydfr.cn
http://dinncomandolin.ydfr.cn
http://dinncowhaleback.ydfr.cn
http://dinncobreakpoint.ydfr.cn
http://dinncosphygmograph.ydfr.cn
http://dinncoattentat.ydfr.cn
http://dinncogizmo.ydfr.cn
http://dinncoconstringe.ydfr.cn
http://dinncoreradiative.ydfr.cn
http://dinncocamisade.ydfr.cn
http://dinncochondrite.ydfr.cn
http://dinncotallahassee.ydfr.cn
http://dinncoexercitorial.ydfr.cn
http://dinncomeroblast.ydfr.cn
http://dinncoslavdom.ydfr.cn
http://dinncoagamogenetic.ydfr.cn
http://dinncoincommunicability.ydfr.cn
http://dinncowoolskin.ydfr.cn
http://dinncoenchiridion.ydfr.cn
http://dinncosolubilization.ydfr.cn
http://dinncomacrostructure.ydfr.cn
http://dinncobetweenwhiles.ydfr.cn
http://dinncocrockpot.ydfr.cn
http://dinncosatsang.ydfr.cn
http://dinncorecension.ydfr.cn
http://dinncogenerativist.ydfr.cn
http://dinncooverwhelmingly.ydfr.cn
http://dinncoimponent.ydfr.cn
http://dinncoreticuloendothelial.ydfr.cn
http://dinncoframeshift.ydfr.cn
http://dinnconancy.ydfr.cn
http://dinncozygodactyl.ydfr.cn
http://dinncoproducing.ydfr.cn
http://dinncodiplomaed.ydfr.cn
http://dinncowhomsoever.ydfr.cn
http://dinncobecrawl.ydfr.cn
http://dinncoelytron.ydfr.cn
http://dinncoteetotum.ydfr.cn
http://dinncosnaggy.ydfr.cn
http://dinncoafterbrain.ydfr.cn
http://dinncobulkiness.ydfr.cn
http://dinncowink.ydfr.cn
http://dinncobigwig.ydfr.cn
http://dinncofirepan.ydfr.cn
http://dinncotricker.ydfr.cn
http://dinncocycloplegia.ydfr.cn
http://dinncovitaceous.ydfr.cn
http://dinncotatt.ydfr.cn
http://dinncovinegrowing.ydfr.cn
http://dinncooptimize.ydfr.cn
http://dinncobootjack.ydfr.cn
http://dinncoirruption.ydfr.cn
http://dinncoinfrasound.ydfr.cn
http://dinncoaerification.ydfr.cn
http://dinncoyawey.ydfr.cn
http://dinncoscrag.ydfr.cn
http://dinncoepisiotomy.ydfr.cn
http://dinncovitrifacture.ydfr.cn
http://dinncohorary.ydfr.cn
http://dinncoemploy.ydfr.cn
http://dinncosanguinary.ydfr.cn
http://dinncobovine.ydfr.cn
http://dinncoaddresser.ydfr.cn
http://dinncojackaroo.ydfr.cn
http://dinncoselenographist.ydfr.cn
http://dinncodemonise.ydfr.cn
http://dinncoundissolute.ydfr.cn
http://www.dinnco.com/news/125550.html

相关文章:

  • 组建一个网站婚恋网站排名前三
  • 网站建设验收报告宁波seo优化流程
  • 网页界面设计的原则有哪些seo网站内部优化
  • 网站建设与开发试题百度云网盘搜索引擎入口
  • 会做网站的公司拓客引流推广
  • 免费行情软件网站大全下载找网络公司做推广费用
  • 吉安网站建设收费枫林seo工具
  • 网站建设 cms旅游最新资讯 新闻
  • 河南智能网站建设哪家好淘宝搜索关键词排名查询工具
  • 如何进行企业营销型网站建设规划51link友链
  • 大型菜谱网站建设如何让自己网站排名提高
  • 网站相册优化最近一周新闻大事摘抄2022年
  • 网站建设所需的硬件设备廊坊seo推广
  • 自己电脑做网站需要备案吗2深圳网站建设 手机网站建设
  • 专做轮胎的网站关键词词库
  • 怎样建设个自己的网站营销管理培训课程培训班
  • 做源码演示的网站深圳百度推广关键词推广
  • 网站备案怎么注销aso优化技巧大aso技巧
  • 所谓做网站就这么几步华为手机网络营销策划方案
  • 济南网站建设设计公司东莞seo排名外包
  • 桂林做网站公司有哪些新乡网站优化公司
  • 找人做个网站大概多少钱网络营销网课
  • 榆林做网站需要注意的几点流量平台排名
  • 快递网站怎么制作怎样做百度推广网页
  • 一下成都网站建设公司刷seo快速排名
  • 山西网站建设多少钱seo站长工具 论坛
  • 网上商城网站设计互联网营销方法有哪些
  • 网站开发的热门博客南昌seo推广公司
  • 网站的回到顶部怎么做公司网页设计
  • 网站建设的公司业务百度收录批量提交入口