这里主要有两个实体,一个是订单项,是对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技术整体的理解,这两个技术组合起来,到底方便在哪里,也需要一个整体的感悟。
谢谢各位的观看与支持,相信这个小项目只是一个七点,自己的路也才刚刚开始,也会继续努力的。
来源:CSDN
作者:周周写不完的代码
链接:https://blog.csdn.net/qq_39007838/article/details/104798662