這裏主要有兩個實體,一個是訂單項,是對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技術整體的理解,這兩個技術組合起來,到底方便在哪裏,也需要一個整體的感悟。
謝謝各位的觀看與支持,相信這個小項目只是一個七點,自己的路也纔剛剛開始,也會繼續努力的。