天猫项目(11)订单管理

帅比萌擦擦* 提交于 2020-03-12 07:11:07

这里主要有两个实体,一个是订单项,是对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技术整体的理解,这两个技术组合起来,到底方便在哪里,也需要一个整体的感悟。

谢谢各位的观看与支持,相信这个小项目只是一个七点,自己的路也才刚刚开始,也会继续努力的。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!