点餐系统---买家端03---订单

DAO 层设计

1.写OrderMaster和OrderDetail两个实体类,因为涉及到订单修改时间的更新,所以添加注解@DynamicUpdate,即在更新时候修改时间数据
2.写OrderStatusEnum和PayStatusEnum两个枚举类

//订单状态
@Getter
public enum OrderStatusEnum {
    /**
     * 新订单
     */
    NEW(0, "新订单"),
    /**
     * 完结
     */
    FINISHED(1, "完结"),
    /**
     * 已取消
     */
    CANCEL(2, "已取消"),
    ;

    private Integer code;
    private String message;

    OrderStatusEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}
//支付状态
@Getter
public enum PayStatusEnum {
    /**
     * 等待支付
     */
    WAIT(0, "等待支付"),
    /**
     * 支付成功
     */
    SUCCESS(1, "支付成功");

    private Integer code;
    private String message;

    PayStatusEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}

3.编写DAO层的两个类OrderMasterRepository和OrderDetailRepository两个类

public interface OrderMasterRepository extends JpaRepository<OrderMaster,String> {
    /**
     * 分页显示,通过买家的openid查找他的订单信息
     */
    Page<OrderMaster> findByBuyerOpenid(String buyerOpenid, Pageable pageable);
}
public interface OrderDetailRepository extends JpaRepository<OrderDetail,String> {
    List<OrderDetail> findByOrderId(String orderId);
}

4.对持久层两个类进行单元测试

Service层设计

1.创建OrderService接口

@Service
public interface OrderService {

    /**
     * 创建订单
     */
    OrderDTO create(OrderDTO orderDTO);

    /**
     * 根据订单ID查询订单
     */
    OrderDTO findOne(String orderId);

    /**
     * 通过买家openid查询他的所有订单,分页返回
     */
    Page<OrderDTO> findList(String buyerOpenid, Pageable pageable);

    /**
     * 取消订单
     */
    OrderDTO cancel(OrderDTO orderDTO);

    /**
     * 完结订单
     */
    OrderDTO finish(OrderDTO orderDTO);

    /**
     * 支付订单
     */
    OrderDTO paid(OrderDTO orderDTO);
}

2.创建OrderDTO这个类,这个类包含了orderMaster所有数据,还加入了List集合

@Data
public class OrderDTO {
    /**
     * 订单id.
     */
    private String orderId;

    /**
     * 买家名字.
     */
    private String buyerName;

    /**
     * 买家手机号.
     */
    private String buyerPhone;

    /**
     * 买家地址.
     */
    private String buyerAddress;

    /**
     * 买家微信Openid.
     */
    private String buyerOpenid;

    /**
     * 订单总金额.
     */
    private BigDecimal orderAmount;

    /**
     * 订单状态, 默认为0新下单.
     */
    private Integer orderStatus ;

    /**
     * 支付状态, 默认为0未支付.
     */
    private Integer payStatus ;

    /**
     * 创建时间.
     */
    private Date createTime;

    /**
     * 更新时间.
     */
    private Date updateTime;

    private List<OrderDetail> orderDetailList;
}

根据order_master和order_detail之间一对多的联系,本来应该在OrderMaster实体类中加入一个字段,进行一对多连接,但是这里为了不要太过混淆,于是创建了dto这个包(数据传输)

3.创建OrderServiceImpl类(代码略),实现OrderService接口

4.在OrderServiceImpl类中涉及到了自定义异常,所以我们在这里创建了一个SellException类放入Exception包中

public class SellException extends RuntimeException {

    private Integer code;

    public SellException(ResultEnum resultEnum) {
        super(resultEnum.getMessage());
        this.code = resultEnum.getCode();
    }
}

5.因为异常有很多类型,所以我们建立一个枚举类ResultEnum,在这个枚举类中放入所有的能使用的异常然后进行调用,枚举类可以访问数据但是不能修改,所以我们使用@Getter标签

@Getter
public enum ResultEnum {
    /**
     * 商品不存在
     */
    Product_not_exist(10,"商品不存在"),
    ;
    
    private Integer code;
    private String message;

    ResultEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}

6.因为订单ID是唯一的,所以创建一个工具类KeyUtil放入Utils包下,由于在创建唯一ID的时候一定会涉及到多线程重复的情况,所以要加上synchronized

public class KeyUtil {

    /**
     * 生成唯一的Key
     */
    public static synchronized String genUniqueKey() {
        Random random = new Random();
        Integer a = random.nextInt(900000) + 10000;
        return System.currentTimeMillis() + String.valueOf(a);
    }
}

7.涉及到商品表中的库存的增加减少问题,返回ProductService中去完成这两个功能。加减库存涉及到了两个数据,即商品ID以及数量,所以我们可以创建一个新的类来存放这两个数据(CartDTO)

@Data
public class CartDTO {

    /**
     * 商品id.
     */
    private String productId;

    /**
     * 商品数量.
     */
    private Integer productQuantity;
}

Controller层设计

具体方法见:api的规范以及使用方式

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
    }]
}

查询订单详情
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

2.创建BuyerOrderController类,完成四个API方法

@RestController
@RequestMapping("/buyer/order")
@Slf4j
public class BuyerOrderController {

    @Autowired
    private OrderService orderService;

    //创建订单
    //@Valid:开启数据校验,假如字段验证不通过,信息绑定到后面定义的BindingResult;
    //需要注意的是@Valid 和 BindingResult 是一 一对应的,如果有多个@Valid,那么每个@Valid后面都需要添加BindingResult用于接收bean中的校验信息
    @GetMapping("/create")
    public ResultVO<Map<String,String>> create(@Valid OrderForm orderForm,
                                                BindingResult bindingResult){

        if(bindingResult.hasErrors()){
            log.error("【创建订单】 参数不正确,orderForm={}",orderForm);
            throw new SellException(ResultEnum.PARAM_ERROR.getCode(),
                    bindingResult.getFieldError().getDefaultMessage());
        }

        //将orderForm转换为OrderDTO类型
        OrderDTO orderDTO = OrderForm2OrderDTOConverter.convert(orderForm);
        if(CollectionUtils.isEmpty(orderDTO.getOrderDetailList())){
            log.error("【创建订单】 购物车不能为空");
            throw new SellException(ResultEnum.CART_EMPTY);
        }
        OrderDTO createResult = orderService.create(orderDTO);
        Map<String,String> map = new HashMap<>();
        map.put("orderId",createResult.getOrderId());

        return ResultVOUtil.success(map);
    }

    //订单列表
    @GetMapping("/list")
    public ResultVO<List<OrderDTO>> list(@RequestParam("openid") String openid,
                                         @RequestParam(value = "page",defaultValue = "0") Integer page,
                                         @RequestParam(value = "size",defaultValue = "10") Integer size){
        if(StringUtils.isEmpty(openid)){
            log.error("【查询订单列表】openid为空");
            throw new SellException(ResultEnum.PARAM_ERROR);
        }

        PageRequest request = PageRequest.of(page,size);
        Page<OrderDTO> orderDTOPage = orderService.findList(openid,request);

        return ResultVOUtil.success(orderDTOPage.getContent());
    }

    //订单详情
    @GetMapping("/detail")
    public ResultVO<OrderDTO> detail(@RequestParam("openid") String openid,
                                     @RequestParam("orderid") String orderid){
        //TODO 不安全,改进
        OrderDTO orderDTO = orderService.findOne(openid);
        return ResultVOUtil.success(orderDTO);

    }

    //取消订单
    @PostMapping("/cancel")
    public ResultVO cancel (@RequestParam("openid") String openid,
                            @RequestParam("orderid") String orderid) {

        //TODO 不安全
        OrderDTO orderDTO = orderService.findOne(orderid);
        orderService.cancel(orderDTO);

        return ResultVOUtil.success();
    }
}

3.前台传过来的是一个post是表单数据,于是我们可以创建一个OrderForm类放在form包下进行表单验证
详见:表单验证

这里使用到了Json转类的方法,所以引入Gson(json类型字符串通过Gson转换为对象)

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

4.进行Date和Long的转换,新建一个序列化类serializer(JsonSerializer:对输出到前端的属性做转换)

public class Date2LongSerializer extends JsonSerializer<Date> {

    @Override
    public void serialize(Date value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeNumber(value.getTime()/1000);
    }
}

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

/**
 * 创建时间.
 */
@JsonSerialize(using = Date2LongSerializer.class)
private Date createTime;

/**
 * 更新时间.
 */
@JsonSerialize(using = Date2LongSerializer.class)
private Date updateTime;

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

1)参数设置一个默认值
2)在类的前面加上标签

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

或者设置在application.yml中设置

spring:
  jackson:
    default-property-inclusion: non_null
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值