• 微信点餐系统(六)-买家端订单(下)


    章节感悟

    1.Springboot的接收表单验证操作

    2.json类型字符串通过Gson转换为对象

    3.对输出到前端的属性做转换,JsonSerialize

    4.使返回到前端的参数不能为null的多种解决方法

    章节问答

    Controller层设计

    1.API分析

    创建订单
    POST /sell/buyer/order/create
    参数
    name: "张三"
    phone: "18868822111"
    address: "慕课网总部"
    openid: "ew3euwhd7sjw9diwkq" //用户的微信openid
    items: [{
        productId: "1423113435324",
        productQuantity: 2 //购买数量
    }]
    
    返回
    {
      "code": 0,
      "msg": "成功",
      "data": {
          "orderId": "147283992738221" 
      }
    }
    订单列表
    GET /sell/buyer/order/list
    参数
    openid: 18eu2jwk2kse3r42e2e
    page: 0 //从第0页开始
    size: 10
    返回
    {
      "code": 0,
      "msg": "成功",
      "data": [
        {
          "orderId": "161873371171128075",
          "buyerName": "张三",
          "buyerPhone": "18868877111",
          "buyerAddress": "慕课网总部",
          "buyerOpenid": "18eu2jwk2kse3r42e2e",
          "orderAmount": 0,
          "orderStatus": 0,
          "payStatus": 0,
          "createTime": 1490171219,
          "updateTime": 1490171219,
          "orderDetailList": null
        },
        {
          "orderId": "161873371171128076",
          "buyerName": "张三",
          "buyerPhone": "18868877111",
          "buyerAddress": "慕课网总部",
          "buyerOpenid": "18eu2jwk2kse3r42e2e",
          "orderAmount": 0,
          "orderStatus": 0,
          "payStatus": 0,
          "createTime": 1490171219,
          "updateTime": 1490171219,
          "orderDetailList": null
        }]
    }
    查询订单详情
    GET /sell/buyer/order/detail
    参数
    openid: 18eu2jwk2kse3r42e2e
    orderId: 161899085773669363
    返回
    {
        "code": 0,
        "msg": "成功",
        "data": {
              "orderId": "161899085773669363",
              "buyerName": "李四",
              "buyerPhone": "18868877111",
              "buyerAddress": "慕课网总部",
              "buyerOpenid": "18eu2jwk2kse3r42e2e",
              "orderAmount": 18,
              "orderStatus": 0,
              "payStatus": 0,
              "createTime": 1490177352,
              "updateTime": 1490177352,
              "orderDetailList": [
                {
                    "detailId": "161899085974995851",
                    "orderId": "161899085773669363",
                    "productId": "157875196362360019",
                    "productName": "招牌奶茶",
                    "productPrice": 9,
                    "productQuantity": 2,
                    "productIcon": "http://xxx.com",
                    "productImage": "http://xxx.com"
                }
            ]
        }
    }
    取消订单
    POST /sell/buyer/order/cancel
    参数
    openid: 18eu2jwk2kse3r42e2e
    orderId: 161899085773669363
    返回
    {
        "code": 0,
        "msg": "成功",
        "data": null
    }
    获取openid
    重定向到 /sell/wechat/authorize
    参数
    returnUrl: http://xxx.com/abc  //【必填】
    返回
    http://xxx.com/abc?openid=oZxSYw5ldcxv6H0EU67GgSXOUrVg
    View Code

    2.创建BuyerOrderController类,写上上面四个API方法,别忘记三个标签@RestController@RequestMapping("/buyer/order")@Slf4j,在方法上面可以写

    package com.xiong.sell.service.impl;
    
    import com.xiong.sell.converter.OrderMaster2OrderDTOConverter;
    import com.xiong.sell.dataobject.OrderDetail;
    import com.xiong.sell.dataobject.OrderMaster;
    import com.xiong.sell.dataobject.ProductInfo;
    import com.xiong.sell.dto.CartDTO;
    import com.xiong.sell.dto.OrderDTO;
    import com.xiong.sell.enums.OrderStatusEnum;
    import com.xiong.sell.enums.ProductStatusEnum;
    import com.xiong.sell.enums.ResultEnum;
    import com.xiong.sell.exception.SellException;
    import com.xiong.sell.repository.OrderDetailRepository;
    import com.xiong.sell.repository.OrderMasterRepository;
    import com.xiong.sell.service.OrderService;
    import com.xiong.sell.service.ProductInfoService;
    import com.xiong.sell.utils.KeyUtil;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.BeanUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.PageImpl;
    import org.springframework.data.domain.Pageable;
    import org.springframework.stereotype.Service;
    import org.springframework.util.CollectionUtils;
    
    import javax.transaction.Transactional;
    import java.math.BigDecimal;
    import java.util.List;
    import java.util.Optional;
    import java.util.stream.Collectors;
    
    /**
     * @author Xiong YuSong
     * 2019/1/18 13:36
     */
    @Service
    @Slf4j
    public class OrderServiceImpl implements OrderService {
    
        @Autowired
        private ProductInfoService productInfoService;
    
        @Autowired
        private OrderDetailRepository orderDetailRepository;
    
        @Autowired
        private OrderMasterRepository orderMasterRepository;
    
    
        @Override
        @Transactional(rollbackOn = Exception.class)
        public OrderDTO create(OrderDTO orderDTO) {
            BigDecimal orderAmount = new BigDecimal(0);
            //生成orderID
            String orderId = KeyUtil.genUniqueKey();
            //1.查询商品(这里只有商品编号和数量)
            for (OrderDetail orderDetail : orderDTO.getOrderDetailList()) {
                //根据Id查到商品之后
                ProductInfo productInfo = productInfoService.findOne(orderDetail.getProductId());
                if (productInfo == null) {
                    throw new SellException(ResultEnum.PRODUCT_NOT_EXIST);
                }
                //2.计算订单总价
                orderAmount = productInfo.getProductPrice()
                        .multiply(new BigDecimal(orderDetail.getProductQuantity()))
                        .add(orderAmount);
                //将订单详情放入数据库中,这里注意orderDetail里面的数据,时候是完整的,正确的
                BeanUtils.copyProperties(productInfo, orderDetail);
                orderDetail.setDetailId(KeyUtil.genUniqueKey());
                orderDetail.setOrderId(orderId);
                orderDetailRepository.save(orderDetail);
            }
            //3.写入订单数据库
            OrderMaster orderMaster = new OrderMaster();
            orderDTO.setOrderId(orderId);
            orderDTO.setOrderAmount(orderAmount);
            BeanUtils.copyProperties(orderDTO, orderMaster);
            orderMaster.setOrderStatus(OrderStatusEnum.NEW.getCode());
            orderMaster.setPayStatus(ProductStatusEnum.PayStatusEnum.WAIT.getCode());
    
            orderMasterRepository.save(orderMaster);
            //4.扣库存
            List<CartDTO> cartDTOList = orderDTO.getOrderDetailList().stream().map(e ->
                    new CartDTO(e.getProductId(), e.getProductQuantity())).collect(Collectors.toList());
            productInfoService.decreaseStock(cartDTOList);
            return orderDTO;
        }
    
        @Override
        public OrderDTO findOne(String orderId) {
            Optional<OrderMaster> optional = orderMasterRepository.findById(orderId);
            if (!optional.isPresent()) {
                throw new SellException(ResultEnum.ORDER_NOT_EXIST);
            }
            OrderMaster orderMaster = optional.get();
            List<OrderDetail> orderDetailList = orderDetailRepository.findByOrderId(orderId);
            if (CollectionUtils.isEmpty(orderDetailList)) {
                throw new SellException(ResultEnum.ORDERDETAIL_NOT_EXIST);
            }
            OrderDTO orderDTO = new OrderDTO();
            BeanUtils.copyProperties(orderMaster, orderDTO);
            orderDTO.setOrderDetailList(orderDetailList);
            return orderDTO;
        }
    
        @Override
        public Page<OrderDTO> findList(String buyerOpenid, Pageable pageable) {
            Page<OrderMaster> orderMasterPage = orderMasterRepository.findByBuyerOpenid(buyerOpenid, pageable);
    
            List<OrderDTO> orderDTOList = OrderMaster2OrderDTOConverter.convert(orderMasterPage.getContent());
            //PageImpl,泛型OrderDTO,需要参数为列表,pageable,以及总数
            return new PageImpl<OrderDTO>(orderDTOList, pageable, orderMasterPage.getTotalElements());
        }
    
        @Override
        @Transactional(rollbackOn = Exception.class)
        public OrderDTO cancel(OrderDTO orderDTO) {
            OrderMaster orderMaster = new OrderMaster();
            //判断订单状态
            if (!orderDTO.getOrderStatus().equals(OrderStatusEnum.NEW.getCode())) {
                log.error("【取消订单】订单状态不正确, orderId={}, orderStatus={}", orderDTO.getOrderId(), orderDTO.getOrderStatus());
                throw new SellException(ResultEnum.ORDER_STATUS_ERROR);
            }
            //修改订单状态
            orderDTO.setOrderStatus(OrderStatusEnum.CANCEL.getCode());
            BeanUtils.copyProperties(orderDTO, orderMaster);
            OrderMaster updateResult = orderMasterRepository.save(orderMaster);
            if (updateResult == null) {
                log.error("【取消订单】更新失败, orderMaster={}", orderMaster);
                throw new SellException(ResultEnum.ORDER_UPDATE_FAIL);
            }
            //返回库存
            if (CollectionUtils.isEmpty(orderDTO.getOrderDetailList())) {
                log.error("【取消订单】订单中无商品详情, orderDTO={}", orderDTO);
                throw new SellException(ResultEnum.ORDER_DETAIL_EMPTY);
            }
            List<CartDTO> cartDTOList = orderDTO.getOrderDetailList().stream()
                    .map(e -> new CartDTO(e.getProductId(), e.getProductQuantity()))
                    .collect(Collectors.toList());
            productInfoService.increaseStock(cartDTOList);
            //如果已支付, 需要退款
            if (orderDTO.getPayStatus().equals(ProductStatusEnum.PayStatusEnum.SUCCESS.getCode())) {
                //TODO
            }
            return orderDTO;
        }
    
        @Override
        @Transactional(rollbackOn = Exception.class)
        public OrderDTO finish(OrderDTO orderDTO) {
            //判断订单状态
            if (!orderDTO.getOrderStatus().equals(OrderStatusEnum.NEW.getCode())) {
                log.error("【完结订单】订单状态不正确, orderId={}, orderStatus={}", orderDTO.getOrderId(), orderDTO.getOrderStatus());
                throw new SellException(ResultEnum.ORDER_STATUS_ERROR);
            }
    
            //修改订单状态
            orderDTO.setOrderStatus(OrderStatusEnum.FINISHED.getCode());
            OrderMaster orderMaster = new OrderMaster();
            BeanUtils.copyProperties(orderDTO, orderMaster);
            OrderMaster updateResult = orderMasterRepository.save(orderMaster);
            if (updateResult == null) {
                log.error("【完结订单】更新失败, orderMaster={}", orderMaster);
                throw new SellException(ResultEnum.ORDER_UPDATE_FAIL);
            }
            return orderDTO;
        }
    
        @Override
        @Transactional(rollbackOn = Exception.class)
        public OrderDTO paid(OrderDTO orderDTO) {
            //判断订单状态
            if (!orderDTO.getOrderStatus().equals(OrderStatusEnum.NEW.getCode())) {
                log.error("【订单支付完成】订单状态不正确, orderId={}, orderStatus={}", orderDTO.getOrderId(), orderDTO.getOrderStatus());
                throw new SellException(ResultEnum.ORDER_STATUS_ERROR);
            }
            //判断支付状态
            if (!orderDTO.getPayStatus().equals(ProductStatusEnum.PayStatusEnum.WAIT.getCode())) {
                log.error("【订单支付完成】订单支付状态不正确, orderDTO={}", orderDTO);
                throw new SellException(ResultEnum.ORDER_PAY_STATUS_ERROR);
            }
            //修改支付状态
            orderDTO.setPayStatus(ProductStatusEnum.PayStatusEnum.SUCCESS.getCode());
            OrderMaster orderMaster = new OrderMaster();
            BeanUtils.copyProperties(orderDTO, orderMaster);
            OrderMaster updateResult = orderMasterRepository.save(orderMaster);
            if (updateResult == null) {
                log.error("【订单支付完成】更新失败, orderMaster={}", orderMaster);
                throw new SellException(ResultEnum.ORDER_UPDATE_FAIL);
            }
            return orderDTO;
        }
    }
    View Code

    3.前台传过来的是一个post是表单数据,于是我们可以创建一个OrderForm类放在form包下进行表单验证,@NotEmpty(message = "姓名必填")

    package com.xiong.sell.form;
    
    import lombok.Data;
    
    import javax.validation.constraints.NotEmpty;
    
    /**
     * @author Xiong YuSong
     * 2019/1/18 19:19
     */
    @Data
    public class OrderForm {
    
        /**
         * 买家姓名
         */
        @NotEmpty(message = "姓名必填")
        private String name;
    
        /**
         * 买家手机号
         */
        @NotEmpty(message = "手机号必填")
        private String phone;
    
        /**
         * 买家地址
         */
        @NotEmpty(message = "地址必填")
        private String address;
    
        /**
         * 买家微信openid
         */
        @NotEmpty(message = "openid必填")
        private String openid;
    
        /**
         * 购物车
         */
        @NotEmpty(message = "购物车不能为空")
        private String items;
    }
    View Code

    4.这里涉及到了OrderFormOrderDTO的转换,所以再建立一个转换类OrderForm2OrderDTOConverter

    package com.xiong.sell.converter;
    
    import com.google.gson.Gson;
    import com.google.gson.reflect.TypeToken;
    import com.xiong.sell.dataobject.OrderDetail;
    import com.xiong.sell.dto.OrderDTO;
    import com.xiong.sell.enums.ResultEnum;
    import com.xiong.sell.exception.SellException;
    import com.xiong.sell.form.OrderForm;
    import lombok.extern.slf4j.Slf4j;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @author Xiong YuSong
     * 2019/1/18 19:52
     */
    @Slf4j
    public class OrderForm2OrderDTOConverter {
    
        public static OrderDTO convert(OrderForm orderForm) {
            Gson gson = new Gson();
            OrderDTO orderDTO = new OrderDTO();
    
            orderDTO.setBuyerName(orderForm.getName());
            orderDTO.setBuyerPhone(orderForm.getPhone());
            orderDTO.setBuyerAddress(orderForm.getAddress());
            orderDTO.setBuyerOpenid(orderForm.getOpenid());
    
            List<OrderDetail> orderDetailList = new ArrayList<>();
            try {
                orderDetailList = gson.fromJson(orderForm.getItems(),
                        new TypeToken<List<OrderDetail>>() {
                        }.getType());
            } catch (Exception e) {
                log.error("【对象转换】错误, string={}", orderForm.getItems());
                throw new SellException(ResultEnum.PARAM_ERROR);
            }
            orderDTO.setOrderDetailList(orderDetailList);
        }
    }
    View Code

    5.这里使用到了Json转类的方法,所以引入Gson,来完成

    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
    </dependency>
    View Code

    6.进行DateLong的转换,新建一个序列化类serializer

    package com.xiong.sell.utils.serializer;
    
    import com.fasterxml.jackson.core.JsonGenerator;
    import com.fasterxml.jackson.databind.JsonSerializer;
    import com.fasterxml.jackson.databind.SerializerProvider;
    
    import java.io.IOException;
    import java.util.Date;
    
    /**
     * @author Xiong YuSong
     * 2019/1/18 20:38
     */
    public class Date2LongSerializer extends JsonSerializer<Date> {
    
        @Override
        public void serialize(Date value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            gen.writeNumber(value.getTime()/1000);
        }
    }
    View Code

    然后再需要转换的属行上@JsonSerialize(using = Date2LongSerializer.class)即可

    /**
     * 创建时间.
     */
    @JsonSerialize(using = Date2LongSerializer.class)
    private Date createTime;
    
    /**
     * 更新时间.
     */
    @JsonSerialize(using = Date2LongSerializer.class)
    private Date updateTime;
    View Code

    7.此时我们让返回的参数不能为空,这个时候我们有两个方法

    1)参数设置一个默认值

    2)在类的前面加上标签

    @Data
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public class OrderDTO {
    }
    View Code

    或者设置在application.yml中设置

    spring:
      datasource:
        driver-class-name: com.mysql.jdbc.Driver
        username: root
        password: 123456
        url: jdbc:mysql://192.168.1.103/sell?characterEncoding=utf-8&useSSl=false
      jpa:
        show-sql: true
      jackson:
        default-property-inclusion: non_null
    server:
      servlet:
        context-path: /sell
    View Code

    8.在进行查看订单详情和取消订单的时候需要验证订单的主人的微信openid是不是传进来的openid,所以这里需要创建一个新的BuyerServer来进行身份验证

    package com.xiong.sell.service;
    
    import com.xiong.sell.dto.OrderDTO;
    
    /**
     * @author Xiong YuSong
     * 2019/1/18 20:59
     */
    public interface BuyerService {
        /**
         * 查询一个订单
         * @param openid
         * @param orderId
         * @return
         */
        OrderDTO findOrderOne(String openid, String orderId);
    
        /**
         * 取消一个订单
         * @param openid
         * @param orderId
         * @return
         */
        OrderDTO cancelOrder(String openid, String orderId);
    }
    View Code
  • 相关阅读:
    php 之fsockopen(转)
    【javascript基础】之BigPipe学习研究【转】
    【javascript基础】之浏览器的时钟精度【转】
    【javascript基础】IE6IE9不支持table.innerHTML的解决方法分享【转】
    github报错 please open the options menu from the dashboard and update your name and email
    泡泡堂如何申请小鸡号
    【javascript基础】各浏览器Iframe对contentWindow、contentDocument、document及frames属性测试 【转】
    【javascript基础】之浅析XSS(Cross Site Script)漏洞原理【转】
    【html】(X)HTML语义与元素名全称(部分)【转】
    【javascript基础】渐进式jpeg(progressive jpeg)图片及其相关【转】
  • 原文地址:https://www.cnblogs.com/xzmxddx/p/10289778.html
Copyright © 2020-2023  润新知