商城项目整合支付宝支付功能细化修改-----商城项目

#“学C++,赢好礼”——侯捷C++系列精品课学习笔记征文活动#
package com.alatus.mall.order.template;

import com.alatus.mall.order.vo.PayVo;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@Data
@ConfigurationProperties(prefix = "alatusmall.alipay")
public class AlipayTemplate {
    public String app_id;

    public String merchant_private_key;

    public String alipay_public_key;

    public String notify_url;

    public String return_url;

    public String sign_type;

    public String charset;

    public String gatewayUrl;

    public String log_path;

    public String pay(PayVo payVo) throws AlipayApiException {
        //获得初始化的AlipayClient
        AlipayClient alipayClient = new DefaultAlipayClient(gatewayUrl,app_id,merchant_private_key, "json",charset,alipay_public_key,sign_type);

        //设置请求参数
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
        alipayRequest.setReturnUrl(return_url);
        alipayRequest.setNotifyUrl(notify_url);

        //商户订单号,商户网站订单系统中唯一订单号,必填
        String out_trade_no = payVo.getOut_trade_no();
        //付款金额,必填
        String total_amount = payVo.getTotal_amount();
        //订单名称,必填
        String subject = payVo.getSubject();
        //商品描述,可空
        String body = payVo.getBody();

        alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
                + "\"total_amount\":\""+ total_amount +"\","
                + "\"subject\":\""+ subject +"\","
                + "\"body\":\""+ body +"\","
                + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");

        //请求
        return  alipayClient.pageExecute(alipayRequest).getBody();
    }

}
package com.alatus.mall.order.template;

import com.alatus.mall.order.vo.PayVo;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@Data
@ConfigurationProperties(prefix = "alatusmall.alipay")
public class AlipayTemplate {
    public String app_id;

    public String merchant_private_key;

    public String alipay_public_key;

    public String notify_url;

    public String return_url;

    public String sign_type;

    public String charset;

    public String gatewayUrl;

    public String log_path;

    public String pay(PayVo payVo) throws AlipayApiException {
        //获得初始化的AlipayClient
        AlipayClient alipayClient = new DefaultAlipayClient(gatewayUrl,app_id,merchant_private_key, "json",charset,alipay_public_key,sign_type);

        //设置请求参数
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
        alipayRequest.setReturnUrl(return_url);
        alipayRequest.setNotifyUrl(notify_url);

        //商户订单号,商户网站订单系统中唯一订单号,必填
        String out_trade_no = payVo.getOut_trade_no();
        //付款金额,必填
        String total_amount = payVo.getTotal_amount();
        //订单名称,必填
        String subject = payVo.getSubject();
        //商品描述,可空
        String body = payVo.getBody();

        alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
                + "\"total_amount\":\""+ total_amount +"\","
                + "\"subject\":\""+ subject +"\","
                + "\"body\":\""+ body +"\","
                + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");

        //请求
        return  alipayClient.pageExecute(alipayRequest).getBody();
    }

}
package com.alatus.mall.order.web;

import com.alatus.mall.order.service.OrderService;
import com.alatus.mall.order.template.AlipayTemplate;
import com.alipay.api.AlipayApiException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class PayWebController {
    @Autowired
    private OrderService orderService;
    @Autowired
    private AlipayTemplate alipayTemplate;
    @GetMapping(value = "/payOrder",produces = "text/html")
    @ResponseBody
    public String payOrder(@RequestParam("orderSn")String orderSn) throws AlipayApiException {
        return alipayTemplate.pay(orderService.getOrderPay(orderSn));
    }
}
package com.alatus.mall.order.web;

import com.alatus.mall.order.service.OrderService;
import com.alatus.mall.order.template.AlipayTemplate;
import com.alipay.api.AlipayApiException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class PayWebController {
    @Autowired
    private OrderService orderService;
    @Autowired
    private AlipayTemplate alipayTemplate;
    @GetMapping(value = "/payOrder",produces = "text/html")
    @ResponseBody
    public String payOrder(@RequestParam("orderSn")String orderSn) throws AlipayApiException {
        return alipayTemplate.pay(orderService.getOrderPay(orderSn));
    }
}
package com.alatus.mall.order.service;

import com.alatus.mall.order.vo.OrderConfirmVo;
import com.alatus.mall.order.vo.OrderSubmitVo;
import com.alatus.mall.order.vo.PayVo;
import com.alatus.mall.order.vo.SubmitOrderResponseVo;
import com.baomidou.mybatisplus.extension.service.IService;
import com.alatus.common.utils.PageUtils;
import com.alatus.mall.order.entity.OrderEntity;

import java.math.BigDecimal;
import java.util.Map;
import java.util.concurrent.ExecutionException;

/**
 * 订单
 *
 * @author alatus
 * @email 1571345941@qq.com
 * @date 2024-03-12 13:50:51
 */
public interface OrderService extends IService<OrderEntity> {

    PageUtils queryPage(Map<String, Object> params);

    OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException;
    BigDecimal changeAddr(Long addrId) throws ExecutionException, InterruptedException;

    SubmitOrderResponseVo submitOrder(OrderSubmitVo orderSubmitVo);

    OrderEntity getOrderByOrderSn(String orderSn);

    void closeOrder(OrderEntity order);

    PayVo getOrderPay(String orderSn);

    PageUtils queryPageWithItem(Map<String, Object> params);
}

 

package com.alatus.mall.order.service;

import com.alatus.mall.order.vo.OrderConfirmVo;
import com.alatus.mall.order.vo.OrderSubmitVo;
import com.alatus.mall.order.vo.PayVo;
import com.alatus.mall.order.vo.SubmitOrderResponseVo;
import com.baomidou.mybatisplus.extension.service.IService;
import com.alatus.common.utils.PageUtils;
import com.alatus.mall.order.entity.OrderEntity;

import java.math.BigDecimal;
import java.util.Map;
import java.util.concurrent.ExecutionException;

/**
 * 订单
 *
 * @author alatus
 * @email 1571345941@qq.com
 * @date 2024-03-12 13:50:51
 */
public interface OrderService extends IService<OrderEntity> {

    PageUtils queryPage(Map<String, Object> params);

    OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException;
    BigDecimal changeAddr(Long addrId) throws ExecutionException, InterruptedException;

    SubmitOrderResponseVo submitOrder(OrderSubmitVo orderSubmitVo);

    OrderEntity getOrderByOrderSn(String orderSn);

    void closeOrder(OrderEntity order);

    PayVo getOrderPay(String orderSn);

    PageUtils queryPageWithItem(Map<String, Object> params);
}
package com.alatus.mall.order.service.impl;

import com.alatus.common.exception.NoStockException;
import com.alatus.common.to.MemberAddressTo;
import com.alatus.common.to.mq.OrderTo;
import com.alatus.common.utils.R;
import com.alatus.common.vo.MemberRespVo;
import com.alatus.common.vo.OrderItemVo;
import com.alatus.common.vo.SkuHasStockVo;
import com.alatus.mall.order.config.RabbitMQConfigProperties;
import com.alatus.mall.order.entity.OrderItemEntity;
import com.alatus.mall.order.enums.OrderStatusEnum;
import com.alatus.mall.order.feign.ProductFeignService;
import com.alatus.mall.order.service.OrderItemService;
import com.alatus.mall.order.to.OrderCreateTo;
import com.alatus.mall.order.constant.OrderConstant;
import com.alatus.mall.order.feign.CartFeignService;
import com.alatus.mall.order.feign.MemberFeignService;
import com.alatus.mall.order.feign.WareFeignService;
import com.alatus.mall.order.interceptor.LoginUserInterceptor;
import com.alatus.mall.order.vo.*;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.alatus.common.utils.PageUtils;
import com.alatus.common.utils.Query;
import com.alatus.mall.order.dao.OrderDao;
import com.alatus.mall.order.entity.OrderEntity;
import com.alatus.mall.order.service.OrderService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {
    @Autowired
    private MemberFeignService memberFeignService;
    @Autowired
    private CartFeignService cartFeignService;
    @Autowired
    private OrderItemService orderItemService;
    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;
    @Autowired
    private WareFeignService wareFeignService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private ProductFeignService productFeignService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private RabbitMQConfigProperties rabbitMQConfigProperties;
    private ThreadLocal<OrderSubmitVo> submitVoThreadLocal = new ThreadLocal<>();
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );
        return new PageUtils(page);
    }

    @Override
    public OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException {
        OrderConfirmVo confirmVo = new OrderConfirmVo();
//        获取原请求信息,避免异步导致丢失
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get();
//        远程查询购物车所有选中的购物项
        CompletableFuture<Void> itemVoList = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            confirmVo.setItemVoList(cartFeignService.getCurrentCartItem());
        }, threadPoolExecutor).thenRunAsync(()->{
//        获取原请求信息,避免异步导致丢失
            RequestContextHolder.setRequestAttributes(requestAttributes);
//            查询库存
            List<OrderItemVo> itemList = confirmVo.getItemVoList();
            List<Long> ids = itemList.stream().map(OrderItemVo::getSkuId).collect(Collectors.toList());
            R skuHasStock = wareFeignService.getSkuHasStock(ids);
            if(skuHasStock.getCode()==0){
                List<SkuHasStockVo> data = skuHasStock.getData(new TypeReference<List<SkuHasStockVo>>(){});
                if(data!=null&& !data.isEmpty()){
                    Map<Long, Boolean> collect = data.stream().collect(Collectors.toMap(SkuHasStockVo::getSkuId, SkuHasStockVo::getHasStock));
                    confirmVo.setStocks(collect);
                }
            }
        },threadPoolExecutor);
//        远程查询所有的用户地址列表
        CompletableFuture<Void> addressTask = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            confirmVo.setAddress(memberFeignService.getAddress(memberRespVo.getId()));
        }, threadPoolExecutor).thenRunAsync(()->{
//            获取运费信息
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<MemberAddressTo> address = confirmVo.getAddress();
            for (MemberAddressTo memberAddressTo : address) {
                if(memberAddressTo.getDefaultStatus()==1){
                    R fare = wareFeignService.getFare(memberAddressTo.getId());
                    if (fare.getCode()==0) {
                        confirmVo.setFare(fare.getData(new TypeReference<BigDecimal>() {}));
                    }
                }
            }
        },threadPoolExecutor);
//        用户积分
        CompletableFuture<Void> integrationTask = CompletableFuture.runAsync(() -> {
            confirmVo.setIntegration(memberRespVo.getIntegration());
        }, threadPoolExecutor);
//        TODO 订单令牌
        //        订单令牌
        CompletableFuture<Void> tokenTask = CompletableFuture.runAsync(() -> {
            String token = UUID.randomUUID().toString().replace("-", "");
            confirmVo.setOrderToken(token);
            redisTemplate.opsForValue().set(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberRespVo.getId(), token, 30, TimeUnit.MINUTES);
        }, threadPoolExecutor);
        CompletableFuture.allOf(addressTask,itemVoList,integrationTask,tokenTask).get();
        return confirmVo;
    }

    @Override
    public BigDecimal changeAddr(Long addrId) throws ExecutionException, InterruptedException {
//        获取原请求信息,避免异步导致丢失
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get();
        CompletableFuture<Void> changeAddr = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            R r = memberFeignService.changeAddr(memberRespVo.getId(), addrId);
            if (r.getCode() != 0) {
                throw new RuntimeException("修改失败");
            }
        }, threadPoolExecutor);
//        查询新的运费信息
        CompletableFuture<BigDecimal> getFareTask = CompletableFuture.supplyAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            R fare = wareFeignService.getFare(addrId);
            if (fare.getCode() == 0) {
                BigDecimal farePay = fare.getData(new TypeReference<BigDecimal>() {});
                return farePay;
            }
            else{
                return new BigDecimal(0);
            }
        }, threadPoolExecutor);
        CompletableFuture.allOf(changeAddr,getFareTask).get();
        return getFareTask.get();
    }

    @Override
    @Transactional
    public SubmitOrderResponseVo submitOrder(OrderSubmitVo orderSubmitVo) {
        SubmitOrderResponseVo responseVo = new SubmitOrderResponseVo();
        submitVoThreadLocal.set(orderSubmitVo);
//        获取当前登录用户
        MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get();
        responseVo.setCode(0);
//        验证令牌是否合法,验证和删除必须保证原子性
        String orderToken = orderSubmitVo.getOrderToken();
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
//        原子删除锁和验证
        Long result = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class),Arrays.asList(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberRespVo.getId()),orderToken);
        if(result == 0L){
//            令牌验证失败
            responseVo.setCode(1);
            return responseVo;
        }
        else{
//            令牌验证成功
            OrderCreateTo order = createOrder();
            BigDecimal payAmount = order.getOrderEntity().getPayAmount();
            BigDecimal payPrice = orderSubmitVo.getPayPrice();
            if(Math.abs(payAmount.subtract(payPrice).doubleValue())<0.01){
//                金额对比成功
//                保存订单
                saveOrder(order);
//                锁定库存,只要没锁到,就抛异常让它回滚
                WareSkuLockVo wareSkuLockVo = new WareSkuLockVo();
                wareSkuLockVo.setOrderSn(order.getOrderEntity().getOrderSn());
                List<OrderItemVo> orderItemVoList = order.getOrderItemEntities().stream().map(orderItemEntity -> {
                    OrderItemVo orderItemVo = new OrderItemVo();
                    orderItemVo.setSkuId(orderItemEntity.getSkuId());
                    orderItemVo.setCount(orderItemEntity.getSkuQuantity());
                    orderItemVo.setTitle(orderItemEntity.getSkuName());
                    return orderItemVo;
                }).collect(Collectors.toList());
                wareSkuLockVo.setLocks(orderItemVoList);
                R stockResult = wareFeignService.orderLockStock(wareSkuLockVo);
//                订单号,skuId,skuName
                if (stockResult.getCode()==0) {
//                    锁定成功
                    responseVo.setOrderEntity(order.getOrderEntity());
//                    TODO 远程扣除积分
//                    订单发送消息给MQ
                    rabbitTemplate.convertAndSend(rabbitMQConfigProperties.getExchange(),rabbitMQConfigProperties.getCreateKey(),order.getOrderEntity());
                    return responseVo;
                }
                else{
//                    锁定失败
                    throw new NoStockException(0L);
                }
            }
            else{
                responseVo.setCode(2);
                return responseVo;
            }
        }
    }

    @Override
    public OrderEntity getOrderByOrderSn(String orderSn) {
        return this.getOne(new QueryWrapper<OrderEntity>().eq("order_sn",orderSn));
    }

    @Override
    public void closeOrder(OrderEntity order) {
        OrderEntity orderEntity = this.getById(order.getId());
//        关单状态
        if(orderEntity.getStatus()==OrderStatusEnum.CREATE_NEW.getCode()){
            OrderEntity entity = new OrderEntity();
            entity.setId(orderEntity.getId());
            entity.setStatus(OrderStatusEnum.CANCLED.getCode());
            this.updateById(entity);
//            发送给MQ解锁库存消息
            OrderTo orderTo = new OrderTo();
            BeanUtils.copyProperties(orderEntity,orderTo);
            try{
//                发一条消息应该做一次记录到日志
                rabbitTemplate.convertAndSend(rabbitMQConfigProperties.getExchange(),rabbitMQConfigProperties.getStockReleaseKey(),orderTo);
            }catch (Exception e){
//                TODO 没发送成功的消息要重新发送
                rabbitTemplate.convertAndSend(rabbitMQConfigProperties.getExchange(),rabbitMQConfigProperties.getStockReleaseKey(),orderTo);
            }
        }
    }

    @Override
    public PayVo getOrderPay(String orderSn) {
//        获取当前订单的支付信息
        PayVo payVo = new PayVo();
        payVo.setTotal_amount(this.getOrderByOrderSn(orderSn).getPayAmount().setScale(2,BigDecimal.ROUND_UP).toString());
        payVo.setOut_trade_no(orderSn);
        List<OrderItemEntity> orderItems = orderItemService.getItemsByOrderSn(orderSn);
        OrderItemEntity orderItemEntity = orderItems.get(0);
        payVo.setSubject(orderItemEntity.getSpuName());
        payVo.setBody(orderItemEntity.getSkuAttrsVals());
        return payVo;
    }

    @Override
    public PageUtils queryPageWithItem(Map<String, Object> params) {
        Long id = LoginUserInterceptor.loginUser.get().getId();
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>().eq("member_id",id)
                        .orderByDesc("id")
        );
        // 转换为 OrderConfirmVo 分页信息
        IPage<OrderCreateTo> orderSn = page.convert(orderEntity -> {
            OrderCreateTo orderPageVo = new OrderCreateTo();
            orderPageVo.setOrderEntity(orderEntity);
//            获取订单项返回
            List<OrderItemEntity> orderItemEntities = orderItemService.list(new QueryWrapper<OrderItemEntity>().eq("order_sn", orderEntity.getOrderSn()));
            orderPageVo.setOrderItemEntities(orderItemEntities);
            // 额外的字段转换
            orderPageVo.setFare(orderEntity.getFreightAmount());
            orderPageVo.setPayPrice(orderEntity.getTotalAmount());
            return orderPageVo;
        });
        return new PageUtils(orderSn);
    }

    private void saveOrder(OrderCreateTo order) {
        OrderEntity orderEntity = order.getOrderEntity();
        List<OrderItemEntity> orderItemEntities = order.getOrderItemEntities();
        orderEntity.setModifyTime(new Date());
        save(orderEntity);
        orderItemService.saveBatch(orderItemEntities);
    }

    //    创建订单
    private OrderCreateTo createOrder(){
        OrderCreateTo orderCreateTo = new OrderCreateTo();
//        利用mybatisPlus的IdWorker生成一个不会重复的订单号
        String orderSn = IdWorker.getTimeId();
//        构建订单
        OrderEntity orderEntity = buildOrder(orderSn);
        orderCreateTo.setOrderEntity(orderEntity);
//        设置订单项
        List<OrderItemEntity> orderItemEntities = buildOrderItems(orderSn);
        orderCreateTo.setOrderItemEntities(orderItemEntities);
//        验证价格
        if(!orderItemEntities.isEmpty()){
            computePrice(orderEntity,orderItemEntities);
        }
        return orderCreateTo;
    }

//    计算价格
    private void computePrice(OrderEntity orderEntity, List<OrderItemEntity> orderItemEntities) {
//        订单价格相关
        BigDecimal totalAmount = new BigDecimal("0.0");
//        优惠卷
        BigDecimal coupon = new BigDecimal("0.0");
//        积分
        BigDecimal integration = new BigDecimal("0.0");
//        折扣
        BigDecimal promotion = new BigDecimal("0.0");
        Integer giftIntegration = 0;
        Integer giftGrowth = 0;
        for (OrderItemEntity orderItemEntity : orderItemEntities) {
            totalAmount = totalAmount.add(orderItemEntity.getRealAmount());
            coupon = coupon.add(orderItemEntity.getCouponAmount());
            integration = integration.add(orderItemEntity.getIntegrationAmount());
            promotion = promotion.add(orderItemEntity.getPromotionAmount());
            giftIntegration += orderItemEntity.getGiftIntegration();
            giftGrowth += orderItemEntity.getGiftGrowth();
        }
//        设置总额
        orderEntity.setTotalAmount(totalAmount);
        orderEntity.setPromotionAmount(promotion);
        orderEntity.setCouponAmount(coupon);
        orderEntity.setIntegrationAmount(integration);
//        设置积分和成长值
        orderEntity.setGrowth(giftGrowth);
        orderEntity.setIntegration(giftIntegration);
//        设置订单删除状态
        orderEntity.setDeleteStatus(0);
//        加上运费就是最终总价
        orderEntity.setPayAmount(totalAmount.add(orderEntity.getFreightAmount()));
    }

    //    构建订单项
    private List<OrderItemEntity> buildOrderItems(String orderSn) {
//        获取购物车订单项
        List<OrderItemVo> currentCartItem = cartFeignService.getCurrentCartItem();
        if(!currentCartItem.isEmpty()){
            return currentCartItem.stream().map(cartItem -> {
//        最后一次再确认订单购物项价格
                OrderItemEntity orderItemEntity = buildOrderItem(cartItem);
                orderItemEntity.setOrderSn(orderSn);
                return orderItemEntity;
            }).collect(Collectors.toList());
        }
        return null;
    }
//    构建每一个订单项
    private OrderItemEntity buildOrderItem(OrderItemVo cartItem) {
        OrderItemEntity orderItemEntity = new OrderItemEntity();
//        订单信息,订单号
//        商品的SPU信息
        R spuInfo = productFeignService.getSpuInfoBySkuId(cartItem.getSkuId());
        SpuInfoVo spuInfoData = spuInfo.getData(new TypeReference<SpuInfoVo>(){});
        orderItemEntity.setSpuPic(cartItem.getImage());
        orderItemEntity.setSpuBrand(spuInfoData.getBrandId().toString());
        orderItemEntity.setSpuId(spuInfoData.getId());
        orderItemEntity.setSpuName(spuInfoData.getSpuName());
        orderItemEntity.setCategoryId(spuInfoData.getCatalogId());
//        商品的SKU信息
        orderItemEntity.setSkuId(cartItem.getSkuId());
        orderItemEntity.setSkuName(cartItem.getTitle());
        orderItemEntity.setSkuPic(cartItem.getImage());
        orderItemEntity.setSkuPrice(cartItem.getPrice());
        orderItemEntity.setSkuAttrsVals(StringUtils.collectionToDelimitedString(cartItem.getSkuAttr(),";"));
        orderItemEntity.setSkuQuantity(cartItem.getCount());
//        积分信息
        orderItemEntity.setGiftGrowth(cartItem.getPrice().intValue()*cartItem.getCount());
        orderItemEntity.setGiftIntegration(cartItem.getPrice().intValue()*cartItem.getCount());
//        总价
//        TODO 商品的优惠信息
//        促销
        orderItemEntity.setPromotionAmount(new BigDecimal("0.0"));
//        优惠卷
        orderItemEntity.setCouponAmount(new BigDecimal("0.0"));
//        积分优惠
        orderItemEntity.setIntegrationAmount(new BigDecimal("0.0"));
//        最终价格
        BigDecimal price = orderItemEntity.getSkuPrice().multiply(new BigDecimal(orderItemEntity.getSkuQuantity()));
//        减去所有的优惠信息
        price = price.subtract(orderItemEntity.getPromotionAmount()).subtract(orderItemEntity.getCouponAmount()).subtract(orderItemEntity.getIntegrationAmount());
        orderItemEntity.setRealAmount(price);
        return orderItemEntity;
    }

    private OrderEntity buildOrder(String orderSn){
//        获取当前登录用户
        MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get();
        OrderEntity entity = new OrderEntity();
        entity.setMemberId(memberRespVo.getId());
        entity.setMemberUsername(memberRespVo.getUsername());
//        设置订单号
        entity.setOrderSn(orderSn);
//        获取物流收货地址信息
        OrderSubmitVo orderSubmitVo = submitVoThreadLocal.get();
//        设置运费信息
        R fareData = wareFeignService.getFare(orderSubmitVo.getAddrId());
        BigDecimal fare = fareData.get("data", new TypeReference<BigDecimal>(){});
        entity.setFreightAmount(fare);
//        获取用户当前收货默认地址
        MemberAddressTo defaultAddr = memberFeignService.getDefaultAddr(memberRespVo.getId());
        entity.setReceiverCity(defaultAddr.getCity());
        entity.setReceiverDetailAddress(defaultAddr.getDetailAddress());
        entity.setReceiverName(defaultAddr.getName());
        entity.setReceiverPhone(defaultAddr.getPhone());
        entity.setReceiverPostCode(defaultAddr.getPostCode());
        entity.setReceiverProvince(defaultAddr.getProvince());
        entity.setReceiverRegion(defaultAddr.getRegion());
//        设置订单相关状态
        entity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
        entity.setAutoConfirmDay(7);
        return entity;
    }
}

 

package com.alatus.mall.order.service.impl;

import com.alatus.common.exception.NoStockException;
import com.alatus.common.to.MemberAddressTo;
import com.alatus.common.to.mq.OrderTo;
import com.alatus.common.utils.R;
import com.alatus.common.vo.MemberRespVo;
import com.alatus.common.vo.OrderItemVo;
import com.alatus.common.vo.SkuHasStockVo;
import com.alatus.mall.order.config.RabbitMQConfigProperties;
import com.alatus.mall.order.entity.OrderItemEntity;
import com.alatus.mall.order.enums.OrderStatusEnum;
import com.alatus.mall.order.feign.ProductFeignService;
import com.alatus.mall.order.service.OrderItemService;
import com.alatus.mall.order.to.OrderCreateTo;
import com.alatus.mall.order.constant.OrderConstant;
import com.alatus.mall.order.feign.CartFeignService;
import com.alatus.mall.order.feign.MemberFeignService;
import com.alatus.mall.order.feign.WareFeignService;
import com.alatus.mall.order.interceptor.LoginUserInterceptor;
import com.alatus.mall.order.vo.*;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.alatus.common.utils.PageUtils;
import com.alatus.common.utils.Query;
import com.alatus.mall.order.dao.OrderDao;
import com.alatus.mall.order.entity.OrderEntity;
import com.alatus.mall.order.service.OrderService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {
    @Autowired
    private MemberFeignService memberFeignService;
    @Autowired
    private CartFeignService cartFeignService;
    @Autowired
    private OrderItemService orderItemService;
    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;
    @Autowired
    private WareFeignService wareFeignService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private ProductFeignService productFeignService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private RabbitMQConfigProperties rabbitMQConfigProperties;
    private ThreadLocal<OrderSubmitVo> submitVoThreadLocal = new ThreadLocal<>();
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );
        return new PageUtils(page);
    }

    @Override
    public OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException {
        OrderConfirmVo confirmVo = new OrderConfirmVo();
//        获取原请求信息,避免异步导致丢失
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get();
//        远程查询购物车所有选中的购物项
        CompletableFuture<Void> itemVoList = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            confirmVo.setItemVoList(cartFeignService.getCurrentCartItem());
        }, threadPoolExecutor).thenRunAsync(()->{
//        获取原请求信息,避免异步导致丢失
            RequestContextHolder.setRequestAttributes(requestAttributes);
//            查询库存
            List<OrderItemVo> itemList = confirmVo.getItemVoList();
            List<Long> ids = itemList.stream().map(OrderItemVo::getSkuId).collect(Collectors.toList());
            R skuHasStock = wareFeignService.getSkuHasStock(ids);
            if(skuHasStock.getCode()==0){
                List<SkuHasStockVo> data = skuHasStock.getData(new TypeReference<List<SkuHasStockVo>>(){});
                if(data!=null&& !data.isEmpty()){
                    Map<Long, Boolean> collect = data.stream().collect(Collectors.toMap(SkuHasStockVo::getSkuId, SkuHasStockVo::getHasStock));
                    confirmVo.setStocks(collect);
                }
            }
        },threadPoolExecutor);
//        远程查询所有的用户地址列表
        CompletableFuture<Void> addressTask = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            confirmVo.setAddress(memberFeignService.getAddress(memberRespVo.getId()));
        }, threadPoolExecutor).thenRunAsync(()->{
//            获取运费信息
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<MemberAddressTo> address = confirmVo.getAddress();
            for (MemberAddressTo memberAddressTo : address) {
                if(memberAddressTo.getDefaultStatus()==1){
                    R fare = wareFeignService.getFare(memberAddressTo.getId());
                    if (fare.getCode()==0) {
                        confirmVo.setFare(fare.getData(new TypeReference<BigDecimal>() {}));
                    }
                }
            }
        },threadPoolExecutor);
//        用户积分
        CompletableFuture<Void> integrationTask = CompletableFuture.runAsync(() -> {
            confirmVo.setIntegration(memberRespVo.getIntegration());
        }, threadPoolExecutor);
//        TODO 订单令牌
        //        订单令牌
        CompletableFuture<Void> tokenTask = CompletableFuture.runAsync(() -> {
            String token = UUID.randomUUID().toString().replace("-", "");
            confirmVo.setOrderToken(token);
            redisTemplate.opsForValue().set(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberRespVo.getId(), token, 30, TimeUnit.MINUTES);
        }, threadPoolExecutor);
        CompletableFuture.allOf(addressTask,itemVoList,integrationTask,tokenTask).get();
        return confirmVo;
    }

    @Override
    public BigDecimal changeAddr(Long addrId) throws ExecutionException, InterruptedException {
//        获取原请求信息,避免异步导致丢失
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get();
        CompletableFuture<Void> changeAddr = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            R r = memberFeignService.changeAddr(memberRespVo.getId(), addrId);
            if (r.getCode() != 0) {
                throw new RuntimeException("修改失败");
            }
        }, threadPoolExecutor);
//        查询新的运费信息
        CompletableFuture<BigDecimal> getFareTask = CompletableFuture.supplyAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            R fare = wareFeignService.getFare(addrId);
            if (fare.getCode() == 0) {
                BigDecimal farePay = fare.getData(new TypeReference<BigDecimal>() {});
                return farePay;
            }
            else{
                return new BigDecimal(0);
            }
        }, threadPoolExecutor);
        CompletableFuture.allOf(changeAddr,getFareTask).get();
        return getFareTask.get();
    }

    @Override
    @Transactional
    public SubmitOrderResponseVo submitOrder(OrderSubmitVo orderSubmitVo) {
        SubmitOrderResponseVo responseVo = new SubmitOrderResponseVo();
        submitVoThreadLocal.set(orderSubmitVo);
//        获取当前登录用户
        MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get();
        responseVo.setCode(0);
//        验证令牌是否合法,验证和删除必须保证原子性
        String orderToken = orderSubmitVo.getOrderToken();
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
//        原子删除锁和验证
        Long result = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class),Arrays.asList(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberRespVo.getId()),orderToken);
        if(result == 0L){
//            令牌验证失败
            responseVo.setCode(1);
            return responseVo;
        }
        else{
//            令牌验证成功
            OrderCreateTo order = createOrder();
            BigDecimal payAmount = order.getOrderEntity().getPayAmount();
            BigDecimal payPrice = orderSubmitVo.getPayPrice();
            if(Math.abs(payAmount.subtract(payPrice).doubleValue())<0.01){
//                金额对比成功
//                保存订单
                saveOrder(order);
//                锁定库存,只要没锁到,就抛异常让它回滚
                WareSkuLockVo wareSkuLockVo = new WareSkuLockVo();
                wareSkuLockVo.setOrderSn(order.getOrderEntity().getOrderSn());
                List<OrderItemVo> orderItemVoList = order.getOrderItemEntities().stream().map(orderItemEntity -> {
                    OrderItemVo orderItemVo = new OrderItemVo();
                    orderItemVo.setSkuId(orderItemEntity.getSkuId());
                    orderItemVo.setCount(orderItemEntity.getSkuQuantity());
                    orderItemVo.setTitle(orderItemEntity.getSkuName());
                    return orderItemVo;
                }).collect(Collectors.toList());
                wareSkuLockVo.setLocks(orderItemVoList);
                R stockResult = wareFeignService.orderLockStock(wareSkuLockVo);
//                订单号,skuId,skuName
                if (stockResult.getCode()==0) {
//                    锁定成功
                    responseVo.setOrderEntity(order.getOrderEntity());
//                    TODO 远程扣除积分
//                    订单发送消息给MQ
                    rabbitTemplate.convertAndSend(rabbitMQConfigProperties.getExchange(),rabbitMQConfigProperties.getCreateKey(),order.getOrderEntity());
                    return responseVo;
                }
                else{
//                    锁定失败
                    throw new NoStockException(0L);
                }
            }
            else{
                responseVo.setCode(2);
                return responseVo;
            }
        }
    }

    @Override
    public OrderEntity getOrderByOrderSn(String orderSn) {
        return this.getOne(new QueryWrapper<OrderEntity>().eq("order_sn",orderSn));
    }

    @Override
    public void closeOrder(OrderEntity order) {
        OrderEntity orderEntity = this.getById(order.getId());
//        关单状态
        if(orderEntity.getStatus()==OrderStatusEnum.CREATE_NEW.getCode()){
            OrderEntity entity = new OrderEntity();
            entity.setId(orderEntity.getId());
            entity.setStatus(OrderStatusEnum.CANCLED.getCode());
            this.updateById(entity);
//            发送给MQ解锁库存消息
            OrderTo orderTo = new OrderTo();
            BeanUtils.copyProperties(orderEntity,orderTo);
            try{
//                发一条消息应该做一次记录到日志
                rabbitTemplate.convertAndSend(rabbitMQConfigProperties.getExchange(),rabbitMQConfigProperties.getStockReleaseKey(),orderTo);
            }catch (Exception e){
//                TODO 没发送成功的消息要重新发送
                rabbitTemplate.convertAndSend(rabbitMQConfigProperties.getExchange(),rabbitMQConfigProperties.getStockReleaseKey(),orderTo);
            }
        }
    }

    @Override
    public PayVo getOrderPay(String orderSn) {
//        获取当前订单的支付信息
        PayVo payVo = new PayVo();
        payVo.setTotal_amount(this.getOrderByOrderSn(orderSn).getPayAmount().setScale(2,BigDecimal.ROUND_UP).toString());
        payVo.setOut_trade_no(orderSn);
        List<OrderItemEntity> orderItems = orderItemService.getItemsByOrderSn(orderSn);
        OrderItemEntity orderItemEntity = orderItems.get(0);
        payVo.setSubject(orderItemEntity.getSpuName());
        payVo.setBody(orderItemEntity.getSkuAttrsVals());
        return payVo;
    }

    @Override
    public PageUtils queryPageWithItem(Map<String, Object> params) {
        Long id = LoginUserInterceptor.loginUser.get().getId();
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>().eq("member_id",id)
                        .orderByDesc("id")
        );
        // 转换为 OrderConfirmVo 分页信息
        IPage<OrderCreateTo> orderSn = page.convert(orderEntity -> {
            OrderCreateTo orderPageVo = new OrderCreateTo();
            orderPageVo.setOrderEntity(orderEntity);
//            获取订单项返回
            List<OrderItemEntity> orderItemEntities = orderItemService.list(new QueryWrapper<OrderItemEntity>().eq("order_sn", orderEntity.getOrderSn()));
            orderPageVo.setOrderItemEntities(orderItemEntities);
            // 额外的字段转换
            orderPageVo.setFare(orderEntity.getFreightAmount());
            orderPageVo.setPayPrice(orderEntity.getTotalAmount());
            return orderPageVo;
        });
        return new PageUtils(orderSn);
    }

    private void saveOrder(OrderCreateTo order) {
        OrderEntity orderEntity = order.getOrderEntity();
        List<OrderItemEntity> orderItemEntities = order.getOrderItemEntities();
        orderEntity.setModifyTime(new Date());
        save(orderEntity);
        orderItemService.saveBatch(orderItemEntities);
    }

    //    创建订单
    private OrderCreateTo createOrder(){
        OrderCreateTo orderCreateTo = new OrderCreateTo();
//        利用mybatisPlus的IdWorker生成一个不会重复的订单号
        String orderSn = IdWorker.getTimeId();
//        构建订单
        OrderEntity orderEntity = buildOrder(orderSn);
        orderCreateTo.setOrderEntity(orderEntity);
//        设置订单项
        List<OrderItemEntity> orderItemEntities = buildOrderItems(orderSn);
        orderCreateTo.setOrderItemEntities(orderItemEntities);
//        验证价格
        if(!orderItemEntities.isEmpty()){
            computePrice(orderEntity,orderItemEntities);
        }
        return orderCreateTo;
    }

//    计算价格
    private void computePrice(OrderEntity orderEntity, List<OrderItemEntity> orderItemEntities) {
//        订单价格相关
        BigDecimal totalAmount = new BigDecimal("0.0");
//        优惠卷
        BigDecimal coupon = new BigDecimal("0.0");
//        积分
        BigDecimal integration = new BigDecimal("0.0");
//        折扣
        BigDecimal promotion = new BigDecimal("0.0");
        Integer giftIntegration = 0;
        Integer giftGrowth = 0;
        for (OrderItemEntity orderItemEntity : orderItemEntities) {
            totalAmount = totalAmount.add(orderItemEntity.getRealAmount());
            coupon = coupon.add(orderItemEntity.getCouponAmount());
            integration = integration.add(orderItemEntity.getIntegrationAmount());
            promotion = promotion.add(orderItemEntity.getPromotionAmount());
            giftIntegration += orderItemEntity.getGiftIntegration();
            giftGrowth += orderItemEntity.getGiftGrowth();
        }
//        设置总额
        orderEntity.setTotalAmount(totalAmount);
        orderEntity.setPromotionAmount(promotion);
        orderEntity.setCouponAmount(coupon);
        orderEntity.setIntegrationAmount(integration);
//        设置积分和成长值
        orderEntity.setGrowth(giftGrowth);
        orderEntity.setIntegration(giftIntegration);
//        设置订单删除状态
        orderEntity.setDeleteStatus(0);
//        加上运费就是最终总价
        orderEntity.setPayAmount(totalAmount.add(orderEntity.getFreightAmount()));
    }

    //    构建订单项
    private List<OrderItemEntity> buildOrderItems(String orderSn) {
//        获取购物车订单项
        List<OrderItemVo> currentCartItem = cartFeignService.getCurrentCartItem();
        if(!currentCartItem.isEmpty()){
            return currentCartItem.stream().map(cartItem -> {
//        最后一次再确认订单购物项价格
                OrderItemEntity orderItemEntity = buildOrderItem(cartItem);
                orderItemEntity.setOrderSn(orderSn);
                return orderItemEntity;
            }).collect(Collectors.toList());
        }
        return null;
    }
//    构建每一个订单项
    private OrderItemEntity buildOrderItem(OrderItemVo cartItem) {
        OrderItemEntity orderItemEntity = new OrderItemEntity();
//        订单信息,订单号
//        商品的SPU信息
        R spuInfo = productFeignService.getSpuInfoBySkuId(cartItem.getSkuId());
        SpuInfoVo spuInfoData = spuInfo.getData(new TypeReference<SpuInfoVo>(){});
        orderItemEntity.setSpuPic(cartItem.getImage());
        orderItemEntity.setSpuBrand(spuInfoData.getBrandId().toString());
        orderItemEntity.setSpuId(spuInfoData.getId());
        orderItemEntity.setSpuName(spuInfoData.getSpuName());
        orderItemEntity.setCategoryId(spuInfoData.getCatalogId());
//        商品的SKU信息
        orderItemEntity.setSkuId(cartItem.getSkuId());
        orderItemEntity.setSkuName(cartItem.getTitle());
        orderItemEntity.setSkuPic(cartItem.getImage());
        orderItemEntity.setSkuPrice(cartItem.getPrice());
        orderItemEntity.setSkuAttrsVals(StringUtils.collectionToDelimitedString(cartItem.getSkuAttr(),";"));
        orderItemEntity.setSkuQuantity(cartItem.getCount());
//        积分信息
        orderItemEntity.setGiftGrowth(cartItem.getPrice().intValue()*cartItem.getCount());
        orderItemEntity.setGiftIntegration(cartItem.getPrice().intValue()*cartItem.getCount());
//        总价
//        TODO 商品的优惠信息
//        促销
        orderItemEntity.setPromotionAmount(new BigDecimal("0.0"));
//        优惠卷
        orderItemEntity.setCouponAmount(new BigDecimal("0.0"));
//        积分优惠
        orderItemEntity.setIntegrationAmount(new BigDecimal("0.0"));
//        最终价格
        BigDecimal price = orderItemEntity.getSkuPrice().multiply(new BigDecimal(orderItemEntity.getSkuQuantity()));
//        减去所有的优惠信息
        price = price.subtract(orderItemEntity.getPromotionAmount()).subtract(orderItemEntity.getCouponAmount()).subtract(orderItemEntity.getIntegrationAmount());
        orderItemEntity.setRealAmount(price);
        return orderItemEntity;
    }

    private OrderEntity buildOrder(String orderSn){
//        获取当前登录用户
        MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get();
        OrderEntity entity = new OrderEntity();
        entity.setMemberId(memberRespVo.getId());
        entity.setMemberUsername(memberRespVo.getUsername());
//        设置订单号
        entity.setOrderSn(orderSn);
//        获取物流收货地址信息
        OrderSubmitVo orderSubmitVo = submitVoThreadLocal.get();
//        设置运费信息
        R fareData = wareFeignService.getFare(orderSubmitVo.getAddrId());
        BigDecimal fare = fareData.get("data", new TypeReference<BigDecimal>(){});
        entity.setFreightAmount(fare);
//        获取用户当前收货默认地址
        MemberAddressTo defaultAddr = memberFeignService.getDefaultAddr(memberRespVo.getId());
        entity.setReceiverCity(defaultAddr.getCity());
        entity.setReceiverDetailAddress(defaultAddr.getDetailAddress());
        entity.setReceiverName(defaultAddr.getName());
        entity.setReceiverPhone(defaultAddr.getPhone());
        entity.setReceiverPostCode(defaultAddr.getPostCode());
        entity.setReceiverProvince(defaultAddr.getProvince());
        entity.setReceiverRegion(defaultAddr.getRegion());
//        设置订单相关状态
        entity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
        entity.setAutoConfirmDay(7);
        return entity;
    }
}
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
	<head>
		<meta charset="UTF-8">
		<title></title>
    <link rel="stylesheet" href="/static/order/pay/css/style.css">
    <script src="/static/order/pay/js/jquery-3.1.1.min.js" charset="utf-8"></script>
	</head>
	<body>
    <div class="One_Jdbox">
      <div class="Jdbox_head">
        <img src="/static/order/pay/img/logo1.jpg" alt=""><span class="bank">收银台</span>
        <ul>
          <li><span>[[${session.get('loginUser').getNickname()}]]</span><span>退出</span></li>
          <li>我的订单</li>
          <li>支付帮助</li>
        </ul>
      </div>
      <div class="Jdbox_BuySuc">
        <dl>
          <dt><img src="/static/order/pay/img/saoyisao.png" alt=""></dt>
          <dd>
            <span>订单提交成功,请尽快付款!订单号:[[${submitOrder.getOrderEntity().getOrderSn()}]]</span>
            <span>应付金额<font>[[${#numbers.formatDecimal(submitOrder.getOrderEntity().getPayAmount(),1,2)}]]</font>元</span>
          </dd>
          <dd>
            <span>推荐使用</span>
            <span>扫码支付请您在<font>24小时</font>内完成支付,否则订单会被自动取消(库存紧订单请参见详情页时限)</span>
            <span>订单详细</span>
          </dd>
        </dl>
      </div>
      <div class="Jd_Con">
        <p class="JdCon_title"><img src="/static/order/pay/img/title.png" alt=""></p>
        <div class="Jd_Fenqi">
          <ul>
            <li><img src="/static/order/pay/img/BAITIAO_2.0.png" alt="">打白条</li>
            <li>
              <span>可用额度 7275.38元</span>
              <span>白条还款日 2018-01-27</span>
              <span><font>优惠</font>随机立减(最高10元)</span>
            </li>
            <li>支付<font>28.90</font>元</li>
          </ul>
          <ol>
            <li>
              <p>不分期</p>
              <p>0服务费</p>
            </li>
            <li>
              <p>3期</p>
              <p>9.48元/期</p>
            </li>
            <li>
              <p>6期</p>
              <p>4.94元/期</p>
            </li>
            <li>
              <p>12期</p>
              <p>2.35元/期</p>
            </li>
            <li>
              <p>24期</p>
              <p>1.44元/期</p>
            </li>
          </ol>
        </div>
        <div class="Jd_main">
          <ul>
            <li>
              <span>
                <img src="/static/order/pay/img/XJKCONSUME.png" alt="">谷粒学院小金库
              </span>
              <span>未开通小金库</span>
            </li>
            <li>
              <span>
                <img src="/static/order/pay/img/CMB.png" alt="">招商银行
              </span>
              <span>信用卡(4337)</span>
              <span><font>优惠</font>单单减最高99元</span>
            </li>
            <li>
              <button>更多付款方式</button>
              <button>添加新卡/网银支付</button>
            </li>
            <li>
              <p>请输入6位数字支付密码</p>
              <input type="password"><span>忘记支付密码?</span>
            </li>
            <li>
              <button>立即支付</button>
            </li>
          </ul>
        </div>
      </div>
      <div class="Jd_footer">
        <ul>
          <a>
            <li>
              <img src="/static/order/pay/img/weixin.png" alt="">微信支付
            </li>
          </a>
		  <a th:href="'http://order.alatusmall.com/payOrder?orderSn='+${submitOrder.getOrderEntity().getOrderSn()}">
            <li>
              <img src="/static/order/pay/img/zhifubao.png" style="weight:auto;height:30px;" alt="">支付宝
            </li>
          </a>
        </ul>
      </div>
      <div class="Jd_foots">
        <p>
          <span>Copyright @2004-2017 谷粒学院gulimall.com 版权所有</span>
          <span>
            <img src="/static/order/pay/img/foots.png" alt="">
          </span>
        </p>
      </div>
    </div>
	</body>
  <script type="text/javascript">
    //头部订单成功 订单详细鼠标移入效果
    $(".Jdbox_BuySuc dl dd:last-child span:last-child").mouseover(function(){
      $(this).css({"cursor":"pointer","color":"#E31613"})
    }).mouseout(function(){
      $(this).css("color","#7EA4FF")
    })
    //分期付款鼠标移入hover效果
    $(".Jd_Fenqi>ol li:not(:first-child)").mouseover(function(){
      $(this).css({"cursor":"pointer","border":"1px solid #E31613"})
    }).mouseout(function(){
      $(this).css("border","1px solid #C9DFFF")
    })
    //支付方式按钮选择hover效果
    $(".Jd_main ul li:nth-child(3) button").mouseover(function(){
      $(this).css({"cursor":"pointer","color":"#E31613"})
    }).mouseout(function(){
      $(this).css("color","#67A4FF")
    })
    //忘记密码鼠标移入效果
    $(".Jd_main ul li:nth-child(4) span").mouseover(function(){
      $(this).css({"cursor":"pointer","color":"#E31613"})
    }).mouseout(function(){
      $(this).css("color","#67A4FF")
    })
    //立即支付按钮效果
    $(".Jd_main ul li:nth-child(5) button").mouseover(function(){
      $(this).css({"cursor":"pointer","background":"#FF5350"})
    }).mouseout(function(){
      $(this).css("background","#FC6E6C")
    })

    $(".Jd_footer ul li").mouseover(function(){
      $(this).css({"cursor":"pointer","color":"#E31613"})
    }).mouseout(function(){
      $(this).css("color","#5E5E5E")
    })

    $(".Jdbox_head>ul li span").mouseover(function(){
      $(this).css({"cursor":"pointer","color":"#E31613"})
    }).mouseout(function(){
      $(this).css("color","#666666")
    })
    $(".Jdbox_head>ul li:not(:first-child)").mouseover(function(){
      $(this).css({"cursor":"pointer","color":"#E31613"})
    }).mouseout(function(){
      $(this).css("color","#666666")
    })


    $(".Jd_Fenqi ul li:first-child").mouseover(function(){
      $(this).css({"cursor":"pointer","color":"#666666"})
    }).mouseout(function(){
      $(this).css({"color":"black"})
    })
  </script>
</html>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
    <head>
       <meta charset="UTF-8">
       <title></title>
    <link rel="stylesheet" href="/static/order/pay/css/style.css">
    <script src="/static/order/pay/js/jquery-3.1.1.min.js" charset="utf-8"></script>
    </head>
    <body>
    <div class="One_Jdbox">
      <div class="Jdbox_head">
        <img src="/static/order/pay/img/logo1.jpg" alt=""><span class="bank">收银台</span>
        <ul>
          <li><span>[[${session.get('loginUser').getNickname()}]]</span><span>退出</span></li>
          <li>我的订单</li>
          <li>支付帮助</li>
        </ul>
      </div>
      <div class="Jdbox_BuySuc">
        <dl>
          <dt><img src="/static/order/pay/img/saoyisao.png" alt=""></dt>
          <dd>
            <span>订单提交成功,请尽快付款!订单号:[[${submitOrder.getOrderEntity().getOrderSn()}]]</span>
            <span>应付金额<font>[[${#numbers.formatDecimal(submitOrder.getOrderEntity().getPayAmount(),1,2)}]]</font>元</span>
          </dd>
          <dd>
            <span>推荐使用</span>
            <span>扫码支付请您在<font>24小时</font>内完成支付,否则订单会被自动取消(库存紧订单请参见详情页时限)</span>
            <span>订单详细</span>
          </dd>
        </dl>
      </div>
      <div class="Jd_Con">
        <p class="JdCon_title"><img src="/static/order/pay/img/title.png" alt=""></p>
        <div class="Jd_Fenqi">
          <ul>
            <li><img src="/static/order/pay/img/BAITIAO_2.0.png" alt="">打白条</li>
            <li>
              <span>可用额度 7275.38元</span>
              <span>白条还款日 2018-01-27</span>
              <span><font>优惠</font>随机立减(最高10元)</span>
            </li>
            <li>支付<font>28.90</font>元</li>
          </ul>
          <ol>
            <li>
              <p>不分期</p>
              <p>0服务费</p>
            </li>
            <li>
              <p>3期</p>
              <p>9.48元/期</p>
            </li>
            <li>
              <p>6期</p>
              <p>4.94元/期</p>
            </li>
            <li>
              <p>12期</p>
              <p>2.35元/期</p>
            </li>
            <li>
              <p>24期</p>
              <p>1.44元/期</p>
            </li>
          </ol>
        </div>
        <div class="Jd_main">
          <ul>
            <li>
              <span>
                <img src="/static/order/pay/img/XJKCONSUME.png" alt="">谷粒学院小金库
              </span>
              <span>未开通小金库</span>
            </li>
            <li>
              <span>
                <img src="/static/order/pay/img/CMB.png" alt="">招商银行
              </span>
              <span>信用卡(4337)</span>
              <span><font>优惠</font>单单减最高99元</span>
            </li>
            <li>
              <button>更多付款方式</button>
              <button>添加新卡/网银支付</button>
            </li>
            <li>
              <p>请输入6位数字支付密码</p>
              <input type="password"><span>忘记支付密码?</span>
            </li>
            <li>
              <button>立即支付</button>
            </li>
          </ul>
        </div>
      </div>
      <div class="Jd_footer">
        <ul>
          <a>
            <li>
              <img src="/static/order/pay/img/weixin.png" alt="">微信支付
            </li>
          </a>
         <a th:href="'http://order.alatusmall.com/payOrder?orderSn='+${submitOrder.getOrderEntity().getOrderSn()}">
            <li>
              <img src="/static/order/pay/img/zhifubao.png" style="weight:auto;height:30px;" alt="">支付宝
            </li>
          </a>
        </ul>
      </div>
      <div class="Jd_foots">
        <p>
          <span>Copyright @2004-2017 谷粒学院gulimall.com 版权所有</span>
          <span>
            <img src="/static/order/pay/img/foots.png" alt="">
          </span>
        </p>
      </div>
    </div>
    </body>
  <script type="text/javascript">
    //头部订单成功 订单详细鼠标移入效果
    $(".Jdbox_BuySuc dl dd:last-child span:last-child").mouseover(function(){
      $(this).css({"cursor":"pointer","color":"#E31613"})
    }).mouseout(function(){
      $(this).css("color","#7EA4FF")
    })
    //分期付款鼠标移入hover效果
    $(".Jd_Fenqi>ol li:not(:first-child)").mouseover(function(){
      $(this).css({"cursor":"pointer","border":"1px solid #E31613"})
    }).mouseout(function(){
      $(this).css("border","1px solid #C9DFFF")
    })
    //支付方式按钮选择hover效果
    $(".Jd_main ul li:nth-child(3) button").mouseover(function(){
      $(this).css({"cursor":"pointer","color":"#E31613"})
    }).mouseout(function(){
      $(this).css("color","#67A4FF")
    })
    //忘记密码鼠标移入效果
    $(".Jd_main ul li:nth-child(4) span").mouseover(function(){
      $(this).css({"cursor":"pointer","color":"#E31613"})
    }).mouseout(function(){
      $(this).css("color","#67A4FF")
    })
    //立即支付按钮效果
    $(".Jd_main ul li:nth-child(5) button").mouseover(function(){
      $(this).css({"cursor":"pointer","background":"#FF5350"})
    }).mouseout(function(){
      $(this).css("background","#FC6E6C")
    })

    $(".Jd_footer ul li").mouseover(function(){
      $(this).css({"cursor":"pointer","color":"#E31613"})
    }).mouseout(function(){
      $(this).css("color","#5E5E5E")
    })

    $(".Jdbox_head>ul li span").mouseover(function(){
      $(this).css({"cursor":"pointer","color":"#E31613"})
    }).mouseout(function(){
      $(this).css("color","#666666")
    })
    $(".Jdbox_head>ul li:not(:first-child)").mouseover(function(){
      $(this).css({"cursor":"pointer","color":"#E31613"})
    }).mouseout(function(){
      $(this).css("color","#666666")
    })


    $(".Jd_Fenqi ul li:first-child").mouseover(function(){
      $(this).css({"cursor":"pointer","color":"#666666"})
    }).mouseout(function(){
      $(this).css({"color":"black"})
    })
  </script>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值