spring项目篇15 --- 商城小项目创建订单以及查看所有订单
深圳肺炎患者突破80了,现在心里慌慌的,不知什么时候返深啊。。。既来之,则安之!
今天,这个简单的小项目最后一步,创建订单以及查看所有订单状态,我们的订单只需要点击一下付款即可完成支付,没有接入第三方支付。下面计划开始学习mybatis。
因为大多是业务代码,我们直接看就可以
先看dao层,在创建订单的时候,因为设计多表操作,因此需要开启事务
// IOrderDao package com.yang.dao; import com.yang.domain.Car; import com.yang.domain.Order; import com.yang.domain.OrderDetail; import java.util.List; public interface IOrderDao { // 获取订单信息 List<Order> getList(Integer userId); // 获取订单详情 List<OrderDetail> getDetailList(Integer orderId); // 获取单个订单信息 Order getOrder(Integer userId, Integer id); // 删除订单 boolean deleteOrder(Integer id); // 添加订单 Integer addOrder(Order order, List<Car> carList); // 更新订单 boolean updateOrder(Integer id, Order order); } // OrderDaoImpl package com.yang.dao.impl; import com.mysql.jdbc.Statement; import com.yang.dao.IOrderDao; import com.yang.domain.Car; import com.yang.domain.Order; import com.yang.domain.OrderDetail; import com.yang.handler.BeanHandler; import com.yang.handler.BeanListHandler; import com.yang.util.CRUDTemplate; import com.yang.util.JdbcUtil; import org.springframework.stereotype.Repository; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.List; @Repository public class OrderDaoImpl implements IOrderDao { @Override public List<Order> getList(Integer userId) { // 建立sql语句 String sql = "select * from orders where userId = ?"; return CRUDTemplate.executeQuery(sql, new BeanListHandler<>(Order.class), userId); } // 获取订单详情 @Override public List<OrderDetail> getDetailList(Integer orderId) { // 建立sql语句 String sql = "select * from order_detail where orderId = ?"; return CRUDTemplate.executeQuery(sql, new BeanListHandler<>(OrderDetail.class), orderId); } // 单个查询 @Override public Order getOrder(Integer userId, Integer id) { // 建立sql语句 String sql = "select * from orders where userId = ? and id = ?"; return CRUDTemplate.executeQuery(sql, new BeanHandler<>(Order.class), userId, id); } // 删除,需要删除订单以及订单详情,数据库一致性没需要开始事务 @Override public boolean deleteOrder(Integer id) { String sql = "delete from orders where id = ?"; String sql2 = "delete from order_detail where orderId = ?"; Connection conn = JdbcUtil.getConn(); PreparedStatement ps = null; boolean flag = true; try { assert conn != null; // 设置数据库不自动提交 conn.setAutoCommit(false); ps = conn.prepareStatement(sql); ps.setInt(1, id); // 预执行 ps.executeUpdate(); ps = conn.prepareStatement(sql2); ps.setInt(1, id); ps.executeUpdate(); // 事务提交 conn.commit(); } catch (Exception e) { flag = false; e.printStackTrace(); try { // 删除失败,数据库回滚 conn.rollback(); } catch (Exception err) { err.printStackTrace(); } } finally { JdbcUtil.close(conn, ps, null); } return flag; } // 增加新的订单 @Override public Integer addOrder(Order order, List<Car> carList) { // 执行语句 String sql = "insert into orders(userId, price) values(?,?)"; String sql2 = "insert into order_detail(orderId, productId, price) values(?,?,?)"; String sql3 = "delete from car where id = ?"; Connection conn = JdbcUtil.getConn(); PreparedStatement ps = null; ResultSet rs = null; int orderId = 0; try { assert conn != null; // 设置不要自动提交 conn.setAutoCommit(false); // 生成订单 ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); ps.setInt(1, order.getUserId()); ps.setFloat(2, order.getPrice()); ps.executeUpdate(); rs = ps.getGeneratedKeys(); if (rs.next()) { // 获取生成订单的id int id = rs.getInt(1); orderId = id; for(Car car : carList){ // 将产品插入订单详情 ps = conn.prepareStatement(sql2); ps.setInt(1, id); ps.setInt(2, car.getProductId()); ps.setFloat(3, car.getPrice()); ps.executeUpdate(); // 从购物车中删除 ps = conn.prepareStatement(sql3); ps.setInt(1, car.getId()); ps.executeUpdate(); } } // 提交事务 conn.commit(); } catch (Exception e) { orderId = 0; e.printStackTrace(); try { // 事务回滚 conn.rollback(); } catch (Exception err) { err.printStackTrace(); } } finally { // 关闭资源 JdbcUtil.close(conn, ps, rs); } return orderId; } @Override public boolean updateOrder(Integer id, Order order) { // 只更新付款状态 String sql = "update orders set status = ? where id = ?"; int result = CRUDTemplate.executeUpdate(sql, order.getStatus(), id); return result == 1; } }
本次购物车代码有更新,一并看一下,补充了一个下面的接口
// 根据购物车Id获取购物车内容 Car getCar(Integer id);
service层不看了,没什么代码量,直接来看controller层
// OrderController package com.yang.controller; import com.yang.domain.*; import com.yang.service.ICarService; import com.yang.service.IOrderService; import com.yang.service.IProductService; import com.yang.service.IUserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @Controller public class OrderController { @Autowired IOrderService iOrderService; @Autowired ICarService iCarService; @Autowired IUserService iUserService; @Autowired IProductService iProductService; // 创建订单并跳转到结算页面 @ResponseBody @RequestMapping("/order/add/{userId}/{carId}") public int AddOrder(@PathVariable("userId") Integer userId, @PathVariable("carId") Integer carId) { List<Car> carList = new ArrayList<>(); float totalPrice = 0; // 检查是单独结算,还是整体结算 if (carId == 0) { carList = iCarService.getList(userId); for (Car car : carList) { totalPrice += car.getPrice(); } } else { Car car = iCarService.getCar(carId); carList.add(car); totalPrice = car.getPrice(); } // 生成订单模型 Order order = new Order(); order.setPrice(totalPrice); order.setUserId(userId); // 返回生成 的订单id return iOrderService.addOrder(order, carList); } // 跳转到订单页面 @RequestMapping("/order/{orderId}/{userId}") public String Order(@PathVariable("orderId") Integer orderId, @PathVariable("userId") Integer userId, Model model) { User user = iUserService.get(userId); // 查询订单 Order order = iOrderService.getOrder(userId, orderId); if (order == null) { model.addAttribute("message", "访问的订单不存在"); return "error"; } // 查询订单下每一行的信息 List<OrderDetail> orderDetails = iOrderService.getDetail(orderId); Map<Integer, Product> productMap = new HashMap<>(); // 获取订单中商品信息,并封装 for (OrderDetail orderDetail : orderDetails) { Product product = iProductService.getProduct(orderDetail.getProductId()); productMap.put(orderDetail.getId(), product); } // 向模型塞数据 model.addAttribute("user", user); model.addAttribute("order", order); model.addAttribute("orderDetails", orderDetails); model.addAttribute("productMap", productMap); return "orders"; } @ResponseBody @RequestMapping("/order/update/{orderId}") public String orderUpdate(@PathVariable Integer orderId) { // 这里新建一个对象的原因是为了以后可扩展,如果修改订单其他数据直接修改controller层数据就好 Order order = new Order(); order.setId(orderId); order.setStatus("已付款"); boolean result = iOrderService.updateOrder(orderId, order); if (result) { return "ok"; } return "fail"; } // 展示当前用户所有的订单 @RequestMapping("/order/list/{userId}") public String orderList(@PathVariable Integer userId, Model model) { User user = iUserService.get(userId); List<Order> orderList = iOrderService.getList(userId); // 封装一下订单详情,键就是订单的id Map<Integer, List<OrderDetail>> orderMap = new HashMap<>(); // 捕捉所有的商品 Map<Integer, Product> productMap = new HashMap<>(); for (Order order : orderList) { List<OrderDetail> orderDetails = iOrderService.getDetail(order.getId()); orderMap.put(order.getId(), orderDetails); for (OrderDetail orderDetail : orderDetails) { Product product = iProductService.getProduct(orderDetail.getProductId()); productMap.put(product.getId(), product); } } model.addAttribute("user", user); model.addAttribute("orderMap", orderMap); model.addAttribute("productMap", productMap); model.addAttribute("orderList", orderList); return "myOrders"; } }
看一下前端页面
购物车的
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <html> <head> <title>${user.username}的购物车</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content=""> <meta name="author" content="yang"> <!-- Bootstrap core CSS --> <link href="${pageContext.request.contextPath}/static/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <nav class="navbar navbar-default"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">杨的购物广场</a> </div> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li><a href="${pageContext.request.contextPath}/">回欢迎页</a></li> <li><a href="#" id="backProduct">返回商品列表</a></li> </ul> <ul class="nav navbar-nav navbar-right"> <li><a href="${pageContext.request.contextPath}/car/${user.id}">购物车</a></li> <li class="dropdown"> <img src="${pageContext.request.contextPath}/${user.avatarUrl}" alt="" style=" max-width: 30px; display: inline-block;"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" style="display: inline-block; padding-left: 3px;">${user.username}<span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="${pageContext.request.contextPath}/userinfo/${user.id}">个人信息</a></li> <li><a href="${pageContext.request.contextPath}/order/list/${user.id}">查看订单</a></li> <li id="logout"><a>退出</a></li> </ul> </li> </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> <div style="max-width: 1440px; margin: 0 auto"> <table class="table table-striped"> <caption>${user.username}的购物车</caption> <thead> <tr> <th>照片</th> <th>商品</th> <th>描述</th> <th>价格</th> <th>操作</th> </tr> </thead> <tbody> <c:forEach items="${carList}" var="car"> <tr> <td><img src="${pageContext.request.contextPath}/${productMap[car.id].pictureUrl}" alt="" class="img-circle" style="max-width: 30px;"></td> <td>${productMap[car.id].name}</td> <td>${productMap[car.id].description}</td> <td>${productMap[car.id].price}</td> <td> <button href="${pageContext.request.contextPath}/car/delete/${car.id}" type="button" class="btn btn-danger delete"> 删除 </button> <button onclick="buy(${car.id})" type="button" class="btn btn-success"> 单独结算 </button> </td> </tr> </c:forEach> </tbody> </table> <div style="display: flex; justify-content: flex-end; align-items: center; border-top:1px solid #333333"> <div style="color: red; font-size: 40px">总计:${totalPrice}</div> <div style="margin: 0 200px 0 20px;"> <button type="button" class="btn btn-primary" onclick="buy(0)">结算</button> </div> </div> </div> <!-- Jquery --> <script src="${pageContext.request.contextPath}/static/js/jquery-1.11.1.min.js"></script> <!-- Bootstrap --> <script src="${pageContext.request.contextPath}/static/js/bootstrap.min.js"></script> <script type="application/javascript"> function buy(carId) { $.ajax({ url: "${pageContext.request.contextPath}/order/add/${user.id}/" + carId, success: function (data) { if(data !== 0){ window.location = "${pageContext.request.contextPath}/order/" + data + "/${user.id}"; return false; } alert("fail"); }, error: function (err) { console.log(err); alert("服务器异常!"); } }) }; $(function () { let token = sessionStorage.getItem("token") || null; // 验证是否存在token,没有则返回登陆 if (token == null) { alert("请先登陆!"); window.location = "${pageContext.request.contextPath}/login"; return false; } document.getElementById("backProduct").href = "${pageContext.request.contextPath}/product?token=" + token; $('.delete').click(function (e) { let url = e.toElement.getAttribute("href"); $.ajax({ type: "get", url: url, success: function (data) { if (data === "ok") { alert("删除成功!"); document.location.reload(); return false; } alert("删除失败,请刷新重试!") }, error: function (err) { console.log(err); alert("服务器故障!") } }) }); $("#logout").click(function () { sessionStorage.removeItem("token"); window.location = "${pageContext.request.contextPath}/login" }); }) </script> </body> </html>
订单的
<%-- Created by IntelliJ IDEA. User: yangshixiong Date: 2020/1/29 Time: 上午10:46 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <html> <head> <title>${user.username}的订单</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content=""> <meta name="author" content="yang"> <!-- Bootstrap core CSS --> <link href="${pageContext.request.contextPath}/static/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <nav class="navbar navbar-default"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">杨的购物广场</a> </div> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li><a href="${pageContext.request.contextPath}/">回欢迎页</a></li> <li><a href="#" id="backProduct">返回商品列表</a></li> </ul> <ul class="nav navbar-nav navbar-right"> <li><a href="${pageContext.request.contextPath}/car/${user.id}">购物车</a></li> <li class="dropdown"> <img src="${pageContext.request.contextPath}/${user.avatarUrl}" alt="" style=" max-width: 30px; display: inline-block;"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" style="display: inline-block; padding-left: 3px;">${user.username}<span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="${pageContext.request.contextPath}/userinfo/${user.id}">个人信息</a></li> <li><a href="${pageContext.request.contextPath}/order/list/${user.id}">查看订单</a></li> <li id="logout"><a>退出</a></li> </ul> </li> </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> <div> <table class="table table-hover"> <caption>${user.username}的购物车</caption> <thead> <tr> <th>照片</th> <th>商品</th> <th>描述</th> <th>价格</th> </tr> </thead> <tbody> <c:forEach items="${orderDetails}" var="orderDetail"> <tr> <td><img src="${pageContext.request.contextPath}/${productMap[orderDetail.id].pictureUrl}" alt="" class="img-circle" style="max-width: 30px;"></td> <td>${productMap[orderDetail.id].name}</td> <td>${productMap[orderDetail.id].description}</td> <td>${productMap[orderDetail.id].price}</td> </tr> </c:forEach> </tbody> </table> <div style="display: flex; justify-content: flex-end; align-items: center; border-top:1px solid #333333"> <div style="color: red; font-size: 40px">总计:${order.price}</div> <c:if test="${order.status == '未付款'}"> <div style="margin: 0 200px 0 20px;"> <button type="button" class="btn btn-primary" id="pay">去付款</button> </div> </c:if> <c:if test="${order.status == '已付款'}"> <div style="margin: 0 200px 0 20px;"> 已付款完成 </div> </c:if> </div> </div> <!-- Jquery --> <script src="${pageContext.request.contextPath}/static/js/jquery-1.11.1.min.js"></script> <!-- Bootstrap --> <script src="${pageContext.request.contextPath}/static/js/bootstrap.min.js"></script> <script type="application/javascript"> $(function () { let token = sessionStorage.getItem("token") || null; // 验证是否存在token,没有则返回登陆 if (token == null) { alert("请先登陆!"); window.location = "${pageContext.request.contextPath}/login"; return false; } document.getElementById("backProduct").href = "${pageContext.request.contextPath}/product?token=" + token; $("#logout").click(function () { sessionStorage.removeItem("token"); window.location = "${pageContext.request.contextPath}/login" }); $("#pay").click(function () { $.ajax({ url: "${pageContext.request.contextPath}/order/update/${order.id}", success: function (data) { if(data === "ok"){ alert("付款成功!") window.location.reload(); return false; } alert("付款失败,请刷新重试!") }, error: function (err) { console.log(err); alert("服务器异常!") } }) }) }) </script> </body> </html>
个人全部订单
<%-- Created by IntelliJ IDEA. User: yangshixiong Date: 2020/1/29 Time: 下午11:10 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <html> <head> <title>${user.username}的订单</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content=""> <meta name="author" content="yang"> <!-- Bootstrap core CSS --> <link href="${pageContext.request.contextPath}/static/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <nav class="navbar navbar-default"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">杨的购物广场</a> </div> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li><a href="${pageContext.request.contextPath}/">回欢迎页</a></li> <li><a href="#" id="backProduct">返回商品列表</a></li> </ul> <ul class="nav navbar-nav navbar-right"> <li><a href="${pageContext.request.contextPath}/car/${user.id}">购物车</a></li> <li class="dropdown"> <img src="${pageContext.request.contextPath}/${user.avatarUrl}" alt="" style=" max-width: 30px; display: inline-block;"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" style="display: inline-block; padding-left: 3px;">${user.username}<span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="${pageContext.request.contextPath}/userinfo/${user.id}">个人信息</a></li> <li><a href="${pageContext.request.contextPath}/order/list/${user.id}">查看订单</a></li> <li id="logout"><a>退出</a></li> </ul> </li> </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> <c:forEach items="${orderList}" var="order"> <table class="table table-hover"> <caption>订单号:${order.id}</caption> <thead> <tr> <th>照片</th> <th>商品</th> <th>描述</th> <th>价格</th> </tr> </thead> <tbody> <c:forEach items="${orderMap[order.id]}" var="orderDetail"> <tr> <td><img src="${pageContext.request.contextPath}/${productMap[orderDetail.productId].pictureUrl}" alt="" class="img-circle" style="max-width: 30px;"></td> <td>${productMap[orderDetail.productId].name}</td> <td>${productMap[orderDetail.productId].description}</td> <td>${orderDetail.price}</td> </tr> </c:forEach> </tbody> </table> <div style="display: flex; justify-content: flex-end; align-items: center; border-top:1px solid #333333; height: 40px"> <div style="color: red; font-size: 20px">总计:${order.price}</div> <c:if test="${order.status == '未付款'}"> <div style="margin: 0 100px 0 20px;"> <button type="button" class="btn btn-primary" id="pay">去付款</button> </div> </c:if> <c:if test="${order.status == '已付款'}"> <div style="margin: 0 100px 0 20px;"> 已付款完成 </div> </c:if> </div> </c:forEach> <!-- Jquery --> <script src="${pageContext.request.contextPath}/static/js/jquery-1.11.1.min.js"></script> <!-- Bootstrap --> <script src="${pageContext.request.contextPath}/static/js/bootstrap.min.js"></script> <script type="application/javascript"> $(function () { let token = sessionStorage.getItem("token") || null; // 验证是否存在token,没有则返回登陆 if (token == null) { alert("请先登陆!"); window.location = "${pageContext.request.contextPath}/login"; return false; } document.getElementById("backProduct").href = "${pageContext.request.contextPath}/product?token=" + token; $("#logout").click(function () { sessionStorage.removeItem("token"); window.location = "${pageContext.request.contextPath}/login" }); }) </script> </body> </html>
这个入门的小项目基本完成,对springMVC基本操作有了一些简单认知,接下来开始学习mybatis。
这个小项目的源码在:GitHub