💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] ## 步骤 1 : 先运行,看到效果,再学习 先将完整的 spring 项目(向老师要相关资料),配置运行起来,确认可用之后,再学习做了哪些步骤以达到这样的效果。 ## 步骤 2 : 模仿和排错 在确保可运行项目能够正确无误地运行之后,再严格照着教程的步骤,对代码模仿一遍。 模仿过程难免代码有出入,导致无法得到期望的运行结果,此时此刻通过比较**正确答案** ( 可运行项目 ) 和自己的代码,来定位问题所在。 采用这种方式,**学习有效果,排错有效率**,可以较为明显地提升学习速度,跨过学习路上的各个槛。 ## 步骤 3 : 准备数据SQL 订单数据,以及其对应的订单项数据,都是由前台功能增加的。 为了在后台演示效果,需要自己在数据库中插入数据 1. 订单: ``` insert into t_order (order_code, address, post, receiver, mobile, user_message, create_date, pay_date, delivery_date, confirm_date, status, user_id) VALUES ('201608241638122609867','某某市,某某区,某某街道,某某号 ','610000','某某某','15111111111',NULL,'2018-08-30',NULL,NULL,NULL,'waitDelivery',6); ``` 注: 倒数第二个参数6是对应的用户id,需要在数据库中存在,请根据自己的数据信息自行修改。 2. 订单项 ``` insert into t_order_item (number, user_id, product_id, order_id) VALUES (2,6,1,1); insert into t_order_item (number, user_id, product_id, order_id) VALUES (3,6,2,1); ``` 注: 第三个参数1、2分别对应的产品id,需要在数据库中存在,请根据自己的数据信息自行修改。 ## 步骤 4 : 页面截图 ![](https://box.kancloud.cn/1920f2555e356f3dddf17625ff454fa4_1847x449.png) ## 步骤 5 : OrderItem OrderItem在自动创建的基础上增加了一个product属性。 因为在订单管理页面需要看到订单下面的订单项里的产品图片。 ``` package com.dodoke.tmall.pojo; public class OrderItem { private Integer id; private Integer number; private Integer userId; private Integer productId; private Integer orderId; /* 非数据库字段 */ private Product product; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getNumber() { return number; } public void setNumber(Integer number) { this.number = number; } public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public Integer getProductId() { return productId; } public void setProductId(Integer productId) { this.productId = productId; } public Integer getOrderId() { return orderId; } public void setOrderId(Integer orderId) { this.orderId = orderId; } public Product getProduct() { return product; } public void setProduct(Product product) { this.product = product; } } ``` ## 步骤 6 : Order.java Order类在自动生成的基础上,新增4个字段: 1. 该订单下的订单项列表 `private List<OrderItem> orderItems;` 2. 该订单对应的用户 ` private User user;` 3. 该订单的总计金额 `private float total;` 4 该订单的总计数量 `private int totalNumber;` 除此之外,还提供了一个getStatusDesc方法,用于把英文表达的Status信息转换为中文: ``` package com.dodoke.tmall.pojo; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import com.dodoke.tmall.service.OrderService; public class Order { private Integer id; 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; private Integer userId; /* 如下是非数据库字段 */ private List<OrderItem> orderItems; private User user; private float total; private int totalNumber; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getOrderCode() { return orderCode; } public void setOrderCode(String orderCode) { this.orderCode = orderCode == null ? null : orderCode.trim(); } public String getAddress() { return address; } public void setAddress(String address) { this.address = address == null ? null : address.trim(); } public String getPost() { return post; } public void setPost(String post) { this.post = post == null ? null : post.trim(); } public String getReceiver() { return receiver; } public void setReceiver(String receiver) { this.receiver = receiver == null ? null : receiver.trim(); } public String getMobile() { return mobile; } public void setMobile(String mobile) { this.mobile = mobile == null ? null : mobile.trim(); } public String getUserMessage() { return userMessage; } public void setUserMessage(String userMessage) { this.userMessage = userMessage == null ? null : userMessage.trim(); } public String getCreateDate() { String createDateFormat = null; if (null != createDate) { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); createDateFormat = simpleDateFormat.format(createDate); } return createDateFormat; } public void setCreateDate(Date createDate) { this.createDate = createDate; } public String getPayDate() { String payDateFormat = null; if (null != payDate) { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); payDateFormat = simpleDateFormat.format(payDate); } return payDateFormat; } public void setPayDate(Date payDate) { this.payDate = payDate; } public String getDeliveryDate() { String deliveryDateFormat = null; if (null != deliveryDate) { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); deliveryDateFormat = simpleDateFormat.format(deliveryDate); } return deliveryDateFormat; } public void setDeliveryDate(Date deliveryDate) { this.deliveryDate = deliveryDate; } public String getConfirmDate() { String confirmDateFormat = null; if (null != confirmDate) { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); confirmDateFormat = simpleDateFormat.format(confirmDate); } return confirmDateFormat; } public void setConfirmDate(Date confirmDate) { this.confirmDate = confirmDate; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status == null ? null : status.trim(); } public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public List<OrderItem> getOrderItems() { return orderItems; } public void setOrderItems(List<OrderItem> orderItems) { this.orderItems = orderItems; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } public String getTotal() { DecimalFormat decimalFormat=new DecimalFormat(".00");//构造方法的字符格式这里如果小数不足2位,会以0补足. return decimalFormat.format(total); } public void setTotal(float total) { this.total = total; } public int getTotalNumber() { return totalNumber; } public void setTotalNumber(int totalNumber) { this.totalNumber = totalNumber; } public static void main(String args[]) { Order o = new Order(); o.setStatus(OrderService.delete); System.out.println(o.getStatusDesc()); } 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 = "未知"; } return desc; } } ``` ## 步骤 7 : OrderItemService 新建OrderItemService,声明CRUD一套,以及`fill(Order order) `和`fill(List<Order> orders) `, 这两个方法有什么用呢? 将在下个步骤OrderItemServiceImpl里讲解。 ``` package com.dodoke.tmall.service; import java.util.List; import com.dodoke.tmall.pojo.Order; import com.dodoke.tmall.pojo.OrderItem; public interface OrderItemService { void add(OrderItem c); void delete(int id); void update(OrderItem c); OrderItem get(int id); List list(); void fill(List<Order> os); void fill(Order o); } ``` ## 步骤 8 : OrderItemServiceImpl OrderItemServiceImpl实现OrderItemService,提供CRUD一套方法的实现。 同时还提供`fill(Order order)`和`fill(List<Order> orders)`, 先说`fill(Order order) `: 为什么要提供这个方法呢? 因为在订单管理界面,首先是遍历多个订单,然后遍历这个订单下的多个订单项。 而由MybatisGenerator逆向工程所创建的一套自动生成代码,是不具备一对多关系的,需要自己去二次开发。 这里就是做订单与订单项的一对多关系。 在`fill(Order order)`中: 1. 根据订单id查询出其对应的所有订单项 2. 通过setProduct为所有的订单项设置Product属性 3. 遍历所有的订单项,然后计算出该订单的总金额和总数量 4. 最后再把订单项设置在订单的orderItems属性上。 在`fill(List<Order> orders)` 中,就是遍历每个订单,然后挨个调用`fill(Order order)`。 ``` package com.dodoke.tmall.service.impl; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.dodoke.tmall.mapper.OrderItemMapper; import com.dodoke.tmall.pojo.Order; import com.dodoke.tmall.pojo.OrderItem; import com.dodoke.tmall.pojo.OrderItemExample; import com.dodoke.tmall.pojo.Product; import com.dodoke.tmall.service.OrderItemService; import com.dodoke.tmall.service.ProductService; @Service public class OrderItemServiceImpl implements OrderItemService { @Autowired OrderItemMapper orderItemMapper; @Autowired ProductService productService; @Override public void add(OrderItem c) { orderItemMapper.insert(c); } @Override public void delete(int id) { orderItemMapper.deleteByPrimaryKey(id); } @Override public void update(OrderItem c) { orderItemMapper.updateByPrimaryKeySelective(c); } @Override public OrderItem get(int id) { OrderItem result = orderItemMapper.selectByPrimaryKey(id); setProduct(result); return result; } public List<OrderItem> list() { OrderItemExample example = new OrderItemExample(); example.setOrderByClause("id desc"); return orderItemMapper.selectByExample(example); } @Override public void fill(List<Order> os) { // 遍历每个订单,然后挨个调用fill(Order order)。 for (Order o : os) { fill(o); } } public void fill(Order o) { // 1. 根据订单id查询出其对应的所有订单项 OrderItemExample example = new OrderItemExample(); example.createCriteria().andOrderIdEqualTo(o.getId()); example.setOrderByClause("id desc"); List<OrderItem> ois = orderItemMapper.selectByExample(example); // 2. 通过setProduct为所有的订单项设置Product属性 setProduct(ois); float total = 0; int totalNumber = 0; // 3. 遍历所有的订单项,然后计算出该订单的总金额和总数量 for (OrderItem oi : ois) { total += oi.getNumber() * oi.getProduct().getPromotePrice(); totalNumber += oi.getNumber(); } o.setTotal(total); o.setTotalNumber(totalNumber); // 4. 最后再把订单项设置在订单的orderItems属性上。 o.setOrderItems(ois); } public void setProduct(List<OrderItem> ois) { for (OrderItem oi : ois) { setProduct(oi); } } private void setProduct(OrderItem oi) { Product p = productService.get(oi.getProductId()); oi.setProduct(p); } } ``` ## 步骤 9 : OrderService 创建OrderService,提供CRUD一套,并提供订单状态的常量值。 ``` package com.dodoke.tmall.service; import java.util.List; import com.dodoke.tmall.pojo.Order; public interface OrderService { String waitPay = "waitPay"; String waitDelivery = "waitDelivery"; String waitConfirm = "waitConfirm"; String waitReview = "waitReview"; String finish = "finish"; String delete = "delete"; void add(Order c); void delete(int id); void update(Order c); Order get(int id); List list(); } ``` ## 步骤 10 : OrderServiceImpl 创建OrderServiceImpl ,实现CRUD一套方法 ``` package com.dodoke.tmall.service.impl; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.dodoke.tmall.mapper.OrderMapper; import com.dodoke.tmall.pojo.Order; import com.dodoke.tmall.pojo.OrderExample; import com.dodoke.tmall.pojo.User; import com.dodoke.tmall.service.OrderService; import com.dodoke.tmall.service.UserService; @Service public class OrderServiceImpl implements OrderService { @Autowired OrderMapper orderMapper; @Autowired UserService userService; @Override public void add(Order c) { orderMapper.insert(c); } @Override public void delete(int id) { orderMapper.deleteByPrimaryKey(id); } @Override public void update(Order c) { orderMapper.updateByPrimaryKeySelective(c); } @Override public Order get(int id) { return orderMapper.selectByPrimaryKey(id); } public List<Order> list() { OrderExample example = new OrderExample(); example.setOrderByClause("id desc"); List<Order> result = orderMapper.selectByExample(example); setUser(result); return result; } public void setUser(List<Order> os) { for (Order o : os) { setUser(o); } } public void setUser(Order o) { int uid = o.getUserId(); User u = userService.get(uid); o.setUser(u); } } ``` ## 步骤 11 : OrderController.java 因为订单的增加和删除,都是在前台进行的。 所以OrderController提供的是list方法和`delivery(发货)`方法 ``` package com.dodoke.tmall.controller; import java.io.IOException; import java.util.Date; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import com.dodoke.tmall.pojo.Order; import com.dodoke.tmall.service.OrderItemService; import com.dodoke.tmall.service.OrderService; import com.dodoke.tmall.util.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; @Controller @RequestMapping("") public class OrderController { @Autowired OrderService orderService; @Autowired OrderItemService orderItemService; /** * 分页查询 * @param model 模型 * @param page 页面对象 * @return 集合 */ @RequestMapping("admin_order_list") public String list(Model model, Page page) { PageHelper.offsetPage(page.getStart(), page.getCount()); List<Order> os = orderService.list(); int total = (int) new PageInfo<>(os).getTotal(); page.setTotal(total); orderItemService.fill(os); model.addAttribute("os", os); model.addAttribute("page", page); return "admin/listOrder"; } /** * 发货 * @param o 订单对象 * @return 页面路径 * @throws IOException */ @RequestMapping("admin_order_delivery") public String delivery(Order o) throws IOException { o.setDeliveryDate(new Date()); o.setStatus(OrderService.waitConfirm); orderService.update(o); return "redirect:admin_order_list"; } } ``` ## 步骤 12 : listOrder.jsp 增加listOrder.jsp。 ## 步骤 13 : 查询功能讲解 访问地址: `http://127.0.0.1:8080/tmall_ssm/admin_order_list` 即可看到订单查询界面。 `admin_order_list `导致`OrderController.list()`方法被调用 1. 获取分页对象 2. 查询订单集合 3. 获取订单总数并设置在分页对象上 4. 借助`orderItemService.fill()`方法为这些订单填充上orderItems信息 5. 把订单集合和分页对象设置在model上 6. 服务端跳转到`admin/listOrder.jsp`页面 7. 在`listOrder.jsp`借助`c:forEach`把订单集合遍历出来 8. 遍历订单的时候,再把当前订单的orderItem订单项集合遍历出来 ![](https://box.kancloud.cn/9322c9792038da7743504b1882428187_1829x427.png) OrderController: ``` /** * 分页查询 * @param model 模型 * @param page 页面对象 * @return 集合 */ @RequestMapping("admin_order_list") public String list(Model model, Page page) { PageHelper.offsetPage(page.getStart(), page.getCount()); List<Order> os = orderService.list(); int total = (int) new PageInfo<>(os).getTotal(); page.setTotal(total); orderItemService.fill(os); model.addAttribute("os", os); model.addAttribute("page", page); return "admin/listOrder"; } ``` listOrder.jsp: ``` <c:forEach items="${os}" var="o"> <tr> <td>${o.id}</td> <td>${o.statusDesc}</td> <td>¥${o.total}</td> <td align="center">${o.totalNumber}</td> <td align="center">${o.user.name}</td> <td>${o.createDate}</td> <td>${o.payDate}</td> <td>${o.deliveryDate}</td> <td>${o.confirmDate}</td> <td> <button oid=${o.id} class="orderPageCheckOrderItems btn btn-primary btn-xs">查看详情</button> <c:if test="${o.status=='waitDelivery'}"> <a href="admin_order_delivery?id=${o.id}"> <button class="btn btn-primary btn-xs">发货</button> </a> </c:if> </td> </tr> <tr class="orderPageOrderItemTR" oid=${o.id}> <td colspan="10" align="center"> <div class="orderPageOrderItem"> <table width="800px" align="center" class="orderPageOrderItemTable"> <c:forEach items="${o.orderItems}" var="oi"> <tr> <td align="left"> <img width="40px" height="40px" src="img/productSingle/${oi.product.firstProductImage.id}.jpg"> </td> <td> <a href="foreproduct?pid=${oi.product.id}"> <span>${oi.product.name}</span> </a> </td> <td align="right"> <span class="text-muted">${oi.number}个</span> </td> <td align="right"> <span class="text-muted">单价:¥${oi.product.promotePrice}</span> </td> </tr> </c:forEach> </table> </div> </td> </tr> </c:forEach> ``` ## 步骤 14 : 发货功能讲解 当订单状态是waitDelivery的时候,就会出现发货按钮 1. 发货按钮链接跳转到`admin_order_delivery` 2. `OrderController.delivery()`方法被调用 2.1 注入订单对象 2.2 修改发货时间,设置发货状态 2.3 更新到数据库 2.4 客户端跳转到`admin_order_list`页面 ![](https://box.kancloud.cn/ab60f562cb2c87c254e813797eada4f7_131x62.png) ``` /** * 发货 * @param o 订单对象 * @return 页面路径 * @throws IOException */ @RequestMapping("admin_order_delivery") public String delivery(Order o) throws IOException { o.setDeliveryDate(new Date()); o.setStatus(OrderService.waitConfirm); orderService.update(o); return "redirect:admin_order_list"; } ``` ## 步骤 15 : 增加,修改,删除功能 订单的增加和删除功能交由前台完成,后台不提供