注意:
ORM 编程思想:(object relational mapping),有点万事万物皆对象那种意思
public class Book {
private Integer id ;
private String bookImg ;
private String bookName ;
private Double price ;
private String author ;
private Integer saleCount ; //销量
private Integer bookCount ; //库存
private Integer bookStatus = 0 ; //0:正常 -1:无效
public Book(){}
public Book(Integer id) {
this.id = id;
}
}
public class CartItem {
private Integer id ;
private Book book ;
private Integer buyCount ;
private User userBean ;
public CartItem(){}
public CartItem(Integer id) {
this.id = id;
}
}
public class OrderBean {
private Integer id ;
private String orderNo ;
private LocalDateTime orderDate;
private User orderUser ;
private Double orderMoney ;
private Integer orderStatus;
private List<OrderItem> orderItemList ; //1:N
public OrderBean(){}
public OrderBean(Integer id){
this.id= id;
}
}
public class OrderItem {
private Integer id ;
private Book book ; //M:1
private Integer buyCount ;
private OrderBean orderBean ; //M:1
public OrderItem(){}
public OrderItem(Integer id) {
this.id = id;
}
}
public class User {
private Integer id ;
private String uname ;
private String pwd ;
private String email;
private Integer role ;
private List<OrderBean> orderList ; //1:N
public User(){}
public User(Integer id) {
this.id = id;
}
}
applicationContext.xml 文件配置,上面 !DOCTYPE
这部分可写可不写,写了后面少依赖关系,会报错提醒,并且放置在 src 目录下(这里将所有后面所有要用到的配置都写上来,后面就不专门写配置文件这一步了):
DOCTYPE beans [
<!ELEMENT beans (bean*)>
<!ELEMENT bean (property*)>
<!ELEMENT property (#PCDATA)>
<!ATTLIST bean id ID #REQUIRED>
<!ATTLIST bean class CDATA #IMPLIED>
<!ATTLIST property name CDATA #IMPLIED>
<!ATTLIST property ref IDREF #IMPLIED>
]>
<beans>
<bean id="page" class="com.atguigu.myssm.myspringmvc.PageController"/>
<bean id="userDAO" class="com.atguigu.book.dao.impl.UserDAOImpl"/>
<bean id="bookDAO" class="com.atguigu.book.dao.impl.BookDAOImpl"/>
<bean id="cartItemDAO" class="com.atguigu.book.dao.impl.CartItemDAOImpl"/>
<bean id="orderDAO" class="com.atguigu.book.dao.impl.OrderDAOImpl"/>
<bean id="orderItemDAO" class="com.atguigu.book.dao.impl.OrderItemDAOImpl"/>
<bean id="userService" class="com.atguigu.book.service.impl.UserServiceImpl">
<property name="userDAO" ref="userDAO"/>
bean>
<bean id="bookService" class="com.atguigu.book.service.impl.BookServiceImpl">
<property name="bookDAO" ref="bookDAO"/>
bean>
<bean id="cartItemService" class="com.atguigu.book.service.impl.CartItemServiceImpl">
<property name="cartItemDAO" ref="cartItemDAO"/>
<property name="bookService" ref="bookService"/>
bean>
<bean id="orderService" class="com.atguigu.book.service.impl.OrderServiceImpl">
<property name="orderDAO" ref="orderDAO"/>
<property name="orderItemDAO" ref="orderItemDAO"/>
<property name="cartItemDAO" ref="cartItemDAO"/>
bean>
<bean id="user" class="com.atguigu.book.controller.UserController">
<property name="userService" ref="userService"/>
<property name="cartItemService" ref="cartItemService"/>
bean>
<bean id="book" class="com.atguigu.book.controller.BookController">
<property name="bookService" ref="bookService"/>
bean>
<bean id="cart" class="com.atguigu.book.controller.CartController">
<property name="cartItemService" ref="cartItemService"/>
bean>
<bean id="order" class="com.atguigu.book.controller.OrderController">
<property name="orderService" ref="orderService"/>
bean>
beans>
jdbc.properties 数据库连接配置,这里使用的是 Durid 数据库连接池:
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/bookdb?useUnicode=true&characterEncoding=utf-8&useSSL=false
username=root
password=abc123
# 初始化时建立物理连接的个数
initialSize=5
# 最大连接池数量
maxActive=10
# 最大等待时间
maxWait=3000
配置文件 web.xml ,因为我们将静态页面粘贴到 WEB-INF 界面下,所以文件中视图前缀改成 /WEB-INF/pages/
,:
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<context-param>
<param-name>view-prefixparam-name>
<param-value>/WEB-INF/pages/param-value>
context-param>
<context-param>
<param-name>view-suffixparam-name>
<param-value>.htmlparam-value>
context-param>
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>applicationContext.xmlparam-value>
context-param>
web-app>
th:href="@{/static/css/style.css}"
;th:action="@{/user.do}"
,并且要实现一个登陆方法
name="uname"
和 name="pwd"
;<div class="form">
<form th:action="@{/user.do}" method="post">
<input type="hidden" name="operate" value="login"/>
<label>用户名称:label>
<input class="itxt" type="text" placeholder="请输入用户名" autocomplete="off" tabindex="1"
name="uname" id="username" value="lina"/>
<br/>
<br/>
<label>用户密码:label>
<input class="itxt" type="password" placeholder="请输入密码" autocomplete="off" tabindex="1"
name="pwd" id="password" value="ok"/>
<br/>
<br/>
<input type="submit" value="登录" id="sub_btn"/>
form>
<div class="tit">
<a th:href="@{/page.do?operate=page&page=user/regist}">立即注册a>
div>
div>
public class UserController {
private UserService userService ;
private CartItemService cartItemService ;
//用户登陆验证
public String login(String uname , String pwd , HttpSession session){
User user = userService.login(uname, pwd);
if(user!=null){
session.setAttribute("currUser",user);
return "redirect:book.do";
}
//如果没有登陆成功,重新回到login登录页面
return "user/login";
}
}
解释:
userService
层中的登陆方法进行登陆验证;实现登陆验证 login 方法:
public class UserServiceImpl implements UserService {
private UserDAO userDAO ;
@Override
public User login(String uname, String pwd) {
return userDAO.getUser(uname,pwd);
}
}
实现 getUser 方法从数据库中获取用户名和密码信息:
public class UserDAOImpl extends BaseDAO<User> implements UserDAO {
@Override
public User getUser(String uname, String pwd) {
return load("select * from t_user where uname like ? and pwd like ? " , uname , pwd );
}
}
return "redirect:book.do";
重定向到 bookController
控制器中去做图书的相关控制;index
方法,所以我们在 bookController 控制器中新建 index 方法展示图书列表;th:each="book : ${session.bookList}"
;<div class="list-content">
<div href="" class="list-item" th:each="book : ${session.bookList}" th:object="${book}">
<img th:src="@{|/static/uploads/*{bookImg}|}" alt="">
<p th:text="|书名:*{bookName}|">书名:活着p>
<p th:text="|作者:*{author}|">作者:余华p>
<p th:text="|价格:¥*{price}|">价格:¥66.6p>
<p th:text="|销量:*{saleCount}|">销量:230p>
<p th:text="|库存:*{bookCount}|">库存:1000p>
<button th:onclick="|addCart(*{id})|">加入购物车button>
div>
div>
解释:
th:object="${book}"
;*{}
就可以了,比如调用 book 中的图片属性:th:src="@{|/static/uploads/*{bookImg}|}"
。public class BookController {
private BookService bookService ;
//在中央控制器中,如果没有发送operate默认index方法
public String index(HttpSession session){
List<Book> bookList = bookService.getBookList();
session.setAttribute("bookList",bookList);
return "index";
}
}
public class BookServiceImpl implements BookService {
private BookDAO bookDAO ;
@Override
public List<Book> getBookList() {
return bookDAO.getBookList();
}
}
public class BookDAOImpl extends BaseDAO<Book> implements BookDAO {
@Override
public List<Book> getBookList() {
return executeQuery("select * from t_book where bookStatus=0");
}
}
th:onclick="|addCart(*{id})|"
;<button th:onclick="|addCart(*{id})|">加入购物车button>
解释;
*{id}
是和上面衔接起来的,因为我们在整个图书列表的 div 块上定义了 th:object="${book}"
。function editCart(cartItemId , buyCount){
window.location.href='cart.do?operate=editCart&cartItemId='+cartItemId+"&buyCount="+buyCount;
}
public class CartItemDAOImpl extends BaseDAO<CartItem> implements CartItemDAO {
@Override
public void addCartItem(CartItem cartItem) {
executeUpdate("insert into t_cart_item values(0,?,?,?)",cartItem.getBook().getId(),cartItem.getBuyCount(),cartItem.getUserBean().getId());
}
@Override
public void updateCartItem(CartItem cartItem) {
executeUpdate("update t_cart_item set buyCount = ? where id = ? " , cartItem.getBuyCount(),cartItem.getId()) ;
}
}
Cart 类的实现,其中存放着购物车项,用来和其他类进行连接:
public class Cart {
private Map<Integer,CartItem> cartItemMap; //购物车中购物车项的集合 , 这个Map集合中的key是Book的id
private Double totalMoney ; //购物车的总金额
private Integer totalCount ; //购物车中购物项的数量,总共有多少项,而不是物品总件数
private Integer totalBookCount ; //购物车中书本的总数量,而不是购物车项的总数量
public Cart(){}
public Map<Integer, CartItem> getCartItemMap() {
return cartItemMap;
}
public void setCartItemMap(Map<Integer, CartItem> cartItemMap) {
this.cartItemMap = cartItemMap;
}
public Double getTotalMoney() {
totalMoney = 0.0;
//如果购物车中有东西,将购物车每一项从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();
totalMoney = totalMoney + cartItem.getBook().getPrice() * cartItem.getBuyCount() ;
}
}
return totalMoney;
}
public Integer getTotalCount() {
totalCount = 0 ;
if(cartItemMap!=null && cartItemMap.size()>0){
totalCount = cartItemMap.size() ;
}
return totalCount;
}
public Integer getTotalBookCount() {
totalBookCount = 0 ;
if(cartItemMap!=null && cartItemMap.size()>0){
for (CartItem cartItem : cartItemMap.values()){
totalBookCount = totalBookCount + cartItem.getBuyCount() ;//每一购物车项它的数量
}
}
return totalBookCount;
}
}
注意:
public class CartItemServiceImpl implements CartItemService {
private CartItemDAO cartItemDAO ;
private BookService bookService ;
@Override
public void addCartItem(CartItem cartItem) {
cartItemDAO.addCartItem(cartItem);
}
@Override
public void updateCartItem(CartItem cartItem) {
cartItemDAO.updateCartItem(cartItem);
}
@Override
public void addOrUpdateCartItem(CartItem cartItem, Cart cart) {
//判断当前用户的购物车中是否有这本书的CartItem,有->update , 无->add
if (cart != null) {
Map<Integer, CartItem> cartItemMap = cart.getCartItemMap();
//如果购物车中的购物车项为空,新建一个map
if (cartItemMap == null) {
cartItemMap = new HashMap<>();
}
//1.如果当前用户的购物车中已经存在这个图书了,那么将购物车中这本图书的数量+1
if (cartItemMap.containsKey(cartItem.getBook().getId())) {
CartItem cartItemTemp = cartItemMap.get(cartItem.getBook().getId());
cartItemTemp.setBuyCount(cartItemTemp.getBuyCount() + 1);
updateCartItem(cartItemTemp);
} else {
//2.否则,在我的购物车中新增一个这本图书的CartItem,数量是1
addCartItem(cartItem);
}
} else { //连购物车都没有的情况
addCartItem(cartItem);
}
}
}
解释:
cartItemMap.containsKey(cartItem.getBook().getId())
;public class CartController {
private CartItemService cartItemService ;
//加书到购物车中
public String addCart(Integer bookId , HttpSession session){
User user = (User)session.getAttribute("currUser");
CartItem cartItem = new CartItem(new Book(bookId),1,user);
//将指定的图书添加到当前用户的购物车中
cartItemService.addOrUpdateCartItem(cartItem,user.getCart());
//这里我们不要点击一本书就跳转到购物车,所以将这里的重定向页面改成index页面
// return "redirect:cart.do";
return "index";
}
}
public CartItem(Book book, Integer buyCount, User userBean) {
this.book = book;
this.buyCount = buyCount;
this.userBean = userBean;
}
Cannot open URL.Please check this URL is correct
,参考文献:IDEA启动项目报错:Cannot open URL.Please check this URL is correct,原因是过滤器部分的设置,先将那个包删掉。java.lang.NoSuchMethodException: java.lang.Double.(java.lang.Integer)
;发现是在 BaseDAO 中判断是否 isNotMyType 的时候,没有将 Double 类型设置上去,所以它默认会去找 Double 类型的构造器,要把它封装成一个 Double 对象,将这句话添加上去。BaseDAO 修改:
private static boolean isNotMyType(String typeName) {
return "java.lang.Integer".equals(typeName)
|| "java.lang.String".equals(typeName)
|| "java.util.Date".equals(typeName)
|| "java.sql.Date".equals(typeName)
|| "java.time.LocalDateTime".equals(typeName)
|| "java.lang.Double".equals(typeName);
}
th:if="${session.currUser==null}"
;th:text="${session.currUser.getUname()}"
;th:text="${session.currUser.cart.getTotalCount()}"
;<div class="topbar-right" th:if="${session.currUser==null}">
<a th:href="@{/page.do?operate=login&page=user/login}" class="login">登录a>
<a th:href="@{/page.do?operate=login&page=user/regist}" class="register">注册a>
<a href="cart/cart.html" class="cart iconfont icon-gouwuche">
购物车
<div class="cart-num">3div>
a>
<a href="manager/book_manager.html" class="admin">后台管理a>
div>
<div class="topbar-right" th:unless="${session.currUser==null}">
<span>欢迎你<b th:text="${session.currUser.getUname()}">张总b>span>
<a href="#" class="register">注销a>
<a th:href="@{/page.do(operate='page',page='cart/cart')}" class="cart iconfont icon-gouwuche">
购物车
<div class="cart-num" th:text="${session.currUser.cart.totalCount}">3div>
a>
<a href="./pages/manager/book_manager.html" class="admin">后台管理a>
div>
解释:
th:text="${session.currUser.cart.getTotalCount()}"
,也可以用 th:text="${session.currUser.cart.totalCount}"
,因为 thymeleaf 作为一个后端的组件,在调用这个属性的时候会自动的调用其中给的 get 方法。//加载当前用户的购物车信息
public String index(HttpSession session){
User user =(User)session.getAttribute("currUser");
Cart cart = cartItemService.getCart(user);
user.setCart(cart);
session.setAttribute("currUser",user);
return "cart/cart";
}
解释:
private Cart cart
,并且给它设置 get/set 方法。//用户登陆验证
public String login(String uname , String pwd , HttpSession session){
User user = userService.login(uname, pwd);
if(user!=null){
Cart cart = cartItemService.getCart(user);
user.setCart(cart);
session.setAttribute("currUser",user);
return "redirect:book.do";
}
//如果没有登陆成功,重新回到login登录页面
return "user/login";
}
@Override
public Cart getCart(User user) {
//拿到购物车项,我们需要将每一项放到一个map中,然后封装到购物车中
List<CartItem> cartItemList = cartItemDAO.getCartItemList(user);
Map<Integer, CartItem> cartItemMap = new HashMap<>();
for (CartItem cartItem : cartItemList) {
cartItemMap.put(cartItem.getBook().getId(), cartItem);
}
//如果当前用户的购物车项为空,那么我们cart也不为空,只不过map为空
Cart cart = new Cart();
cart.setCartItemMap(cartItemMap);
return cart;
}
解释:
@Override
public List<CartItem> getCartItemList(User user) {
return executeQuery("select * from t_cart_item where userBean = ? " , user.getId());
}
getCart(User user)
方法,我们之前已经创建过这个方法了;//加载当前用户的购物车信息
public String index(HttpSession session){
User user =(User)session.getAttribute("currUser");
Cart cart = cartItemService.getCart(user);
user.setCart(cart);
session.setAttribute("currUser",user);
return "cart/cart";
}
th:each="cartItem : ${session.currUser.cart.cartItemMap.values()}"
,表示从当前用户绑定的购物车中的购物车项 map 中获取它的 values 即那些 cartItem 项;th:src="@{|/static/uploads/${cartItem.book.bookImg}|}"
th:text="${cartItem.book.bookName}"
th:value="${cartItem.buyCount}"
th:text="${session.currUser.cart.totalBookCount}"
th:text="${session.currUser.cart.totalMoney}"
<table>
<tbody>
<tr th:each="cartItem : ${session.currUser.cart.cartItemMap.values()}">
<td>
<img th:src="@{|/static/uploads/${cartItem.book.bookImg}|}" alt=""/>
td>
<td th:text="${cartItem.book.bookName}">活着td>
<td>
<span class="count" >-span>
<input class="count-num" type="text" value="1" th:value="${cartItem.buyCount}"/>
<span class="count">+span>
td>
<td th:text="${cartItem.book.price}">36.8td>
<td><a href="">删除a>td>
tr>
tbody>
table>
<div class="footer">
<div class="footer-right">
<div>共<span th:text="${session.currUser.cart.totalBookCount}">3span>件商品div>
<div class="total-price">总金额<span th:text="${session.currUser.cart.totalMoney}">99.9span>元div>
<a class="pay" th:href="@{/order.do(operate='checkout')}">去结账a>
div>
div>
解决:
@Override
public List<CartItem> getCartItemList(User user) {
List<CartItem> cartItemList = cartItemDAO.getCartItemList(user);
for (CartItem cartItem : cartItemList) {
Book book = bookService.getBook(cartItem.getBook().getId());
cartItem.setBook(book);
}
return cartItemList;
}
@Override
public Book getBook(Integer id) {
return bookDAO.getBook(id);
}