欧美午夜精品久久久久免费视/欧美黄色精品/国产一级A片在线播出/A片免费视频在线观看

關(guān)于訂單主表與訂單詳情表的一些事兒!
2023-12-06 15:01:35 歡樂點

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

答:用戶類,訂單主表類、訂單詳情類、枚舉類、異常類、數(shù)據(jù)傳輸DTO類、前端視圖VO類、對象轉(zhuǎn)換類工具類等。

為何須要這種類?

用戶類:作為用戶訂單中的主角,不可省略。

訂單主表類:主要儲存一些關(guān)于訂單的外置屬性。諸如:訂單狀態(tài)、支付狀態(tài)、用戶的各類信息、訂單單價等。

訂單詳情表:主要儲存在一個訂單中用所訂購的商品信息。諸如:商品名稱、商品總價、商品數(shù)目等。

關(guān)系:訂單主表與訂單詳情表為一對多的關(guān)系,由于在一個訂單中有多個商品。

枚舉類:對于類似訂單狀態(tài)、支付狀態(tài)等都存在多種狀態(tài),同時也要給后端返回與之對應(yīng)的狀態(tài)碼,因而須要進行屬性的分裝,以便直接獲取,同時前端拋出去的異常也是借助枚舉的支付串方式。(只須要獲取就行,不能被設(shè)置)。下邊是模板:

@Getter
public enum OrderAmountEnum {
    NEW(0, "新訂單"),
    FINISHED(1, "完結(jié)"),
    CANCEL(2, "已取消"),
    ;
    /**
     * 狀態(tài)值
     */
    private Integer code;
    /**
     * 狀態(tài)描述
     */
    private String message;
    OrderAmountEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}

異常處理類:當(dāng)程序碰到某個未知的錯誤,我們?yōu)榱税踩灾耄瑨伋鲞\行時異常,中止這項懇求我的訂單詳情查詢,同時也可以借助異常提示,更換為自定義的異常,將自己想復(fù)印的異常打出。

@Data
public class SellException extends RuntimeException {
    private Integer code;
//用過調(diào)用枚舉的異常描述
    public SellException(ResultEnum resultEnum){
        super(resultEnum.getMessage());
        this.code = resultEnum.getCode();
    }
    public SellException(Integer code, String messsage){
        super(messsage);
        this.code = code;
    }
}

DTO類:假如遇見實體一對多情況的時侯,也就得在與數(shù)據(jù)庫對應(yīng)的實體中出現(xiàn)了數(shù)據(jù)庫數(shù)組不存在屬性(比如:List)這么假如我們給這個實體添加了一個該屬性,這么必然造成后期出先數(shù)組為空或影響其他業(yè)務(wù)。同時數(shù)據(jù)不須要返回給后端只是在dao、、之間做傳輸。采取這樣的方法是將前端實體、前端懇求實體、傳輸實體相互分開,以便剖析業(yè)務(wù)邏輯。

From類:假如后端傳入過來的是JSON字符對象,其中包含的屬性比較多的時侯,就須要表單類。常常用于實名認證、用戶下訂單等業(yè)務(wù)中。通常命名為

類:這個類就是用戶對象的轉(zhuǎn)換,之后拼接對象的時侯盡量也選擇分拆出去的技巧。寫在業(yè)務(wù)邏輯上面會促使業(yè)務(wù)龐大。

工具類:提供了業(yè)務(wù)插口所需的技巧。時間類、UUID、JSON等。

常用到的插口有什么?

答:常用到主體業(yè)務(wù)插口有依據(jù)用戶id查詢訂單列表、創(chuàng)建訂單、根據(jù)訂單ID查詢訂單詳情、取消訂單、完結(jié)訂單、支付訂單。

業(yè)務(wù)插口的界定:使用的話基本不須要在Dao做過多的插口,不過須要編撰測試方式。通常有條件的查詢做處理的時侯須要根據(jù)命名規(guī)則去編撰業(yè)務(wù)插口。

創(chuàng)建一個訂單的基本思路是哪些?

當(dāng)后端傳入一個JSON對象給后臺,后臺可以直接接收字符串,也可以通過@Valid注解去檢驗傳過來的JSON對象中的name與實體對象是否一致。同時須要借助去判定JSON的參數(shù)是否正確。之后經(jīng)過各類對象的轉(zhuǎn)換,就可以直接調(diào)用創(chuàng)建訂單的插口了,最后直接返回須要的數(shù)據(jù)給后端。那創(chuàng)建訂單的基本流程是哪些呢?首先須要我們通過后端用戶訂單上面的每一個商品去后臺獲取商品數(shù)據(jù),這樣做的誘因就是由于后端傳過來的數(shù)據(jù)可能存在問題我的訂單詳情查詢,制止篡改數(shù)據(jù),之后去選購的可能。(這也是代碼安全性的考驗)。之后我們就可以去估算總價格了(這個地方可能有讓利券、積分等成份)最后借助對象的拷貝方式(這個是按照名稱來拷貝的)將后臺查到的數(shù)據(jù)從新形參給后端傳過來的數(shù)據(jù)(這兒也是為了保證數(shù)據(jù)的正確性),最終就可以創(chuàng)建一個訂單詳情了。(這兒是由于訂購的商品可能是一個List,因而一邊遍歷一邊保存訂單詳情)。那訂單主表我豈不也該創(chuàng)建?對的,下一步就是拿來創(chuàng)建訂單主表,這兒與前面類似的方式。到目前為止訂單都早已創(chuàng)建好了,而且為何在沒有看到扣庫存的操作呀?雖然在這有兩種方法。一種是在創(chuàng)建詳情的時侯可以減掉庫存,然而這樣對于各類異常處理就就會分裝在這個業(yè)務(wù)上面,不利于維護。第二種是借助購物車的形式,也就是創(chuàng)建一個訂單詳情購物車,將用戶所訂購的商品集合實例化到購物車對象中,之后將購物車傳入扣庫存的方式就好了,至于各類異常,他都將會在該方式中實現(xiàn)。那扣庫存又是怎樣實現(xiàn)的?雖然就是遍歷購物車,首先查找數(shù)據(jù)庫中該商品的信息,假如沒有就不給與操作,假如有這么我們直接借助數(shù)據(jù)庫庫存-訂購的庫存,最后直接保存進去就行。

實例化代碼:

//創(chuàng)建訂單
@PostMapping("/create")
public ResultVo> create(@Valid OrderFrom orderFrom,
                                            BindingResult bindingResult) {
    //先校驗,看傳入?yún)?shù)是否正確
    if (bindingResult.hasErrors()) {
        log.error("【創(chuàng)建訂單】 參數(shù)不正確,orderFrom={}", orderFrom);
        throw new SellException(ResultEnum.PARAM_ERROR.getCode(), bindingResult.getFieldError().getDefaultMessage());
    }
    OrderDto orderDto = OrderFrom2OrderDTOConverter.convert(orderFrom);
    //集合判斷為空的方法
    if (CollectionUtils.isEmpty(orderDto.getOrderDetailList())) {
        log.error("【創(chuàng)建訂單】 訂單中不能沒有商品,orderFrom={}", orderFrom);
        throw new SellException(ResultEnum.CART_ERROR);
    }
    //創(chuàng)建訂單
    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);
        //用戶收購買的商品列表(這里為了實現(xiàn)一次性扣庫存)
        //List cartDtoList = new ArrayList<>();
        //在創(chuàng)建訂單的時候生成訂單主表id
        String orderMasterId = KeyUtil.genUniquekey();
        //1.查詢商品(數(shù)量,價格)
        for (OrderDetail orderDetail : orderDto.getOrderDetailList()) {
            ProductInfo productInfo = productService.findOne(orderDetail.getProductId());
            //判斷商品是否存在,如果不存在就拋出一個異常
            if (productInfo == null) {
                throw new SellException(ResultEnum.PRODUCT_NOT_EXIST);
            }
            //3.計算訂單總價(商品單價*(multiply)商品數(shù)量+(add)基礎(chǔ)價格)
            bigDecimal = productInfo.getProductPrice().multiply(new BigDecimal(orderDetail.getProductQuantity())).add(bigDecimal);
            //4.訂單詳情入庫(用的是數(shù)據(jù)庫的數(shù)據(jù),避免前端更改)
            BeanUtils.copyProperties(productInfo, orderDetail);
            orderDetail.setOrderId(orderMasterId);
            orderDetail.setDetailId(KeyUtil.genUniquekey());
            //保存訂單詳情表入庫
            orderDetailRepository.save(orderDetail);
            //減庫存(根據(jù)當(dāng)前程序去扣庫存,可以使用一次性扣多個商品庫存的方法)
//            CartDto cartDto = new CartDto(orderDetail.getProductId(),orderDetail.getProductQuantity());
//            cartDtoList.add(cartDto);
        }
        //5.寫入數(shù)據(jù)庫 先拷貝在設(shè)置,不然orderDto里面的空數(shù)據(jù)會覆蓋之前設(shè)置進去的值
        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,為新添加的數(shù)據(jù)生成惟一字段

public class KeyUtil {
    /**
     * 生成唯一主鍵  (synchronized,防止多線程的時候時間一致)
     * 時間(毫秒)+隨機數(shù)(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數(shù)據(jù)對象,之后將此數(shù)據(jù)儲存到前端須要改數(shù)據(jù)的實體。常常用于解析list數(shù)據(jù)。

@Slf4j
public class OrderFrom2OrderDTOConverter {
    public static OrderDto convert(OrderFrom orderFrom) {
        //json轉(zhuǎn)換器
        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轉(zhuǎn)換
        try {
//            獲取json里面list數(shù)據(jù)的谷歌json獲取方式
            orderDetailList = gson.fromJson(orderFrom.getItems(), new TypeToken>() {}.getType());
        } catch (Exception e) {
            log.error("【對象轉(zhuǎn)換】錯誤,strig={}", orderFrom.getItems());
            throw new SellException(ResultEnum.PARAM_ERROR);
        }
        orderDto.setOrderDetailList(orderDetailList);
        return orderDto;
    }
}

JSON低格工具:該工具常常用于日志的輸出,顯示療效。倘若不使用,這么下來的JSON是經(jīng)過壓縮的,看上去十分的不便捷。

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

免責(zé)聲明:部分文章信息來源于網(wǎng)絡(luò)以及網(wǎng)友投稿,本站只負責(zé)對文章進行整理、排版、編輯,出于傳遞更多信息之目的,并不意味著贊同其觀點或證實其內(nèi)容的真實性,如本站文章和轉(zhuǎn)稿涉及版權(quán)等問題,請作者在及時聯(lián)系本站,我們會盡快為您處理。

歡樂點

留言咨詢

×