关于订单主表与订单详情表的一些事儿!
2023-12-06 15:01:35 欢乐点

涉及到的基本对象有什么?

答:用户类,订单主表类、订单详情类、枚举类、异常类、数据传输DTO类、前端视图VO类、对象转换类工具类等。

为何须要这种类?

用户类:作为用户订单中的主角,不可省略。

订单主表类:主要储存一些关于订单的外置属性。诸如:订单状态、支付状态、用户的各类信息、订单单价等。

订单详情表:主要储存在一个订单中用所订购的商品信息。诸如:商品名称、商品总价、商品数目等。

关系:订单主表与订单详情表为一对多的关系,由于在一个订单中有多个商品。

枚举类:对于类似订单状态、支付状态等都存在多种状态,同时也要给后端返回与之对应的状态码,因而须要进行属性的分装,以便直接获取,同时前端抛出去的异常也是借助枚举的支付串方式。(只须要获取就行,不能被设置)。下边是模板:

@Getter
public enum OrderAmountEnum {
    NEW(0, "新订单"),
    FINISHED(1, "完结"),
    CANCEL(2, "已取消"),
    ;
    /**
     * 状态值
     */
    private Integer code;
    /**
     * 状态描述
     */
    private String message;
    OrderAmountEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}

异常处理类:当程序碰到某个未知的错误,我们为了安全性着想,抛出运行时异常,中止这项恳求我的订单详情查询,同时也可以借助异常提示,更换为自定义的异常,将自己想复印的异常打出。

订单详情查询步骤_我的订单详情查询_订单详情查询为空

@Data
public class SellException extends RuntimeException {
    private Integer code;
//用过调用枚举的异常描述
    public SellException(ResultEnum resultEnum){
        super(resultEnum.getMessage());
        this.code = resultEnum.getCode();
    }
    public SellException(Integer code, String messsage){
        super(messsage);
        this.code = code;
    }
}

DTO类:假如遇见实体一对多情况的时侯,也就得在与数据库对应的实体中出现了数据库数组不存在属性(比如:List)这么假如我们给这个实体添加了一个该属性,这么必然造成后期出先数组为空或影响其他业务。同时数据不须要返回给后端只是在dao、、之间做传输。采取这样的方法是将前端实体、前端恳求实体、传输实体相互分开,以便剖析业务逻辑。

From类:假如后端传入过来的是JSON字符对象,其中包含的属性比较多的时侯,就须要表单类。常常用于实名认证、用户下订单等业务中。通常命名为

类:这个类就是用户对象的转换,之后拼接对象的时侯尽量也选择分拆出去的技巧。写在业务逻辑上面会促使业务庞大。

工具类:提供了业务插口所需的技巧。时间类、UUID、JSON等。

常用到的插口有什么?

答:常用到主体业务插口有依据用户id查询订单列表、创建订单、根据订单ID查询订单详情、取消订单、完结订单、支付订单。

业务插口的界定:使用的话基本不须要在Dao做过多的插口,不过须要编撰测试方式。通常有条件的查询做处理的时侯须要根据命名规则去编撰业务插口。

创建一个订单的基本思路是哪些?

我的订单详情查询_订单详情查询为空_订单详情查询步骤

当后端传入一个JSON对象给后台,后台可以直接接收字符串,也可以通过@Valid注解去检验传过来的JSON对象中的name与实体对象是否一致。同时须要借助去判定JSON的参数是否正确。之后经过各类对象的转换,就可以直接调用创建订单的插口了,最后直接返回须要的数据给后端。那创建订单的基本流程是哪些呢?首先须要我们通过后端用户订单上面的每一个商品去后台获取商品数据,这样做的诱因就是由于后端传过来的数据可能存在问题我的订单详情查询,制止篡改数据,之后去选购的可能。(这也是代码安全性的考验)。之后我们就可以去估算总价格了(这个地方可能有让利券、积分等成份)最后借助对象的拷贝方式(这个是按照名称来拷贝的)将后台查到的数据从新形参给后端传过来的数据(这儿也是为了保证数据的正确性),最终就可以创建一个订单详情了。(这儿是由于订购的商品可能是一个List,因而一边遍历一边保存订单详情)。那订单主表我岂不也该创建?对的,下一步就是拿来创建订单主表,这儿与前面类似的方式。到目前为止订单都早已创建好了,而且为何在没有看到扣库存的操作呀?虽然在这有两种方法。一种是在创建详情的时侯可以减掉库存,然而这样对于各类异常处理就就会分装在这个业务上面,不利于维护。第二种是借助购物车的形式,也就是创建一个订单详情购物车,将用户所订购的商品集合实例化到购物车对象中,之后将购物车传入扣库存的方式就好了,至于各类异常,他都将会在该方式中实现。那扣库存又是怎样实现的?虽然就是遍历购物车,首先查找数据库中该商品的信息,假如没有就不给与操作,假如有这么我们直接借助数据库库存-订购的库存,最后直接保存进去就行。

实例化代码:

//创建订单
@PostMapping("/create")
public ResultVo> create(@Valid OrderFrom orderFrom,
                                            BindingResult bindingResult) {
    //先校验,看传入参数是否正确
    if (bindingResult.hasErrors()) {
        log.error("【创建订单】 参数不正确,orderFrom={}", orderFrom);
        throw new SellException(ResultEnum.PARAM_ERROR.getCode(), bindingResult.getFieldError().getDefaultMessage());
    }
    OrderDto orderDto = OrderFrom2OrderDTOConverter.convert(orderFrom);
    //集合判断为空的方法
    if (CollectionUtils.isEmpty(orderDto.getOrderDetailList())) {
        log.error("【创建订单】 订单中不能没有商品,orderFrom={}", orderFrom);
        throw new SellException(ResultEnum.CART_ERROR);
    }
    //创建订单
    OrderDto createResult = orderService.create(orderDto);
    Map map = new HashMap<>();
    map.put("orderId", createResult.getOrderId());
    return ResultUtil.Success(map);
}
Servrce:
@Override
    @Transactional
    public OrderDto create(OrderDto orderDto) {
        //默认价格为0.00
        BigDecimal bigDecimal = new BigDecimal(BigInteger.ZERO);
        //用户收购买的商品列表(这里为了实现一次性扣库存)
        //List cartDtoList = new ArrayList<>();
        //在创建订单的时候生成订单主表id
        String orderMasterId = KeyUtil.genUniquekey();
        //1.查询商品(数量,价格)
        for (OrderDetail orderDetail : orderDto.getOrderDetailList()) {
            ProductInfo productInfo = productService.findOne(orderDetail.getProductId());
            //判断商品是否存在,如果不存在就抛出一个异常
            if (productInfo == null) {
                throw new SellException(ResultEnum.PRODUCT_NOT_EXIST);
            }
            //3.计算订单总价(商品单价*(multiply)商品数量+(add)基础价格)
            bigDecimal = productInfo.getProductPrice().multiply(new BigDecimal(orderDetail.getProductQuantity())).add(bigDecimal);
            //4.订单详情入库(用的是数据库的数据,避免前端更改)
            BeanUtils.copyProperties(productInfo, orderDetail);
            orderDetail.setOrderId(orderMasterId);
            orderDetail.setDetailId(KeyUtil.genUniquekey());
            //保存订单详情表入库
            orderDetailRepository.save(orderDetail);
            //减库存(根据当前程序去扣库存,可以使用一次性扣多个商品库存的方法)
//            CartDto cartDto = new CartDto(orderDetail.getProductId(),orderDetail.getProductQuantity());
//            cartDtoList.add(cartDto);
        }
        //5.写入数据库 先拷贝在设置,不然orderDto里面的空数据会覆盖之前设置进去的值
        OrderMaster orderMaster = new OrderMaster();
        orderDto.setOrderId(orderMasterId);
        BeanUtils.copyProperties(orderDto, orderMaster);
        orderMaster.setOrderAmount(bigDecimal);
        orderMaster.setOrderStatus(OrderAmountEnum.NEW.getCode());
        orderMaster.setPayStatus(PayStatusEnum.WAIT.getCode());
        //保存订单主表入库
        orderMasterRepository.save(orderMaster);
        //4.减库存(一下减掉多个商品的库存)
        List cartDtoList = orderDto.getOrderDetailList().stream().map(e -> new CartDto(e.getProductId(), e.getProductQuantity())).collect(Collectors.toList());
        productService.decreaseStock(cartDtoList);
        //5.消息推送
        webSocket.sendMessage("有新的订单消息,注意查收!");
        return orderDto;
    }

实用的工具类

生成字段id:该方式常常用户生成字段uuid,为新添加的数据生成惟一字段

public class KeyUtil {
    /**
     * 生成唯一主键  (synchronized,防止多线程的时候时间一致)
     * 时间(毫秒)+随机数(6位)
     */
    public static synchronized String genUniquekey(){
        Random random = new Random();
        Integer number =  random.nextInt(900000)+100000;
        return System.currentTimeMillis()+String.valueOf(number);
    }
}

JSON解析器:JSON解析器中用于解析后端传过来的json数据对象,之后将此数据储存到前端须要改数据的实体。常常用于解析list数据。

@Slf4j
public class OrderFrom2OrderDTOConverter {
    public static OrderDto convert(OrderFrom orderFrom) {
        //json转换器
        Gson gson = new Gson();
        OrderDto orderDto = new OrderDto();
        orderDto.setBuyerName(orderFrom.getName());
        orderDto.setBuyerPhone(orderFrom.getPhone());
        orderDto.setBuyerOpenid(orderFrom.getOpenid());
        orderDto.setBuyerAddress(orderFrom.getAddress());
        List orderDetailList = new ArrayList<>();
        //json转换
        try {
//            获取json里面list数据的谷歌json获取方式
            orderDetailList = gson.fromJson(orderFrom.getItems(), new TypeToken>() {}.getType());
        } catch (Exception e) {
            log.error("【对象转换】错误,strig={}", orderFrom.getItems());
            throw new SellException(ResultEnum.PARAM_ERROR);
        }
        orderDto.setOrderDetailList(orderDetailList);
        return orderDto;
    }
}

JSON低格工具:该工具常常用于日志的输出,显示疗效。倘若不使用,这么下来的JSON是经过压缩的,看上去十分的不便捷。

public class JsonUtil {
    public static String toJson(Object object){
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.setPrettyPrinting();
        Gson gson = gsonBuilder.create();
        return gson.toJson(object);
    }
}

免责声明:部分文章信息来源于网络以及网友投稿,本站只负责对文章进行整理、排版、编辑,出于传递更多信息之目的,并不意味着赞同其观点或证实其内容的真实性,如本站文章和转稿涉及版权等问题,请作者在及时联系本站,我们会尽快为您处理。

欢乐点

留言咨询

×