天貓項目(11)訂單管理

這裏主要有兩個實體,一個是訂單項,是對product的多對一,產品生成多個訂單項,一個用戶也可以有多個訂單項,一個訂單也可以有多個訂單項,這是對訂單項的er圖分析,另外一個是訂單,一個訂單由多個訂單項組成,一個用戶可以有多個訂單,這是對訂單的er圖分析

然後這裏的頁面要實現的功能,一個就是查詢訂單的功能,這個可以靠查詢訂單的訂單項完成,然後根據所有訂單項的數據計算出訂單的一些書信和;另外一個則是發貨功能,這裏會記錄下訂單的很多狀態,這裏其實最難實現的是這個,也是這個模塊的重點

1.pojo

OrderItem

public class OrderItem {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @ManyToOne
    @JoinColumn(name = "pid")
    private Product product;

    @ManyToOne
    @JoinColumn(name = "oid")
    private Order order;

    @ManyToOne
    @JoinColumn(name = "uid")
    private User user;

    private int number;

   
}

沒啥可說的,和三個表多對一映射

Order

@Entity
@Table(name = "order_")
@JsonIgnoreProperties({
        "handler","hibernateLazyInitializer"
})
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @ManyToOne
    @JoinColumn(name = "uid")
    private User user;

    private String orderCode;
    private String address;
    private String post;
    private String receiver;
    private String mobile;
    private String userMessage;
    //和時間相關的一些
    private Date createDate;
    private Date payDate;
    private Date deliveryDate;
    private Date confirmDate;
    private String status;

    //訂單項列表
    @Transient
    private List<OrderItem> orderItems;

    //總計金額
    @Transient
    private float total;

    //總計數量
    @Transient
    private int totalNumber;

    //訂單狀態
    @Transient
    private String statusDesc;

    public String getStatusDesc(){
        String desc ="未知";
        switch(status){
            case OrderService.waitPay:
                desc="待付款";
                break;
            case OrderService.waitDelivery:
                desc="待發貨";
                break;
            case OrderService.waitConfirm:
                desc="待收貨";
                break;
            case OrderService.waitReview:
                desc="等評價";
                break;
            case OrderService.finish:
                desc="完成";
                break;
            case OrderService.delete:
                desc="刪除";
                break;
            default:
                desc="未知";
        }
        statusDesc = desc;
        return statusDesc;
    }

    public void setStatusDesc(String statusDesc) {
        this.statusDesc = statusDesc;
    }
}

當OrderService進行相關操作時,改變statusDesc的值

2.dao

沒啥可說的,OrderItem多了一個根據Order查找的方法,然後倒排序,就不需要後續傳入Sort什麼的了

 List<OrderItem> findByOrderOrderByIdDesc(Order order);

3.service

OrderItem

@Service
public class OrderItemService {

    @Autowired
    OrderItemDAO orderItemDAO;

    @Autowired
    ProductImageService productImageService;

    public void fill(List<Order> orders) {
        for (Order order : orders) {
            fill(order);
        }
    }

    public void fill(Order order) {
        List<OrderItem> orderItems = listByOrder(order);
        float total = 0;
        int totalNumber = 0;

        for (OrderItem orderItem : orderItems) {
            total += orderItem.getNumber() * orderItem.getProduct().getPromotePrice();
            totalNumber += orderItem.getNumber();
            productImageService.setFirstProductImage(orderItem.getProduct());
        }
        order.setTotal(total);
        order.setOrderItems(orderItems);
        order.setTotalNumber(totalNumber);
    }

    public List<OrderItem> listByOrder(Order order) {
        return orderItemDAO.findByOrderOrderByIdDesc(order);
    }
}

主要就是兩個方法,一個就是根絕order查找出來orderItem,這個沒啥好說的,另外一個就是根絕orderItem反過來去填充order的一些屬性,這些屬性是不會映射在數據庫的,這裏的設計方法也需要學習,去計算的主要就是想給每一個item加上產品圖片,然後計算出價格之和還有數量之和

Order

@Service
public class OrderService {

    public static final String waitPay = "waitPay";
    public static final String waitDelivery = "waitDelivery";
    public static final String waitConfirm = "waitConfirm";
    public static final String waitReview = "waitReview";
    public static final String finish = "finish";
    public static final String delete = "delete";

    @Autowired
    OrderDAO orderDAO;

    public Page4Navigator<Order> list(int start, int size, int navigatePages) {
        Sort sort = new Sort(Sort.Direction.DESC,"id");
        Pageable pageable = new PageRequest(start, size, sort);
        Page pageFromJPA = orderDAO.findAll(pageable);
        return new Page4Navigator<>(pageFromJPA,navigatePages);
    }

    public void removeOrderFromOrderItem(List<Order> orders) {
        for (Order order : orders) {
            removeOrderFromOrderItem(order);
        }
    }

    public void removeOrderFromOrderItem(Order order) {
        List<OrderItem> orderItems = order.getOrderItems();
        for (OrderItem orderItem : orderItems) {
            orderItem.setOrder(null);
        }
    }

    public Order get(int oid) {
        return orderDAO.findOne(oid);
    }

    public void update(Order order) {
        orderDAO.save(order);
    }
}

別的都比較常規,主要講一下爲何要removeOrderFromOrderItem這個方法,作用其實也挺容易看出來的,九十八訂單裏的訂單項的屬性設置爲空,目的就是爲了防止springMVC的無限遞歸

4.controller

orderitem不需要寫controller,所以只有order的controller

@RestController
public class OrderController {

    @Autowired
    OrderService orderService;

    @Autowired
    OrderItemService orderItemService;

    @GetMapping("/orders")
    public Page4Navigator<Order> list(@RequestParam(value = "start", defaultValue = "0") int start,@RequestParam(value = "size", defaultValue = "5") int size) {
        start = start>0?0:start;
        Page4Navigator<Order> page = orderService.list(start, size, 5);
        orderItemService.fill(page.getContent());
        orderService.removeOrderFromOrderItem(page.getContent());
        return page;
    }

    @PutMapping("deliveryOrder/{oid}")
    public Object deliveryOrder(@PathVariable int oid) {
        Order o = orderService.get(oid);
        o.setDeliveryDate(new Date());
        o.setStatus(OrderService.waitConfirm);
        orderService.update(o);
        return Result.success();
    }
}

第一個方法,就是list出來經過上一層整合的order,沒啥可說的

第二個方法,就是實現發貨功能,這裏會有用到一個包裝的rest工具類

public class Result {

    public static int SUCCESS_CODE = 0;
    public static int FAIL_CODE = 1;

    int code;
    String message;
    Object data;

    public Result(int code, String message, Object data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    public static Result success() {
        return new Result(SUCCESS_CODE, null, null);
    }

    public static Result success(Object data) {
        return new Result(SUCCESS_CODE, "", data);
    }

    public static Result fail(String message) {
        return new Result(FAIL_CODE, message, null);
    }

}

封裝了返回的結果,據說後續會用到

4.listOrder.html

<script>
    $(function(){
        var data4Vue = {
            uri: 'orders',
            beans: [],
            pagination: {}
        };

        //ViewModel
        var vue = new Vue({
            el: '#workingArea',
            data: data4Vue,
            mounted:function () {
                //mounted 表示這個Vue被加載成功了
                this.list(0);
            },
            methods: {
                list: function (start) {
                    var url = this.uri + "?start=" + start;
                    axios.get(url).then(function (response) {
                        vue.beans = response.data.content;
                        vue.pagination = response.data;
                    });
                },
                showOrderItems: function (order) {
                  var id = order.id;
                  $("#orderItemsTR"+id).show();
                },
                jump: function (page) {
                    jump(page,vue);
                },
                jumpByNumber: function (start) {
                    jumpByNumber(start,vue);
                },
                deliveryOrder: function (order, e) {
                    var url = "deliveryOrder/" + order.id;
                    axios.put(url).then(function (response) {
                        $(e.target).hide();
                    });
                }
            }
        });
        Vue.filter('formatDateFilter', function (value, formatString) {
            if(null==value)
                return "";
            formatString = formatString || 'YYYY-MM-DD HH:mm:ss';
            return moment(value).format(formatString);
        });
    });
</script>
<table class="table table-striped table-bordered table-hover  table-condensed">
            <thead>
            <tr class="success">
                <th>狀態</th>
                <th>金額</th>
                <th width="100px">商品數量</th>
                <th width="100px">買家名稱</th>
                <th>創建時間</th>
                <th>支付時間</th>
                <th>發貨時間</th>
                <th>確認收貨時間</th>
                <th width="120px">操作</th>
            </tr>
            </thead>
            <tbody>
            <!-- 在業務上需要一個訂單數據產生兩行 tr, 此時就不能在 tr上進行 v-for, 而需要用 template 標籤 -->
            <template v-for="bean in beans ">
                <tr >
                    <td>
                        {{bean.statusDesc}}
                    </td>
                    <td>
                        {{bean.total}}
                    </td>
                    <td>
                        {{bean.totalNumber}}
                    </td>
                    <td>
                        {{bean.user.name}}
                    </td>
                    <td>
                        {{bean.createDate | formatDateFilter}}
                    </td>
                    <td>
                        {{bean.payDate | formatDateFilter}}
                    </td>
                    <td>
                        {{bean.deliveryDate | formatDateFilter}}
                    </td>
                    <td>
                        {{bean.confirmDate | formatDateFilter}}
                    </td>
                    <td>
                        <button @click="showOrderItems(bean)" class="orderPageCheckOrderItems btn btn-primary btn-xs">查看詳情</button>

                        <button v-if="bean.status=='waitDelivery'" @click="deliveryOrder(bean,$event)" class="btn btn-primary btn-xs">發貨</button>
                    </td>
                </tr>
                <tr class="orderPageOrderItemTR"  :id="'orderItemsTR'+bean.id">
                    <td colspan="10" align="center">

                        <div  class="orderPageOrderItem">
                            <table width="800px" align="center" class="orderPageOrderItemTable">
                                <tr v-for="orderItem in bean.orderItems">
                                    <td align="left">
                                        <img width="40px" height="40px" :src="'img/productSingle/'+orderItem.product.firstProductImage.id+'.jpg'">
                                    </td>

                                    <td>
                                        <a :href="'product?product.id='+orderItem.product.id">
                                            <span>{{orderItem.product.name}}</span>
                                        </a>
                                    </td>
                                    <td align="right">

                                        <span class="text-muted">{{orderItem.number}}個</span>
                                    </td>
                                    <td align="right">

                                        <span class="text-muted">單價:¥{{orderItem.product.promotePrice}}</span>
                                    </td>

                                </tr>
                            </table>
                        </div>
                    </td>
                </tr>
            </template>
            </tbody>
        </table>

主要功能其實就是把收到的order list出來,第二個就是一個發貨功能的實現,其中多了一個過濾器,對日期過濾

 

哈哈,終於把後端部分做完了

完結,撒花

 

後一部分需要重點學習的,一個就是數據庫的設計,第二個呢,就是vue綁定的一些細節,還有axios的一些操作方式,第三個呢,可以總結一下,各個層次之間的協作關係,可以更深層次的理解,其中比如pojo哪些需要映射,哪些就不需要,再比如,service中處理哪些問題比較合適,這個項目中有很多比較個性化的需求,在處理過程中是怎樣的一個思路,再有就是前端頁面中vue綁定的一些實現策略,之前一直都是紙上談兵,當面對實際的開發場景的時候,是如何應用這些工具的,這纔是能力得到根本性提高的核心之處。最後就是對使用springboot+vue技術整體的理解,這兩個技術組合起來,到底方便在哪裏,也需要一個整體的感悟。

謝謝各位的觀看與支持,相信這個小項目只是一個七點,自己的路也纔剛剛開始,也會繼續努力的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章