在购物车界面点击去结账,要实现三件事情,三个功能:
@Override
public void addOrderBean(OrderBean orderBean) {
int orderBeanId = super.executeUpdate("insert into t_order values(0,?,?,?,?,?)",orderBean.getOrderNo(),orderBean.getOrderDate(),orderBean.getOrderUser().getId(),orderBean.getOrderMoney(),orderBean.getOrderStatus());
orderBean.setId(orderBeanId);
}
思考: 此处为什么需要接受 executeUpdate 的返回值,然后设置到 OrderBean 中的 id 属性上?
if (insertFlag) {
rs = psmt.getGeneratedKeys();
if (rs.next()) {
return ((Long) rs.getLong(1)).intValue();
}
}
public class OrderItemDAOImpl extends BaseDAO<OrderItem> implements OrderItemDAO {
@Override
public void addOrderItem(OrderItem orderItem) {
super.executeUpdate("insert into t_order_item values(0,?,?,?)",orderItem.getBook().getId(),orderItem.getBuyCount(),orderItem.getOrderBean().getId()) ;
}
}
@Override
public void delCartItem(CartItem cartItem) {
super.executeUpdate("delete from t_cart_item where id = ?" , cartItem.getId());
}
addOrderBean(OrderBean orderBean)
方法,实现订单表中添加一条记录;addOrderItem(OrderItem orderItem)
方法,对应当前用户的当前订单,生成多条订单详情项;delCartItem(CartItem cartItem)
方法,将购物车中的这 N 项都删除了;public class OrderServiceImpl implements OrderService {
private OrderDAO orderDAO ;
private OrderItemDAO orderItemDAO ;
private CartItemDAO cartItemDAO ;
@Override
public void addOrderBean(OrderBean orderBean) {
//1) 订单表添加一条记录
//2) 订单详情表添加7条记录
//3) 购物车项表中需要删除对应的7条记录
//第1步:
orderDAO.addOrderBean(orderBean); //执行完这一步,orderBean中的id是有值的
//第2步:
//orderBean中的orderItemList是空的,此处我们应该根据用户的购物车中的购物车项去转换成一个一个的订单项
User currUser = orderBean.getOrderUser();
Map<Integer, CartItem> cartItemMap = currUser.getCart().getCartItemMap();
for(CartItem cartItem : cartItemMap.values()){
OrderItem orderItem = new OrderItem();
orderItem.setBook(cartItem.getBook());
orderItem.setBuyCount(cartItem.getBuyCount());
orderItem.setOrderBean(orderBean);
orderItemDAO.addOrderItem(orderItem);
}
//第3步:删除购物车每一项
for(CartItem cartItem : cartItemMap.values()){
cartItemDAO.delCartItem(cartItem);
}
}
}
解释:
addOrderItem(OrderItem orderItem)
方法中已经实现了属性设置;public class OrderController {
private OrderService orderService ;
//结账功能,就是生成一个订单,将所有的数据从session中获取或者新建之后set上去
public String checkout(HttpSession session){
OrderBean orderBean = new OrderBean() ;
LocalDateTime localDateTime = LocalDateTime.now();
int year = localDateTime.getYear();
int month = localDateTime.getMonth().getValue();
int day = localDateTime.getDayOfMonth();
int hour = localDateTime.getHour();
int min = localDateTime.getMinute();
int sec = localDateTime.getSecond();
//订单编号是32位全球唯一随机数+年月日时分秒
orderBean.setOrderNo(UUID.randomUUID().toString()+"_"+year+month+day+hour+min+sec);
orderBean.setOrderDate(localDateTime);
User user =(User)session.getAttribute("currUser");
orderBean.setOrderUser(user);
orderBean.setOrderMoney(user.getCart().getTotalMoney());
orderBean.setOrderStatus(0);
orderService.addOrderBean(orderBean);
return "index" ;
}
}
解释:
32 位全球唯一随机数+年月日时分秒
,这里对于新时间日期 LocalDataTime 的创建方法,参考java8 — 新日期时间API篇;th:href="@{/order.do(operate='checkout')}"
,这边是因为 thymeleaf 表达式对于 url 地址后面赋值可以用小括号括起来,即 (key='value')
的方式;解决方法:
解决方法:
return "cart/checkout" ;
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>结算页面title>
<link type="text/css" rel="stylesheet" th:href="@{/static/css/style.css}" >
<link rel="stylesheet" th:href="@{/static/css/minireset.css}" />
<link rel="stylesheet" th:href="@{/static/css/common.css}" />
<link rel="stylesheet" th:href="@{/static/css/cart.css}" />
<style type="text/css">
h1 {
text-align: center;
margin-top: 200px;
font-size: 26px;
}
.oid{
color: red;
font-weight: bolder;
}
style>
head>
<body>
<div class="header">
<div class="w">
<div class="header-left">
<a th:href="@{/index}">
<img th:src="@{/static/img/logo.gif}" alt=""/>a>
<span>我的购物车span>
div>
<div class="header-right">
<h3>欢迎<span th:text="${session.currUser.uname}">张总span>光临尚硅谷书城h3>
<div class="order"><a th:href="@{/order.do(operate='getOrderList')}">我的订单a>div>
<div class="destory"><a href="index.html">注销a>div>
<div class="gohome">
<a href="@{/page.do?operate=page&page=index}">返回a>
div>
div>
div>
div>
<div id="main">
<h1>你的订单已结算,订单号为:<span class="oid" th:text="${session.OrderNo}">546845626455846span>h1>
div>
<div id="bottom">
<span>
尚硅谷书城.Copyright ©2015
span>
div>
body>
html>
th:href="@{/order.do(operate='getOrderList')}"
;th:href="@{/order.do(operate='getOrderList')}"
;getOrderList(User user)
方法来查询订单列表功能;//查看订单列表
public String getOrderList(HttpSession session){
User user =(User)session.getAttribute("currUser");
List<OrderBean> orderList = orderService.getOrderList(user);
user.setOrderList(orderList);
session.setAttribute("currUser",user);
return "order/order" ;
}
使用 方法2 的实现:
getOrderList(User user)
获取数据库中所有的订单信息之外,还要调用 orderDAO 层的 getOrderTotalBookCount(OrderBean orderBean)
获取所有的图书数量信息;@Override
public List<OrderBean> getOrderList(User user) {
List<OrderBean> orderBeanList = orderDAO.getOrderList(user);
for (OrderBean orderBean: orderBeanList) {
Integer totalBookCount = orderDAO.getOrderTotalBookCount(orderBean);
orderBean.setTotalBookCount(totalBookCount);
}
return orderBeanList ;
}
@Override
public List<OrderBean> getOrderList(User user) {
return executeQuery("SELECT * FROM t_order WHERE orderUser = ?",user.getId());
}
@Override
public Integer getOrderTotalBookCount(OrderBean orderBean) {
String sql = "SELECT SUM(t3.buyCount) AS totalBookCount , t3.orderBean FROM " +
"(" +
"SELECT t1.id , t2.buyCount , t2.orderBean FROM t_order t1 INNER JOIN t_order_item t2 " +
"ON t1.id = t2.orderBean WHERE t1.orderUser = ? " +
") t3 WHERE t3.orderBean = ? GROUP BY t3.orderBean" ;
return ((BigDecimal)executeComplexQuery(sql,orderBean.getOrderUser().getId(),orderBean.getId())[0]).intValue();
}
解释:
user类
中新增 orderList
属性,并实现get/set
方法;BigDecimal
类型的,将类型强转成这个类之后再 intValue()
获取它的数值就可以了。th:xxx
;th:each="orderBean : ${session.currUser.orderList}" th:object="${orderBean}"
th:text="*{orderNo}"
th:text="*{orderDate}"
th:text="*{orderMoney}"
th:text="*{totalBookCount}"
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>我的订单title>
<link rel="stylesheet" th:href="@{/static/css/minireset.css}"/>
<link rel="stylesheet" th:href="@{/static/css/common.css}"/>
<link rel="stylesheet" th:href="@{/static/css/cart.css}"/>
<link rel="stylesheet" th:href="@{/static/css/bookManger.css}"/>
<link rel="stylesheet" th:href="@{/static/css/orderManger.css}"/>
<base th:href="@{/}">
head>
<body>
<div class="header">
<div class="w">
<div class="header-left">
<a href="../index.html">
<img th:src="@{/static/img/logo.gif}" alt=""/>a>
<h1>我的订单h1>
div>
<div class="header-right">
<h3>欢迎<span th:text="${session.currUser.uname}">张总span>光临尚硅谷书城h3>
<div class="order"><a th:href="@{/order.do(operate='getOrderList')}">我的订单a>div>
<div class="destory"><a href="../index.html">注销a>div>
<div class="gohome">
<a th:href="@{/page.do?operate=page&page=index}">返回a>
div>
div>
div>
div>
<div class="list">
<div class="w">
<table>
<thead>
<tr>
<th>订单号th>
<th>订单日期th>
<th>订单金额th>
<th>订单数量th>
<th>订单状态th>
<th>订单详情th>
tr>
thead>
<tbody>
<tr th:each="orderBean : ${session.currUser.orderList}" th:object="${orderBean}">
<td th:text="*{orderNo}">12354456895td>
<td th:text="*{orderDate}">2015.04.23td>
<td th:text="*{orderMoney}">90.00td>
<td th:text="*{totalBookCount}">88td>
<td><a href="" class="send">等待发货a>td>
<td><a href="">查看详情a>td>
tr>
tbody>
table>
<div class="footer">
<div class="footer-right">
<div>首页div>
<div>上一页div>
<ul>
<li class="active">1li>
<li>2li>
<li>3li>
ul>
<div>下一页div>
<div>末页div>
<span>共10页span>
<span>30条记录span>
<span>到第span>
<input type="text"/>
<span>页span>
<button>确定button>
div>
div>
div>
div>
<div class="bottom">
<div class="w">
<div class="top">
<ul>
<li>
<a href="">
<img th:src="static/img/bottom1.png" alt=""/>
<span>大咖级讲师亲自授课span>
a>
li>
<li>
<a href="">
<img src="static/img/bottom.png" alt=""/>
<span>课程为学员成长持续赋能span>
a>
li>
<li>
<a href="">
<img src="static/img/bottom2.png" alt=""/>
<span>学员真是情况大公开span>
a>
li>
ul>
div>
<div class="content">
<dl>
<dt>关于尚硅谷dt>
<dd>教育理念dd>
dl>
<dl>
<dt>资源下载dt>
<dd>视频下载dd>
dl>
<dl>
<dt>加入我们dt>
<dd>招聘岗位dd>
dl>
<dl>
<dt>联系我们dt>
<dd>http://www.atguigu.comdd>
<dd>dd>
dl>
div>
div>
<div class="down">
尚硅谷书城.Copyright ©2015
div>
div>
body>
html>
点击去结账:
Caused by: java.lang.NullPointerException: Cannot load from object array because the return value of "com.atguigu.book.dao.impl.OrderDAOImpl.executeComplexQuery(String, Object[])" is null
原因就是查询图书数量的时候,这里执行复杂查询返回的是 BigDecimal ,一个对象属性,当图书的数量为 0 的时候返回的就是 null;
解决方法:
OrderController 对应的修改:
//结账功能,就是生成一个订单,将所有的数据从session中获取或者新建之后set上去
public String checkout(HttpSession session){
User user =(User)session.getAttribute("currUser");
if (user.getCart().getTotalBookCount() == 0){
return "index";
}
OrderBean orderBean = new OrderBean() ;
LocalDateTime localDateTime = LocalDateTime.now();
int year = localDateTime.getYear();
int month = localDateTime.getMonth().getValue();
int day = localDateTime.getDayOfMonth();
int hour = localDateTime.getHour();
int min = localDateTime.getMinute();
int sec = localDateTime.getSecond();
//订单编号是32位全球唯一随机数+年月日时分秒
String orderNo = UUID.randomUUID().toString()+"_"+year+month+day+hour+min+sec;
orderBean.setOrderNo(orderNo);
session.setAttribute("OrderNo",orderNo);
orderBean.setOrderDate(localDateTime);
orderBean.setOrderUser(user);
orderBean.setOrderMoney(user.getCart().getTotalMoney());
orderBean.setOrderStatus(0);
orderService.addOrderBean(orderBean);
return "cart/checkout" ;
}
解释:
th:disabled="${}"
表达式是不可取的,因为 去结账 这个不是一个输入按钮,而是一个超链接,所以不能使用这个表达式来让它不可用。session
作用域中,也可以在形参上加 request 作用域,放到 request 作用域中(最好是这样,因为一个订单号一次请求有效,下次生成的是新的订单号了)。+
or -
会给服务端发送请求,用来改变当前这一项的数量,即修改 t_cart_item 中的 buyCount 数量;th:onclick="|editCart(${cartItem.id} , ${cartItem.buyCount-1})|"
,并且当th:disabled="${cartItem.buyCount == 1}"
,th:onclick="|editCart(${cartItem.id} , ${cartItem.buyCount+1})|"
<td>
<input class="count" value="-" th:onclick="|editCart(${cartItem.id},${cartItem.buyCount-1})|" th:disabled="${cartItem.buyCount == 1}">input>
<input class="count-num" type="text" value="1" th:value="${cartItem.buyCount}"/>
<span class="count" th:onclick="|editCart(${cartItem.id} , ${cartItem.buyCount+1})|">+span>
td>
解释:
||
代表字符串拼接,${}
表示里面有表达式;th:disabled
不起作用),只能触发一些动态功能,为了让它变成一个输入,我们将这个标签变成 input
。updateCartItem
方法;//编辑购物车中的图书数量功能
public String editCart(Integer cartItemId , Integer buyCount){
cartItemService.updateCartItem(new CartItem(cartItemId , buyCount));
return "redirect:cart.do";
}
解决方法:
.doubleValue()
转换成 Double 类型的数据。public Double getXj() {
BigDecimal bigDecimalPrice = new BigDecimal(""+getBook().getPrice());
BigDecimal bigDecimalBuyCount = new BigDecimal(""+buyCount);
BigDecimal bigDecimalXJ = bigDecimalPrice.multiply(bigDecimalBuyCount);
xj = bigDecimalXJ.doubleValue() ;
return xj;
}
getTotalMoney()
方法也要改成使用 BigDecimal 类型来计算;public Double getTotalMoney() {
totalMoney = 0.0;
BigDecimal bigDecimalTotalMoney = new BigDecimal("" + totalMoney);
//如果购物车中有东西,将购物车每一项从map中取出来,根据cartItem确定数的价格和购买的数量
if (cartItemMap != null && cartItemMap.size() > 0) {
Set<Map.Entry<Integer, CartItem>> entries = cartItemMap.entrySet();//取出购物车中的所有键值对
for (Map.Entry<Integer, CartItem> cartItemEntry : entries) {
CartItem cartItem = cartItemEntry.getValue();//每一个购物车项
Double xj = cartItem.getXj();
bigDecimalTotalMoney = bigDecimalTotalMoney.add(new BigDecimal("" + xj));
}
}
return bigDecimalTotalMoney.doubleValue();
}
最终效果:
解决方法:(使用过滤器和白名单)
@WebFilter(urlPatterns = {"*.do", "*.html"},
initParams = {
@WebInitParam(name = "bai",
value = "/page.do?operate=page&page=user/login," +
"/user.do?null," +
"/page.do?operate=page&page=user/regist," +
"/book.do?null")
})
public class SessionFilter implements Filter {
List<String> baiList = null;//放置所有的过滤器白名单
@Override
public void init(FilterConfig config) throws ServletException {
String bai = config.getInitParameter("bai");
String[] baiArr = bai.split(",");
baiList = Arrays.asList(baiArr);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//http://localhost:8080/page.do?operate=page&page=user/login
System.out.println("request.getRequestURI() = " + request.getRequestURI());// /page.do
System.out.println("request.getQueryString() = " + request.getQueryString());// operate=page&page=user/login
String uri = request.getRequestURI();
String queryString = request.getQueryString();
String str = uri + "?" + queryString;
//如果你请求的页面在白名单中
if (baiList.contains(str)) {
filterChain.doFilter(request, response);
} else {
HttpSession session = request.getSession();
Object currUserObj = session.getAttribute("currUser");
if (currUserObj == null) {
response.sendRedirect("page.do?operate=page&page=user/login");
} else {
filterChain.doFilter(request, response);
}
}
}
@Override
public void destroy() {}
}
解释:
doFilter
过滤方法中,如果请求在白名单中直接放行;currUser
键值对,也就是用户没有登录的情况下,非法操作跳转到登陆界面;CharacterEncodingFilter
字符过滤器还能生效的话,这个新的过滤器按字母排序要在 myssm 包之后,所以新建一个z字母开头的包;SessionFilter
要在 CharacterEncodingFilter
之后。