微信點餐系統(六)-買家端訂單(下)

章節感悟

1.Springboot的接收表單驗證操做
前端

2.json類型字符串經過Gson轉換爲對象java

3.對輸出到前端的屬性作轉換,JsonSerializemysql

4.使返回到前端的參數不能爲null的多種解決方法spring

章節問答sql

 

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,在方法上面能夠寫json

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的轉換,因此再創建一個轉換類OrderForm2OrderDTOConverterapp

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,來完成dom

<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
相關文章
相關標籤/搜索